SPB Git forge

spb/spb-cloud

Public
10commits 1branches 0releases
3.2 MBsize
maindefault branch
3 h agolast push
JavaScript 56.7% TypeScript 42.6%
2.4 KB · 78 lines tsx
Raw Blame History
1"use client";23import { useEffect } from "react";4import { motion } from "framer-motion";5import Sidebar from "./Sidebar";6import MobileNav from "./MobileNav";7import MobileTabBar from "./MobileTabBar";8import TopBar from "./TopBar";9import CommandPalette from "./CommandPalette";10import PreferencesModal from "../theme/PreferencesModal";11import AiPanel from "../ai/AiPanel";12import TopLoader from "../ui/TopLoader";13import { ShellProvider, useShell } from "./ShellContext";1415interface AppShellProps {16  children: React.ReactNode;17  /** Masquer la barre supérieure (pages qui gèrent leur propre en-tête plein écran) */18  hideTopBar?: boolean;19}2021function ShellFrame({ children, hideTopBar }: AppShellProps) {22  const { sidebarCollapsed, toggleSidebar, mobileNavOpen, setMobileNavOpen } = useShell();2324  // ⌘B / Ctrl+B : replier la barre latérale25  useEffect(() => {26    const onKey = (e: KeyboardEvent) => {27      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "b") {28        const t = e.target as HTMLElement | null;29        if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;30        e.preventDefault();31        toggleSidebar();32      }33    };34    window.addEventListener("keydown", onKey);35    return () => window.removeEventListener("keydown", onKey);36  }, [toggleSidebar]);3738  return (39    <div className="h-[100dvh] overflow-hidden bg-canvas flex transition-colors">40      <TopLoader />4142      {/* Barre latérale desktop (repliable) */}43      <motion.div44        initial={false}45        animate={{ width: sidebarCollapsed ? 72 : 264 }}46        transition={{ type: "spring", stiffness: 380, damping: 36 }}47        className="hidden lg:flex flex-col shrink-0 h-full overflow-hidden"48      >49        <Sidebar collapsed={sidebarCollapsed} showCollapse />50      </motion.div>5152      {/* Tiroir mobile */}53      <MobileNav isOpen={mobileNavOpen} onClose={() => setMobileNavOpen(false)} />5455      {/* Colonne principale */}56      <div className="flex-1 flex flex-col min-w-0 h-full overflow-hidden">57        {!hideTopBar && <TopBar />}58        <main className="flex-1 overflow-auto min-h-0 pb-tabbar" id="main">59          {children}60        </main>61      </div>6263      <MobileTabBar />64      <CommandPalette />65      <PreferencesModal />66      <AiPanel />67    </div>68  );69}7071export default function AppShell(props: AppShellProps) {72  return (73    <ShellProvider>74      <ShellFrame {...props} />75    </ShellProvider>76  );77}78