Files
TasGrid/src/components/Layout.tsx
T

95 lines
3.8 KiB
TypeScript

import { type Component, type JSX, createSignal, Show, lazy, Suspense, onMount } from "solid-js";
import { Sidebar, BottomNav } from "./Navigation";
import { store, activeTaskId, setActiveTaskId } from "@/store";
import { PanelLeftOpen } from "lucide-solid";
const TaskDetail = lazy(() => import("./TaskDetail").then(m => ({ default: m.TaskDetail })));
const QuickEntry = lazy(() => import("./QuickEntry").then(m => ({ default: m.QuickEntry })));
import { Button } from "./ui/button";
import { cn } from "@/lib/utils";
import { FilterBar } from "./FilterBar";
interface LayoutProps {
children: JSX.Element;
currentView: string;
setView: (v: string) => void;
}
export const Layout: Component<LayoutProps> = (props) => {
const [isSidebarLocked, setIsSidebarLocked] = createSignal(true);
const [isSidebarPeeking, setIsSidebarPeeking] = createSignal(false);
onMount(() => {
// Preload heavy components in background when idle
const idleCallback = (window as any).requestIdleCallback || ((cb: any) => setTimeout(cb, 2000));
idleCallback(() => {
import("./TaskDetail");
import("./QuickEntry");
import("./TaskEditor");
});
});
// Derived active task for the detail view
const activeTask = () => store.tasks.find(t => t.id === activeTaskId());
return (
<div class="flex h-screen w-full min-w-0 bg-background overflow-hidden relative font-sans antialiased text-foreground">
<Sidebar
currentView={props.currentView}
setView={props.setView}
isLocked={isSidebarLocked()}
setIsLocked={setIsSidebarLocked}
isPeeking={isSidebarPeeking()}
setIsPeeking={setIsSidebarPeeking}
/>
<div class={cn(
"flex-1 flex flex-col h-full transition-all duration-300 ease-in-out relative",
isSidebarLocked() ? "md:ml-48" : "ml-0"
)}>
{/* Expand Trigger Button (visible when not locked) */}
{!isSidebarLocked() && (
<div class="fixed top-4 left-4 z-[60] md:flex hidden">
<Button
variant="ghost"
size="icon"
onMouseEnter={() => setIsSidebarPeeking(true)}
onClick={() => setIsSidebarLocked(true)}
class="bg-background/80 backdrop-blur-sm border border-border hover:bg-muted shadow-sm"
>
<PanelLeftOpen size={18} />
</Button>
</div>
)}
{/* Main Content Area */}
<main class="flex-1 min-w-0 overflow-y-auto overflow-x-hidden pb-32 sm:pb-6 relative scroll-smooth">
<div class="w-full max-w-screen-2xl mx-auto px-4 sm:px-8 lg:px-12 pt-16 sm:pt-20 pb-8 space-y-6 sm:space-y-8">
<Show when={props.currentView.toLowerCase() !== "settings"}>
<FilterBar />
</Show>
{props.children}
</div>
</main>
{/* Mobile Bottom Nav */}
<BottomNav currentView={props.currentView} setView={props.setView} />
</div>
<Suspense>
<QuickEntry />
</Suspense>
<Show when={activeTask()}>
<Suspense>
<TaskDetail
task={activeTask()!}
isOpen={!!activeTaskId()}
onClose={() => setActiveTaskId(null)}
/>
</Suspense>
</Show>
</div>
);
};