remove panel hover + optimize bottom panel
This commit is contained in:
parent
4f14ff00d5
commit
60b5024f63
5 changed files with 121 additions and 138 deletions
|
|
@ -13,115 +13,122 @@ 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, isPanelOpen } = useSettings();
|
||||
const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily, isPanelOpen, panelPosition } = useSettings();
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header"
|
||||
className={cx(
|
||||
'flex-none text-black z-[100] text-sm select-none min-h-10',
|
||||
'flex-none text-black z-[100] text-sm select-none min-h-10',
|
||||
!isZen && !isEmbedded && 'bg-lineHighlight',
|
||||
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full justify-between',
|
||||
isEmbedded ? 'flex' : 'sm:flex',
|
||||
'flex items-center',
|
||||
)}
|
||||
style={{ fontFamily }}
|
||||
>
|
||||
<div className="px-4 pt-1 flex space-x-2 md:pt-0 select-none">
|
||||
<h1
|
||||
onClick={() => {
|
||||
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
|
||||
}}
|
||||
className={cx(
|
||||
isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
|
||||
'text-foreground font-bold flex space-x-2 items-center',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
'mt-[1px]',
|
||||
started && !isCSSAnimationDisabled && 'animate-spin',
|
||||
'cursor-pointer text-blue-500',
|
||||
isZen && 'fixed top-2 right-4',
|
||||
)}
|
||||
<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">
|
||||
<h1
|
||||
onClick={() => {
|
||||
if (!isEmbedded) {
|
||||
setIsZen(!isZen);
|
||||
}
|
||||
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
|
||||
}}
|
||||
>
|
||||
<span className="block text-foreground rotate-90">
|
||||
<StrudelIcon className="w-5 h-5 fill-foreground" />
|
||||
</span>
|
||||
</div>
|
||||
{!isZen && (
|
||||
<div className="space-x-2">
|
||||
<span className="">strudel</span>
|
||||
<span className="text-sm font-medium">REPL</span>
|
||||
{!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-2 h-10 justify-end">
|
||||
<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 ? 'text-l cursor-pointer' : 'text-xl',
|
||||
'text-foreground font-bold flex space-x-2 items-center',
|
||||
)}
|
||||
>
|
||||
{!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}
|
||||
<div
|
||||
className={cx(
|
||||
'mt-[1px]',
|
||||
started && !isCSSAnimationDisabled && 'animate-spin',
|
||||
'cursor-pointer text-blue-500',
|
||||
isZen && 'fixed top-2 right-4',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!isEmbedded) {
|
||||
setIsZen(!isZen);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
)}
|
||||
{!isEmbedded && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 pl-2 pr-1')}
|
||||
onClick={() => setIsPanelOpened(!isPanelOpen)}
|
||||
>
|
||||
<span>menu</span>
|
||||
<Bars3Icon className="w-5 h-5" />
|
||||
</button>
|
||||
)}
|
||||
<span className="block text-foreground rotate-90">
|
||||
<StrudelIcon className="w-5 h-5 fill-foreground" />
|
||||
</span>
|
||||
</div>
|
||||
{!isZen && (
|
||||
<div className="space-x-2">
|
||||
<span className="">strudel</span>
|
||||
<span className="text-sm font-medium">REPL</span>
|
||||
{!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('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>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{!isEmbedded && !isZen && panelPosition === 'right' && (
|
||||
<button
|
||||
title="share"
|
||||
className={cx(
|
||||
'cursor-pointer hover:opacity-50 flex items-center space-x-1 pr-3 text-foreground',
|
||||
// isPanelOpen && 'opacity-0',
|
||||
)}
|
||||
onClick={() => setIsPanelOpened(!isPanelOpen)}
|
||||
>
|
||||
{/* <span>menu</span> */}
|
||||
<Bars3Icon className="w-5 h-5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,27 +14,25 @@ import ExportTab from './ExportTab';
|
|||
const TAURI = typeof window !== 'undefined' && window.__TAURI__;
|
||||
|
||||
export function HorizontalPanel({ context }) {
|
||||
const settings = useSettings();
|
||||
const { isPanelOpen, activeFooter: tab } = settings;
|
||||
|
||||
const { isPanelOpen, activeFooter: tab } = useSettings();
|
||||
return (
|
||||
<PanelNav
|
||||
settings={settings}
|
||||
className={cx(isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-12 max-h-12', 'overflow-hidden flex flex-col')}
|
||||
className={cx(
|
||||
isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-10 max-h-10',
|
||||
'overflow-hidden flex flex-col relative ',
|
||||
)}
|
||||
>
|
||||
<div className="flex justify-between min-h-10 max-h-10 grid-cols-2 items-center">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
</div>
|
||||
<div className="absolute right-0 top-1">
|
||||
<PanelActionButton />
|
||||
</div>
|
||||
{isPanelOpen && (
|
||||
<div className="flex h-full overflow-auto pr-10 ">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="absolute right-4 pt-4">
|
||||
<PanelActionButton settings={settings} />
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between min-h-12 max-h-12 grid-cols-2 items-center">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
</div>
|
||||
</PanelNav>
|
||||
);
|
||||
}
|
||||
|
|
@ -53,7 +51,7 @@ export function VerticalPanel({ context }) {
|
|||
<div className={cx('flex flex-col h-full')}>
|
||||
<div className="flex justify-between w-full ">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelActionButton settings={settings} />
|
||||
{/* <PanelActionButton settings={settings} /> */}
|
||||
</div>
|
||||
|
||||
<div className="overflow-auto h-full">
|
||||
|
|
@ -77,8 +75,8 @@ if (TAURI) {
|
|||
tabNames.files = 'files';
|
||||
}
|
||||
|
||||
function PanelNav({ children, className, settings, ...props }) {
|
||||
const isHoverBehavior = settings.togglePanelTrigger === 'hover';
|
||||
function PanelNav({ children, className, ...props }) {
|
||||
const settings = useSettings();
|
||||
return (
|
||||
<nav
|
||||
onClick={() => {
|
||||
|
|
@ -86,16 +84,6 @@ function PanelNav({ children, className, settings, ...props }) {
|
|||
setIsPanelOpened(true);
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (isHoverBehavior && !settings.isPanelOpen) {
|
||||
setIsPanelOpened(true);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (isHoverBehavior && !settings.isPanelPinned) {
|
||||
setIsPanelOpened(false);
|
||||
}
|
||||
}}
|
||||
aria-label="Menu Panel"
|
||||
className={cx('bg-lineHighlight group overflow-x-auto', className)}
|
||||
{...props}
|
||||
|
|
@ -142,27 +130,24 @@ function PanelTab({ label, isSelected, onClick }) {
|
|||
</>
|
||||
);
|
||||
}
|
||||
function Tabs({ setTab, tab, className }) {
|
||||
function Tabs({ className }) {
|
||||
const { isPanelOpen, activeFooter: tab } = useSettings();
|
||||
return (
|
||||
<div className={cx('flex select-none max-w-full overflow-auto pb-2', className)}>
|
||||
{Object.keys(tabNames).map((key) => {
|
||||
const val = tabNames[key];
|
||||
return <PanelTab key={key} isSelected={tab === val} label={key} onClick={() => setTab(val)} />;
|
||||
return <PanelTab key={key} isSelected={tab === val && isPanelOpen} label={key} onClick={() => setTab(val)} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PanelActionButton({ settings }) {
|
||||
const { togglePanelTrigger, isPanelPinned, isPanelOpen } = settings;
|
||||
const isHoverBehavior = togglePanelTrigger === 'hover';
|
||||
function PanelActionButton() {
|
||||
const settings = useSettings();
|
||||
const { isPanelOpen } = settings;
|
||||
if (!isPanelOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHoverBehavior) {
|
||||
return <PinButton pinned={isPanelPinned} />;
|
||||
}
|
||||
return <CloseButton onClick={() => setIsPanelOpened(false)} />;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ export function SettingsTab({ started }) {
|
|||
panelPosition,
|
||||
audioDeviceName,
|
||||
audioEngineTarget,
|
||||
togglePanelTrigger,
|
||||
maxPolyphony,
|
||||
multiChannelOrbits,
|
||||
isTabIndentationEnabled,
|
||||
|
|
@ -256,13 +255,6 @@ export function SettingsTab({ started }) {
|
|||
items={{ bottom: 'Bottom', right: 'Right' }}
|
||||
></ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem label="Open Panel on: ">
|
||||
<ButtonGroup
|
||||
value={togglePanelTrigger}
|
||||
onChange={(value) => settingsMap.setKey('togglePanelTrigger', value)}
|
||||
items={{ click: 'Click', hover: 'Hover' }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="More Settings">
|
||||
<Checkbox
|
||||
label="Enable bracket matching"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export function WelcomeTab({ context }) {
|
|||
const { fontFamily } = useSettings();
|
||||
return (
|
||||
<div className="prose dark:prose-invert min-w-full pt-2 font-sans pb-8 px-4 " style={{ fontFamily }}>
|
||||
<h3>꩜ welcome</h3>
|
||||
<h3>welcome</h3>
|
||||
<p>
|
||||
You have found <span className="underline">strudel</span>, a new live coding platform to write dynamic music
|
||||
pieces in the browser! It is free and open-source and made for beginners and experts alike. To get started:
|
||||
|
|
@ -30,7 +30,7 @@ export function WelcomeTab({ context }) {
|
|||
</a>{' '}
|
||||
to ask any questions, give feedback or just say hello.
|
||||
</p>
|
||||
<h3>꩜ about</h3>
|
||||
<h3>about</h3>
|
||||
<p>
|
||||
strudel is a JavaScript version of{' '}
|
||||
<a href="https://tidalcycles.org/" target="_blank">
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ export const defaultSettings = {
|
|||
panelPosition: 'right',
|
||||
isPanelPinned: false,
|
||||
isPanelOpen: true,
|
||||
togglePanelTrigger: 'click', //click | hover
|
||||
userPatterns: '{}',
|
||||
prebakeScript: '',
|
||||
audioEngineTarget: audioEngineTargets.webaudio,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue