@zevra/ui 0.7.0 → 0.9.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/DECISIONS.md +227 -0
- package/dist/actions.d.ts +13 -3
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +9 -2
- package/dist/actions.js.map +1 -1
- package/dist/catalogue.d.ts.map +1 -1
- package/dist/catalogue.js +160 -11
- package/dist/catalogue.js.map +1 -1
- package/dist/css-inline.d.ts.map +1 -1
- package/dist/css-inline.js +1 -1
- package/dist/css-inline.js.map +1 -1
- package/dist/data-table.d.ts +30 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +35 -0
- package/dist/data-table.js.map +1 -0
- package/dist/data.d.ts +34 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +27 -0
- package/dist/data.js.map +1 -1
- package/dist/feedback.d.ts +49 -0
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +24 -0
- package/dist/feedback.js.map +1 -1
- package/dist/forms.d.ts +36 -0
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +24 -0
- package/dist/forms.js.map +1 -1
- package/dist/icon-data.d.ts +1 -1
- package/dist/icon-data.d.ts.map +1 -1
- package/dist/icon-data.js +42 -0
- package/dist/icon-data.js.map +1 -1
- package/dist/icon.d.ts +1 -1
- package/dist/icon.js +1 -1
- package/dist/layout.d.ts +21 -0
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +18 -0
- package/dist/layout.js.map +1 -1
- package/dist/navigation.d.ts +45 -7
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +54 -7
- package/dist/navigation.js.map +1 -1
- package/dist/surfaces.d.ts +18 -0
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +6 -0
- package/dist/surfaces.js.map +1 -1
- package/icons/index.json +126 -0
- package/icons/sprite.svg +21 -0
- package/package.json +18 -2
- package/react/actions.tsx +28 -2
- package/react/catalogue.tsx +343 -17
- package/react/css-inline.ts +1 -1
- package/react/data-table.tsx +153 -0
- package/react/data.tsx +87 -1
- package/react/feedback.tsx +98 -0
- package/react/forms.tsx +90 -0
- package/react/icon-data.ts +63 -0
- package/react/icon.tsx +2 -2
- package/react/layout.tsx +39 -0
- package/react/navigation.tsx +108 -6
- package/react/surfaces.tsx +45 -0
- package/src/base.css +16 -0
- package/src/components.css +135 -3
- package/src/data.css +188 -1
- package/src/feedback.css +196 -37
- package/src/forms.css +137 -1
- package/src/layout.css +72 -0
- package/src/navigation.css +207 -12
- package/src/surfaces.css +76 -7
- package/src/tokens.css +6 -0
- package/tokens/index.js +2 -0
package/react/catalogue.tsx
CHANGED
|
@@ -22,31 +22,34 @@ import {
|
|
|
22
22
|
Quote, Rows, RowsItem, Src, SrcRow, StatCard, Tag, UiPreview,
|
|
23
23
|
} from './content.js'
|
|
24
24
|
import {
|
|
25
|
-
Avatar, Break, Cell, Chip, ChipRow, Cite, CiteRow,
|
|
26
|
-
|
|
27
|
-
Trunc, Unwrap,
|
|
25
|
+
Avatar, Break, Cell, Chip, ChipRow, Cite, CiteRow, Code, CodeBlock,
|
|
26
|
+
FileType, Fold, KV, KVRow, Kbd, List, ListMain, ListName, ListRow, Meta,
|
|
27
|
+
MetaRow, Row, Table, TableHead, Trunc, Unwrap,
|
|
28
28
|
} from './data.js'
|
|
29
29
|
import {
|
|
30
|
-
Alert, Badge, Caret, Dot, Empty, Loading, Progress,
|
|
30
|
+
Alert, Badge, Caret, Dot, Empty, Loading, Progress, Skeleton, Spinner,
|
|
31
|
+
Status, Tooltip,
|
|
31
32
|
} from './feedback.js'
|
|
32
33
|
import {
|
|
33
|
-
Checkbox, Drop, Field, Input,
|
|
34
|
-
SelectAnchor, SelectTrigger, Switch, Textarea,
|
|
34
|
+
Checkbox, Drop, Field, Input, InputAffix, Radio, Range, Search, Seg,
|
|
35
|
+
SegGroup, Select, SelectAnchor, SelectTrigger, Switch, Textarea,
|
|
35
36
|
} from './forms.js'
|
|
36
37
|
import { ICONES, Icon, IconButton, NOMS_ICONES } from './icon.js'
|
|
37
38
|
import {
|
|
38
|
-
CTA, Col, Footer, FooterMini, Grid, Grid12,
|
|
39
|
-
|
|
40
|
-
Stats, Step, Steps,
|
|
39
|
+
Banner, CTA, Carousel, CarouselItem, Col, Footer, FooterMini, Grid, Grid12,
|
|
40
|
+
Gutter, Hero, Nav, NavLink, NavLinks, NavLogo, ProofBar, SectionHead,
|
|
41
|
+
SectionRule, SheetSection, Stat, Stats, Step, Steps,
|
|
41
42
|
} from './layout.js'
|
|
42
43
|
import {
|
|
43
44
|
ChromeButton, CitePanel, Crumbs, Menu, MenuItem, Pager, PagerArrow,
|
|
44
|
-
PagerRank, PagerStep, Scroll, SideGroup, SideLink, Sidebar,
|
|
45
|
-
SidebarHead, Tabs, Topbar, TopbarTitle,
|
|
45
|
+
PagerRank, PagerStep, Popover, Scroll, SideGroup, SideLink, Sidebar,
|
|
46
|
+
SidebarFoot, SidebarHead, Tabs, Topbar, TopbarTitle,
|
|
46
47
|
} from './navigation.js'
|
|
47
48
|
import { Drawer, Modal, Toast, Toasts } from './overlays.js'
|
|
48
49
|
import { SelectMenu } from './select-menu.js'
|
|
49
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
Band, Fade, Glyph, GridFloor, Halo, PanelNavy, SocialFrame, TextOnDark, anim,
|
|
52
|
+
} from './surfaces.js'
|
|
50
53
|
import {
|
|
51
54
|
Body, CardTitle, Display, Em, H1, H2, H3, Heading, Kicker, Lead, Link, Mono, Note,
|
|
52
55
|
Rule, Spec, Tagline,
|
|
@@ -248,6 +251,66 @@ function DemoDrop() {
|
|
|
248
251
|
)
|
|
249
252
|
}
|
|
250
253
|
|
|
254
|
+
function DemoRange() {
|
|
255
|
+
const [sources, setSources] = useState(12)
|
|
256
|
+
return (
|
|
257
|
+
<div style={{ maxWidth: 320 }}>
|
|
258
|
+
<Field
|
|
259
|
+
label="SOURCES INTERROGÉES"
|
|
260
|
+
htmlFor="ex-range"
|
|
261
|
+
help={`${sources} sources sur 17`}
|
|
262
|
+
>
|
|
263
|
+
<Range
|
|
264
|
+
id="ex-range"
|
|
265
|
+
min={1}
|
|
266
|
+
max={17}
|
|
267
|
+
value={sources}
|
|
268
|
+
onChange={(e) => setSources(Number(e.currentTarget.value))}
|
|
269
|
+
/>
|
|
270
|
+
</Field>
|
|
271
|
+
</div>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function DemoTabsLine() {
|
|
276
|
+
const [actif, setActif] = useState<'apercu' | 'sources' | 'journal'>('apercu')
|
|
277
|
+
return (
|
|
278
|
+
<Tabs
|
|
279
|
+
variante="soulignes"
|
|
280
|
+
actif={actif}
|
|
281
|
+
onChange={setActif}
|
|
282
|
+
onglets={[
|
|
283
|
+
{ id: 'apercu', label: 'Aperçu' },
|
|
284
|
+
{ id: 'sources', label: 'Sources', compte: 12 },
|
|
285
|
+
{ id: 'journal', label: 'Journal' },
|
|
286
|
+
]}
|
|
287
|
+
/>
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function DemoPopover() {
|
|
292
|
+
const [ouvert, setOuvert] = useState(false)
|
|
293
|
+
return (
|
|
294
|
+
<SelectAnchor>
|
|
295
|
+
<Button variante="fantome" compact aria-expanded={ouvert} onClick={() => setOuvert(!ouvert)}>
|
|
296
|
+
Colonnes affichées
|
|
297
|
+
</Button>
|
|
298
|
+
{ouvert && (
|
|
299
|
+
<Popover>
|
|
300
|
+
<div style={{ display: 'grid', gap: 8 }}>
|
|
301
|
+
{['Nom', 'Taille', 'Statut'].map((c) => (
|
|
302
|
+
<label key={c} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
|
303
|
+
<Checkbox defaultChecked={c !== 'Taille'} />
|
|
304
|
+
<span className="zv-body zv-body--dense">{c}</span>
|
|
305
|
+
</label>
|
|
306
|
+
))}
|
|
307
|
+
</div>
|
|
308
|
+
</Popover>
|
|
309
|
+
)}
|
|
310
|
+
</SelectAnchor>
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
|
|
251
314
|
/* ── Le catalogue ─────────────────────────────────────────────────── */
|
|
252
315
|
|
|
253
316
|
export const CATALOGUE: GroupeCatalogue[] = [
|
|
@@ -368,7 +431,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
368
431
|
couche: 'commun',
|
|
369
432
|
css: 'components.css',
|
|
370
433
|
resume:
|
|
371
|
-
"
|
|
434
|
+
"Quatre variantes, et UNE SEULE pleine par page — « danger » comprise, la règle compte les aplats, pas les couleurs : c'est ce qui fait que l'action principale se voit. Un écran à deux boutons pleins n'en a plus aucun.",
|
|
372
435
|
exemples: [
|
|
373
436
|
{
|
|
374
437
|
id: 'boutons',
|
|
@@ -408,6 +471,24 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
408
471
|
</div>
|
|
409
472
|
),
|
|
410
473
|
},
|
|
474
|
+
{
|
|
475
|
+
id: 'etats',
|
|
476
|
+
nom: 'États',
|
|
477
|
+
resume:
|
|
478
|
+
'« danger » COMPTE comme le bouton plein de la page — la règle compte les aplats, pas les couleurs ; à réserver à la confirmation destructive. « occupe » pose aria-busy et aria-disabled et AVALE le clic sans sortir le bouton du parcours clavier : le LIBELLÉ doit changer avec lui, l’estompement seul ne dit pas ce qu’on attend. Survol et appui sont dans le CSS, rien à câbler.',
|
|
479
|
+
code: `<Button variante="danger">Supprimer définitivement</Button>
|
|
480
|
+
<Button occupe>Connexion…</Button>
|
|
481
|
+
<Button variante="fantome" disabled>Envoyer</Button>`,
|
|
482
|
+
rendu: (
|
|
483
|
+
<ButtonRow>
|
|
484
|
+
<Button variante="danger">Supprimer définitivement</Button>
|
|
485
|
+
<Button occupe>Connexion…</Button>
|
|
486
|
+
<Button variante="fantome" disabled>
|
|
487
|
+
Envoyer
|
|
488
|
+
</Button>
|
|
489
|
+
</ButtonRow>
|
|
490
|
+
),
|
|
491
|
+
},
|
|
411
492
|
{
|
|
412
493
|
id: 'lien-fleche',
|
|
413
494
|
nom: 'Lien fléché',
|
|
@@ -560,6 +641,54 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
560
641
|
</div>
|
|
561
642
|
),
|
|
562
643
|
},
|
|
644
|
+
{
|
|
645
|
+
id: 'affixe',
|
|
646
|
+
nom: 'Champ à affixe',
|
|
647
|
+
resume:
|
|
648
|
+
'« 30 », seul dans un champ, ne dit pas s’il s’agit de jours ou d’euros. Le champ intérieur est un <Input nu> : c’est le CADRE qui fait le champ. Les identifiants d’affixe (idAvant/idApres) se citent en aria-describedby sur le champ, sinon l’unité reste muette au lecteur d’écran. À ne pas employer quand l’unité est déjà dans l’intitulé.',
|
|
649
|
+
code: `<Field label="HONORAIRES" htmlFor="hono">
|
|
650
|
+
<InputAffix avant="€" apres="HT" idAvant="hono-avant" idApres="hono-apres">
|
|
651
|
+
<Input nu id="hono" type="number" defaultValue={1200}
|
|
652
|
+
aria-describedby="hono-avant hono-apres" />
|
|
653
|
+
</InputAffix>
|
|
654
|
+
</Field>`,
|
|
655
|
+
rendu: (
|
|
656
|
+
<div style={{ display: 'grid', gap: 16, maxWidth: 320 }}>
|
|
657
|
+
<Field label="DÉLAI DE RÉPONSE" htmlFor="ex-delai">
|
|
658
|
+
<InputAffix apres="JOURS" idApres="ex-delai-apres">
|
|
659
|
+
<Input
|
|
660
|
+
nu
|
|
661
|
+
id="ex-delai"
|
|
662
|
+
type="number"
|
|
663
|
+
defaultValue={30}
|
|
664
|
+
aria-describedby="ex-delai-apres"
|
|
665
|
+
/>
|
|
666
|
+
</InputAffix>
|
|
667
|
+
</Field>
|
|
668
|
+
<Field label="HONORAIRES" htmlFor="ex-hono">
|
|
669
|
+
<InputAffix avant="€" apres="HT" idAvant="ex-hono-avant" idApres="ex-hono-apres">
|
|
670
|
+
<Input
|
|
671
|
+
nu
|
|
672
|
+
id="ex-hono"
|
|
673
|
+
type="number"
|
|
674
|
+
defaultValue={1200}
|
|
675
|
+
aria-describedby="ex-hono-avant ex-hono-apres"
|
|
676
|
+
/>
|
|
677
|
+
</InputAffix>
|
|
678
|
+
</Field>
|
|
679
|
+
</div>
|
|
680
|
+
),
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
id: 'curseur',
|
|
684
|
+
nom: 'Curseur',
|
|
685
|
+
resume:
|
|
686
|
+
'Natif habillé : clavier, bornes et annonce viennent du navigateur ; le remplissage suit la valeur en contrôlé. Toujours un intitulé ET la valeur affichée en clair — un curseur seul ne dit ni ce qu’il règle, ni sur combien. Pas de spectre sur la piste : ce n’est pas une barre de progression.',
|
|
687
|
+
code: `<Field label="SOURCES INTERROGÉES" htmlFor="prof" help={\`\${sources} sources sur 17\`}>
|
|
688
|
+
<Range id="prof" min={1} max={17} value={sources} onChange={…} />
|
|
689
|
+
</Field>`,
|
|
690
|
+
rendu: <DemoRange />,
|
|
691
|
+
},
|
|
563
692
|
{
|
|
564
693
|
id: 'puces',
|
|
565
694
|
nom: 'Puces de filtre',
|
|
@@ -589,7 +718,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
589
718
|
couche: 'applicatif',
|
|
590
719
|
css: 'feedback.css',
|
|
591
720
|
resume:
|
|
592
|
-
"Rien n'
|
|
721
|
+
"Rien n'y crie : le bandeau porte le ton, la pastille l'état, la phrase le travail. La roue, le squelette et l'infobulle — longtemps refusés faute de relevé — sont arbitrés depuis le 25/08/2026 (DECISIONS.md), chacun avec son périmètre écrit ; « Loading », qui nomme ce qu'on attend, reste le motif d'attente par défaut.",
|
|
593
722
|
exemples: [
|
|
594
723
|
{
|
|
595
724
|
id: 'alertes',
|
|
@@ -682,6 +811,56 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
682
811
|
</div>
|
|
683
812
|
),
|
|
684
813
|
},
|
|
814
|
+
{
|
|
815
|
+
id: 'roue',
|
|
816
|
+
nom: 'Roue',
|
|
817
|
+
resume:
|
|
818
|
+
'Attente COURTE et LOCALE : un bouton, une cellule, un panneau sans la place d’une phrase. Pour l’attente d’un écran, « Loading » reste le motif — la phrase dit sur quoi et sur combien. Sans label, la roue est décorative et masquée aux lecteurs d’écran.',
|
|
819
|
+
code: `<Spinner label="Vérification du dépôt…" />
|
|
820
|
+
<Spinner grand />`,
|
|
821
|
+
rendu: (
|
|
822
|
+
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
|
|
823
|
+
<Spinner label="Vérification du dépôt…" />
|
|
824
|
+
<Spinner grand />
|
|
825
|
+
</div>
|
|
826
|
+
),
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
id: 'squelette',
|
|
830
|
+
nom: 'Squelette',
|
|
831
|
+
resume:
|
|
832
|
+
'Il ANNONCE une structure connue — la carte, la ligne qui va venir ; pour un contenu de forme inconnue, c’est « Loading ». La géométrie vient de l’appelant : un squelette qui invente ses dimensions ne ressemble jamais au contenu. C’est la zone qui charge qui porte aria-busy, pas chaque os.',
|
|
833
|
+
code: `<div aria-busy="true">
|
|
834
|
+
<Skeleton texte largeur="60%" />
|
|
835
|
+
<Skeleton texte />
|
|
836
|
+
<Skeleton hauteur={96} />
|
|
837
|
+
</div>`,
|
|
838
|
+
rendu: (
|
|
839
|
+
<div aria-busy="true" style={{ display: 'grid', gap: 10, maxWidth: 380 }}>
|
|
840
|
+
<Skeleton texte largeur="60%" />
|
|
841
|
+
<Skeleton texte />
|
|
842
|
+
<Skeleton hauteur={96} />
|
|
843
|
+
</div>
|
|
844
|
+
),
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
id: 'infobulle',
|
|
848
|
+
nom: 'Infobulle',
|
|
849
|
+
resume:
|
|
850
|
+
'Un COMPLÉMENT dispensable — un raccourci, une date exacte, une unité : une commande n’a pas le droit d’y cacher son nom, et le tactile ne survole pas. Liage aria-describedby EXPLICITE (id), comme le htmlFor de Field — pas de useId, le rendu serveur reste possible. Apparition retardée de 300 ms, disparition immédiate, Échap la ferme.',
|
|
851
|
+
code: `<Tooltip id="th-date" contenu="Déposé le 12/08/2026 à 14 h 02">
|
|
852
|
+
<Button variante="fantome" compact aria-describedby="th-date">12 août</Button>
|
|
853
|
+
</Tooltip>`,
|
|
854
|
+
rendu: (
|
|
855
|
+
<div style={{ paddingTop: 44 }}>
|
|
856
|
+
<Tooltip id="ex-th-date" contenu="Déposé le 12/08/2026 à 14 h 02">
|
|
857
|
+
<Button variante="fantome" compact aria-describedby="ex-th-date">
|
|
858
|
+
12 août
|
|
859
|
+
</Button>
|
|
860
|
+
</Tooltip>
|
|
861
|
+
</div>
|
|
862
|
+
),
|
|
863
|
+
},
|
|
685
864
|
],
|
|
686
865
|
},
|
|
687
866
|
|
|
@@ -1089,6 +1268,45 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
1089
1268
|
</div>
|
|
1090
1269
|
),
|
|
1091
1270
|
},
|
|
1271
|
+
{
|
|
1272
|
+
id: 'depliant',
|
|
1273
|
+
nom: 'Rangée dépliante',
|
|
1274
|
+
resume:
|
|
1275
|
+
'<details> NATIF : clavier, annonce et état viennent du navigateur, aucun JavaScript. Le pliage APPLICATIF — options avancées, détail d’une ligne de journal ; la FAQ (contenu) reste celui de la vitrine. Plusieurs rangées se posent bord à bord, le filet mitoyen tombe seul.',
|
|
1276
|
+
code: `<Fold titre="Options avancées">…</Fold>
|
|
1277
|
+
<Fold titre="Journal d'indexation" ouvert>…</Fold>`,
|
|
1278
|
+
rendu: (
|
|
1279
|
+
<div style={{ maxWidth: 420 }}>
|
|
1280
|
+
<Fold titre="Options avancées">
|
|
1281
|
+
Périmètre, profondeur et sources exclues se règlent par dossier, jamais
|
|
1282
|
+
par requête.
|
|
1283
|
+
</Fold>
|
|
1284
|
+
<Fold titre="Journal d’indexation" ouvert>
|
|
1285
|
+
Reçu, OCR, indexation : chaque étape est datée, et l’échec d’une page
|
|
1286
|
+
n’interrompt pas les suivantes.
|
|
1287
|
+
</Fold>
|
|
1288
|
+
</div>
|
|
1289
|
+
),
|
|
1290
|
+
},
|
|
1291
|
+
{
|
|
1292
|
+
id: 'code',
|
|
1293
|
+
nom: 'Code et raccourcis',
|
|
1294
|
+
resume:
|
|
1295
|
+
'La chasse fixe RÉELLE (--font-code) : --font-mono est proportionnelle et n’aligne pas du code, tabular-nums n’aligne que les chiffres. Aucune coloration syntaxique — elle imposerait une palette que la charte n’a pas. « ⌘K » fait DEUX touches, donc deux Kbd.',
|
|
1296
|
+
code: `<Body>Lancer <Code>pnpm build</Code>, puis <Kbd>⌘</Kbd> <Kbd>K</Kbd>.</Body>
|
|
1297
|
+
<CodeBlock>claude mcp add --transport http zevra-design …</CodeBlock>`,
|
|
1298
|
+
rendu: (
|
|
1299
|
+
<div style={{ display: 'grid', gap: 12, maxWidth: 520 }}>
|
|
1300
|
+
<Body taille="dense">
|
|
1301
|
+
Lancer <Code>pnpm build</Code>, puis ouvrir la recherche avec <Kbd>⌘</Kbd>{' '}
|
|
1302
|
+
<Kbd>K</Kbd>.
|
|
1303
|
+
</Body>
|
|
1304
|
+
<CodeBlock>
|
|
1305
|
+
{'claude mcp add --transport http zevra-design \\\n https://mcp.design.zevra.tech/mcp --scope user'}
|
|
1306
|
+
</CodeBlock>
|
|
1307
|
+
</div>
|
|
1308
|
+
),
|
|
1309
|
+
},
|
|
1092
1310
|
],
|
|
1093
1311
|
},
|
|
1094
1312
|
|
|
@@ -1160,15 +1378,37 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
1160
1378
|
},
|
|
1161
1379
|
{
|
|
1162
1380
|
id: 'onglets',
|
|
1163
|
-
nom: 'Onglets',
|
|
1381
|
+
nom: 'Onglets en puces',
|
|
1164
1382
|
resume:
|
|
1165
|
-
'
|
|
1383
|
+
'La rangée de puces, grammaire d’état de Seg — le motif des FILTRES, qui restreignent une collection. Ce composant n’ajoute que l’ARIA. Pour les VUES d’un même objet, prendre la variante soulignée.',
|
|
1166
1384
|
code: `<Tabs actif={actif} onChange={setActif} onglets={[
|
|
1167
1385
|
{ id: 'apercu', label: 'Aperçu' },
|
|
1168
1386
|
{ id: 'sources', label: 'Sources', compte: 12 },
|
|
1169
1387
|
]} />`,
|
|
1170
1388
|
rendu: <DemoTabs />,
|
|
1171
1389
|
},
|
|
1390
|
+
{
|
|
1391
|
+
id: 'onglets-soulignes',
|
|
1392
|
+
nom: 'Onglets soulignés',
|
|
1393
|
+
resume:
|
|
1394
|
+
'L’arbitrage longtemps en attente, tranché le 25/08/2026 : trait actif de 2 px — l’épaisseur des filets dessinés du système — en accent, PAS en spectre (un quatrième emploi n’existe pas). Pour les VUES d’un même objet (Aperçu / Sources) ; pour filtrer, les puces.',
|
|
1395
|
+
code: `<Tabs variante="soulignes" actif={actif} onChange={setActif} onglets={[
|
|
1396
|
+
{ id: 'apercu', label: 'Aperçu' },
|
|
1397
|
+
{ id: 'sources', label: 'Sources', compte: 12 },
|
|
1398
|
+
]} />`,
|
|
1399
|
+
rendu: <DemoTabsLine />,
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
id: 'popover',
|
|
1403
|
+
nom: 'Popover',
|
|
1404
|
+
resume:
|
|
1405
|
+
'Surface ancrée LIBRE — aide contextuelle, mini-formulaire de filtre — dans la même ancre que le menu (SelectAnchor). Ce n’est PAS une infobulle : le popover s’ouvre au CLIC et peut porter de l’interactif. Fermeture par clic extérieur et Échap : à l’appelant, comme pour le menu.',
|
|
1406
|
+
code: `<SelectAnchor>
|
|
1407
|
+
<Button variante="fantome" compact aria-expanded={ouvert} onClick={…}>Colonnes affichées</Button>
|
|
1408
|
+
{ouvert && <Popover>…</Popover>}
|
|
1409
|
+
</SelectAnchor>`,
|
|
1410
|
+
rendu: <DemoPopover />,
|
|
1411
|
+
},
|
|
1172
1412
|
{
|
|
1173
1413
|
id: 'pagination',
|
|
1174
1414
|
nom: 'Pagination',
|
|
@@ -1297,7 +1537,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
1297
1537
|
couche: 'commun',
|
|
1298
1538
|
css: 'icons.css',
|
|
1299
1539
|
resume:
|
|
1300
|
-
"
|
|
1540
|
+
"55 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.",
|
|
1301
1541
|
exemples: [
|
|
1302
1542
|
{
|
|
1303
1543
|
id: 'jeu',
|
|
@@ -1660,6 +1900,57 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
1660
1900
|
</div>
|
|
1661
1901
|
),
|
|
1662
1902
|
},
|
|
1903
|
+
{
|
|
1904
|
+
id: 'bandeau',
|
|
1905
|
+
nom: 'Bandeau d’annonce',
|
|
1906
|
+
resume:
|
|
1907
|
+
'La bande AU-DESSUS de la barre de navigation : annonce de version, information réglementaire. UN SEUL par page, et jamais pour du marketing permanent — un bandeau qui ne part pas devient un bourrelet de chrome. Le lien s’y souligne : sur un fond déjà indigo, la couleur seule ne le distingue plus.',
|
|
1908
|
+
code: `<Banner>
|
|
1909
|
+
La charte 0.8 est en ligne — angles vifs sur tout le système.{' '}
|
|
1910
|
+
<a href="/journal">Ce qui change</a>
|
|
1911
|
+
</Banner>`,
|
|
1912
|
+
rendu: (
|
|
1913
|
+
<Banner>
|
|
1914
|
+
La charte 0.8 est en ligne — angles vifs sur tout le système.{' '}
|
|
1915
|
+
<a href="#">Ce qui change</a>
|
|
1916
|
+
</Banner>
|
|
1917
|
+
),
|
|
1918
|
+
},
|
|
1919
|
+
{
|
|
1920
|
+
id: 'carrousel',
|
|
1921
|
+
nom: 'Carrousel',
|
|
1922
|
+
resume:
|
|
1923
|
+
'Défilement natif scroll-snap, AUCUN JavaScript : pas de flèches, pas de points ; le conteneur prend le focus, et son label est OBLIGATOIRE — une région qui défile sans nom est une énigme au lecteur d’écran. Un carrousel reste un aveu d’espace : la règle de variété lui préfère une grille tant que le contenu tient.',
|
|
1924
|
+
code: `<Carousel label="La suite Zevra">
|
|
1925
|
+
<CarouselItem style={{ width: 260 }}>
|
|
1926
|
+
<Card>…</Card>
|
|
1927
|
+
</CarouselItem>
|
|
1928
|
+
…
|
|
1929
|
+
</Carousel>`,
|
|
1930
|
+
rendu: (
|
|
1931
|
+
<div style={{ maxWidth: 560 }}>
|
|
1932
|
+
<Carousel label="La suite Zevra">
|
|
1933
|
+
{(
|
|
1934
|
+
[
|
|
1935
|
+
['Mémoire', 'Votre savoir, interrogeable en une phrase.'],
|
|
1936
|
+
['Lexform', 'Vos actes, anonymisés à la volée.'],
|
|
1937
|
+
['Campus', 'La profession qui se rééquipe se forme.'],
|
|
1938
|
+
['MCP juridique', 'Vos sources, branchées sur vos agents.'],
|
|
1939
|
+
] as const
|
|
1940
|
+
).map(([nom, phrase]) => (
|
|
1941
|
+
<CarouselItem key={nom} style={{ width: 240 }}>
|
|
1942
|
+
<Card>
|
|
1943
|
+
<div style={{ display: 'grid', gap: 8 }}>
|
|
1944
|
+
<CardTitle>{nom}</CardTitle>
|
|
1945
|
+
<Body taille="dense">{phrase}</Body>
|
|
1946
|
+
</div>
|
|
1947
|
+
</Card>
|
|
1948
|
+
</CarouselItem>
|
|
1949
|
+
))}
|
|
1950
|
+
</Carousel>
|
|
1951
|
+
</div>
|
|
1952
|
+
),
|
|
1953
|
+
},
|
|
1663
1954
|
],
|
|
1664
1955
|
},
|
|
1665
1956
|
|
|
@@ -1774,6 +2065,41 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
1774
2065
|
</div>
|
|
1775
2066
|
),
|
|
1776
2067
|
},
|
|
2068
|
+
{
|
|
2069
|
+
id: 'format-social',
|
|
2070
|
+
nom: 'Formats sociaux',
|
|
2071
|
+
resume:
|
|
2072
|
+
'Planches d’EXPORT — paysage 1200×630 (OpenGraph, lien LinkedIn), carré 1080 (post), story 1080×1920 — FIGÉES en pixels : on les capture, on ne les publie pas en HTML, et elles ignorent le point de rupture. Un visuel social EST une publication : jamais de faux chiffre ni de fausse citation. Rendue ici à l’échelle 0,35.',
|
|
2073
|
+
code: `<SocialFrame manifeste pied={<><Mono ton="on-dark">ZEVRA</Mono><Mono ton="on-dark">zevra.tech</Mono></>}>
|
|
2074
|
+
<Kicker surSombre><Mono ton="on-dark">Manifeste · Article 1ᵉʳ</Mono></Kicker>
|
|
2075
|
+
<Heading taille="h2" as="p">
|
|
2076
|
+
Émanciper les avocats et les juristes des outils qu'on leur <Em surSombre>impose</Em>.
|
|
2077
|
+
</Heading>
|
|
2078
|
+
</SocialFrame>`,
|
|
2079
|
+
rendu: (
|
|
2080
|
+
<div style={{ width: 421, height: 221, overflow: 'hidden' }}>
|
|
2081
|
+
<div style={{ transform: 'scale(0.35)', transformOrigin: 'top left' }}>
|
|
2082
|
+
<SocialFrame
|
|
2083
|
+
manifeste
|
|
2084
|
+
pied={
|
|
2085
|
+
<>
|
|
2086
|
+
<Mono ton="on-dark">ZEVRA</Mono>
|
|
2087
|
+
<Mono ton="on-dark">zevra.tech</Mono>
|
|
2088
|
+
</>
|
|
2089
|
+
}
|
|
2090
|
+
>
|
|
2091
|
+
<Kicker surSombre>
|
|
2092
|
+
<Mono ton="on-dark">Manifeste · Article 1ᵉʳ</Mono>
|
|
2093
|
+
</Kicker>
|
|
2094
|
+
<Heading taille="h2" as="p">
|
|
2095
|
+
Émanciper les avocats et les juristes des outils qu’on leur{' '}
|
|
2096
|
+
<Em surSombre>impose</Em>.
|
|
2097
|
+
</Heading>
|
|
2098
|
+
</SocialFrame>
|
|
2099
|
+
</div>
|
|
2100
|
+
</div>
|
|
2101
|
+
),
|
|
2102
|
+
},
|
|
1777
2103
|
],
|
|
1778
2104
|
},
|
|
1779
2105
|
]
|