124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
import React from 'react';
|
|
import { Shuffle, Grid, LayoutGrid, Plus, ZoomIn, Lock, Unlock, SlidersHorizontal } from 'lucide-react';
|
|
import { SyncStatus } from '../types';
|
|
|
|
interface BottomBarProps {
|
|
onShuffle?: () => void;
|
|
onToggleLayout?: () => void;
|
|
onTogglePen?: () => void;
|
|
onAddCard?: () => void;
|
|
onCycleZoom?: () => void;
|
|
onToggleLock?: () => void;
|
|
onOpenSettings?: () => void;
|
|
penActive?: boolean;
|
|
isGrid?: boolean;
|
|
zoomLevel?: number;
|
|
syncStatus?: SyncStatus;
|
|
isLocked?: boolean;
|
|
}
|
|
|
|
export const BottomBar: React.FC<BottomBarProps> = ({
|
|
onShuffle,
|
|
onToggleLayout,
|
|
onAddCard,
|
|
onCycleZoom,
|
|
onToggleLock,
|
|
onOpenSettings,
|
|
isGrid = false,
|
|
zoomLevel = 1.0,
|
|
syncStatus = 'synced',
|
|
isLocked = false
|
|
}) => {
|
|
return (
|
|
<>
|
|
{/* 1. Desktop: Keyboard hints */}
|
|
<footer className="fixed bottom-2 left-1/2 -translate-x-1/2 z-40 px-3.5 py-1 bg-black/60 text-neutral-400 rounded-full text-[11px] font-mono backdrop-blur-sm pointer-events-none select-none border border-white/5 hidden md:flex items-center gap-2 shadow-lg">
|
|
<span className="flex items-center gap-1.5">
|
|
<span
|
|
className={`w-1.5 h-1.5 rounded-full inline-block ${
|
|
syncStatus === 'synced'
|
|
? 'bg-emerald-400'
|
|
: syncStatus === 'syncing'
|
|
? 'bg-amber-400 animate-pulse'
|
|
: 'bg-neutral-500'
|
|
}`}
|
|
/>
|
|
<span className="capitalize">{syncStatus}</span>
|
|
</span>
|
|
<span className="text-neutral-600">·</span>
|
|
<span>drag anything</span>
|
|
<span className="text-neutral-600">·</span>
|
|
<span>flick to throw</span>
|
|
<span className="text-neutral-600">·</span>
|
|
<span>double-click to edit</span>
|
|
<span className="text-neutral-600">·</span>
|
|
<span className="text-neutral-300 font-semibold">L</span> {isLocked ? 'unlock' : 'lock'}
|
|
<span className="text-neutral-600">·</span>
|
|
<span className="text-neutral-300 font-semibold">S</span> shuffle
|
|
<span className="text-neutral-600">·</span>
|
|
<span className="text-neutral-300 font-semibold">G</span> grid
|
|
<span className="text-neutral-600">·</span>
|
|
<span className="text-neutral-300 font-semibold">N</span> new
|
|
<span className="text-neutral-600">·</span>
|
|
<span className="text-neutral-300 font-semibold">Space</span> scatter
|
|
</footer>
|
|
|
|
{/* 2. Mobile: Thumb-friendly floating dock */}
|
|
<footer className="fixed bottom-3 left-1/2 -translate-x-1/2 z-40 px-3 py-1.5 bg-[#1C1A17]/95 text-neutral-300 rounded-full shadow-2xl border border-neutral-700/80 backdrop-blur-md flex md:hidden items-center gap-2 select-none">
|
|
<button
|
|
onClick={onOpenSettings}
|
|
className="p-2 rounded-full bg-neutral-800 hover:bg-neutral-700 active:scale-95 text-amber-400 transition border border-neutral-700/60"
|
|
title="Workspaces & Settings"
|
|
>
|
|
<SlidersHorizontal size={15} />
|
|
</button>
|
|
|
|
<button
|
|
onClick={onToggleLock}
|
|
className={`p-2 rounded-full transition active:scale-95 ${
|
|
isLocked
|
|
? 'bg-amber-500 text-neutral-950 font-bold border border-amber-400 shadow-md'
|
|
: 'bg-neutral-800 text-neutral-300 hover:bg-neutral-700'
|
|
}`}
|
|
title={isLocked ? 'Desk Locked (Tap to Unlock)' : 'Desk Unlocked (Tap to Lock)'}
|
|
>
|
|
{isLocked ? <Lock size={15} /> : <Unlock size={15} />}
|
|
</button>
|
|
|
|
<button
|
|
onClick={onShuffle}
|
|
className="p-2 rounded-full bg-neutral-800 hover:bg-neutral-700 active:scale-95 text-neutral-200 transition"
|
|
title="Shuffle Desk"
|
|
>
|
|
<Shuffle size={15} />
|
|
</button>
|
|
|
|
<button
|
|
onClick={onToggleLayout}
|
|
className="p-2 rounded-full bg-neutral-800 hover:bg-neutral-700 active:scale-95 text-neutral-200 transition"
|
|
title="Toggle Grid / Scatter"
|
|
>
|
|
{isGrid ? <LayoutGrid size={15} className="text-amber-400" /> : <Grid size={15} />}
|
|
</button>
|
|
|
|
<button
|
|
onClick={onCycleZoom}
|
|
className="px-2 py-1.5 rounded-full bg-neutral-800 hover:bg-neutral-700 active:scale-95 text-neutral-200 transition font-mono text-[11px] flex items-center gap-1 border border-neutral-700"
|
|
title="Scale Desk (Tap to cycle zoom)"
|
|
>
|
|
<ZoomIn size={13} className="text-amber-400" />
|
|
<span>{Math.round(zoomLevel * 100)}%</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={onAddCard}
|
|
className="p-2 rounded-full bg-amber-500 hover:bg-amber-400 active:scale-95 text-neutral-950 font-bold transition shadow-md"
|
|
title="Add Note, Photo or Bookmark"
|
|
>
|
|
<Plus size={17} />
|
|
</button>
|
|
</footer>
|
|
</>
|
|
);
|
|
};
|