mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 06:19:33 -04:00
piping hot (main menu in footer) + border around panel toggle
This commit is contained in:
@@ -5,6 +5,7 @@ import { useSettings, setIsZen } from '../../settings.mjs';
|
||||
import { StrudelIcon } from '@src/repl/components/icons/StrudelIcon';
|
||||
import '../Repl.css';
|
||||
import { PanelToggle } from '@src/repl/components/panel/Panel';
|
||||
import { PlayIcon, StopIcon } from '@heroicons/react/16/solid';
|
||||
|
||||
const { BASE_URL } = import.meta.env;
|
||||
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
||||
@@ -17,15 +18,16 @@ export function Header({ context, isEmbedded = false }) {
|
||||
<header
|
||||
id="header"
|
||||
className={cx(
|
||||
'border-b border-muted flex-none text-black z-[100] text-sm select-none min-h-10',
|
||||
'border-b border-muted flex-none text-black z-[100] text-sm select-none min-h-10 max-h-10',
|
||||
!isZen && !isEmbedded && 'bg-lineHighlight',
|
||||
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full justify-between',
|
||||
// isZen ? 'h-12 w-8 fixed top-0 left-0' : 'h-10 sticky top-0 w-full justify-between',
|
||||
isZen ? 'h-12 w-8 fixed top-0 left-0' : '',
|
||||
'flex items-center',
|
||||
)}
|
||||
style={{ fontFamily }}
|
||||
>
|
||||
<div className={cx(isEmbedded ? 'flex' : 'sm:flex', 'w-full sm:justify-between')}>
|
||||
<div className="px-3 pt-1 flex space-x-2 sm:pt-0 select-none">
|
||||
<div className={cx('flex w-full flex-wrap justify-between')}>
|
||||
<div className="px-3 py-1 flex space-x-2 select-none">
|
||||
<h1
|
||||
onClick={() => {
|
||||
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
|
||||
@@ -56,59 +58,18 @@ export function Header({ context, isEmbedded = false }) {
|
||||
<div className="space-x-2">
|
||||
<span className="">strudel</span>
|
||||
<span className="text-sm font-medium">REPL</span>
|
||||
{!isEmbedded && isButtonRowHidden && (
|
||||
{/* !isEmbedded && isButtonRowHidden && (
|
||||
<a href={`${baseNoTrailing}/learn`} className="text-sm opacity-25 font-medium">
|
||||
DOCS
|
||||
</a>
|
||||
)}
|
||||
) */}
|
||||
</div>
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
{!isZen && !isButtonRowHidden && (
|
||||
<div className="flex max-w-full overflow-auto text-foreground px-3 h-10">
|
||||
<button
|
||||
onClick={handleTogglePlay}
|
||||
title={started ? 'stop' : 'play'}
|
||||
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-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />}
|
||||
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
|
||||
</span>
|
||||
) : (
|
||||
<>loading...</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleEvaluate}
|
||||
title="update"
|
||||
className={cx(
|
||||
'flex items-center space-x-1 px-2',
|
||||
!isDirty || !activeCode ? 'opacity-50' : 'hover:opacity-50',
|
||||
)}
|
||||
>
|
||||
{!isEmbedded && <span>update</span>}
|
||||
</button>
|
||||
{!isEmbedded && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 px-2')}
|
||||
onClick={handleShare}
|
||||
>
|
||||
<span>share</span>
|
||||
</button>
|
||||
)}
|
||||
{!isEmbedded && (
|
||||
<a
|
||||
title="learn"
|
||||
href={`${baseNoTrailing}/workshop/getting-started/`}
|
||||
className={cx('hover:opacity-50 flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
|
||||
>
|
||||
<span>learn</span>
|
||||
</a>
|
||||
)}
|
||||
<div className="flex grow justify-end">
|
||||
{/* <MainMenu isEmbedded={isEmbedded} context={context} /> */}
|
||||
<PanelToggle isEmbedded={isEmbedded} isZen={isZen} />
|
||||
</div>
|
||||
)}
|
||||
@@ -116,3 +77,60 @@ export function Header({ context, isEmbedded = false }) {
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export function Footer({ context, isEmbedded = false }) {
|
||||
return (
|
||||
<div className="border-t border-muted bg-lineHighlight">
|
||||
<MainMenu context={context} isEmbedded={isEmbedded} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MainMenu({ context, isEmbedded = false }) {
|
||||
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShare } = context;
|
||||
const { isCSSAnimationDisabled } = useSettings();
|
||||
return (
|
||||
<div className="flex text-sm max-w-full shrink-0 overflow-hidden text-foreground px-2 h-10">
|
||||
<button
|
||||
onClick={handleTogglePlay}
|
||||
title={started ? 'stop' : 'play'}
|
||||
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-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />} */}
|
||||
{started ? <StopIcon className="w-5 h-5" /> : <PlayIcon className="w-5 h-5" />}
|
||||
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
|
||||
</span>
|
||||
{/* ) : (
|
||||
<>loading...</>
|
||||
)} */}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleEvaluate}
|
||||
title="update"
|
||||
className={cx('flex items-center space-x-1 px-2', !isDirty || !activeCode ? 'opacity-50' : 'hover:opacity-50')}
|
||||
>
|
||||
{!isEmbedded && <span>update</span>}
|
||||
</button>
|
||||
{!isEmbedded && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 px-2')}
|
||||
onClick={handleShare}
|
||||
>
|
||||
<span>share</span>
|
||||
</button>
|
||||
)}
|
||||
{!isEmbedded && (
|
||||
<a
|
||||
title="learn"
|
||||
href={`${baseNoTrailing}/workshop/getting-started/`}
|
||||
className={cx('hover:opacity-50 flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
|
||||
>
|
||||
<span>learn</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Loader from '@src/repl/components/Loader';
|
||||
import { HorizontalPanel, VerticalPanel, PanelToggle } from '@src/repl/components/panel/Panel';
|
||||
import { Code } from '@src/repl/components/Code';
|
||||
import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage';
|
||||
import { Header } from './Header';
|
||||
import { Footer, Header } from './Header';
|
||||
import { useSettings } from '@src/settings.mjs';
|
||||
|
||||
// type Props = {
|
||||
@@ -23,9 +23,11 @@ export default function ReplEditor(Props) {
|
||||
<div className="flex flex-col grow overflow-hidden">
|
||||
<Header context={context} isEmbedded={isEmbedded} />
|
||||
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
|
||||
{/* <Footer context={context} isEmbedded={isEmbedded} /> */}
|
||||
</div>
|
||||
{!isZen && panelPosition === 'right' && <VerticalPanel context={context} />}
|
||||
</div>
|
||||
<Footer context={context} isEmbedded={isEmbedded} />
|
||||
<UserFacingErrorMessage error={error} />
|
||||
{!isZen && panelPosition === 'bottom' && <HorizontalPanel context={context} />}
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ function PanelCloseButton() {
|
||||
isPanelOpen && (
|
||||
<button
|
||||
onClick={() => setIsPanelOpened(false)}
|
||||
className={cx('px-2 py-0 text-foreground hover:opacity-50')}
|
||||
className={cx('border-l border-muted px-2 py-0 text-foreground hover:opacity-50')}
|
||||
aria-label="Close Menu"
|
||||
>
|
||||
<XMarkIcon className="w-6 h-6" />
|
||||
@@ -60,17 +60,17 @@ export function VerticalPanel({ context }) {
|
||||
<PanelNav
|
||||
settings={settings}
|
||||
className={cx(
|
||||
'border-l border-muted shrink-0',
|
||||
//'border-l border-muted shrink-0',
|
||||
'border-0 border-muted shrink-0',
|
||||
isPanelOpen ? `min-w-[min(600px,100vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12',
|
||||
)}
|
||||
>
|
||||
<div className={cx('flex flex-col h-full')}>
|
||||
<div className="flex justify-between w-full border-b border-muted">
|
||||
<div className="flex justify-between w-full border-b border-muted min-h-10 max-h-10">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelCloseButton />
|
||||
</div>
|
||||
|
||||
<div className="overflow-auto h-full">
|
||||
<div className="overflow-auto h-full border-l border-muted">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,7 +149,12 @@ function PanelTab({ label, isSelected, onClick }) {
|
||||
function Tabs({ className }) {
|
||||
const { isPanelOpen, activeFooter: tab } = useSettings();
|
||||
return (
|
||||
<div className={cx('w-full flex select-none max-w-full h-10 overflow-auto items-center', className)}>
|
||||
<div
|
||||
className={cx(
|
||||
'px-2 border-l border-muted w-full flex select-none max-w-full h-10 max-h-10 min-h-10 overflow-auto items-center',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{Object.keys(tabNames).map((key) => {
|
||||
const val = tabNames[key];
|
||||
return <PanelTab key={key} isSelected={tab === val && isPanelOpen} label={key} onClick={() => setTab(val)} />;
|
||||
@@ -166,13 +171,11 @@ export function PanelToggle({ isEmbedded, isZen }) {
|
||||
panelPosition === 'right' && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx(
|
||||
'ml-4 rounded-0 cursor-pointer hover:opacity-80 flex justify-center items-center space-x-1 text-foreground ',
|
||||
isPanelOpen && 'hidden',
|
||||
)}
|
||||
className={cx('border-l border-muted px-2 py-0 text-foreground hover:opacity-50', isPanelOpen && 'hidden')}
|
||||
onClick={() => setIsPanelOpened(!isPanelOpen)}
|
||||
>
|
||||
<Bars3Icon className="w-5 h-5" />
|
||||
{/* <span>menu</span> */}
|
||||
<Bars3Icon className="w-6 h-6" />
|
||||
</button>
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user