skcr-design-tokens 1.0.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 ADDED
@@ -0,0 +1,122 @@
1
+ # skcr-design-tokens
2
+
3
+ Le design system SkillCorner, en CSS pur et sans dépendance : tokens de couleur,
4
+ utilitaires typographiques et classes de composants. Source unique pour orion et
5
+ gaffer, et contrat de rendu de la librairie de composants `skcr-autechre`.
6
+
7
+ Aucune dépendance, aucun build : le paquet publie les fichiers `.css` tels quels.
8
+ Il est donc consommable par n'importe quel front — Angular, React ou vanilla.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install skcr-design-tokens
14
+ ```
15
+
16
+ Dans le `styles.css` (ou `styles.scss`) de l'application :
17
+
18
+ ```css
19
+ @import 'tailwindcss';
20
+ @import 'skcr-design-tokens/tokens.css';
21
+ @import 'skcr-design-tokens/utilities.css';
22
+ @import 'skcr-design-tokens/components.css';
23
+ ```
24
+
25
+ ## Applications qui consomment skcr-autechre
26
+
27
+ Tailwind ne scanne pas `node_modules`. Les classes que les composants de la
28
+ librairie écrivent dans leurs templates ne seraient donc jamais générées, et les
29
+ styles manqueraient sans qu'aucune erreur ne le signale. Une ligne suffit :
30
+
31
+ ```css
32
+ @source '../node_modules/skcr-autechre/fesm2022/*.mjs';
33
+ ```
34
+
35
+ Le chemin vise le JavaScript **construit**, où ng-packagr a inliné les templates :
36
+ c'est là que les classes se trouvent dans le paquet publié.
37
+
38
+ ## Thème clair / sombre
39
+
40
+ L'attribut se pose sur `<html>`, **jamais sur `<body>`**. Tailwind émet le bloc
41
+ `@theme` dans `:root`, c'est-à-dire sur `<html>` ; or une custom property est
42
+ substituée à l'élément où elle est déclarée. Une surcharge posée sur `<body>`
43
+ serait invisible pour les utilitaires, qui hériteraient d'une valeur déjà
44
+ résolue avec la palette claire — les couleurs écrites à la main basculeraient,
45
+ les classes Tailwind non.
46
+
47
+ Pour éviter tout scintillement au chargement, l'attribut doit être posé **avant
48
+ la première peinture**. Aucun mécanisme applicatif ne peut le faire : un
49
+ initialiseur Angular s'exécute après le premier rendu. Coller ce script dans
50
+ `index.html`, dans le `<head>` :
51
+
52
+ ```html
53
+ <script>
54
+ try {
55
+ document.documentElement.dataset.theme = localStorage.getItem('skcr-theme') || 'light';
56
+ } catch {
57
+ document.documentElement.dataset.theme = 'light';
58
+ }
59
+ </script>
60
+ ```
61
+
62
+ Les applications Angular utilisent ensuite le `ThemeService` de `skcr-autechre`
63
+ pour la bascule et la synchronisation entre onglets. Il ne fait pas
64
+ l'initialisation : le script ci-dessus l'a déjà faite.
65
+
66
+ ## Contenu
67
+
68
+ | Entrée | Contenu |
69
+ | --- | --- |
70
+ | `tokens.css` | Bloc `@theme` : couleurs primaires, neutres, de statut, de dataviz, et familles de polices |
71
+ | `utilities.css` | `text-body-*`, `text-caption`, `info-caption`, `title-one` à `title-five` |
72
+ | `components.css` | Famille `.btn`, utilitaires de barre de défilement, correction Angular Material du sélecteur de date |
73
+ | `display.css` | **Opt-in.** Classes de présentation. Aucune application du socle ne l'importe. |
74
+
75
+ ## Ce qui reste dans l'application
76
+
77
+ Trois catégories ne montent pas ici, et c'est délibéré :
78
+
79
+ - **Les `@font-face`.** Shentox est une police commerciale : la redistribuer
80
+ dans un paquet npm public serait une violation de licence. Le paquet déclare
81
+ la famille (`--font-title`), l'application fournit les fichiers.
82
+ - **Les resets globaux.** `html, body { height: 100vh; overflow: hidden }` est
83
+ une décision d'application monopage, pas une décision de design.
84
+ - **Les tokens de domaine.** `--color-tactical` (gaffer), `--color-tooltip-*`
85
+ (orion) : ils ne servent qu'à une application.
86
+
87
+ ## Règles d'extension
88
+
89
+ La distinction est nette, et c'est elle qui empêche le design system de
90
+ re-diverger comme il l'a fait entre les trois applications :
91
+
92
+ **Surcharger une valeur est libre.** Une application peut redéfinir n'importe
93
+ quel token dans son propre `styles.css`, après les `@import` :
94
+
95
+ ```css
96
+ :root {
97
+ --color-primary: #0f766e;
98
+ }
99
+ ```
100
+
101
+ C'est le mécanisme du thème sombre, et c'est ce qui permet à un projet de se
102
+ repeindre sans forker le paquet. Le contrat reste le même, seules les valeurs
103
+ changent.
104
+
105
+ **Définir un utilitaire ne l'est pas.** Ajouter un `@utility`, une classe
106
+ `.btn-*` ou une classe de présentation dans le `styles.css` d'une application
107
+ est interdit : c'est exactement comme ça que `.btn-icon` s'est retrouvé dans
108
+ orion seul, et que la famille `.btn` a divergé sur cinq points. Une nouvelle
109
+ définition passe par une merge request sur ce paquet.
110
+
111
+ **Ajouter dans `display.css`.** C'est le fichier prévu pour les besoins neufs,
112
+ notamment ceux des projets qui n'ont pas de design validé. Il vise les **projets vibe-codés**, à qui il donne une uniformité de façade ; les
113
+ applications de la plateforme ont leurs propres besoins, tranchés par le product
114
+ design, et ne l'importent pas. Trois règles :
115
+
116
+ 1. Une classe n'utilise que les tokens de `tokens.css`. Aucune couleur en dur —
117
+ c'est ce qui garantit qu'elle suivra le thème sombre sans retouche.
118
+ 2. Une classe ne redéfinit jamais une classe du socle. En cas de doute sur un
119
+ nom, vérifier dans `components.css`.
120
+ 3. Ne pas écrire pour le socle. Ces classes n'ont pas vocation à y remonter : ce
121
+ n'est pas une antichambre. Si l'une devait un jour servir orion ou gaffer, ce
122
+ serait une décision explicite et exceptionnelle, pas un glissement.
package/components.css ADDED
@@ -0,0 +1,243 @@
1
+ /* ---------------------------------------------------------------------------
2
+ Classes de composants du design system SkillCorner.
3
+
4
+ Exige `tokens.css` et `utilities.css`.
5
+
6
+ La famille `.btn` reprend la variante d'orion, choisie comme référence.
7
+ gaffer s'y aligne : ombre portée, base en `py-2`,
8
+ `.btn-mini` en `py-1.5`, survol neutre en `bg-slate-100`, et `.btn-selected`
9
+ sans `px-2.5`. `.btn-input` vient de gaffer, qui l'emploie ; `.btn-select`
10
+ n'est repris nulle part : il était défini sans être utilisé nulle part.
11
+
12
+ La famille `.btn` est passée aux tokens sémantiques. Le rendu en thème clair
13
+ est identique au précédent, à une exception près : le survol de
14
+ `.btn-transparent` passe de slate-50 à slate-100, d'un cran. Les survols ont
15
+ leurs propres tokens plutôt qu'une opacité, parce qu'en sombre le fond
16
+ primaire est CLAIR : son survol doit s'éclaircir, là où en clair il assombrit.
17
+
18
+ La famille `.badge` garde en revanche ses teintes brutes, et c'est délibéré :
19
+ `badge-purple` est violet par définition, pas par rôle. Ses pastilles sont des
20
+ fonds clairs à texte sombre, ce qui reste lisible sur une interface sombre.
21
+
22
+ `.badge` reprend la variante de gaffer, seule à être réellement employée — 38
23
+ usages. La variante écartée portait des classes `dark:` qui n'auraient de toute
24
+ façon pas répondu au `data-theme`.
25
+ `.link`, `.step-number` (gaffer) et le motif `.has-tooltip` (orion) montent
26
+ ici : génériques et additifs, aucune application n'y perd quelque chose.
27
+
28
+ `.spinner` NE monte PAS, et c'est délibéré : orion en définit un global qui
29
+ duplique le style encapsulé du `skcr-submit-button`, avec une bordure haute
30
+ grise au lieu de blanche. Une règle globale et un style de composant ont la
31
+ même spécificité — le vainqueur dépend de l'ordre d'injection. Le monter ici
32
+ repeindrait le spinner du bouton de soumission dans les trois applications.
33
+ À terme, orion devrait abandonner le sien au profit du composant.
34
+
35
+ `.mat-datepicker-content-container` n'est pas du design system : c'est une
36
+ correction Angular Material qu'exige le `skcr-date-picker` de la librairie.
37
+ Elle vit ici parce que les trois applications la portent déjà à l'identique
38
+ et qu'une librairie Angular ne peut pas livrer de style global.
39
+ --------------------------------------------------------------------------- */
40
+
41
+ @layer components {
42
+ .mat-datepicker-content-container {
43
+ background-color: var(--color-popover);
44
+ }
45
+
46
+ .btn {
47
+ @apply rounded-md leading-5 shadow-sm items-center flex gap-1 justify-center py-2 px-3 max-w-sm text-body-small outline-1 -outline-offset-1 outline-border-color focus:outline-2 focus:-outline-offset-2 font-medium relative overflow-hidden z-0 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50;
48
+
49
+ &.btn-large {
50
+ @apply px-4 py-2.5;
51
+ }
52
+
53
+ &.btn-mini {
54
+ @apply px-2.5 py-1.5;
55
+ }
56
+
57
+ &.btn-icon {
58
+ @apply size-8 p-0 rounded-lg shadow-none;
59
+ }
60
+
61
+ &.btn-input {
62
+ @apply py-2;
63
+ }
64
+
65
+ &.btn-full {
66
+ @apply max-w-full;
67
+ }
68
+
69
+ &.btn-selected {
70
+ @apply bg-primary-subtle text-primary-subtle-foreground;
71
+ }
72
+
73
+ &.btn-primary {
74
+ @apply bg-primary text-primary-foreground hover:bg-primary-hover focus:outline-primary;
75
+ }
76
+
77
+ &.btn-neutral {
78
+ @apply bg-card hover:bg-muted;
79
+ }
80
+
81
+ &.btn-transparent {
82
+ @apply hover:bg-muted outline-0;
83
+ }
84
+
85
+ &.btn-danger {
86
+ @apply bg-destructive text-destructive-foreground hover:bg-destructive-hover;
87
+ }
88
+ }
89
+
90
+ .badge {
91
+ @apply inline-flex items-center justify-center gap-0.5 rounded-lg border border-transparent bg-slate-100 px-2 py-0.5 text-xs leading-4 font-medium text-slate-950;
92
+
93
+ &.badge-primary {
94
+ @apply border-primary-300 bg-primary-100;
95
+ }
96
+
97
+ &.badge-green {
98
+ @apply border-green-300 bg-green-100;
99
+ }
100
+
101
+ &.badge-yellow {
102
+ @apply border-yellow-300 bg-yellow-100;
103
+ }
104
+
105
+ &.badge-orange {
106
+ @apply border-orange-300 bg-orange-100;
107
+ }
108
+
109
+ &.badge-destructive {
110
+ @apply border-red-300 bg-red-100;
111
+ }
112
+
113
+ &.badge-blue {
114
+ @apply border-blue-300 bg-blue-100;
115
+ }
116
+
117
+ &.badge-purple {
118
+ @apply border-purple-300 bg-purple-100;
119
+ }
120
+
121
+ &.badge-pink {
122
+ @apply border-pink-300 bg-pink-100;
123
+ }
124
+
125
+ &.badge-cyan {
126
+ @apply border-cyan-300 bg-cyan-100;
127
+ }
128
+
129
+ &.badge-strong-yellow {
130
+ @apply bg-yellow-300;
131
+ }
132
+
133
+ &.badge-strong-orange {
134
+ @apply bg-orange-300;
135
+ }
136
+
137
+ &.badge-strong-red {
138
+ @apply bg-red-300;
139
+ }
140
+
141
+ &.badge-strong-slate {
142
+ @apply bg-slate-200;
143
+ }
144
+ }
145
+
146
+ .link {
147
+ @apply text-primary underline cursor-pointer;
148
+ }
149
+
150
+ .step-number {
151
+ @apply flex h-8 w-8 items-center justify-center rounded-full bg-primary p-2 text-xl text-primary-foreground;
152
+ }
153
+
154
+ .tooltip {
155
+ @apply invisible absolute;
156
+ }
157
+
158
+ .has-tooltip:hover .tooltip {
159
+ @apply visible z-50;
160
+ }
161
+
162
+ .has-tooltip {
163
+ @apply relative;
164
+ }
165
+
166
+ .scrollbar-hide {
167
+ /* IE et Edge */
168
+ -ms-overflow-style: none;
169
+ /* Firefox */
170
+ scrollbar-width: none;
171
+ /* Safari et Chrome */
172
+ &::-webkit-scrollbar {
173
+ display: none;
174
+ }
175
+ }
176
+
177
+ .scrollbar-hide-y {
178
+ /* IE et Edge — impossible de masquer la seule barre verticale */
179
+ -ms-overflow-style: none;
180
+ /* Firefox */
181
+ scrollbar-width: none;
182
+ /* Safari et Chrome */
183
+ &::-webkit-scrollbar {
184
+ height: auto; /* barre horizontale conservée */
185
+ width: 0; /* barre verticale masquée */
186
+ }
187
+ }
188
+
189
+ .scrollbar-hide-x {
190
+ /* IE et Edge — impossible de masquer la seule barre horizontale */
191
+ -ms-overflow-style: none;
192
+ /* Firefox */
193
+ scrollbar-width: none;
194
+ /* Safari et Chrome */
195
+ &::-webkit-scrollbar {
196
+ height: 0; /* barre horizontale masquée */
197
+ width: auto; /* barre verticale conservée */
198
+ }
199
+ }
200
+
201
+ .scrollbar-default {
202
+ /* IE et Edge */
203
+ -ms-overflow-style: auto;
204
+ /* Firefox */
205
+ scrollbar-width: auto;
206
+ /* Safari et Chrome */
207
+ &::-webkit-scrollbar {
208
+ display: block;
209
+ }
210
+ }
211
+ }
212
+
213
+ /* ---------------------------------------------------------------------------
214
+ Angular Material dérive tout son habillage des tokens système `--mat-sys-*`,
215
+ dont son thème préfabriqué fixe la teinte. Sans cette redirection, le
216
+ calendrier et le panneau d'heures de `skcr-date-picker` et
217
+ `skcr-datetime-picker` sortent en bleu azur au milieu d'une interface verte.
218
+
219
+ Les variables pointent vers les tokens du design system plutôt que d'en
220
+ recopier les valeurs : un changement de charte — ou de thème — les suit.
221
+ C'est pour cette raison que la surface vise `--color-popover` et non un
222
+ blanc littéral : le calendrier est un panneau flottant, il doit suivre la
223
+ même surface que les autres.
224
+
225
+ Volontairement hors couche : Material déclare ses propres `--mat-sys-*` sans
226
+ `@layer`, et une déclaration layerisée perdrait l'arbitrage de cascade.
227
+
228
+ Inerte pour une application qui n'affiche aucun composant Material : ni orion ni
229
+ gaffer n'importe Material directement. gaffer, en
230
+ revanche, affiche un `skcr-datetime-picker` sans cette recette — ce picker
231
+ rend donc aujourd'hui en bleu.
232
+ --------------------------------------------------------------------------- */
233
+ :root {
234
+ --mat-sys-primary: var(--color-primary);
235
+ --mat-sys-on-primary: var(--color-primary-foreground);
236
+ --mat-sys-surface: var(--color-popover);
237
+ --mat-sys-surface-container-high: var(--color-popover);
238
+ --mat-sys-on-surface: var(--color-foreground);
239
+ --mat-sys-on-surface-variant: var(--color-muted-foreground);
240
+ --mat-sys-outline: var(--color-border-color);
241
+ --mat-sys-outline-variant: var(--color-border-color);
242
+ --mat-sys-corner-large: 0.5rem;
243
+ }
package/display.css ADDED
@@ -0,0 +1,44 @@
1
+ /* ---------------------------------------------------------------------------
2
+ Classes de présentation — entrée OPT-IN.
3
+
4
+ Ce fichier n'est importé par aucune application de la plateforme : ni orion, ni
5
+ gaffer n'en dépendent. Il existe pour donner une uniformité de façade aux PROJETS
6
+ VIBE-CODÉS — qu'un outil monté vite ne réinvente pas sa carte, son badge et sa
7
+ pastille à chaque fois. C'est un garde-fou, pas un catalogue de composants.
8
+
9
+ Ces classes n'ont PAS vocation à remonter un jour dans le socle : ce n'est pas une
10
+ antichambre. Un besoin de la plateforme se traite par le product design, pas en
11
+ promouvant une classe écrite pour un autre usage.
12
+
13
+ Trois règles, détaillées dans le README :
14
+ 1. Aucune couleur en dur — uniquement les tokens de `tokens.css`. C'est ce qui
15
+ garantit qu'une classe suivra le thème sombre sans retouche.
16
+ 2. Aucune redéfinition d'une classe du socle : vérifier `components.css`.
17
+ 3. Ne pas écrire pour le socle. Si une classe devait un jour servir orion ou gaffer,
18
+ ce serait une décision explicite et exceptionnelle, jamais un glissement.
19
+
20
+ Les deux classes ci-dessous sont des exemples de référence, tirés de motifs
21
+ réellement répétés dans les applications, pas inventés :
22
+
23
+ - `.card` : 19 fichiers d'orion écrivent `bg-white border border-border-color
24
+ rounded-lg p-5` à la main, aucun composant partagé ne le couvre. La classe
25
+ porte la SURFACE ; la mise en page (`flex`, `gap-4`, `flex-1`, `mb-8`, qui
26
+ varient d'un usage à l'autre) reste dans le template.
27
+ - `.avatar` : reprend la géométrie du `user-avatar` d'orion. Le repli sur les
28
+ initiales, lui, porte de la logique — c'est le premier candidat à un vrai
29
+ composant, une fois la classe confrontée à l'usage.
30
+
31
+ Noter que `bg-card` et `border-background` remplacent ici les `bg-white` et
32
+ `border-white` de l'existant : à valeur identique aujourd'hui, mais suivant le
33
+ thème demain. C'est la règle 1 en pratique.
34
+ --------------------------------------------------------------------------- */
35
+
36
+ @layer components {
37
+ .card {
38
+ @apply bg-card border border-border-color rounded-lg p-5;
39
+ }
40
+
41
+ .avatar {
42
+ @apply size-8 rounded-full object-cover border-2 border-background;
43
+ }
44
+ }
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "skcr-design-tokens",
3
+ "version": "1.0.0",
4
+ "description": "Design system SkillCorner : tokens de couleur, utilitaires typographiques et classes de composants. CSS pur, sans dépendance.",
5
+ "license": "UNLICENSED",
6
+ "sideEffects": [
7
+ "*.css"
8
+ ],
9
+ "files": [
10
+ "*.css",
11
+ "README.md"
12
+ ],
13
+ "exports": {
14
+ "./tokens.css": "./tokens.css",
15
+ "./utilities.css": "./utilities.css",
16
+ "./components.css": "./components.css",
17
+ "./display.css": "./display.css"
18
+ }
19
+ }
package/tokens.css ADDED
@@ -0,0 +1,199 @@
1
+ /* ---------------------------------------------------------------------------
2
+ Tokens du design system SkillCorner.
3
+
4
+ Source unique des valeurs qu'orion et gaffer recopiaient chacun dans son
5
+ `styles.scss`. Les couleurs primaires, neutres, de statut et de
6
+ dataviz y étaient déjà rigoureusement identiques dans les trois. Les tokens
7
+ d'infobulle ne venaient que d'orion : ils montent ici avec le motif
8
+ `.has-tooltip` de `components.css`, et sont donc additifs pour les deux
9
+ autres applications.
10
+
11
+ Délibérément absents, parce qu'ils n'appartiennent qu'à une application :
12
+ - `--color-tactical` (gaffer) : concept métier.
13
+ - `--animate-splash-*` et leurs `@keyframes` (orion) : écran de chargement.
14
+ - les `@font-face` Shentox : police commerciale, non redistribuable dans un
15
+ paquet npm public. Chaque application fournit les siens ; ce fichier ne
16
+ déclare que la famille.
17
+
18
+ Thème sombre — l'attribut se pose sur `<html>`, jamais sur `<body>` :
19
+ Tailwind émet ce bloc `@theme` dans `:root`, donc sur `<html>`. Une custom
20
+ property est substituée à l'élément où elle est déclarée ; une surcharge
21
+ posée sur `<body>` serait donc invisible pour les utilitaires, qui hériteraient
22
+ d'une valeur déjà résolue avec la palette claire. Sur `<html>`, les deux
23
+ déclarations vivent sur le même élément et la surcharge s'applique :
24
+
25
+ :root[data-theme='dark'] { --color-card: …; }
26
+
27
+ Le sélecteur d'attribut l'emporte sur le `:root` du bloc `@theme`, qui est
28
+ par ailleurs émis dans une couche (`@layer theme`) — les deux mécanismes
29
+ pointent dans le même sens.
30
+ --------------------------------------------------------------------------- */
31
+
32
+ @theme {
33
+ --font-sans: 'Inter', sans-serif;
34
+ --font-title: 'Shentox', serif;
35
+
36
+ /* Couleurs primaires */
37
+ --color-primary-50: #edfff1;
38
+ --color-primary-100: #d5ffe1;
39
+ --color-primary-200: #aeffc5;
40
+ --color-primary-300: #6fff9a;
41
+ --color-primary-400: #32fe6b;
42
+ --color-primary-500: #02e540;
43
+ --color-primary-600: #00bf30;
44
+ --color-primary-700: #008a26;
45
+ --color-primary-800: #057626;
46
+ --color-primary-900: #066122;
47
+ --color-primary: #008a26;
48
+ /* Survols. Un `/90` d'opacité aurait suffi en clair mais pas en sombre, où le fond
49
+ primaire est CLAIR : son survol doit s'éclaircir, pas s'assombrir. C'est pourquoi
50
+ chaque couleur d'action a son token de survol plutôt qu'une opacité. */
51
+ --color-primary-hover: #057626; /* primary-800 */
52
+ /* Libellé lisible SUR un fond primaire. En sombre le primaire s'éclaircit,
53
+ donc ce libellé s'assombrit : `bg-primary text-white` ne peut pas suivre
54
+ le thème, `bg-primary text-primary-foreground` si. */
55
+ --color-primary-foreground: theme(colors.white);
56
+ /* Surface primaire discrète : option sélectionnée d'une liste, pastille. */
57
+ --color-primary-subtle: #edfff1;
58
+ --color-primary-subtle-foreground: #057626;
59
+
60
+ /* Couleurs neutres */
61
+ --color-background: theme(colors.white);
62
+ --color-card: theme(colors.white);
63
+ --color-popover: theme(colors.white);
64
+ --color-card-foreground: theme(colors.slate.950);
65
+ --color-popover-foreground: theme(colors.slate.950);
66
+ --color-foreground: theme(colors.slate.950);
67
+ --color-muted: theme(colors.slate.100);
68
+ --color-muted-foreground: theme(colors.slate.500);
69
+ --color-border-color: theme(colors.slate.200);
70
+ --color-input: theme(colors.slate.200);
71
+ --color-ring: theme(colors.slate.950);
72
+ --color-subtitle: theme(colors.slate.500);
73
+ /* Fond d'un contrôle désactivé. Distinct de `muted`, qui est un fond de
74
+ zone : les deux valeurs sont voisines en clair mais divergent en sombre. */
75
+ --color-disabled: theme(colors.slate.50);
76
+ /* Fond de piste : conteneur d'onglets, onglet non sélectionné, rail d'un
77
+ interrupteur. Un cran plus marqué que `muted`, qui est un fond de zone. */
78
+ --color-track: theme(colors.slate.200);
79
+ /* Surface surélevée : ce qui est POSÉ sur une autre surface — onglet actif sur sa piste,
80
+ pastille d'interrupteur sur son rail, point d'un bouton radio coché sur son fond
81
+ primaire. À distinguer d'un CREUX, qui prend `background` : le cercle d'un radio non
82
+ coché, le fond d'un champ. En clair elle vaut blanc, comme le fond de page ; en sombre
83
+ elle doit être plus CLAIRE que ce qu'elle surmonte, sans quoi l'élément en relief
84
+ paraît creusé — et aucun autre token ne le permet, `popover` y valant exactement
85
+ `track`. */
86
+ --color-elevated: theme(colors.white);
87
+ /* Voile de modale. Seul token qui ne s'inverse pas : un voile doit assombrir
88
+ dans les deux thèmes, il ne peut donc pas suivre `foreground`. */
89
+ --color-scrim: theme(colors.slate.500);
90
+
91
+ /* Couleurs de statut */
92
+ --color-info: theme(colors.blue.700);
93
+ --color-info-hover: theme(colors.blue.800);
94
+ --color-info-foreground: theme(colors.blue.100);
95
+ --color-success: theme(colors.green.700);
96
+ --color-success-foreground: theme(colors.green.100);
97
+ --color-destructive: theme(colors.red.700);
98
+ --color-destructive-hover: theme(colors.red.800);
99
+ --color-destructive-foreground: theme(colors.red.100);
100
+ --color-warning: theme(colors.orange.700);
101
+ --color-warning-hover: theme(colors.orange.800);
102
+ --color-warning-foreground: theme(colors.orange.100);
103
+ --color-neutral: theme(colors.slate.700);
104
+ --color-neutral-foreground: theme(colors.slate.100);
105
+
106
+ /* Infobulles — consommés par le motif `.has-tooltip` de components.css */
107
+ --color-tooltip-surface: theme(colors.slate.800);
108
+ --color-tooltip-border: theme(colors.slate.500);
109
+ --color-tooltip-foreground: theme(colors.white);
110
+ --color-tooltip-subtitle: theme(colors.slate.200);
111
+
112
+ /* Couleurs de dataviz */
113
+ --color-chart-1: theme(colors.green.500);
114
+ --color-chart-1-accent: theme(colors.green.300);
115
+ --color-chart-1-foreground: theme(colors.green.100);
116
+ --color-chart-2: theme(colors.lime.500);
117
+ --color-chart-2-accent: theme(colors.lime.300);
118
+ --color-chart-2-foreground: theme(colors.lime.100);
119
+ --color-chart-3: theme(colors.yellow.500);
120
+ --color-chart-3-accent: theme(colors.yellow.300);
121
+ --color-chart-3-foreground: theme(colors.yellow.100);
122
+ --color-chart-4: theme(colors.orange.500);
123
+ --color-chart-4-accent: theme(colors.orange.300);
124
+ --color-chart-4-foreground: theme(colors.orange.100);
125
+ --color-chart-5: theme(colors.red.500);
126
+ --color-chart-5-accent: theme(colors.red.300);
127
+ --color-chart-5-foreground: theme(colors.red.100);
128
+ --color-chart-6: theme(colors.gray.500);
129
+ --color-chart-6-accent: theme(colors.gray.300);
130
+ --color-chart-6-foreground: theme(colors.gray.100);
131
+ }
132
+
133
+ /* ---------------------------------------------------------------------------
134
+ Thème sombre.
135
+
136
+ Hors `@theme` et donc hors couche : le sélecteur d'attribut l'emporte à la
137
+ fois par spécificité et par la règle des couches, ce qui rend la bascule
138
+ déterministe.
139
+
140
+ Toutes les paires de texte sont vérifiées au ratio WCAG AA (4.5:1). Les plus
141
+ serrées sont ici plus confortables qu'en thème clair, où `primary` est à
142
+ exactement 4.50.
143
+
144
+ Les échelles numériques (`--color-primary-50` à `900`, `--color-chart-*`) ne
145
+ sont PAS inversées : ce sont des gammes, choisies délibérément par une
146
+ application, pas des rôles. Les usages qui avaient besoin de suivre le thème
147
+ sont passés aux tokens sémantiques ci-dessous.
148
+ --------------------------------------------------------------------------- */
149
+ :root[data-theme='dark'] {
150
+ /* Surfaces, du plus sombre au plus clair : le fond de page porte les cartes,
151
+ les cartes portent les panneaux flottants. En sombre l'ombre portée ne
152
+ sépare presque rien — c'est la valeur de fond qui fait ce travail. */
153
+ --color-background: #020617; /* slate-950 */
154
+ --color-card: #0f172a; /* slate-900 */
155
+ --color-popover: #1e293b; /* slate-800 */
156
+
157
+ --color-foreground: #f8fafc; /* slate-50 */
158
+ --color-card-foreground: #f8fafc;
159
+ --color-popover-foreground: #f8fafc;
160
+ --color-muted: #1e293b; /* slate-800 */
161
+ --color-muted-foreground: #94a3b8; /* slate-400 */
162
+ --color-subtitle: #94a3b8;
163
+ --color-border-color: #334155; /* slate-700 */
164
+ --color-input: #334155;
165
+ --color-ring: #cbd5e1; /* slate-300 */
166
+ --color-disabled: #1e293b; /* slate-800 */
167
+ /* slate-800 et non slate-700 : les onglets non sélectionnés posent `text-subtitle`
168
+ dessus, et sur slate-700 la paire tombe à 4.04, sous le seuil AA de 4.5. */
169
+ --color-track: #1e293b; /* slate-800 */
170
+ --color-elevated: #334155; /* slate-700 : un cran AU-DESSUS de track */
171
+ --color-scrim: #020617; /* slate-950 : le voile assombrit, il ne s'inverse pas */
172
+
173
+ --color-primary: #32fe6b; /* primary-400 : #008a26 échoue au contraste sur fond sombre */
174
+ --color-primary-hover: #6fff9a; /* primary-300 : le survol ÉCLAIRCIT sur fond clair */
175
+ --color-primary-foreground: #020617;
176
+ --color-primary-subtle: #052e16;
177
+ --color-primary-subtle-foreground: #32fe6b;
178
+
179
+ --color-info: #60a5fa; /* blue-400 */
180
+ --color-info-hover: #93c5fd; /* blue-300 */
181
+ --color-info-foreground: #172554; /* blue-950 */
182
+ --color-success: #4ade80; /* green-400 */
183
+ --color-success-foreground: #052e16; /* green-950 */
184
+ --color-destructive: #f87171; /* red-400 */
185
+ --color-destructive-hover: #fca5a5; /* red-300 */
186
+ --color-destructive-foreground: #450a0a; /* red-950 */
187
+ --color-warning: #fb923c; /* orange-400 */
188
+ --color-warning-hover: #fdba74; /* orange-300 */
189
+ --color-warning-foreground: #431407; /* orange-950 */
190
+ --color-neutral: #cbd5e1; /* slate-300 */
191
+ --color-neutral-foreground: #020617;
192
+
193
+ /* L'infobulle s'inverse : sombre sur clair, elle ne se détacherait plus d'une
194
+ interface déjà sombre. */
195
+ --color-tooltip-surface: #e2e8f0; /* slate-200 */
196
+ --color-tooltip-border: #94a3b8; /* slate-400 */
197
+ --color-tooltip-foreground: #020617;
198
+ --color-tooltip-subtitle: #334155; /* slate-700 */
199
+ }
package/utilities.css ADDED
@@ -0,0 +1,49 @@
1
+ /* ---------------------------------------------------------------------------
2
+ Utilitaires typographiques du design system SkillCorner.
3
+
4
+ Exige `tokens.css` : `font-title` et `text-subtitle` viennent de là.
5
+
6
+ `title-three` est en `font-semibold`, l'usage d'orion ; gaffer rendait en
7
+ `font-medium` et s'aligne.
8
+ `info-caption` venait de gaffer seul : générique et additif, il monte ici.
9
+ --------------------------------------------------------------------------- */
10
+
11
+ @utility text-body-large {
12
+ @apply text-lg leading-7;
13
+ }
14
+
15
+ @utility text-body-medium {
16
+ @apply text-base leading-6;
17
+ }
18
+
19
+ @utility text-body-small {
20
+ @apply text-sm leading-5;
21
+ }
22
+
23
+ @utility text-caption {
24
+ @apply text-xs leading-4;
25
+ }
26
+
27
+ @utility info-caption {
28
+ @apply text-caption italic text-subtitle;
29
+ }
30
+
31
+ @utility title-one {
32
+ @apply font-bold text-6xl leading-10 font-title;
33
+ }
34
+
35
+ @utility title-two {
36
+ @apply font-semibold text-5xl leading-12 font-title;
37
+ }
38
+
39
+ @utility title-three {
40
+ @apply font-semibold text-4xl leading-10 font-title;
41
+ }
42
+
43
+ @utility title-four {
44
+ @apply font-medium text-3xl leading-8 font-title;
45
+ }
46
+
47
+ @utility title-five {
48
+ @apply font-medium text-2xl leading-7 font-title;
49
+ }