Files
CollectFlow/src/components/ui/page-header.tsx
T
Claude 0c890c84c5 feat(ui): lot 2 — socle visuel, menu regroupé et composants communs
Thème
- Clair par défaut ; les classes dark: suivent le bouton de thème (et non
  plus le réglage du système) ; animations tw-animate-css enfin importées.
- Couleurs shadcn branchées sur les variables (survols des menus visibles),
  libellés gris au contraste AA dans les deux thèmes, fond plein pour le
  menu et l'en-tête.

Composants partagés (src/components/ui)
- PageHeader, Card/Field, StatCard, Badge/DeltaBadge/StoreBadge/GammeBadge,
  Tabs/Segmented/useUrlTab, Select/SearchInput, EmptyState/ErrorState/
  Skeleton, Tooltip/Terme (glossaire), toast et confirmer, Pagination,
  DataTable (recherche, filtres, tri, pagination, export, totaux).
- Sources uniques : magasins, gammes (avec leur sens), glossaire, seuils de
  marge, export Excel.

Navigation
- Menu groupé (Au quotidien / Analyses / Suivi / Administration), déplié
  par défaut, libellés en français.
- En-tête : nom de la page, thème, menu du compte avec le vrai nom, la
  hauteur des lignes de la Grille et la déconnexion. La recherche globale,
  qui ne filtrait que la Grille, est retirée.
- Page Historique (sessions + exports) ; /snapshots et /exports y
  redirigent.
- Squelettes de chargement au lieu de la fenêtre plein écran, pages
  d'erreur et « introuvable » en français, arrivée sur l'Accueil après
  connexion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcA129WzGTH6zxPHFBGWmn
2026-10-03 20:45:03 +00:00

46 lines
1.8 KiB
TypeScript

import type { ReactNode } from "react";
import type { LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";
interface PageHeaderProps {
title: ReactNode;
/** Une phrase : à quoi sert la page, en langage courant. */
description?: ReactNode;
icon?: LucideIcon;
/** Boutons ou filtres alignés à droite du titre. */
actions?: ReactNode;
className?: string;
}
/**
* En-tête commun à toutes les pages : même taille de titre, même place pour
* l'explication et pour les actions. Il y en avait sept variantes.
*/
export function PageHeader({ title, description, icon: Icon, actions, className }: PageHeaderProps) {
return (
<header className={cn("flex flex-wrap items-start justify-between gap-4 mb-6", className)}>
<div className="flex items-start gap-3 min-w-0">
{Icon && (
<div
className="mt-0.5 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border"
style={{ background: "var(--accent-bg)", borderColor: "var(--accent-border)", color: "var(--accent)" }}
>
<Icon className="h-5 w-5" strokeWidth={2} />
</div>
)}
<div className="min-w-0">
<h1 className="text-2xl font-bold tracking-tight" style={{ color: "var(--text-primary)" }}>
{title}
</h1>
{description && (
<p className="mt-1 text-sm max-w-3xl" style={{ color: "var(--text-secondary)" }}>
{description}
</p>
)}
</div>
</div>
{actions && <div className="flex flex-wrap items-center gap-2">{actions}</div>}
</header>
);
}