SPB Git forge

spb/spb-cloud

Public
10commits 1branches 0releases
3.2 MBsize
maindefault branch
2 h agolast push
JavaScript 56.7% TypeScript 42.6%
6.0 KB · 127 lines tsx
Raw Blame History
1"use client";23import Link from "next/link";4import { usePathname, useRouter } from "next/navigation";5import { Menu, Search, Upload, Sparkles, ChevronRight, Home } from "lucide-react";6import ThemeToggle from "../theme/ThemeToggle";7import NotificationBell from "./NotificationBell";8import Kbd, { modKey } from "../ui/Kbd";9import { useShell, toggleAiPanel } from "./ShellContext";10import { useEffect, useState } from "react";1112const routeTitles: Record<string, string> = {13  "/dashboard": "Accueil",14  "/dashboard/files": "Fichiers",15  "/dashboard/favorites": "Favoris",16  "/dashboard/recent": "Récents",17  "/dashboard/graph": "Visualisation",18  "/dashboard/shared-with-me": "Partagé avec moi",19  "/dashboard/passwords": "Mots de passe",20  "/dashboard/trash": "Corbeille",21  "/dashboard/security": "Sécurité",22  "/admin": "Administration",23  "/admin/users": "Utilisateurs",24  "/admin/shared-spaces": "Espaces partagés",25  "/admin/shares": "Liens partagés",26  "/admin/activity": "Activité",27  "/admin/snapshots": "Snapshots",28  "/admin/backup": "Backups",29  "/admin/api-keys": "Clés API",30  "/admin/settings": "Paramètres",31};3233export default function TopBar() {34  const pathname = usePathname();35  const router = useRouter();36  const { header, openCommand, setMobileNavOpen } = useShell();37  const [mod, setMod] = useState("⌘");38  useEffect(() => setMod(modKey()), []);3940  const isFiles = pathname.startsWith("/dashboard/files") || pathname.startsWith("/dashboard/folder");41  const title = header.title || routeTitles[pathname] || (pathname.startsWith("/dashboard/shared-space") ? "Espace partagé" : isFiles ? "Fichiers" : "SPB Cloud");42  const crumbs = header.crumbs;4344  return (45    <header className="h-14 lg:h-16 shrink-0 flex items-center gap-2 px-3 sm:px-4 lg:px-6 border-b border-line dark:border-white/[0.07] bg-surface/70 dark:bg-canvas/70 backdrop-blur-xl safe-top z-30">46      {/* Mobile : menu */}47      <button48        onClick={() => setMobileNavOpen(true)}49        className="lg:hidden w-10 h-10 -ml-1 flex items-center justify-center rounded-xl text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10 transition-colors"50        aria-label="Ouvrir le menu"51      >52        <Menu className="w-5 h-5" />53      </button>5455      {/* Titre / fil d'Ariane */}56      <div className="flex-1 min-w-0 flex items-center">57        {crumbs ? (58          <nav className="flex items-center gap-1 text-sm overflow-x-auto scrollbar-none whitespace-nowrap" aria-label="Fil d'Ariane">59            <Link href="/dashboard/files" className="flex items-center gap-1.5 text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors px-1.5 py-1 rounded-lg hover:bg-gray-100 dark:hover:bg-white/5" data-crumb-root>60              <Home className="w-4 h-4" />61              <span className={crumbs.length ? "hidden sm:inline" : "font-semibold text-gray-900 dark:text-white"}>Fichiers</span>62            </Link>63            {crumbs.map((c, i) => {64              const last = i === crumbs.length - 1;65              return (66                <span key={c.id} className="flex items-center gap-1">67                  <ChevronRight className="w-3.5 h-3.5 text-gray-300 dark:text-gray-600 shrink-0" />68                  <Link69                    href={`/dashboard/folder/${c.id}`}70                    data-crumb-id={c.id}71                    className={`px-1.5 py-1 rounded-lg transition-colors truncate max-w-[10rem] sm:max-w-[16rem] ${last ? "font-semibold text-gray-900 dark:text-white" : "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-white/5"}`}72                    aria-current={last ? "page" : undefined}73                  >74                    {c.name}75                  </Link>76                </span>77              );78            })}79          </nav>80        ) : (81          <h1 className="text-[15px] lg:text-base font-semibold tracking-tight text-gray-900 dark:text-white truncate">{title}</h1>82        )}83      </div>8485      {/* Recherche / palette */}86      <button87        onClick={() => openCommand("")}88        className="hidden md:flex items-center gap-2 h-10 w-64 lg:w-80 px-3 rounded-xl bg-gray-100/80 dark:bg-white/[0.06] border border-transparent hover:border-line dark:hover:border-white/10 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors text-sm text-left"89        aria-label="Rechercher ou exécuter une commande"90      >91        <Search className="w-4 h-4 shrink-0" />92        <span className="flex-1 truncate">Rechercher, naviguer, agir…</span>93        <span className="flex items-center gap-0.5"><Kbd>{mod}</Kbd><Kbd>K</Kbd></span>94      </button>95      <button96        onClick={() => openCommand("")}97        className="md:hidden w-10 h-10 flex items-center justify-center rounded-xl text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10 transition-colors"98        aria-label="Rechercher"99      >100        <Search className="w-5 h-5" />101      </button>102103      {/* Actions */}104      <div className="flex items-center gap-0.5 sm:gap-1">105        <button106          onClick={() => router.push(isFiles ? `${pathname}?upload=1` : "/dashboard/files?upload=1")}107          className="hidden sm:flex items-center gap-1.5 h-10 px-3 rounded-xl text-white bg-accent-gradient text-sm font-medium shadow-[inset_0_1px_0_rgb(255_255_255/.18)] hover:brightness-110 hover:shadow-glow transition-all"108          title="Envoyer des fichiers"109        >110          <Upload className="w-4 h-4" />111          <span className="hidden lg:inline">Envoyer</span>112        </button>113        <button114          onClick={toggleAiPanel}115          className="hidden sm:flex w-10 h-10 items-center justify-center rounded-xl text-gray-500 hover:text-blue-600 hover:bg-blue-500/10 dark:text-gray-400 dark:hover:text-blue-300 transition-colors"116          title="Assistant IA"117          aria-label="Assistant IA"118        >119          <Sparkles className="w-[18px] h-[18px]" />120        </button>121        <NotificationBell />122        <ThemeToggle />123      </div>124    </header>125  );126}127