proper strudel icon + toggle menu from top bar

This commit is contained in:
Felix Roos
2026-01-20 22:13:03 +01:00
parent 7e34069021
commit 83d542d06a
3 changed files with 48 additions and 72 deletions
+21 -44
View File
@@ -1,8 +1,10 @@
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon';
import cx from '@src/cx.mjs';
import { useSettings, setIsZen } from '../../settings.mjs';
import { useSettings, setIsZen, setIsPanelOpened } from '../../settings.mjs';
import { StrudelIcon } from '@src/repl/components/icons/StrudelIcon';
import '../Repl.css';
import { Bars3Icon } from '@heroicons/react/16/solid';
const { BASE_URL } = import.meta.env;
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
@@ -11,13 +13,13 @@ export function Header({ context, embedded = false }) {
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } =
context;
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily } = useSettings();
const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily, isPanelOpen } = useSettings();
return (
<header
id="header"
className={cx(
'flex-none text-black z-[100] text-lg select-none h-20 md:h-14',
'flex-none text-black z-[100] text-lg select-none h-10',
!isZen && !isEmbedded && 'bg-lineHighlight',
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full py-1 justify-between',
isEmbedded ? 'flex' : 'md:flex',
@@ -47,7 +49,9 @@ export function Header({ context, embedded = false }) {
}
}}
>
<span className="block text-foreground rotate-90"></span>
<span className="block text-foreground rotate-90">
<StrudelIcon className="w-5 h-5 fill-foreground" />
</span>
</div>
{!isZen && (
<div className="space-x-2">
@@ -63,19 +67,15 @@ export function Header({ context, embedded = false }) {
</h1>
</div>
{!isZen && !isButtonRowHidden && (
<div className="flex max-w-full overflow-auto text-foreground px-1 md:px-2">
<div className="flex max-w-full overflow-auto text-foreground px-2">
<button
onClick={handleTogglePlay}
title={started ? 'stop' : 'play'}
className={cx(
!isEmbedded ? 'p-2' : 'px-2',
'hover:opacity-50',
!started && !isCSSAnimationDisabled && 'animate-pulse',
)}
className={cx('px-2 hover:opacity-50', !started && !isCSSAnimationDisabled && 'animate-pulse')}
>
{!pending ? (
<span className={cx('flex items-center space-x-2')}>
{started ? <StopCircleIcon className="w-6 h-6" /> : <PlayCircleIcon className="w-6 h-6" />}
{started ? <StopCircleIcon className="w-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />}
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
</span>
) : (
@@ -86,29 +86,16 @@ export function Header({ context, embedded = false }) {
onClick={handleEvaluate}
title="update"
className={cx(
'flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2',
'flex items-center space-x-1 px-2',
!isDirty || !activeCode ? 'opacity-50' : 'hover:opacity-50',
)}
>
{!isEmbedded && <span>update</span>}
</button>
{/* !isEmbedded && (
<button
title="shuffle"
className="hover:opacity-50 p-2 flex items-center space-x-1"
onClick={handleShuffle}
>
<span> shuffle</span>
</button>
) */}
{!isEmbedded && (
<button
title="share"
className={cx(
'cursor-pointer hover:opacity-50 flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2',
)}
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 px-2')}
onClick={handleShare}
>
<span>share</span>
@@ -123,26 +110,16 @@ export function Header({ context, embedded = false }) {
<span>learn</span>
</a>
)}
{/* {isEmbedded && (
<button className={cx('hover:opacity-50 px-2')}>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
🚀
</a>
{!isEmbedded && (
<button
title="share"
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 px-2')}
onClick={() => setIsPanelOpened(!isPanelOpen)}
>
<span>menu</span>
<Bars3Icon className="w-5 h-5" />
</button>
)}
{isEmbedded && (
<button className={cx('hover:opacity-50 px-2')}>
<a
onClick={() => {
window.location.href = initialUrl;
window.location.reload();
}}
title="Reset"
>
💔
</a>
</button>
)} */}
</div>
)}
</header>
@@ -0,0 +1,13 @@
// Source: https://commons.wikimedia.org/wiki/File:CHAM_PUNCTUATION_SPIRAL.svg
// License: SIL Open Font License, Version 1.1. The license text is available at https://openfontlicense.org/open-font-license-official-text/
export function StrudelIcon({ className = '' }) {
return (
<svg className={className} width="100%" height="100%" viewBox="0 0 213 213">
<g>
<g id="_1" serif:id="1">
<path d="M199.905,102.467c-0,17.959 -3.695,33.45 -11.078,46.468c-7.369,13.024 -17.9,23.079 -31.586,30.173c-13.673,7.093 -29.994,10.64 -48.961,10.64c-19.964,0 -37.183,-3.874 -51.66,-11.617c-14.482,-7.749 -25.592,-18.775 -33.334,-33.103c-7.749,-14.322 -11.617,-31.407 -11.617,-51.248l17.143,-0c-0,16.95 3.187,31.503 9.561,43.666c6.373,12.15 15.485,21.48 27.346,27.989c11.874,6.509 26.061,9.766 42.561,9.766c15.485,0 28.798,-2.898 39.94,-8.687c11.154,-5.789 19.693,-14.11 25.624,-24.956c5.943,-10.858 8.918,-23.812 8.918,-38.86c-0,-20.85 -5.5,-37.202 -16.5,-49.063c-11,-11.874 -26.344,-17.811 -46.031,-17.811c-17.515,-0 -31.266,4.883 -41.251,14.649c-9.991,9.767 -14.983,23.337 -14.983,40.711c-0,15.781 4.015,28.13 12.054,37.035c8.031,8.893 19.07,13.339 33.103,13.339c12.452,0 22.186,-3.431 29.196,-10.306c7.023,-6.888 10.538,-16.333 10.538,-28.348c-0,-10.281 -2.57,-18.415 -7.711,-24.416c-5.14,-6.014 -12.413,-9.021 -21.82,-9.021c-7.813,-0 -13.93,2.178 -18.351,6.528c-4.407,4.337 -6.605,10.197 -6.605,17.579c0,1.44 0.064,2.815 0.206,4.112c4.485,-7.363 11.141,-11.051 19.97,-11.051c5.5,-0 9.875,1.561 13.133,4.678c3.27,3.103 4.909,7.324 4.909,12.67c-0,5.796 -1.966,10.506 -5.886,14.136c-3.906,3.617 -9.265,5.423 -16.063,5.423c-8.533,-0 -15.337,-2.814 -20.407,-8.456c-5.076,-5.654 -7.607,-13.114 -7.607,-22.386c-0,-11.135 3.431,-19.957 10.306,-26.472c6.888,-6.528 16.121,-9.792 27.706,-9.792c13.467,0 24.03,4.164 31.689,12.491c7.672,8.327 11.515,19.584 11.515,33.771c-0,16.057 -4.884,28.753 -14.65,38.089c-9.767,9.343 -23.195,14.008 -40.274,14.008c-12.594,-0 -23.491,-2.603 -32.692,-7.814c-9.188,-5.204 -16.243,-12.625 -21.178,-22.257c-4.921,-9.625 -7.376,-21.023 -7.376,-34.182c0,-14.342 2.93,-26.64 8.79,-36.907c5.873,-10.281 14.271,-18.203 25.187,-23.774c10.93,-5.584 23.928,-8.379 38.989,-8.379c16.359,0 30.469,3.258 42.33,9.767c11.874,6.515 20.985,15.819 27.346,27.911c6.374,12.08 9.561,26.518 9.561,43.307Zm-86.408,-6.939c-7.235,-0 -11.867,4.491 -13.904,13.467c2.756,3.033 6.528,4.549 11.308,4.549c7.659,0 11.489,-3.11 11.489,-9.329c-0,-2.757 -0.797,-4.89 -2.39,-6.4c-1.581,-1.523 -3.746,-2.287 -6.503,-2.287Z" />
</g>
</g>
</svg>
);
}
+14 -28
View File
@@ -42,36 +42,24 @@ export function HorizontalPanel({ context }) {
export function VerticalPanel({ context }) {
const settings = useSettings();
const { activeFooter: tab, isPanelOpen } = settings;
if (!isPanelOpen) {
return;
}
return (
<PanelNav
settings={settings}
className={cx(isPanelOpen ? `min-w-[min(600px,80vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12')}
>
{isPanelOpen ? (
<div className={cx('flex flex-col h-full')}>
<div className="flex justify-between w-full ">
<Tabs setTab={setTab} tab={tab} />
<PanelActionButton settings={settings} />
</div>
<div className="overflow-auto h-full">
<PanelContent context={context} tab={tab} />
</div>
<div className={cx('flex flex-col h-full')}>
<div className="flex justify-between w-full ">
<Tabs setTab={setTab} tab={tab} />
<PanelActionButton settings={settings} />
</div>
) : (
<button
onClick={(e) => {
setIsPanelOpened(true);
}}
aria-label="open menu panel"
className={cx(
'flex flex-col hover:bg-lineBackground items-center cursor-pointer justify-center w-full h-full',
)}
>
<ChevronLeftIcon className="text-foreground opacity-50 w-6 h-6" />
</button>
)}
<div className="overflow-auto h-full">
<PanelContent context={context} tab={tab} />
</div>
</div>
</PanelNav>
);
}
@@ -207,12 +195,10 @@ function CloseButton({ onClick }) {
return (
<button
onClick={onClick}
className={cx(
'text-foreground max-h-8 min-h-8 max-w-8 min-w-8 items-center justify-center p-1.5 group-hover:flex',
)}
className={cx('text-foreground max-h-8 min-h-8 max-w-8 min-w-8 items-center justify-center p-0 mr-2')}
aria-label="Close Menu"
>
<XMarkIcon />
<XMarkIcon className="w-7 h-7" />
</button>
);
}