@zevra/ui 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -1
- package/dist/actions.d.ts +41 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +24 -0
- package/dist/actions.js.map +1 -0
- package/dist/catalogue.d.ts +30 -0
- package/dist/catalogue.d.ts.map +1 -0
- package/dist/catalogue.js +830 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/content.d.ts +135 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +85 -0
- package/dist/content.js.map +1 -0
- package/dist/css-inline.d.ts +11 -0
- package/dist/css-inline.d.ts.map +1 -0
- package/dist/css-inline.js +13 -0
- package/dist/css-inline.js.map +1 -0
- package/dist/cx.d.ts +16 -0
- package/dist/cx.d.ts.map +1 -0
- package/dist/cx.js +20 -0
- package/dist/cx.js.map +1 -0
- package/dist/data.d.ts +136 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +98 -0
- package/dist/data.js.map +1 -0
- package/dist/feedback.d.ts +88 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +38 -0
- package/dist/feedback.js.map +1 -0
- package/dist/forms.d.ts +120 -0
- package/dist/forms.d.ts.map +1 -0
- package/dist/forms.js +60 -0
- package/dist/forms.js.map +1 -0
- package/dist/icon-data.d.ts +6 -0
- package/dist/icon-data.d.ts.map +1 -0
- package/dist/icon-data.js +77 -0
- package/dist/icon-data.js.map +1 -0
- package/dist/icon.d.ts +33 -0
- package/dist/icon.d.ts.map +1 -0
- package/dist/icon.js +13 -0
- package/dist/icon.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +166 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +120 -0
- package/dist/layout.js.map +1 -0
- package/dist/navigation.d.ts +150 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +104 -0
- package/dist/navigation.js.map +1 -0
- package/dist/overlays.d.ts +68 -0
- package/dist/overlays.d.ts.map +1 -0
- package/dist/overlays.js +114 -0
- package/dist/overlays.js.map +1 -0
- package/dist/surfaces.d.ts +61 -0
- package/dist/surfaces.d.ts.map +1 -0
- package/dist/surfaces.js +54 -0
- package/dist/surfaces.js.map +1 -0
- package/dist/typography.d.ts +89 -0
- package/dist/typography.d.ts.map +1 -0
- package/dist/typography.js +76 -0
- package/dist/typography.js.map +1 -0
- package/package.json +36 -4
- package/react/actions.tsx +138 -0
- package/react/catalogue.tsx +1644 -0
- package/react/content.tsx +313 -0
- package/react/css-inline.ts +14 -0
- package/react/cx.ts +20 -0
- package/react/data.tsx +300 -0
- package/react/feedback.tsx +229 -0
- package/react/forms.tsx +383 -0
- package/react/icon-data.ts +114 -0
- package/react/icon.tsx +84 -0
- package/react/index.ts +42 -0
- package/react/layout.tsx +347 -0
- package/react/navigation.tsx +329 -0
- package/react/overlays.tsx +237 -0
- package/react/surfaces.tsx +161 -0
- package/react/typography.tsx +220 -0
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Catalogue — la planche de tous les composants, avec un exemple rendu et le
|
|
4
|
+
// code qui le produit.
|
|
5
|
+
//
|
|
6
|
+
// Il est PUBLIÉ avec le paquet, pas cantonné aux tests, et c'est délibéré :
|
|
7
|
+
// · la page « Design system » de l'admin le rend tel quel, donc la
|
|
8
|
+
// documentation ne peut pas dériver des composants — c'est le même code ;
|
|
9
|
+
// · tests/react.test.js le rend en HTML et vérifie que chaque classe émise
|
|
10
|
+
// existe dans le CSS. Un composant absent du catalogue n'est pas couvert :
|
|
11
|
+
// c'est le rappel le plus efficace qu'on ait trouvé pour le tenir complet.
|
|
12
|
+
//
|
|
13
|
+
// « use client » parce que les enrobages ont besoin d'état pour se démontrer.
|
|
14
|
+
// Ce module n'est jamais importé par le barrel : une app qui ne l'importe pas
|
|
15
|
+
// ne l'embarque pas.
|
|
16
|
+
import { useState } from 'react';
|
|
17
|
+
import { Button, ButtonLink, ButtonRow, LinkArrow } from './actions.js';
|
|
18
|
+
import { Card, Check, Divider, Ent, EntText, Faq, FaqItem, Glass, Inset, MiniStat, MiniStatItem, Pill, Price, Quote, Src, SrcRow, StatCard, Tag, UiPreview, } from './content.js';
|
|
19
|
+
import { Avatar, Break, Cell, Chip, ChipRow, Cite, CiteRow, FileType, KV, KVRow, List, ListMain, ListName, ListRow, Meta, MetaRow, Row, Table, TableHead, Trunc, Unwrap, } from './data.js';
|
|
20
|
+
import { Alert, Badge, Caret, Dot, Empty, Loading, Progress, Status, } from './feedback.js';
|
|
21
|
+
import { Checkbox, Drop, Field, Input, Radio, Search, Seg, SegGroup, Select, SelectAnchor, SelectTrigger, Switch, Textarea, } from './forms.js';
|
|
22
|
+
import { ICONES, Icon, IconButton, NOMS_ICONES } from './icon.js';
|
|
23
|
+
import { CTA, Col, Footer, FooterMini, Grid, Grid12, Gutter, Hero, Nav, NavLink, NavLinks, NavLogo, ProofBar, SectionHead, SectionRule, SheetSection, Stat, Stats, Step, Steps, } from './layout.js';
|
|
24
|
+
import { ChromeButton, CitePanel, Crumbs, Menu, MenuItem, Pager, PagerArrow, PagerRank, PagerStep, Scroll, SideGroup, SideLink, Sidebar, SidebarFoot, SidebarHead, Tabs, Topbar, TopbarTitle, } from './navigation.js';
|
|
25
|
+
import { Drawer, Modal, Toast, Toasts } from './overlays.js';
|
|
26
|
+
import { Band, Fade, Glyph, GridFloor, Halo, PanelNavy, TextOnDark, anim } from './surfaces.js';
|
|
27
|
+
import { Body, CardTitle, Display, Em, H1, H2, H3, Heading, Kicker, Lead, Link, Mono, Note, Rule, Spec, Tagline, } from './typography.js';
|
|
28
|
+
/* ── Démonstrations qui ont besoin d'état ─────────────────────────── */
|
|
29
|
+
function DemoSwitch() {
|
|
30
|
+
const [on, setOn] = useState(true);
|
|
31
|
+
return _jsx(Switch, { on: on, texte: on ? 'ACTIVÉ' : 'DÉSACTIVÉ', onClick: () => setOn(!on) });
|
|
32
|
+
}
|
|
33
|
+
function DemoSeg() {
|
|
34
|
+
const [actif, setActif] = useState('tous');
|
|
35
|
+
return (_jsx(SegGroup, { children: [
|
|
36
|
+
['tous', 'Tous', 128],
|
|
37
|
+
['contrats', 'Contrats', 42],
|
|
38
|
+
['jugements', 'Jugements', 9],
|
|
39
|
+
].map(([id, label, n]) => (_jsx(Seg, { on: actif === id, compte: n, onClick: () => setActif(id), children: label }, id))) }));
|
|
40
|
+
}
|
|
41
|
+
function DemoTabs() {
|
|
42
|
+
const [actif, setActif] = useState('apercu');
|
|
43
|
+
return (_jsx(Tabs, { actif: actif, onChange: setActif, onglets: [
|
|
44
|
+
{ id: 'apercu', label: 'Aperçu' },
|
|
45
|
+
{ id: 'sources', label: 'Sources', compte: 12 },
|
|
46
|
+
] }));
|
|
47
|
+
}
|
|
48
|
+
function DemoMenu() {
|
|
49
|
+
const [ouvert, setOuvert] = useState(false);
|
|
50
|
+
const [valeur, setValeur] = useState('Toute la base');
|
|
51
|
+
return (_jsxs(SelectAnchor, { children: [_jsx(SelectTrigger, { label: "P\u00C9RIM\u00C8TRE", value: valeur, onClick: () => setOuvert(!ouvert) }), ouvert && (_jsx(Menu, { children: ['Toute la base', 'Contrats', 'Jugements'].map((v) => (_jsx(MenuItem, { actif: v === valeur, onClick: () => {
|
|
52
|
+
setValeur(v);
|
|
53
|
+
setOuvert(false);
|
|
54
|
+
}, children: v }, v))) }))] }));
|
|
55
|
+
}
|
|
56
|
+
function DemoDrawer() {
|
|
57
|
+
const [ouvert, setOuvert] = useState(false);
|
|
58
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, { variante: "fantome", compact: true, onClick: () => setOuvert(true), children: "Ouvrir le tiroir" }), _jsx(Drawer, { ouvert: ouvert, onClose: () => setOuvert(false), fermeture: _jsx(ChromeButton, { "aria-label": "Fermer", onClick: () => setOuvert(false), children: "\u00D7" }), children: _jsxs(Sidebar, { children: [_jsx(SidebarHead, { children: _jsx(Mono, { ton: "label", children: "ZEVRA" }) }), _jsxs(SideGroup, { titre: "Espace", children: [_jsx(SideLink, { href: "#", courant: true, num: "01", children: "Biblioth\u00E8que" }), _jsx(SideLink, { href: "#", num: "02", children: "R\u00E9pertoire" })] })] }) })] }));
|
|
59
|
+
}
|
|
60
|
+
function DemoModal() {
|
|
61
|
+
const [ouvert, setOuvert] = useState(false);
|
|
62
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, { variante: "fantome", compact: true, onClick: () => setOuvert(true), children: "Ouvrir la modale" }), _jsx(Modal, { ouvert: ouvert, onClose: () => setOuvert(false), titre: "Supprimer l'organisation", danger: true, pied: _jsxs(ButtonRow, { children: [_jsx(Button, { variante: "fantome", onClick: () => setOuvert(false), children: "Annuler" }), _jsx(Button, { onClick: () => setOuvert(false), children: "Supprimer" })] }), children: _jsx(Body, { children: "Les 4 812 documents index\u00E9s et leurs annotations seront d\u00E9truits. Cette action est irr\u00E9versible." }) })] }));
|
|
63
|
+
}
|
|
64
|
+
function DemoDrop() {
|
|
65
|
+
const [survol, setSurvol] = useState(false);
|
|
66
|
+
return (_jsx(Drop, { survol: survol, titre: "D\u00E9poser des documents", spec: "PDF, DOCX \u00B7 25 Mo par fichier", parcourir: "Parcourir les fichiers", onDragOver: (e) => {
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
setSurvol(true);
|
|
69
|
+
}, onDragLeave: () => setSurvol(false), onDrop: (e) => {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
setSurvol(false);
|
|
72
|
+
} }));
|
|
73
|
+
}
|
|
74
|
+
/* ── Le catalogue ─────────────────────────────────────────────────── */
|
|
75
|
+
export const CATALOGUE = [
|
|
76
|
+
{
|
|
77
|
+
id: 'typographie',
|
|
78
|
+
nom: 'Typographie',
|
|
79
|
+
couche: 'commun',
|
|
80
|
+
css: 'base.css',
|
|
81
|
+
resume: "Titres, corps, kickers, labels mono. La TAILLE est un choix de mise en page, la BALISE un choix de structure : d'où la prop « as », qui les sépare.",
|
|
82
|
+
exemples: [
|
|
83
|
+
{
|
|
84
|
+
id: 'headings',
|
|
85
|
+
nom: 'Titres',
|
|
86
|
+
resume: 'Six paliers. Une page n’a qu’un <h1>, mais peut avoir plusieurs blocs à sa taille — passer « as » plutôt que de casser le plan du document.',
|
|
87
|
+
code: `<H1>La recherche juridique, sourcée</H1>
|
|
88
|
+
<H2 as="h3">Ce que voit votre équipe</H2>
|
|
89
|
+
<H3>Indexation continue</H3>
|
|
90
|
+
<CardTitle>Bibliothèque</CardTitle>`,
|
|
91
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsx(H1, { children: "La recherche juridique, sourc\u00E9e" }), _jsx(H2, { as: "h3", children: "Ce que voit votre \u00E9quipe" }), _jsx(H3, { children: "Indexation continue" }), _jsx(CardTitle, { children: "Biblioth\u00E8que" })] })),
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'display',
|
|
95
|
+
nom: 'Display',
|
|
96
|
+
resume: 'Chiffre ou mot posé pour sa présence, HORS de la hiérarchie des titres — annoncé comme titre de section, il pollue le plan du document.',
|
|
97
|
+
code: `<Display>4 812</Display>`,
|
|
98
|
+
rendu: _jsx(Display, { children: "4 812" }),
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'corps',
|
|
102
|
+
nom: 'Corps et chapô',
|
|
103
|
+
resume: 'Trois densités de corps, plus le chapô qui suit un titre de section et la note de bas de bloc.',
|
|
104
|
+
code: `<Lead>Chaque réponse cite ses sources.</Lead>
|
|
105
|
+
<Body>Le moteur relit l’intégralité des pièces déposées…</Body>
|
|
106
|
+
<Body taille="dense">Variante resserrée, pour une carte.</Body>
|
|
107
|
+
<Note>Hébergement souverain, données chiffrées au repos.</Note>`,
|
|
108
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsx(Lead, { children: "Chaque r\u00E9ponse cite ses sources." }), _jsx(Body, { children: "Le moteur relit l\u2019int\u00E9gralit\u00E9 des pi\u00E8ces d\u00E9pos\u00E9es, y compris les annexes scann\u00E9es, et rattache chaque affirmation au passage qui la fonde." }), _jsx(Body, { taille: "dense", children: "Variante resserr\u00E9e, pour une carte." }), _jsx(Note, { children: "H\u00E9bergement souverain, donn\u00E9es chiffr\u00E9es au repos." })] })),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'kicker',
|
|
112
|
+
nom: 'Kicker et filet',
|
|
113
|
+
resume: 'Le filet de spectre 56×2 devant un sur-titre. PREMIER des trois emplois autorisés du spectre — jamais en fond, jamais en texte.',
|
|
114
|
+
code: `<Kicker>Méthode</Kicker>
|
|
115
|
+
<Kicker variante="stack">Sécurité</Kicker>
|
|
116
|
+
<Spec petit />`,
|
|
117
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 14 }, children: [_jsx(Kicker, { children: "M\u00E9thode" }), _jsx(Kicker, { variante: "stack", children: "S\u00E9curit\u00E9" })] })),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'mono',
|
|
121
|
+
nom: 'Label mono',
|
|
122
|
+
resume: 'Capitales espacées, RÉSERVÉES aux libellés. Une date ou un nom de fichier en capitales espacées devient illisible : pour ceux-là c’est « Meta ».',
|
|
123
|
+
code: `<Mono ton="label">PÉRIMÈTRE</Mono>
|
|
124
|
+
<Mono ton="ink">12 SOURCES</Mono>
|
|
125
|
+
<Mono ton="muted" micro>V2.4.1</Mono>`,
|
|
126
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 18, alignItems: 'baseline', flexWrap: 'wrap' }, children: [_jsx(Mono, { ton: "label", children: "P\u00C9RIM\u00C8TRE" }), _jsx(Mono, { ton: "ink", children: "12 SOURCES" }), _jsx(Mono, { ton: "muted", micro: true, children: "V2.4.1" })] })),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'texte-inline',
|
|
130
|
+
nom: 'Dans le fil du texte',
|
|
131
|
+
resume: 'Mise en valeur, lien, signature de marque, filet neutre. « Em » a un pendant « surSombre » parce que l’indigo d’accent devient illisible sur la bande manifeste.',
|
|
132
|
+
code: `<Body>Une réponse <Em>toujours sourcée</Em>, jamais inventée.</Body>
|
|
133
|
+
<Link href="/methode">Voir la méthode</Link>
|
|
134
|
+
<Tagline>L’intelligence documentaire souveraine</Tagline>
|
|
135
|
+
<Rule />`,
|
|
136
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsxs(Body, { children: ["Une r\u00E9ponse ", _jsx(Em, { children: "toujours sourc\u00E9e" }), ", jamais invent\u00E9e."] }), _jsx(Link, { href: "#", children: "Voir la m\u00E9thode" }), _jsx(Tagline, { children: "L\u2019intelligence documentaire souveraine" }), _jsx(Rule, {})] })),
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'actions',
|
|
142
|
+
nom: 'Actions',
|
|
143
|
+
couche: 'commun',
|
|
144
|
+
css: 'components.css',
|
|
145
|
+
resume: "Trois variantes, et UNE SEULE pleine par page : c'est ce qui fait que l'action principale se voit. Un écran à deux boutons pleins n'en a plus aucun.",
|
|
146
|
+
exemples: [
|
|
147
|
+
{
|
|
148
|
+
id: 'boutons',
|
|
149
|
+
nom: 'Boutons',
|
|
150
|
+
resume: '« plein » pour l’action principale, « fantôme » pour l’alternative, « encre » sur une surface claire où l’indigo se perdrait.',
|
|
151
|
+
code: `<ButtonRow>
|
|
152
|
+
<Button>Demander une démonstration</Button>
|
|
153
|
+
<Button variante="fantome">En savoir plus</Button>
|
|
154
|
+
<Button variante="encre">Se connecter</Button>
|
|
155
|
+
</ButtonRow>`,
|
|
156
|
+
rendu: (_jsxs(ButtonRow, { children: [_jsx(Button, { children: "Demander une d\u00E9monstration" }), _jsx(Button, { variante: "fantome", children: "En savoir plus" }), _jsx(Button, { variante: "encre", children: "Se connecter" })] })),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'boutons-gabarits',
|
|
160
|
+
nom: 'Gabarits',
|
|
161
|
+
resume: '« compact » dans une barre d’outils ou un pied de carte ; « bloc » pour un formulaire mobile, où l’action doit être atteignable au pouce.',
|
|
162
|
+
code: `<Button compact>Enregistrer</Button>
|
|
163
|
+
<Button bloc>Se connecter</Button>
|
|
164
|
+
<ButtonLink href="/tarifs" variante="fantome">Voir les tarifs</ButtonLink>`,
|
|
165
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10, maxWidth: 280 }, children: [_jsxs(ButtonRow, { children: [_jsx(Button, { compact: true, children: "Enregistrer" }), _jsx(ButtonLink, { href: "#", variante: "fantome", compact: true, children: "Voir les tarifs" })] }), _jsx(Button, { bloc: true, children: "Se connecter" })] })),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: 'lien-fleche',
|
|
169
|
+
nom: 'Lien fléché',
|
|
170
|
+
resume: 'La flèche fait partie du composant, pas du contenu : recopiée à la main, elle a produit trois tracés différents.',
|
|
171
|
+
code: `<LinkArrow href="/methode">Comment ça marche</LinkArrow>`,
|
|
172
|
+
rendu: _jsx(LinkArrow, { href: "#", children: "Comment \u00E7a marche" }),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: 'icon-btn',
|
|
176
|
+
nom: 'Bouton d’icône',
|
|
177
|
+
resume: 'Le libellé accessible est OBLIGATOIRE, et s’écrit pour l’ACTION (« Fermer le panneau ») et non pour le dessin (« Croix »).',
|
|
178
|
+
code: `<IconButton icone="fermer" label="Fermer le panneau" />
|
|
179
|
+
<IconButton icone="telecharger" label="Télécharger le document" />`,
|
|
180
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 6 }, children: [_jsx(IconButton, { icone: ICONES[0], label: NOMS_ICONES[ICONES[0]] }), _jsx(IconButton, { icone: ICONES[1], label: NOMS_ICONES[ICONES[1]] }), _jsx(IconButton, { icone: ICONES[2], label: NOMS_ICONES[ICONES[2]] })] })),
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'saisie',
|
|
186
|
+
nom: 'Saisie',
|
|
187
|
+
couche: 'applicatif',
|
|
188
|
+
css: 'forms.css',
|
|
189
|
+
resume: "Le liage intitulé ↔ contrôle est EXPLICITE : même valeur en « htmlFor » sur le champ et en « id » sur le contrôle. Sans useId, ces composants restent rendus au serveur.",
|
|
190
|
+
exemples: [
|
|
191
|
+
{
|
|
192
|
+
id: 'champ',
|
|
193
|
+
nom: 'Champ',
|
|
194
|
+
resume: 'L’aide et l’erreur occupent la même place : la seconde efface la première, sinon les deux se chevauchent.',
|
|
195
|
+
code: `<Field label="ADRESSE E-MAIL" htmlFor="mail" help="Votre adresse professionnelle.">
|
|
196
|
+
<Input id="mail" type="email" placeholder="prenom.nom@cabinet.fr" />
|
|
197
|
+
</Field>`,
|
|
198
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 16, maxWidth: 380 }, children: [_jsx(Field, { label: "ADRESSE E-MAIL", htmlFor: "ex-mail", help: "Votre adresse professionnelle.", children: _jsx(Input, { id: "ex-mail", type: "email", placeholder: "prenom.nom@cabinet.fr" }) }), _jsx(Field, { label: "IDENTIFIANT D\u2019ORGANISATION", htmlFor: "ex-org", erreur: "Cet identifiant n\u2019existe pas.", children: _jsx(Input, { id: "ex-org", mono: true, erreur: true, defaultValue: "zvr-8841-x", "aria-describedby": "ex-org-err" }) }), _jsx(Field, { label: "MOT DE PASSE", htmlFor: "ex-mdp", action: _jsx(Link, { href: "#", children: "Oubli\u00E9 ?" }), children: _jsx(Input, { id: "ex-mdp", type: "password", defaultValue: "\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7" }) })] })),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'select',
|
|
202
|
+
nom: 'Sélection',
|
|
203
|
+
resume: '<select> NATIF : la flèche, l’ouverture au clavier et l’annonce viennent du navigateur. C’est le motif de choix par défaut.',
|
|
204
|
+
code: `<Field label="RÔLE" htmlFor="role">
|
|
205
|
+
<Select id="role"><option>Administrateur</option>…</Select>
|
|
206
|
+
</Field>`,
|
|
207
|
+
rendu: (_jsx("div", { style: { maxWidth: 260 }, children: _jsx(Field, { label: "R\u00D4LE", htmlFor: "ex-role", children: _jsxs(Select, { id: "ex-role", defaultValue: "R\u00E9dacteur", children: [_jsx("option", { children: "Administrateur" }), _jsx("option", { children: "R\u00E9dacteur" }), _jsx("option", { children: "Lecture seule" })] }) }) })),
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: 'textarea',
|
|
211
|
+
nom: 'Zone de texte',
|
|
212
|
+
resume: 'Redimensionnable verticalement SEULEMENT : en libre, l’utilisateur l’élargit hors de sa colonne et casse la mise en page.',
|
|
213
|
+
code: `<Textarea placeholder="Contexte de la demande…" />`,
|
|
214
|
+
rendu: (_jsx("div", { style: { maxWidth: 380 }, children: _jsx(Textarea, { placeholder: "Contexte de la demande\u2026" }) })),
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 'recherche',
|
|
218
|
+
nom: 'Recherche',
|
|
219
|
+
resume: 'Cadre + loupe + champ nu. Deux marquages au clavier (l’anneau du champ ET le filet du cadre) : assumé — supprimer l’un rend le champ invisible, l’autre prive la souris de retour.',
|
|
220
|
+
code: `<Search placeholder="Rechercher un document…" />`,
|
|
221
|
+
rendu: (_jsx("div", { style: { maxWidth: 380 }, children: _jsx(Search, { placeholder: "Rechercher un document\u2026" }) })),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 'menu-select',
|
|
225
|
+
nom: 'Déclencheur de menu',
|
|
226
|
+
resume: 'Menu MAISON, à réserver aux filtres. À poser dans « SelectAnchor » : c’est l’enveloppe qui ancre le menu, pas le déclencheur.',
|
|
227
|
+
code: `<SelectAnchor>
|
|
228
|
+
<SelectTrigger label="PÉRIMÈTRE" value="Toute la base" onClick={…} />
|
|
229
|
+
{ouvert && <Menu><MenuItem actif>Toute la base</MenuItem>…</Menu>}
|
|
230
|
+
</SelectAnchor>`,
|
|
231
|
+
rendu: _jsx(DemoMenu, {}),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: 'bascules',
|
|
235
|
+
nom: 'Bascules',
|
|
236
|
+
resume: 'Contrôles natifs (appearance:none seulement) : clavier, focus visible et annonce viennent du navigateur, pas d’un <div> à réoutiller.',
|
|
237
|
+
code: `<Checkbox defaultChecked /> <Radio name="x" defaultChecked />
|
|
238
|
+
<Switch on={on} texte="ACTIVÉ" onClick={…} />`,
|
|
239
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 20, alignItems: 'center', flexWrap: 'wrap' }, children: [_jsxs("label", { style: { display: 'flex', gap: 8, alignItems: 'center' }, children: [_jsx(Checkbox, { defaultChecked: true }), " ", _jsx("span", { className: "zv-body zv-body--dense", children: "Anonymiser" })] }), _jsxs("label", { style: { display: 'flex', gap: 8, alignItems: 'center' }, children: [_jsx(Radio, { name: "ex-r", defaultChecked: true }), " ", _jsx("span", { className: "zv-body zv-body--dense", children: "Tout" })] }), _jsx(DemoSwitch, {})] })),
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'puces',
|
|
243
|
+
nom: 'Puces de filtre',
|
|
244
|
+
resume: 'Le seul mécanisme de filtrage du système. Sélection DOUCE par défaut ; la variante « plein » est bornée à un groupe par page.',
|
|
245
|
+
code: `<SegGroup>
|
|
246
|
+
<Seg on compte={128} onClick={…}>Tous</Seg>
|
|
247
|
+
<Seg compte={42} onClick={…}>Contrats</Seg>
|
|
248
|
+
</SegGroup>`,
|
|
249
|
+
rendu: _jsx(DemoSeg, {}),
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: 'depot',
|
|
253
|
+
nom: 'Zone de dépôt',
|
|
254
|
+
resume: 'role="button" + tabIndex posés par le composant : sans eux la page d’import est inatteignable au clavier. Remettre value="" après chaque sélection.',
|
|
255
|
+
code: `<Drop titre="Déposer des documents" spec="PDF, DOCX · 25 Mo"
|
|
256
|
+
parcourir="Parcourir les fichiers" survol={survol} … />`,
|
|
257
|
+
rendu: _jsx(DemoDrop, {}),
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: 'retours',
|
|
263
|
+
nom: 'Retours',
|
|
264
|
+
couche: 'applicatif',
|
|
265
|
+
css: 'feedback.css',
|
|
266
|
+
resume: "Rien n'est interactif ici. ⚠️ Ni roue, ni squelette, ni infobulle : le CSS n'en a aucun, parce que le relevé de production n'en contenait aucun. Le travail en cours se dit par « Loading », qui nomme ce qu'on attend.",
|
|
267
|
+
exemples: [
|
|
268
|
+
{
|
|
269
|
+
id: 'alertes',
|
|
270
|
+
nom: 'Bandeaux',
|
|
271
|
+
resume: 'Le ton est OBLIGATOIRE : sans lui, le bandeau hérite d’un filet en currentColor, soit un trait d’encre autour d’un fond blanc.',
|
|
272
|
+
code: `<Alert ton="info">Les documents sont indexés en continu.</Alert>
|
|
273
|
+
<Alert ton="err" taille="sm">Identifiants incorrects.</Alert>
|
|
274
|
+
<Alert ton="warn" taille="lg">Le moteur est en charge…</Alert>`,
|
|
275
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsx(Alert, { ton: "info", children: "Les documents sont index\u00E9s en continu." }), _jsx(Alert, { ton: "ok", taille: "sm", children: "Organisation enregistr\u00E9e." }), _jsx(Alert, { ton: "warn", children: "Trois pi\u00E8ces n\u2019ont pas pu \u00EAtre oc\u00E9ris\u00E9es." }), _jsx(Alert, { ton: "err", taille: "sm", children: "Identifiants incorrects." }), _jsx(Alert, { ton: "dash", children: "Aucune source ne couvre cette p\u00E9riode." })] })),
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'badges',
|
|
279
|
+
nom: 'Étiquettes',
|
|
280
|
+
resume: 'Les capitales s’écrivent dans le CONTENU, pas en CSS : transformé par le navigateur, « INDEXÉ » se casse selon la locale.',
|
|
281
|
+
code: `<Badge ton="ok">INDEXÉ</Badge>
|
|
282
|
+
<Badge ton="warn" gabarit="micro">WARN</Badge>
|
|
283
|
+
<Badge ton="accent" pastille>IA DÉDIÉE</Badge>`,
|
|
284
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }, children: [_jsx(Badge, { children: "ADMIN" }), _jsx(Badge, { ton: "accent", pastille: true, children: "IA D\u00C9DI\u00C9E" }), _jsx(Badge, { ton: "ok", children: "INDEX\u00C9" }), _jsx(Badge, { ton: "warn", gabarit: "micro", children: "WARN" }), _jsx(Badge, { ton: "err", gabarit: "micro", children: "ERROR" }), _jsx(Badge, { ton: "ok", gabarit: "state", children: "OK" })] })),
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
id: 'pastilles',
|
|
288
|
+
nom: 'Pastilles et statut',
|
|
289
|
+
resume: 'Sans état, la pastille reste GRISE : un statut ajouté côté serveur et pas encore côté interface ne doit pas passer pour un succès. La pastille CARRÉE marque une source, pas un état.',
|
|
290
|
+
code: `<Status etat="indexe">Indexé · 42 pages</Status>
|
|
291
|
+
<Dot etat="erreur" /> <Dot carree /> <Dot taille="lg" etat="ok" />`,
|
|
292
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsx(Status, { etat: "indexe", children: "Index\u00E9 \u00B7 42 pages" }), _jsx(Status, { etat: "indexation", children: "Indexation en cours" }), _jsx(Status, { etat: "erreur", children: "Fichier illisible : page 3 corrompue" }), _jsx(Status, { children: "Statut inconnu" })] })),
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: 'absence',
|
|
296
|
+
nom: 'Absence',
|
|
297
|
+
resume: '⚠️ DEUX objets. Sans titre : la LIGNE d’absence, un filtre trop étroit, l’en-tête du tableau reste visible. Avec titre et « page » : l’ÉCRAN d’absence, la collection est vide. Les confondre affiche un écran de bienvenue à chaque filtre strict.',
|
|
298
|
+
code: `<Empty>Aucun document ne correspond à ces filtres.</Empty>
|
|
299
|
+
|
|
300
|
+
<Empty page titre="Aucun document" action={<Button compact>Importer</Button>}>
|
|
301
|
+
Déposez vos premières pièces pour lancer l’indexation.
|
|
302
|
+
</Empty>`,
|
|
303
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 16 }, children: [_jsx(Empty, { children: "Aucun document ne correspond \u00E0 ces filtres." }), _jsx(Empty, { page: true, titre: "Aucun document", action: _jsx(Button, { compact: true, children: "Importer" }), children: "D\u00E9posez vos premi\u00E8res pi\u00E8ces pour lancer l\u2019indexation." })] })),
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: 'attente',
|
|
307
|
+
nom: 'Travail en cours',
|
|
308
|
+
resume: 'STATIQUE : la pastille ne bat pas. Une roue dit « attendez » ; cette phrase dit sur quoi, sur combien, et qu’il ne se passe rien d’anormal.',
|
|
309
|
+
code: `<Loading>Recherche dans 4 812 documents anonymisés…</Loading>
|
|
310
|
+
<Progress valeur={0.62} label="Indexation" />
|
|
311
|
+
<span>…réponse en cours<Caret /></span>`,
|
|
312
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsx(Loading, { children: "Recherche dans 4 812 documents anonymis\u00E9s\u2026" }), _jsx(Progress, { valeur: 0.62, label: "Indexation" }), _jsxs("span", { className: "zv-body zv-body--dense", children: ["La clause de non-concurrence est limit\u00E9e \u00E0 vingt-quatre mois", _jsx(Caret, {})] })] })),
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
id: 'contenu',
|
|
318
|
+
nom: 'Contenu',
|
|
319
|
+
couche: 'commun',
|
|
320
|
+
css: 'components.css',
|
|
321
|
+
resume: 'Surfaces, encarts, étiquettes éditoriales et blocs de preuve. ⚠️ Deux règles de charte y sont opposables : jamais de fausse citation, jamais de lorem dans un aperçu produit.',
|
|
322
|
+
exemples: [
|
|
323
|
+
{
|
|
324
|
+
id: 'cartes',
|
|
325
|
+
nom: 'Cartes',
|
|
326
|
+
resume: '« Glass » ne fonctionne QUE devant un halo ou une scène : posée sur du papier nu, elle disparaît.',
|
|
327
|
+
code: `<Card padding="large">…</Card>
|
|
328
|
+
<Card etat="ok">…</Card>
|
|
329
|
+
<Card flottante>…</Card>`,
|
|
330
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12, gridTemplateColumns: 'repeat(auto-fit,minmax(180px,1fr))' }, children: [_jsxs(Card, { children: [_jsx(CardTitle, { children: "Biblioth\u00E8que" }), _jsx(Body, { taille: "dense", children: "4 812 pi\u00E8ces index\u00E9es." })] }), _jsx(Card, { etat: "ok", children: _jsx(Body, { taille: "dense", children: "Sauvegarde v\u00E9rifi\u00E9e il y a 2 h." }) }), _jsx(Card, { etat: "err", children: _jsx(Body, { taille: "dense", children: "Trois pi\u00E8ces illisibles." }) })] })),
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
id: 'encarts',
|
|
334
|
+
nom: 'Encarts',
|
|
335
|
+
resume: 'DEUX objets longtemps confondus : la citation d’interface, et l’extrait de document (« discret » : fond panel, très aéré).',
|
|
336
|
+
code: `<Inset>La demande est recevable.</Inset>
|
|
337
|
+
<Inset discret>« … le délai de préavis court à compter … »</Inset>`,
|
|
338
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsx(Inset, { children: _jsx(Body, { taille: "dense", children: "Trois arr\u00EAts post\u00E9rieurs confirment cette lecture." }) }), _jsx(Inset, { discret: true, children: _jsx(Body, { taille: "dense", children: "\u00AB Le d\u00E9lai de pr\u00E9avis court \u00E0 compter de la premi\u00E8re pr\u00E9sentation de la lettre recommand\u00E9e. \u00BB" }) })] })),
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
id: 'etiquettes',
|
|
342
|
+
nom: 'Étiquettes éditoriales',
|
|
343
|
+
resume: '⚠️ Trois objets qui se ressemblent et ne se remplacent pas : « Pill » (pastille pleine), « Tag » (kicker mono), « Src » (puce de source).',
|
|
344
|
+
code: `<Pill>Nouveau</Pill>
|
|
345
|
+
<Tag etat="ok">CONFORME</Tag>
|
|
346
|
+
<SrcRow><Src>BOSS</Src><Src>Judilibre</Src><Src attenue>+ 11</Src></SrcRow>`,
|
|
347
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }, children: [_jsx(Pill, { children: "Nouveau" }), _jsx(Tag, { children: "M\u00C9THODE" }), _jsx(Tag, { etat: "ok", children: "CONFORME" }), _jsx(Tag, { etat: "err", children: "\u00C9CART" })] }), _jsxs(SrcRow, { children: [_jsx(Src, { children: "BOSS" }), _jsx(Src, { children: "Judilibre" }), _jsx(Src, { children: "KALI" }), _jsx(Src, { attenue: true, children: "+ 11" })] })] })),
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: 'entites',
|
|
351
|
+
nom: 'Entités pseudonymisées',
|
|
352
|
+
resume: 'Le paragraphe hôte respire davantage : sans lui, les jetons se télescopent d’une ligne à l’autre.',
|
|
353
|
+
code: `<Body><EntText>Le contrat lie <Ent>SOCIÉTÉ_A</Ent> à <Ent>M. B</Ent>…</EntText></Body>`,
|
|
354
|
+
rendu: (_jsx(Body, { children: _jsxs(EntText, { children: ["Le contrat lie ", _jsx(Ent, { children: "SOCI\u00C9T\u00C9_A" }), " \u00E0 ", _jsx(Ent, { children: "M. B" }), ", domicili\u00E9", ' ', _jsx(Ent, { children: "ADRESSE_1" }), ", pour une dur\u00E9e de trente-six mois."] }) })),
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 'preuve',
|
|
358
|
+
nom: 'Aperçu d’interface',
|
|
359
|
+
resume: '⚠️ RÈGLE DE CHARTE : toujours de VRAIES données réalistes, jamais de lorem — c’est ce bloc qui porte la crédibilité de la page.',
|
|
360
|
+
code: `<UiPreview question="Quelle est la durée de préavis ?"
|
|
361
|
+
sources="12 sources" puces={<SrcRow>…</SrcRow>}>
|
|
362
|
+
Trois mois pour les cadres…
|
|
363
|
+
</UiPreview>`,
|
|
364
|
+
rendu: (_jsx(UiPreview, { question: "Quelle dur\u00E9e de pr\u00E9avis s\u2019applique aux cadres ?", sources: "12 sources", puces: _jsxs(SrcRow, { children: [_jsx(Src, { children: "Convention Syntec" }), _jsx(Src, { children: "Cass. soc. 2019" })] }), children: "Trois mois, sauf stipulation plus favorable du contrat de travail. La convention Syntec ne pr\u00E9voit pas de r\u00E9duction en cas de dispense." })),
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: 'stats-carte',
|
|
368
|
+
nom: 'Statistiques de carte',
|
|
369
|
+
resume: 'Paire au pied d’une carte produit, ou carte autonome. ⚠️ Ne pas confondre avec « Stats » (layout), qui est la rangée de chiffres d’une page vitrine : celle-ci vit DANS une carte.',
|
|
370
|
+
code: `<MiniStat>
|
|
371
|
+
<MiniStatItem valeur="4 812">documents</MiniStatItem>
|
|
372
|
+
<MiniStatItem valeur="1,2 s">latence</MiniStatItem>
|
|
373
|
+
</MiniStat>
|
|
374
|
+
|
|
375
|
+
<StatCard valeur="99,95 %">disponibilité sur 90 jours</StatCard>`,
|
|
376
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsxs(MiniStat, { children: [_jsx(MiniStatItem, { valeur: "4 812", children: "documents" }), _jsx(MiniStatItem, { valeur: "1,2 s", children: "latence m\u00E9diane" })] }), _jsx(StatCard, { valeur: "99,95 %", children: "disponibilit\u00E9 sur 90 jours" })] })),
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: 'faq',
|
|
380
|
+
nom: 'FAQ',
|
|
381
|
+
resume: '⚠️ Cinq questions par page au MAXIMUM. Au-delà, ce n’est plus une FAQ, c’est une documentation mal rangée.',
|
|
382
|
+
code: `<Faq>
|
|
383
|
+
<FaqItem question="Où sont hébergées les données ?">En France, chez OVHcloud.</FaqItem>
|
|
384
|
+
</Faq>`,
|
|
385
|
+
rendu: (_jsxs(Faq, { children: [_jsx(FaqItem, { question: "O\u00F9 sont h\u00E9berg\u00E9es les donn\u00E9es ?", children: "En France, sur une infrastructure OVHcloud d\u00E9di\u00E9e, sans r\u00E9plication hors Union europ\u00E9enne." }), _jsx(FaqItem, { question: "Le mod\u00E8le apprend-il sur nos documents ?", children: "Non. Les pi\u00E8ces d\u00E9pos\u00E9es ne servent qu\u2019\u00E0 r\u00E9pondre \u00E0 vos requ\u00EAtes et ne sont jamais vers\u00E9es \u00E0 un entra\u00EEnement." })] })),
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
id: 'prix',
|
|
389
|
+
nom: 'Tarifs',
|
|
390
|
+
resume: '« recommande » pose le bandeau indigo. Trois cartes par page au plus : au-delà, la comparaison ne se fait plus d’un coup d’œil.',
|
|
391
|
+
code: `<Price montant="490 €" unite="HT · par mois" recommande
|
|
392
|
+
note="Engagement 12 mois">…</Price>`,
|
|
393
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12, gridTemplateColumns: 'repeat(auto-fit,minmax(190px,1fr))' }, children: [_jsx(Price, { montant: "190 \u20AC", unite: "HT / mois", note: "Jusqu\u2019\u00E0 3 utilisateurs", children: _jsx(CardTitle, { children: "Cabinet" }) }), _jsx(Price, { montant: "490 \u20AC", unite: "HT / mois", recommande: true, note: "Engagement 12 mois", children: _jsx(CardTitle, { children: "\u00C9tude" }) })] })),
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
id: 'filets-check',
|
|
397
|
+
nom: 'Filets et coche',
|
|
398
|
+
resume: '⚠️ « Check » n’est PAS un contrôle : c’est une coche décorative en tête de liste d’arguments. Le contrôle, c’est « Checkbox ».',
|
|
399
|
+
code: `<Divider /> <Divider marque />
|
|
400
|
+
<li><Check /> Réponses sourcées</li>`,
|
|
401
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 10 }, children: [_jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'center' }, children: [_jsx(Check, {}), _jsx("span", { className: "zv-body zv-body--dense", children: "Chaque r\u00E9ponse cite ses sources" })] }), _jsx(Divider, {}), _jsx(Divider, { marque: true })] })),
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
id: 'citation',
|
|
405
|
+
nom: 'Citation client',
|
|
406
|
+
resume: '⚠️ RÈGLE DE CHARTE : jamais de fausse citation. Tant qu’un verbatim n’a pas été recueilli, ce bloc reste EN RÉSERVE — un placeholder crédible finit toujours par partir en production.',
|
|
407
|
+
code: `<Band><Quote auteur="— Nom, cabinet">Verbatim réel uniquement.</Quote></Band>`,
|
|
408
|
+
surSombre: true,
|
|
409
|
+
rendu: (_jsx(Band, { children: _jsx(Quote, { auteur: "\u2014 en attente d\u2019un verbatim recueilli", children: "Ce bloc reste en r\u00E9serve tant qu\u2019aucune citation r\u00E9elle n\u2019a \u00E9t\u00E9 recueillie." }) })),
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
id: 'donnees',
|
|
415
|
+
nom: 'Données',
|
|
416
|
+
couche: 'applicatif',
|
|
417
|
+
css: 'data.css',
|
|
418
|
+
resume: "Le tableau n'est PAS un <table> : c'est une grille CSS, parce qu'une même rangée doit se rendre en colonnes au-dessus du point de rupture et en carte empilée en dessous, sans dupliquer le balisage.",
|
|
419
|
+
exemples: [
|
|
420
|
+
{
|
|
421
|
+
id: 'tableau',
|
|
422
|
+
nom: 'Tableau',
|
|
423
|
+
resume: 'Le gabarit de colonnes se pose UNE FOIS sur le cadre ; l’en-tête et les lignes en héritent. Recopié aux deux endroits, on l’oublie à l’un et les intitulés se décalent des valeurs sans que rien ne casse visiblement.',
|
|
424
|
+
code: `<Table gabarit="minmax(0,2fr) 110px 90px">
|
|
425
|
+
<TableHead>
|
|
426
|
+
<Cell>Document</Cell><Cell>État</Cell><Cell registre="num">Pages</Cell>
|
|
427
|
+
</TableHead>
|
|
428
|
+
<Row href="/doc/1">
|
|
429
|
+
<Cell registre="nom"><Trunc>Contrat-cadre.pdf</Trunc></Cell>
|
|
430
|
+
<Cell label="État"><Status etat="indexe">Indexé</Status></Cell>
|
|
431
|
+
<Cell registre="num" label="Pages" unite="p.">42</Cell>
|
|
432
|
+
</Row>
|
|
433
|
+
</Table>`,
|
|
434
|
+
rendu: (_jsxs(Table, { gabarit: "minmax(0,2fr) 120px 90px", children: [_jsxs(TableHead, { children: [_jsx(Cell, { children: "Document" }), _jsx(Cell, { children: "\u00C9tat" }), _jsx(Cell, { registre: "num", children: "Pages" })] }), [
|
|
435
|
+
['Contrat-cadre-Syntec.pdf', 'indexe', 'Indexé', 42],
|
|
436
|
+
['Assignation-2024-114.docx', 'indexation', 'Indexation', 8],
|
|
437
|
+
['Annexe-3-scannee.pdf', 'erreur', 'Page 3 corrompue', 3],
|
|
438
|
+
].map(([nom, etat, libelle, pages]) => (_jsxs(Row, { children: [_jsx(Cell, { registre: "nom", children: _jsx(Trunc, { children: nom }) }), _jsx(Cell, { label: "\u00C9tat", children: _jsx(Status, { etat: etat, children: libelle }) }), _jsx(Cell, { registre: "num", label: "Pages", unite: "p.", children: pages })] }, nom)))] })),
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
id: 'unwrap',
|
|
442
|
+
nom: 'Dégroupage',
|
|
443
|
+
resume: 'La primitive structurelle du module : un groupe qui rassemble deux ou trois cellules pour l’empilement mobile, puis s’efface (display: contents) et rend ses enfants DIRECTEMENT à la grille. ⚠️ Il n’exprime QUE ce sens-là.',
|
|
444
|
+
code: `<Row>
|
|
445
|
+
<Unwrap><Cell registre="nom">…</Cell><Cell label="Auteur">…</Cell></Unwrap>
|
|
446
|
+
<Cell registre="num">…</Cell>
|
|
447
|
+
</Row>`,
|
|
448
|
+
rendu: (_jsx(Table, { gabarit: "minmax(0,2fr) 120px 80px", children: _jsxs(Row, { children: [_jsxs(Unwrap, { children: [_jsx(Cell, { registre: "nom", children: "M\u00E9moire en d\u00E9fense" }), _jsx(Cell, { label: "Auteur", children: _jsx(Meta, { children: "M. Dubois" }) })] }), _jsx(Cell, { registre: "num", label: "Pages", children: "17" })] }) })),
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
id: 'liste',
|
|
452
|
+
nom: 'Liste sans colonnes',
|
|
453
|
+
resume: 'Même cadre que le tableau, mais rien à aligner : ni en-tête, ni gabarit.',
|
|
454
|
+
code: `<List>
|
|
455
|
+
<ListRow>
|
|
456
|
+
<ListMain><FileType format="pdf" /><ListName>…</ListName></ListMain>
|
|
457
|
+
<Meta>2,4 Mo</Meta>
|
|
458
|
+
</ListRow>
|
|
459
|
+
</List>`,
|
|
460
|
+
rendu: (_jsxs(List, { children: [_jsxs(ListRow, { children: [_jsxs(ListMain, { children: [_jsx(FileType, { format: "pdf" }), _jsx(ListName, { children: "Contrat-cadre-Syntec.pdf" })] }), _jsx(Meta, { children: "2,4 Mo" })] }), _jsxs(ListRow, { upload: true, children: [_jsxs(ListMain, { children: [_jsx(FileType, { format: "docx" }), _jsx(ListName, { children: "Assignation-2024-114.docx" })] }), _jsx(Progress, { valeur: 0.4, label: "Envoi" })] })] })),
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: 'meta',
|
|
464
|
+
nom: 'Métadonnées',
|
|
465
|
+
resume: 'Second registre mono, en BAS DE CASSE : taille, date, latence. Ni capitales ni interlettrage — c’est ce qui le distingue de « Mono », et une date en capitales espacées devient illisible.',
|
|
466
|
+
code: `<MetaRow><Meta>12 mars 2026</Meta><Meta taille="sm">1,2 s</Meta></MetaRow>`,
|
|
467
|
+
rendu: (_jsxs(MetaRow, { children: [_jsx(Meta, { taille: "md", children: "12 mars 2026" }), _jsx(Meta, { children: "14:07:22" }), _jsx(Meta, { taille: "sm", children: "1,24 s" }), _jsx(Meta, { discret: true, children: "2,4 Mo" })] })),
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
id: 'kv',
|
|
471
|
+
nom: 'Clé-valeur',
|
|
472
|
+
resume: '⚠️ La CLÉ est en mono, en accent, et se coupe ; la VALEUR est en texte courant, en gris, et ne se coupe jamais. Inverser les deux change ce que l’œil balaie en premier.',
|
|
473
|
+
code: `<KV variante="grid">
|
|
474
|
+
<KVRow cle="ORGANISATION">Cabinet Duflot & Associés</KVRow>
|
|
475
|
+
<KVRow cle="IDENTIFIANT"><Break>zvr-8841-x-3c9f2a</Break></KVRow>
|
|
476
|
+
</KV>`,
|
|
477
|
+
rendu: (_jsxs(KV, { variante: "grid", children: [_jsx(KVRow, { cle: "ORGANISATION", children: "Cabinet Duflot & Associ\u00E9s" }), _jsx(KVRow, { cle: "IDENTIFIANT", children: _jsx(Break, { children: "zvr-8841-x-3c9f2a" }) }), _jsx(KVRow, { cle: "FORMULE", children: "\u00C9tude \u00B7 12 postes" })] })),
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
id: 'avatar-chip',
|
|
481
|
+
nom: 'Pastilles et catégories',
|
|
482
|
+
resume: 'Avatar CARRÉ, jamais rond : le rond est un usage de réseau social. ⚠️ Sa teinte dit la NATURE de l’entité — la changer, c’est changer le sens.',
|
|
483
|
+
code: `<Avatar ton="accent">MD</Avatar>
|
|
484
|
+
<ChipRow><Chip>Droit social</Chip><Chip variante="outline">2024</Chip></ChipRow>`,
|
|
485
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsxs("div", { style: { display: 'flex', gap: 8 }, children: [_jsx(Avatar, { ton: "accent", children: "MD" }), _jsx(Avatar, { ton: "ink", children: "JL" }), _jsx(Avatar, { ton: "soft", children: "AB" }), _jsx(Avatar, { ton: "soft", petit: true, children: "ZV" })] }), _jsxs(ChipRow, { children: [_jsx(Chip, { children: "Droit social" }), _jsx(Chip, { children: "Convention collective" }), _jsx(Chip, { variante: "mono", children: "2024-114" }), _jsx(Chip, { variante: "outline", children: "Archiv\u00E9" })] })] })),
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
id: 'citations-src',
|
|
489
|
+
nom: 'Citations',
|
|
490
|
+
resume: 'Référence cliquable, dans le fil du texte ou groupée en pied de réponse : elle ouvre la feuille de source.',
|
|
491
|
+
code: `<CiteRow><Cite>1</Cite><Cite>2</Cite></CiteRow>`,
|
|
492
|
+
rendu: (_jsxs(CiteRow, { children: [_jsx(Cite, { children: "Convention Syntec, art. 15" }), _jsx(Cite, { children: "Cass. soc., 4 d\u00E9c. 2019" })] })),
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
id: 'formats',
|
|
496
|
+
nom: 'Format de fichier',
|
|
497
|
+
resume: '⚠️ Ces deux couleurs ne viennent PAS de la charte : ce sont celles que le monde associe à ces formats, et les détourner rendrait les vignettes illisibles au premier coup d’œil. Seul usage autorisé : la pastille de format.',
|
|
498
|
+
code: `<FileType format="pdf" /> <FileType format="docx" />`,
|
|
499
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 8 }, children: [_jsx(FileType, { format: "pdf" }), _jsx(FileType, { format: "docx" })] })),
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: 'navigation',
|
|
505
|
+
nom: 'Navigation',
|
|
506
|
+
couche: 'applicatif',
|
|
507
|
+
css: 'navigation.css',
|
|
508
|
+
resume: "Rien n'a d'état propre : l'entrée courante, la page courante et l'item sélectionné viennent de l'appelant — c'est ce qui permet à une colonne de navigation Next de rester rendue au serveur.",
|
|
509
|
+
exemples: [
|
|
510
|
+
{
|
|
511
|
+
id: 'sidebar',
|
|
512
|
+
nom: 'Colonne latérale',
|
|
513
|
+
resume: 'Une colonne, un filet, rien d’autre. « courant » pose aria-current="page" en plus de la classe : sans lui, l’entrée courante est marquée pour l’œil et muette au lecteur d’écran.',
|
|
514
|
+
code: `<Sidebar>
|
|
515
|
+
<SidebarHead>…</SidebarHead>
|
|
516
|
+
<SideGroup titre="Espace">
|
|
517
|
+
<SideLink href="/bibliotheque" courant num="01">Bibliothèque</SideLink>
|
|
518
|
+
</SideGroup>
|
|
519
|
+
<SidebarFoot>…</SidebarFoot>
|
|
520
|
+
</Sidebar>`,
|
|
521
|
+
rendu: (_jsxs(Sidebar, { style: { height: 260 }, children: [_jsx(SidebarHead, { children: _jsx(Mono, { ton: "ink", children: "ZEVRA" }) }), _jsxs(SideGroup, { titre: "Espace", children: [_jsx(SideLink, { href: "#", courant: true, num: "01", children: "Biblioth\u00E8que" }), _jsx(SideLink, { href: "#", num: "02", children: "R\u00E9pertoire" }), _jsx(SideLink, { href: "#", num: "03", children: "Import" })] }), _jsx(SidebarFoot, { children: _jsx(Meta, { discret: true, children: "v2.4.1" }) })] })),
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
id: 'topbar',
|
|
525
|
+
nom: 'Barre supérieure',
|
|
526
|
+
resume: '⚠️ Elle REMPLACE la colonne sous le point de rupture : masquée au-dessus, elle n’apparaît que dans le bloc mobile du CSS. Ne jamais la conditionner en JavaScript — le serveur ne connaît pas la largeur de l’écran.',
|
|
527
|
+
code: `<Topbar>
|
|
528
|
+
<TopbarBurger aria-label="Ouvrir la navigation">☰</TopbarBurger>
|
|
529
|
+
<TopbarLogo><img src="/logo.svg" alt="" /></TopbarLogo>
|
|
530
|
+
<TopbarTitle>Bibliothèque</TopbarTitle>
|
|
531
|
+
</Topbar>`,
|
|
532
|
+
rendu: (_jsx(Topbar, { style: { display: 'flex', position: 'static' }, children: _jsx(TopbarTitle, { children: "Biblioth\u00E8que" }) })),
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
id: 'crumbs',
|
|
536
|
+
nom: 'Fil d’Ariane',
|
|
537
|
+
resume: '⚠️ Le fil ENTIER est cliquable — c’est un seul nœud, pas une liste de liens. Le DERNIER segment est plus sombre : c’est celui qu’on lit, le reste n’est qu’un chemin.',
|
|
538
|
+
code: `<Crumbs href="/dossiers/2024" segments={['Dossiers', '2024', 'Duflot']} />`,
|
|
539
|
+
rendu: _jsx(Crumbs, { href: "#", segments: ['Dossiers', '2024', 'Duflot & Associés'] }),
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
id: 'onglets',
|
|
543
|
+
nom: 'Onglets',
|
|
544
|
+
resume: '⚠️ Il n’existe AUCUNE classe d’onglet dans le CSS : une rangée d’onglets EST une rangée de puces. Ce composant n’ajoute que l’ARIA, pas un style de plus. L’onglet souligné reste à arbitrer avec la DA.',
|
|
545
|
+
code: `<Tabs actif={actif} onChange={setActif} onglets={[
|
|
546
|
+
{ id: 'apercu', label: 'Aperçu' },
|
|
547
|
+
{ id: 'sources', label: 'Sources', compte: 12 },
|
|
548
|
+
]} />`,
|
|
549
|
+
rendu: _jsx(DemoTabs, {}),
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
id: 'pagination',
|
|
553
|
+
nom: 'Pagination',
|
|
554
|
+
resume: '⚠️ Une flèche désactivée reste ATTEIGNABLE au clavier (aria-disabled, pas disabled) : sinon elle disparaît du parcours sans être annoncée.',
|
|
555
|
+
code: `<Pager>
|
|
556
|
+
<PagerArrow aria-label="Page précédente" desactive>‹</PagerArrow>
|
|
557
|
+
<PagerRank>p. 12 / 31</PagerRank>
|
|
558
|
+
<PagerArrow aria-label="Page suivante">›</PagerArrow>
|
|
559
|
+
</Pager>
|
|
560
|
+
|
|
561
|
+
<Pager pied>
|
|
562
|
+
<Meta>128 documents</Meta>
|
|
563
|
+
<PagerStep>‹ Précédent · Suivant ›</PagerStep>
|
|
564
|
+
</Pager>`,
|
|
565
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsxs(Pager, { children: [_jsx(PagerArrow, { "aria-label": "Page pr\u00E9c\u00E9dente", desactive: true, children: "\u2039" }), _jsx(PagerRank, { children: "p. 12 / 31" }), _jsx(PagerArrow, { "aria-label": "Page suivante", children: "\u203A" })] }), _jsxs(Pager, { pied: true, children: [_jsx(Meta, { children: "128 documents" }), _jsx(PagerStep, { children: "\u2039 Pr\u00E9c\u00E9dent \u00B7 Suivant \u203A" })] })] })),
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
id: 'cite-panel',
|
|
569
|
+
nom: 'Feuille de source',
|
|
570
|
+
resume: 'Le panneau qu’ouvre une citation : l’extrait, sa référence, ses actions.',
|
|
571
|
+
code: `<CitePanel titre="Convention Syntec, art. 15"
|
|
572
|
+
actions={<ChromeButton aria-label="Fermer">×</ChromeButton>}
|
|
573
|
+
pied={<Button compact bloc>Ouvrir le document</Button>}>
|
|
574
|
+
…
|
|
575
|
+
</CitePanel>`,
|
|
576
|
+
rendu: (_jsx(CitePanel, { titre: "Convention Syntec, art. 15", actions: _jsx(ChromeButton, { "aria-label": "Fermer la feuille", children: "\u00D7" }), pied: _jsx(Button, { compact: true, children: "Ouvrir le document" }), style: { position: 'static', width: 'auto', height: 'auto' }, children: _jsx(Body, { taille: "dense", children: "\u00AB Le d\u00E9lai de pr\u00E9avis est de trois mois pour les salari\u00E9s relevant de la position 3. \u00BB" }) })),
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
id: 'defilement',
|
|
580
|
+
nom: 'Zone défilante',
|
|
581
|
+
resume: '⚠️ Porte min-height: 0 ET min-width: 0. Sans les deux, un enfant flex refuse de rétrécir sous son contenu : la zone déborde et c’est la PAGE qui part en défilement horizontal. La faute la plus fréquente de ce gabarit.',
|
|
582
|
+
code: `<Scroll habillee>…</Scroll>`,
|
|
583
|
+
rendu: (_jsx(Scroll, { habillee: true, style: { height: 90, border: '1px solid var(--line)', padding: 10 }, children: _jsx(Body, { taille: "dense", children: "L\u2019habillage de barre est OPT-IN : sur macOS et iOS, habiller la barre la rend permanente et elle mange une colonne. Par d\u00E9faut, la barre native du syst\u00E8me est conserv\u00E9e." }) })),
|
|
584
|
+
},
|
|
585
|
+
],
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
id: 'enrobages',
|
|
589
|
+
nom: 'Enrobages',
|
|
590
|
+
couche: 'commun',
|
|
591
|
+
css: 'overlays.css',
|
|
592
|
+
resume: "Le seul module marqué « use client ». Tout ce qui vit ici vole le regard à la page : il faut Échap, un piège de focus et un verrou de défilement — rien de cela ne s'écrit en CSS. Le hook « useOverlay » est exporté pour les enrobages maison.",
|
|
593
|
+
exemples: [
|
|
594
|
+
{
|
|
595
|
+
id: 'tiroir',
|
|
596
|
+
nom: 'Tiroir',
|
|
597
|
+
resume: '⚠️ Le tiroir n’existe QUE sous le point de rupture : au-dessus, la navigation est une colonne et il n’y a rien à ouvrir. Réduis la fenêtre pour le voir.',
|
|
598
|
+
code: `<Drawer ouvert={ouvert} onClose={() => setOuvert(false)}
|
|
599
|
+
fermeture={<ChromeButton aria-label="Fermer" onClick={…}>×</ChromeButton>}>
|
|
600
|
+
<Sidebar>…</Sidebar>
|
|
601
|
+
</Drawer>`,
|
|
602
|
+
rendu: _jsx(DemoDrawer, {}),
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
id: 'modale',
|
|
606
|
+
nom: 'Modale',
|
|
607
|
+
resume: 'Fermée, elle n’est pas rendue du tout : son contenu — un formulaire, le plus souvent — ne doit pas rester dans le DOM à l’état fantôme. « danger » met l’avertissement dans le filet HAUT, pas dans un fond rouge qui rendrait le texte pénible à lire.',
|
|
608
|
+
code: `<Modal ouvert={ouvert} onClose={…} titre="Supprimer" danger
|
|
609
|
+
pied={<ButtonRow>…</ButtonRow>}>
|
|
610
|
+
…
|
|
611
|
+
</Modal>`,
|
|
612
|
+
rendu: _jsx(DemoModal, {}),
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
id: 'toast',
|
|
616
|
+
nom: 'Notification',
|
|
617
|
+
resume: '⚠️ Ne remplace PAS « Alert » : une erreur de formulaire se dit à côté du champ, jamais dans un coin qui disparaît. Réserver à ce qui est vrai APRÈS COUP — « copié », « enregistré », « envoyé ».',
|
|
618
|
+
code: `<Toasts>
|
|
619
|
+
<Toast ton="ok">Lien copié.</Toast>
|
|
620
|
+
</Toasts>`,
|
|
621
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 8 }, children: [_jsx(Toast, { ton: "ok", children: "Lien copi\u00E9 dans le presse-papiers." }), _jsx(Toast, { children: "Brouillon enregistr\u00E9." }), _jsx(Toast, { ton: "err", children: "L\u2019envoi a \u00E9chou\u00E9. R\u00E9essayez." })] })),
|
|
622
|
+
},
|
|
623
|
+
],
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
id: 'icones',
|
|
627
|
+
nom: 'Icônes',
|
|
628
|
+
couche: 'commun',
|
|
629
|
+
css: 'icons.css',
|
|
630
|
+
resume: "34 icônes TRACÉES, jamais pleines : trait 2, bouts arrondis, grille de 24. Elles héritent de la couleur du texte — c'est ce qui leur permet de fonctionner sur papier comme sur la bande manifeste sans déclinaison. Le tracé est inliné : rien à résoudre côté bundler, rien à autoriser côté CSP.",
|
|
631
|
+
exemples: [
|
|
632
|
+
{
|
|
633
|
+
id: 'jeu',
|
|
634
|
+
nom: 'Le jeu complet',
|
|
635
|
+
resume: 'Sans « titre », l’icône est DÉCORATIVE et masquée aux lecteurs d’écran — le bon défaut : accolée à un libellé qui la répète, elle crée une annonce double.',
|
|
636
|
+
code: `<Icon nom="recherche" />
|
|
637
|
+
<Icon nom="document" taille="lg" />
|
|
638
|
+
<Icon nom="alerte" titre="Alerte" />`,
|
|
639
|
+
rendu: (_jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 14 }, children: ICONES.map((id) => (_jsxs("span", { title: NOMS_ICONES[id], style: { display: 'grid', gap: 4, justifyItems: 'center', width: 64 }, children: [_jsx(Icon, { nom: id, taille: "lg" }), _jsx("span", { className: "zv-meta zv-meta--sm zv-trunc", style: { maxWidth: 64 }, children: id })] }, id))) })),
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
id: 'tailles',
|
|
643
|
+
nom: 'Tailles',
|
|
644
|
+
resume: 'Le trait s’épaissit optiquement quand l’icône rétrécit : « sm » et « xl » le compensent. Une rangée de tailles mêlées sans cette compensation paraît déséquilibrée.',
|
|
645
|
+
code: `<Icon nom="document" taille="sm" /> <Icon nom="document" />
|
|
646
|
+
<Icon nom="document" taille="lg" /> <Icon nom="document" taille="xl" />`,
|
|
647
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 14, alignItems: 'center' }, children: [_jsx(Icon, { nom: ICONES[0], taille: "sm" }), _jsx(Icon, { nom: ICONES[0] }), _jsx(Icon, { nom: ICONES[0], taille: "lg" }), _jsx(Icon, { nom: ICONES[0], taille: "xl" }), _jsx(Icon, { nom: ICONES[0], taille: "lg", discret: true })] })),
|
|
648
|
+
},
|
|
649
|
+
],
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
id: 'mise-en-page',
|
|
653
|
+
nom: 'Mise en page',
|
|
654
|
+
couche: 'vitrine',
|
|
655
|
+
css: 'layout.css',
|
|
656
|
+
resume: "Gouttières, grille 12, sections, frise d'étapes, pieds de page. Une application n'a aucune raison de charger ce module. Les cinq étages d'empilement y sont nommés une fois pour toutes : un z-index écrit à la main finit toujours par passer devant ce qu'il ne fallait pas.",
|
|
657
|
+
exemples: [
|
|
658
|
+
{
|
|
659
|
+
id: 'gouttiere',
|
|
660
|
+
nom: 'Gouttière',
|
|
661
|
+
resume: 'La largeur de colonne du système. Toute la vitrine s’aligne dessus : un bloc qui pose sa propre largeur maximale se décale de tous les autres.',
|
|
662
|
+
code: `<Page>
|
|
663
|
+
<Gutter>…</Gutter>
|
|
664
|
+
<Gutter variante="wide">…</Gutter>
|
|
665
|
+
<Gutter variante="chrome"><Nav>…</Nav></Gutter>
|
|
666
|
+
</Page>`,
|
|
667
|
+
rendu: (_jsx(Gutter, { style: { border: '1px dashed var(--accent-line)', padding: 12 }, children: _jsx(Body, { taille: "dense", children: "Contenu align\u00E9 sur la colonne du syst\u00E8me." }) })),
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
id: 'grille',
|
|
671
|
+
nom: 'Grilles',
|
|
672
|
+
resume: '⚠️ Seules les portées 3, 4, 6, 8 et 9 existent : ce sont les découpes employées par la vitrine. En ajouter une revient à ajouter une mise en page — c’est une décision de DA, pas une utilité.',
|
|
673
|
+
code: `<Grid12>
|
|
674
|
+
<Col span={8}>…</Col>
|
|
675
|
+
<Col span={4}>…</Col>
|
|
676
|
+
</Grid12>
|
|
677
|
+
|
|
678
|
+
<Grid colonnes={3}>…</Grid>`,
|
|
679
|
+
rendu: (_jsxs("div", { style: { display: 'grid', gap: 12 }, children: [_jsxs(Grid12, { children: [_jsx(Col, { span: 8, children: _jsx(Card, { children: _jsx(Body, { taille: "dense", children: "span 8" }) }) }), _jsx(Col, { span: 4, children: _jsx(Card, { children: _jsx(Body, { taille: "dense", children: "span 4" }) }) })] }), _jsx(Grid, { colonnes: 3, children: ['Indexer', 'Interroger', 'Vérifier'].map((t) => (_jsx(Card, { children: _jsx(Body, { taille: "dense", children: t }) }, t))) })] })),
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
id: 'sections',
|
|
683
|
+
nom: 'Sections',
|
|
684
|
+
resume: 'Le bloc « aside » tombe SOUS le titre en dessous du point de rupture — c’est le CSS qui le fait, pas une condition de rendu.',
|
|
685
|
+
code: `<SectionHead aside={<LinkArrow href="/methode">Tout voir</LinkArrow>}>
|
|
686
|
+
<Kicker>Méthode</Kicker>
|
|
687
|
+
<H2>Trois étapes, rien de plus</H2>
|
|
688
|
+
</SectionHead>
|
|
689
|
+
<SectionRule />`,
|
|
690
|
+
rendu: (_jsxs("div", { children: [_jsxs(SectionHead, { aside: _jsx(LinkArrow, { href: "#", children: "Tout voir" }), children: [_jsx(Kicker, { children: "M\u00E9thode" }), _jsx(Heading, { taille: "h2-sm", children: "Trois \u00E9tapes, rien de plus" })] }), _jsx(SectionRule, {})] })),
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
id: 'sheet-section',
|
|
694
|
+
nom: 'Section de document',
|
|
695
|
+
resume: 'Un intitulé mono, un filet, du corps — pour un document long.',
|
|
696
|
+
code: `<SheetSection titre="ENGAGEMENTS">…</SheetSection>`,
|
|
697
|
+
rendu: (_jsx(SheetSection, { titre: "ENGAGEMENTS", children: _jsx(Body, { taille: "dense", children: "Les donn\u00E9es restent h\u00E9berg\u00E9es en France et ne sont jamais vers\u00E9es \u00E0 un entra\u00EEnement." }) })),
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
id: 'nav-vitrine',
|
|
701
|
+
nom: 'Navigation vitrine',
|
|
702
|
+
resume: '⚠️ « NavLink » est la navigation de VITRINE ; l’entrée applicative s’appelle « SideLink ». Les deux ne doivent jamais se recouvrir. La rangée disparaît sous le point de rupture, remplacée par le burger.',
|
|
703
|
+
code: `<Nav>
|
|
704
|
+
<NavLogo>…</NavLogo>
|
|
705
|
+
<NavLinks>
|
|
706
|
+
<NavLink href="/produit">Produit</NavLink>
|
|
707
|
+
<NavLink href="/connexion" discret>Se connecter</NavLink>
|
|
708
|
+
</NavLinks>
|
|
709
|
+
<NavBurger aria-label="Ouvrir le menu">…</NavBurger>
|
|
710
|
+
</Nav>`,
|
|
711
|
+
rendu: (_jsxs(Nav, { style: { border: '1px solid var(--hairline)', padding: '0 12px' }, children: [_jsx(NavLogo, { children: _jsx(Mono, { ton: "ink", children: "ZEVRA" }) }), _jsxs(NavLinks, { children: [_jsx(NavLink, { href: "#", children: "Produit" }), _jsx(NavLink, { href: "#", children: "M\u00E9thode" }), _jsx(NavLink, { href: "#", discret: true, children: "Se connecter" })] })] })),
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
id: 'etapes',
|
|
715
|
+
nom: 'Frise d’étapes',
|
|
716
|
+
resume: 'Le point de méthode est le TROISIÈME et dernier emploi autorisé du spectre (avec le filet de kicker et la barre de progression). Jamais en fond, jamais en texte.',
|
|
717
|
+
code: `<Steps avancement={0.66}>
|
|
718
|
+
<Step>Indexer</Step>
|
|
719
|
+
<Step teinte="violet">Interroger</Step>
|
|
720
|
+
<Step teinte="cyan">Vérifier</Step>
|
|
721
|
+
</Steps>`,
|
|
722
|
+
rendu: (_jsxs(Steps, { avancement: 0.66, children: [_jsx(Step, { children: _jsx(Body, { taille: "dense", children: "Indexer" }) }), _jsx(Step, { teinte: "violet", children: _jsx(Body, { taille: "dense", children: "Interroger" }) }), _jsx(Step, { teinte: "cyan", children: _jsx(Body, { taille: "dense", children: "V\u00E9rifier" }) })] })),
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
id: 'stats-page',
|
|
726
|
+
nom: 'Ligne de statistiques',
|
|
727
|
+
resume: 'La rangée de chiffres d’une page vitrine, sous un hero ou dans une bande.',
|
|
728
|
+
code: `<Stats>
|
|
729
|
+
<Stat valeur="4 812">documents indexés</Stat>
|
|
730
|
+
<Stat valeur="1,2 s">latence médiane</Stat>
|
|
731
|
+
</Stats>`,
|
|
732
|
+
rendu: (_jsxs(Stats, { children: [_jsx(Stat, { valeur: "4 812", children: "documents index\u00E9s" }), _jsx(Stat, { valeur: "1,2 s", children: "latence m\u00E9diane" }), _jsx(Stat, { valeur: "100 %", children: "r\u00E9ponses sourc\u00E9es" })] })),
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
id: 'hero-cta',
|
|
736
|
+
nom: 'Blocs centrés',
|
|
737
|
+
resume: 'Le hero d’ouverture et le bloc d’appel à l’action de fin de page.',
|
|
738
|
+
code: `<Hero><Kicker>…</Kicker><H1>…</H1><Lead>…</Lead></Hero>
|
|
739
|
+
<CTA><Heading taille="h2-cta">…</Heading><Button>…</Button></CTA>`,
|
|
740
|
+
rendu: (_jsxs(CTA, { style: { padding: '24px 0' }, children: [_jsx(Heading2Cta, {}), _jsx(ButtonRow, { children: _jsx(Button, { children: "Demander une d\u00E9monstration" }) })] })),
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
id: 'pieds',
|
|
744
|
+
nom: 'Pieds de page',
|
|
745
|
+
resume: '⚠️ « ProofBar » ne cite que de VRAIS clients : un nom inventé dans une bande de preuve sociale est un faux, pas un placeholder.',
|
|
746
|
+
code: `<Footer marque={<><Mono ton="ink">ZEVRA</Mono><Tagline>…</Tagline></>}>
|
|
747
|
+
…
|
|
748
|
+
</Footer>
|
|
749
|
+
<FooterMini logo={<Mono ton="ink">ZEVRA</Mono>}>© 2026</FooterMini>`,
|
|
750
|
+
rendu: (_jsx(FooterMini, { logo: _jsx(Mono, { ton: "ink", children: "ZEVRA" }), children: _jsx(Note, { children: "\u00A9 2026 Zevra \u00B7 H\u00E9berg\u00E9 en France" }) })),
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
id: 'visibilite',
|
|
754
|
+
nom: 'Visibilité',
|
|
755
|
+
resume: '⚠️ Rendu par le CSS, PAS par JavaScript : le serveur ne connaît pas la largeur de l’écran, et conditionner le rendu produit un décalage d’hydratation. Les deux nœuds sont posés, le CSS en masque un.',
|
|
756
|
+
code: `<OnlyDesktop><NavLinks>…</NavLinks></OnlyDesktop>
|
|
757
|
+
<OnlyMobile><NavBurger aria-label="Menu">…</NavBurger></OnlyMobile>`,
|
|
758
|
+
rendu: (_jsxs("div", { style: { display: 'flex', gap: 10 }, children: [_jsx("span", { className: "zv-only-desktop", children: _jsx(Badge, { ton: "accent", children: "VISIBLE \u2265 768" }) }), _jsx("span", { className: "zv-only-mobile", children: _jsx(Badge, { ton: "accent", children: "VISIBLE < 768" }) })] })),
|
|
759
|
+
},
|
|
760
|
+
],
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: 'surfaces',
|
|
764
|
+
nom: 'Surfaces',
|
|
765
|
+
couche: 'vitrine',
|
|
766
|
+
css: 'surfaces.css + motion.css',
|
|
767
|
+
resume: "Ce qui distingue une page Zevra d'une page blanche bien composée. ⚠️ Tout y est DÉCORATIF : posé en absolu derrière le contenu, sans capter le pointeur, masqué aux lecteurs d'écran — et suppose un parent « position: relative; overflow: hidden ».",
|
|
768
|
+
exemples: [
|
|
769
|
+
{
|
|
770
|
+
id: 'bande',
|
|
771
|
+
nom: 'Bande manifeste',
|
|
772
|
+
resume: '⚠️ LA surface sombre du système. Les surfaces sombres se font avec elle et --accent-on-dark, JAMAIS en inversant les neutres : les contrastes ont été réglés dans ce sens-là et pas dans l’autre.',
|
|
773
|
+
code: `<Band lueur filigrane={<Glyph variante="watermark">…</Glyph>}>
|
|
774
|
+
<Kicker surSombre>Souveraineté</Kicker>
|
|
775
|
+
<H2>Vos pièces ne quittent pas la France.</H2>
|
|
776
|
+
</Band>`,
|
|
777
|
+
surSombre: true,
|
|
778
|
+
rendu: (_jsxs(Band, { lueur: true, children: [_jsx(Kicker, { surSombre: true, children: "Souverainet\u00E9" }), _jsx(Heading, { taille: "h2-sm", children: "Vos pi\u00E8ces ne quittent pas la France." }), _jsx(Body, { children: "Infrastructure d\u00E9di\u00E9e, chiffrement au repos, aucun transfert hors Union europ\u00E9enne." }), _jsxs("div", { style: { display: 'flex', gap: 8, marginTop: 12 }, children: [_jsx(Tag, { surSombre: true, etat: "ok", children: "CHIFFR\u00C9" }), _jsx(Tag, { surSombre: true, children: "OVHCLOUD \u00B7 GRA" })] })] })),
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
id: 'panneau-navy',
|
|
782
|
+
nom: 'Panneau sombre',
|
|
783
|
+
resume: 'Plus petit qu’une bande : une carte, un encart. « TextOnDark » repeint un texte isolé — « Band » le fait déjà pour son contenu courant, l’ajouter dedans ne sert à rien.',
|
|
784
|
+
code: `<PanelNavy><TextOnDark>…</TextOnDark></PanelNavy>`,
|
|
785
|
+
surSombre: true,
|
|
786
|
+
rendu: (_jsx(PanelNavy, { children: _jsxs(TextOnDark, { children: [_jsx(Mono, { ton: "on-dark", children: "CHIFFREMENT" }), _jsx(Body, { children: "AES-256 au repos, TLS 1.3 en transit." })] }) })),
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
id: 'halo',
|
|
790
|
+
nom: 'Halo, sol, voile',
|
|
791
|
+
resume: 'Le violet et le cyan du spectre, très dilués. Ce n’est PAS un emploi du spectre en aplat : c’est une lumière — elle ne compte pas dans les trois emplois autorisés.',
|
|
792
|
+
code: `<section style={{ position: 'relative', overflow: 'hidden' }}>
|
|
793
|
+
<Halo place="hero" />
|
|
794
|
+
<GridFloor />
|
|
795
|
+
<Fade blanc />
|
|
796
|
+
…
|
|
797
|
+
</section>`,
|
|
798
|
+
rendu: (_jsxs("div", { style: {
|
|
799
|
+
position: 'relative',
|
|
800
|
+
overflow: 'hidden',
|
|
801
|
+
height: 150,
|
|
802
|
+
display: 'grid',
|
|
803
|
+
placeItems: 'center',
|
|
804
|
+
}, children: [_jsx(Halo, { place: "core" }), _jsx(GridFloor, { carte: true }), _jsx(Fade, { blanc: true }), _jsx(Mono, { ton: "label", style: { position: 'relative' }, children: "HALO \u00B7 SOL \u00B7 VOILE" })] })),
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
id: 'glyphe',
|
|
808
|
+
nom: 'Glyphe',
|
|
809
|
+
resume: 'Enveloppe d’un logo produit posé comme motif. Le glyphe lui-même est une image du paquet (@zevra/ui/logos/…), pas un tracé du CSS.',
|
|
810
|
+
code: `<Glyph variante="deep"><img src="…/logos/memoire-glyph-orig.png" alt="" /></Glyph>`,
|
|
811
|
+
rendu: (_jsx(Glyph, { children: _jsx(Icon, { nom: ICONES[0], taille: "xl" }) })),
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
id: 'mouvement',
|
|
815
|
+
nom: 'Mouvement',
|
|
816
|
+
resume: '⚠️ Les neuf animations sont pilotées AU DÉFILEMENT et réservées à la vitrine : le chrome applicatif n’anime rien. « prefers-reduced-motion » les coupe toutes, globalement, depuis base.css.',
|
|
817
|
+
code: `<div className={anim('rise')}>…</div>
|
|
818
|
+
<div className={anim('pop', 3)}>…</div>
|
|
819
|
+
<div className={anim('converge', 'tr')}>…</div>`,
|
|
820
|
+
rendu: (_jsx("div", { style: { display: 'flex', gap: 8, flexWrap: 'wrap' }, children: ['rise', 'pop', 'filet', 'glyph-in', 'converge', 'breathe', 'drift', 'dot-active', 'progress'].map((nom) => (_jsx("span", { className: anim(nom), children: _jsx(Chip, { variante: "mono", children: nom }) }, nom))) })),
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
},
|
|
824
|
+
];
|
|
825
|
+
function Heading2Cta() {
|
|
826
|
+
return _jsx(Heading, { taille: "h2-cta", children: "Voir Zevra sur vos propres pi\u00E8ces." });
|
|
827
|
+
}
|
|
828
|
+
/** Tous les exemples à plat — pratique pour une recherche ou un test. */
|
|
829
|
+
export const EXEMPLES = CATALOGUE.flatMap((g) => g.exemples.map((e) => ({ ...e, groupe: g.id })));
|
|
830
|
+
//# sourceMappingURL=catalogue.js.map
|