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.4 KB · 117 lines tsx
Raw Blame History
1"use client";23import { Sun, Moon, Monitor, Check, Rows3, AlignJustify, Zap, ZapOff } from "lucide-react";4import Modal from "../ui/Modal";5import { useTheme } from "./ThemeProvider";6import { useShell } from "../layout/ShellContext";7import { ACCENTS, type ThemePref } from "@/lib/prefs";89const themeOptions: { id: ThemePref; label: string; icon: typeof Sun }[] = [10  { id: "light", label: "Clair", icon: Sun },11  { id: "dark", label: "Sombre", icon: Moon },12  { id: "system", label: "Système", icon: Monitor },13];1415export default function PreferencesModal() {16  const { prefsOpen, setPrefsOpen } = useShell();17  const { themePref, setThemePref, accent, setAccent, density, setDensity, reduceMotion, setReduceMotion } = useTheme();1819  return (20    <Modal isOpen={prefsOpen} onClose={() => setPrefsOpen(false)} title="Apparence" description="Vos préférences sont enregistrées sur cet appareil." maxWidth="max-w-lg">21      <div className="space-y-6">22        {/* Thème */}23        <section>24          <h3 className="text-[12px] font-semibold uppercase tracking-[0.12em] text-gray-400 mb-2.5">Thème</h3>25          <div className="grid grid-cols-3 gap-2">26            {themeOptions.map((o) => {27              const on = themePref === o.id;28              return (29                <button30                  key={o.id}31                  onClick={() => setThemePref(o.id)}32                  className={`relative flex flex-col items-center gap-2 p-3 rounded-2xl border transition-all ${on ? "border-blue-500 bg-blue-500/10 shadow-glow" : "border-line dark:border-white/10 hover:border-gray-300 dark:hover:border-white/20"}`}33                >34                  <span className={`w-full h-12 rounded-xl overflow-hidden border border-black/5 dark:border-white/10 ${o.id === "light" ? "bg-[#f5f6f8]" : o.id === "dark" ? "bg-[#0a0b10]" : "bg-gradient-to-r from-[#f5f6f8] to-[#0a0b10]"}`}>35                    <span className={`block mt-2 ml-2 w-1/2 h-2 rounded-full ${o.id === "dark" ? "bg-white/20" : "bg-black/10"}`} />36                    <span className={`block mt-1.5 ml-2 w-2/3 h-2 rounded-full ${o.id === "dark" ? "bg-white/10" : "bg-black/5"}`} />37                  </span>38                  <span className="flex items-center gap-1.5 text-[13px] font-medium text-gray-800 dark:text-gray-100"><o.icon className="w-3.5 h-3.5" />{o.label}</span>39                  {on && <Check className="absolute top-2 right-2 w-4 h-4 text-blue-600 dark:text-blue-300" />}40                </button>41              );42            })}43          </div>44        </section>4546        {/* Accent */}47        <section>48          <h3 className="text-[12px] font-semibold uppercase tracking-[0.12em] text-gray-400 mb-2.5">Couleur d&apos;accent</h3>49          <div className="flex flex-wrap gap-2.5">50            {ACCENTS.map((a) => {51              const on = accent === a.id;52              return (53                <button54                  key={a.id}55                  onClick={() => setAccent(a.id)}56                  title={`${a.label} — ${a.hint}`}57                  className={`group flex items-center gap-2 pl-1.5 pr-3 h-10 rounded-full border transition-all ${on ? "border-gray-900 dark:border-white bg-gray-900/5 dark:bg-white/10" : "border-line dark:border-white/10 hover:border-gray-300 dark:hover:border-white/25"}`}58                >59                  <span className="w-7 h-7 rounded-full flex items-center justify-center shadow-inner" style={{ background: `linear-gradient(135deg, ${a.hex}, ${a.hex}cc)` }}>60                    {on && <Check className="w-4 h-4 text-white drop-shadow" />}61                  </span>62                  <span className="text-[13px] font-medium text-gray-800 dark:text-gray-100">{a.label}</span>63                </button>64              );65            })}66          </div>67        </section>6869        {/* Densité */}70        <section>71          <h3 className="text-[12px] font-semibold uppercase tracking-[0.12em] text-gray-400 mb-2.5">Densité des listes</h3>72          <div className="grid grid-cols-2 gap-2">73            {[74              { id: "comfortable" as const, label: "Confortable", icon: Rows3, hint: "Lignes aérées" },75              { id: "compact" as const, label: "Compacte", icon: AlignJustify, hint: "Plus de fichiers à l'écran" },76            ].map((d) => {77              const on = density === d.id;78              return (79                <button key={d.id} onClick={() => setDensity(d.id)} className={`flex items-center gap-3 p-3 rounded-2xl border text-left transition-all ${on ? "border-blue-500 bg-blue-500/10" : "border-line dark:border-white/10 hover:border-gray-300 dark:hover:border-white/20"}`}>80                  <d.icon className={`w-5 h-5 ${on ? "text-blue-600 dark:text-blue-300" : "text-gray-400"}`} />81                  <span>82                    <span className="block text-[13px] font-medium text-gray-800 dark:text-gray-100">{d.label}</span>83                    <span className="block text-[11.5px] text-gray-400">{d.hint}</span>84                  </span>85                </button>86              );87            })}88          </div>89        </section>9091        {/* Mouvement */}92        <section>93          <button94            onClick={() => setReduceMotion(!reduceMotion)}95            className="w-full flex items-center gap-3 p-3 rounded-2xl border border-line dark:border-white/10 hover:border-gray-300 dark:hover:border-white/20 transition-colors text-left"96            role="switch"97            aria-checked={reduceMotion}98          >99            {reduceMotion ? <ZapOff className="w-5 h-5 text-gray-400" /> : <Zap className="w-5 h-5 text-blue-500" />}100            <span className="flex-1">101              <span className="block text-[13px] font-medium text-gray-800 dark:text-gray-100">Réduire les animations</span>102              <span className="block text-[11.5px] text-gray-400">Désactive les transitions et effets de mouvement</span>103            </span>104            <span className={`relative w-11 h-6 rounded-full transition-colors ${reduceMotion ? "bg-blue-500" : "bg-gray-300 dark:bg-white/15"}`}>105              <span className={`absolute top-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform ${reduceMotion ? "translate-x-[22px]" : "translate-x-0.5"}`} />106            </span>107          </button>108        </section>109110        <p className="text-[11.5px] text-gray-400 text-center">111          Raccourcis : <kbd>⌘K</kbd> palette · <kbd>⌘B</kbd> barre latérale · <kbd>⌘,</kbd> préférences · <kbd>/</kbd> recherche112        </p>113      </div>114    </Modal>115  );116}117