109 lines
4.9 KiB
TypeScript
109 lines
4.9 KiB
TypeScript
import { type Component, For } from "solid-js";
|
|
import { LayoutDashboard, ListTodo, Settings, Clock, ArrowUpCircle, PanelLeftClose } from "lucide-solid";
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "./ui/button";
|
|
|
|
interface NavItem {
|
|
icon: any;
|
|
label: string;
|
|
view: string;
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{ icon: ListTodo, label: "Focus", view: "critical" },
|
|
{ icon: Clock, label: "Time", view: "urgency" },
|
|
{ icon: ArrowUpCircle, label: "Priority", view: "priority" },
|
|
{ icon: LayoutDashboard, label: "Matrix", view: "matrix" },
|
|
{ icon: Settings, label: "Settings", view: "settings" },
|
|
];
|
|
|
|
export const BottomNav: Component<{ currentView: string; setView: (v: string) => void }> = (props) => {
|
|
return (
|
|
<nav class="fixed bottom-0 left-0 right-0 bg-background border-t border-border flex justify-around items-center h-16 md:hidden z-50">
|
|
<For each={navItems}>
|
|
{(item) => (
|
|
<button
|
|
onClick={() => props.setView(item.view)}
|
|
class={cn(
|
|
"flex flex-col items-center justify-center w-full h-full space-y-1 transition-colors",
|
|
props.currentView === item.view ? "text-primary" : "text-muted-foreground"
|
|
)}
|
|
>
|
|
<item.icon size={20} />
|
|
<span class="text-[10px] font-medium uppercase tracking-wider">{item.label}</span>
|
|
</button>
|
|
)}
|
|
</For>
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
export const Sidebar: Component<{
|
|
currentView: string;
|
|
setView: (v: string) => void;
|
|
isLocked: boolean;
|
|
setIsLocked: (v: boolean) => void;
|
|
isPeeking: boolean;
|
|
setIsPeeking: (v: boolean) => void;
|
|
}> = (props) => {
|
|
return (
|
|
<aside
|
|
onMouseEnter={() => !props.isLocked && props.setIsPeeking(true)}
|
|
onMouseLeave={() => !props.isLocked && props.setIsPeeking(false)}
|
|
class={cn(
|
|
"hidden md:flex flex-col border-r border-border bg-card h-screen fixed left-0 top-0 transition-all duration-300 ease-in-out z-[50]",
|
|
props.isLocked ? "w-48 translate-x-0" : "w-48 -translate-x-full",
|
|
!props.isLocked && props.isPeeking && "translate-x-0 shadow-2xl ring-1 ring-border"
|
|
)}
|
|
>
|
|
<div class={cn("p-4 flex items-center justify-between", !props.isLocked && "pl-14")}>
|
|
<h1 class="text-xl font-bold tracking-tighter text-primary px-2">Tasgrid</h1>
|
|
{/* Close Button - Only visible when Locked (to collapse) or Peeking (manual close) */}
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
class="h-8 w-8 text-muted-foreground hover:text-foreground"
|
|
onClick={() => {
|
|
props.setIsLocked(false);
|
|
props.setIsPeeking(false);
|
|
}}
|
|
>
|
|
<PanelLeftClose size={16} />
|
|
</Button>
|
|
</div>
|
|
<nav class="flex-1 px-3 space-y-1 mt-2">
|
|
<For each={navItems.filter(i => i.view !== "settings")}>
|
|
{(item) => (
|
|
<button
|
|
onClick={() => props.setView(item.view)}
|
|
class={cn(
|
|
"flex items-center space-x-3 w-full px-3 py-2.5 rounded-lg transition-all duration-200 group text-sm",
|
|
props.currentView === item.view
|
|
? "bg-primary text-primary-foreground shadow-sm"
|
|
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
)}
|
|
>
|
|
<item.icon size={16} class={cn("transition-transform group-hover:scale-110")} />
|
|
<span class="font-medium">{item.label}</span>
|
|
</button>
|
|
)}
|
|
</For>
|
|
</nav>
|
|
<div class="p-3 border-t border-border mt-auto">
|
|
<button
|
|
onClick={() => props.setView("settings")}
|
|
class={cn(
|
|
"flex items-center space-x-3 w-full px-3 py-2.5 rounded-lg transition-all duration-200 group text-sm",
|
|
props.currentView === "settings"
|
|
? "bg-primary text-primary-foreground shadow-sm"
|
|
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
)}
|
|
>
|
|
<Settings size={16} class={cn("transition-transform group-hover:scale-110")} />
|
|
<span class="font-medium">Settings</span>
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
);
|
|
};
|