orbital-ds 0.3.0 → 0.4.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/AGENTS.md +3 -0
- package/README.md +6 -0
- package/contract.json +82 -2
- package/dist/themes/twitter.css +290 -0
- package/dist/themes/twitter.fonts.css +6 -0
- package/dist/themes/twitter.scoped.css +290 -0
- package/dist/themes/zyro.css +38 -0
- package/dist/themes/zyro.scoped.css +38 -0
- package/docs/CONTRACT.md +29 -0
- package/package.json +6 -4
- package/scripts/doctor.mjs +22 -0
- package/scripts/init.mjs +55 -0
package/AGENTS.md
CHANGED
|
@@ -22,6 +22,9 @@ adivinar. Lee antes: `README.md`, `docs/CONTRACT.md`, `contract.json` y
|
|
|
22
22
|
foco incluido).
|
|
23
23
|
6. **Un tema cumple el contrato completo** (`contract.json`) y define en `:root` todo
|
|
24
24
|
`--ds-*` que defina el tema base.
|
|
25
|
+
7. **La marca de una app vive en SU `brand.css`**, no en el tema del paquete. Para
|
|
26
|
+
personalizar una app (color, radio, fuentes) edita ese fichero; nunca `node_modules` ni
|
|
27
|
+
los temas. `pnpm exec orbital-ds-init` lo crea sin sobrescribir.
|
|
25
28
|
|
|
26
29
|
## Cómo cambiar el aspecto
|
|
27
30
|
|
package/README.md
CHANGED
|
@@ -32,6 +32,12 @@ import { Button } from 'orbital-ds/ui/button';
|
|
|
32
32
|
Cambiar de identidad = cambiar `qratia` por `zyro` en esas dos líneas de tema/fuentes.
|
|
33
33
|
Detalle del contrato, tokens y reglas de nombres en [`docs/CONTRACT.md`](docs/CONTRACT.md).
|
|
34
34
|
|
|
35
|
+
## Marca de una app
|
|
36
|
+
|
|
37
|
+
Lo propio de cada app (color principal, acento, radio, fuentes) va en **su** `src/brand.css`,
|
|
38
|
+
importado después del tema. Ninguna actualización de orbital-ds lo toca. `pnpm exec orbital-ds-init`
|
|
39
|
+
lo crea la primera vez. Detalle en [`docs/CONTRACT.md`](docs/CONTRACT.md).
|
|
40
|
+
|
|
35
41
|
## Regla
|
|
36
42
|
|
|
37
43
|
Ningún componente lleva valores propios (colores, medidas, sombras, z-index, duraciones):
|
package/contract.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 3,
|
|
3
3
|
"descripcion": "Contrato de tema de orbital-ds: todo tema (themes/*.css) debe definir estos tokens en :root. Nombres en inglés estándar; los de shadcn sin prefijo; los propios con --ds-. baseTheme es el tema aplicado siempre (los demás se aplican encima, con ámbito).",
|
|
4
4
|
"root": [
|
|
5
5
|
"radius",
|
|
@@ -78,5 +78,85 @@
|
|
|
78
78
|
"link"
|
|
79
79
|
]
|
|
80
80
|
},
|
|
81
|
-
"baseTheme": "qratia"
|
|
81
|
+
"baseTheme": "qratia",
|
|
82
|
+
"brand": {
|
|
83
|
+
"descripcion": "Grupo ESTABLE de variables que una app suele personalizar en su fichero de marca (brand.css). Renombrar o quitar una es versión MAYOR. Todas están también en `root` salvo las --ds-*.",
|
|
84
|
+
"tokens": [
|
|
85
|
+
{
|
|
86
|
+
"name": "primary",
|
|
87
|
+
"example": "oklch(0.55 0.2 260)",
|
|
88
|
+
"about": "color de acción principal (botones, foco)"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "primary-foreground",
|
|
92
|
+
"example": "#ffffff",
|
|
93
|
+
"about": "texto sobre el color principal (comprueba el contraste)"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "ring",
|
|
97
|
+
"example": "oklch(0.55 0.2 260)",
|
|
98
|
+
"about": "anillo de foco; suele ir igual que primary"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "link",
|
|
102
|
+
"example": "oklch(0.5 0.15 260)",
|
|
103
|
+
"about": "texto de enlace: más oscuro que primary para tener contraste"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "link-hover",
|
|
107
|
+
"example": "oklch(0.42 0.13 260)",
|
|
108
|
+
"about": "enlace al pasar el ratón"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "brand",
|
|
112
|
+
"example": "oklch(0.7 0.13 220)",
|
|
113
|
+
"about": "acento de marca (detalles, selección)"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "brand-bright",
|
|
117
|
+
"example": "oklch(0.8 0.13 220)",
|
|
118
|
+
"about": "acento de marca sobre fondos oscuros"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "sidebar-primary",
|
|
122
|
+
"example": "oklch(0.8 0.13 220)",
|
|
123
|
+
"about": "acento dentro del sidebar"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "sidebar-primary-foreground",
|
|
127
|
+
"example": "#04121c",
|
|
128
|
+
"about": "texto sobre el acento del sidebar"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "sidebar-accent-foreground",
|
|
132
|
+
"example": "oklch(0.85 0.1 220)",
|
|
133
|
+
"about": "texto del destino activo del sidebar"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "accent-foreground",
|
|
137
|
+
"example": "oklch(0.5 0.15 260)",
|
|
138
|
+
"about": "texto sobre superficies de acento suave"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "chart-1",
|
|
142
|
+
"example": "oklch(0.55 0.2 260)",
|
|
143
|
+
"about": "primera serie de las gráficas: la marca"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "radius",
|
|
147
|
+
"example": "12px",
|
|
148
|
+
"about": "redondez base (en temas cuya rampa deriva de ella)"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "ds-font-sans",
|
|
152
|
+
"example": "'Inter', system-ui, sans-serif",
|
|
153
|
+
"about": "fuente del cuerpo (carga la fuente en tu app)"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"name": "ds-font-display",
|
|
157
|
+
"example": "'Sora', system-ui, sans-serif",
|
|
158
|
+
"about": "fuente de los titulares"
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
82
162
|
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* TEMA twitter — la interfaz de Twitter anterior a X (rediseño de 2021).
|
|
3
|
+
*
|
|
4
|
+
* Personalidad: PLANO y de alto contraste. Sin sombras ni cristal en el contenido;
|
|
5
|
+
* separación por filetes de 1px; botones en píldora con peso 700; tarjetas de 16px
|
|
6
|
+
* sin elevación; sidebar a ras de borde, sin fondo, con filas en píldora y la activa
|
|
7
|
+
* en negrita; pestañas con subrayado de acento. Azul de marca #1D9BF0 (confirmado) con
|
|
8
|
+
* «menos azul»: la acción más importante puede ir en tinta (negro/blanco).
|
|
9
|
+
*
|
|
10
|
+
* VALORES APROXIMADOS: el azul de marca y la fuente (Chirp, propietaria) están
|
|
11
|
+
* documentados; los grises, bordes y los fondos de «Dim» son de memoria y NO se han
|
|
12
|
+
* contrastado con la hoja de estilos real — ajústalos con una captura de referencia.
|
|
13
|
+
* Chirp no se puede distribuir: se usa la pila del sistema como respaldo.
|
|
14
|
+
*
|
|
15
|
+
* Importar DESPUÉS de la estructura. Variables `--zt-*`: privadas de este tema.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* ── VARIABLES · PIEL CLARA ──────────────────────────────────────────────── */
|
|
19
|
+
:root {
|
|
20
|
+
--radius: 16px;
|
|
21
|
+
|
|
22
|
+
--ds-font-sans: 'Chirp', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
23
|
+
--ds-font-display: var(--ds-font-sans);
|
|
24
|
+
--ds-font-mono: ui-monospace, 'SF Mono', Menlo, monospace;
|
|
25
|
+
--ds-heading-tracking: normal;
|
|
26
|
+
|
|
27
|
+
/* Color */
|
|
28
|
+
--background: #ffffff;
|
|
29
|
+
--foreground: #0f1419;
|
|
30
|
+
|
|
31
|
+
--card: #ffffff;
|
|
32
|
+
--card-foreground: #0f1419;
|
|
33
|
+
--popover: #ffffff;
|
|
34
|
+
--popover-foreground: #0f1419;
|
|
35
|
+
|
|
36
|
+
--primary: #1d9bf0;
|
|
37
|
+
--primary-foreground: #ffffff;
|
|
38
|
+
--secondary: #eff3f4;
|
|
39
|
+
--secondary-foreground: #0f1419;
|
|
40
|
+
--muted: #f7f9f9;
|
|
41
|
+
--muted-foreground: #536471;
|
|
42
|
+
--accent: rgba(29, 155, 240, 0.1);
|
|
43
|
+
--accent-foreground: #1a8cd8;
|
|
44
|
+
--destructive: #f4212e;
|
|
45
|
+
--destructive-foreground: #ffffff;
|
|
46
|
+
|
|
47
|
+
--border: #eff3f4;
|
|
48
|
+
--input: #cfd9de;
|
|
49
|
+
--ring: #1d9bf0;
|
|
50
|
+
|
|
51
|
+
--chart-1: #1d9bf0;
|
|
52
|
+
--chart-2: #00ba7c;
|
|
53
|
+
--chart-3: #ffd400;
|
|
54
|
+
--chart-4: #f91880;
|
|
55
|
+
--chart-5: #7856ff;
|
|
56
|
+
|
|
57
|
+
--sidebar: transparent;
|
|
58
|
+
--sidebar-foreground: #0f1419;
|
|
59
|
+
--sidebar-primary: #1d9bf0;
|
|
60
|
+
--sidebar-primary-foreground: #ffffff;
|
|
61
|
+
--sidebar-accent: rgba(15, 20, 25, 0.1);
|
|
62
|
+
--sidebar-accent-foreground: #0f1419;
|
|
63
|
+
--sidebar-border: #eff3f4;
|
|
64
|
+
--sidebar-ring: #1d9bf0;
|
|
65
|
+
|
|
66
|
+
--danger: #d4141f;
|
|
67
|
+
--danger-soft: rgba(244, 33, 46, 0.1);
|
|
68
|
+
--warning: #8a6d00;
|
|
69
|
+
--warning-soft: rgba(255, 212, 0, 0.2);
|
|
70
|
+
--success: #00875a;
|
|
71
|
+
--success-soft: rgba(0, 186, 124, 0.12);
|
|
72
|
+
--info: #1a8cd8;
|
|
73
|
+
--info-soft: rgba(29, 155, 240, 0.1);
|
|
74
|
+
--neutral: #536471;
|
|
75
|
+
--neutral-soft: #eff3f4;
|
|
76
|
+
|
|
77
|
+
--link: #1d9bf0;
|
|
78
|
+
--link-hover: #1a8cd8;
|
|
79
|
+
--inset: #f7f9f9;
|
|
80
|
+
--inset-foreground: #0f1419;
|
|
81
|
+
--brand: #1d9bf0;
|
|
82
|
+
--brand-bright: #1d9bf0;
|
|
83
|
+
|
|
84
|
+
/* Formas: píldoras para acciones, 16px para superficies */
|
|
85
|
+
--ds-radius-sm: 8px;
|
|
86
|
+
--ds-radius-md: 12px;
|
|
87
|
+
--ds-radius-lg: 16px;
|
|
88
|
+
--ds-radius-xl: 16px;
|
|
89
|
+
--ds-radius-2xl: 20px;
|
|
90
|
+
--ds-radius-control: 9999px;
|
|
91
|
+
--ds-radius-overlay: 16px;
|
|
92
|
+
|
|
93
|
+
/* Sin elevación: solo los menús flotantes llevan sombra, muy suave */
|
|
94
|
+
--ds-shadow-card: 0 0 #0000;
|
|
95
|
+
--ds-shadow-card-hover: 0 0 #0000;
|
|
96
|
+
--ds-shadow-control: 0 0 #0000;
|
|
97
|
+
--ds-shadow-raised: 0 0 #0000;
|
|
98
|
+
--ds-shadow-overlay: 0 0 15px rgba(101, 119, 134, 0.2), 0 0 3px 1px rgba(101, 119, 134, 0.15);
|
|
99
|
+
--ds-shadow-popover: 0 0 15px rgba(101, 119, 134, 0.2), 0 0 3px 1px rgba(101, 119, 134, 0.15);
|
|
100
|
+
|
|
101
|
+
/* Medidas */
|
|
102
|
+
--ds-control-h-sm: 2rem;
|
|
103
|
+
--ds-control-h-md: 2.25rem;
|
|
104
|
+
--ds-control-h-lg: 3.25rem;
|
|
105
|
+
--ds-button-px-sm: 1rem;
|
|
106
|
+
--ds-button-px-md: 1.25rem;
|
|
107
|
+
--ds-button-px-lg: 2rem;
|
|
108
|
+
--ds-field-px: 1rem;
|
|
109
|
+
--ds-card-spacing: 1rem;
|
|
110
|
+
--ds-card-spacing-sm: 0.75rem;
|
|
111
|
+
|
|
112
|
+
/* Materiales: ninguno (plano) */
|
|
113
|
+
--ds-card-backdrop: none;
|
|
114
|
+
--ds-overlay-backdrop: none;
|
|
115
|
+
--ds-field-backdrop: none;
|
|
116
|
+
--ds-sidebar-backdrop: none;
|
|
117
|
+
--ds-page-backdrop: none;
|
|
118
|
+
|
|
119
|
+
/* Sidebar a ras de borde, sin silueta; filas en píldora grandes */
|
|
120
|
+
--ds-sidebar-pad: 0px;
|
|
121
|
+
--ds-sidebar-radius: 0px;
|
|
122
|
+
--ds-sidebar-shadow: 0 0 #0000;
|
|
123
|
+
--ds-sidebar-ring: 0px;
|
|
124
|
+
--ds-sidebar-edge: 1px solid var(--sidebar-border);
|
|
125
|
+
--ds-sidebar-item-radius: 9999px;
|
|
126
|
+
--ds-sidebar-item-h: 3.25rem;
|
|
127
|
+
|
|
128
|
+
/* Privadas de twitter */
|
|
129
|
+
--zt-hover: rgba(15, 20, 25, 0.1);
|
|
130
|
+
--zt-hover-soft: rgba(15, 20, 25, 0.03);
|
|
131
|
+
--zt-line-strong: #cfd9de;
|
|
132
|
+
--zt-ink: #0f1419;
|
|
133
|
+
--zt-ink-foreground: #ffffff;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* ── VARIABLES · PIEL OSCURA («Dim») ─────────────────────────────────────── */
|
|
137
|
+
.dark {
|
|
138
|
+
--background: #15202b;
|
|
139
|
+
--foreground: #f7f9f9;
|
|
140
|
+
|
|
141
|
+
--card: #15202b;
|
|
142
|
+
--card-foreground: #f7f9f9;
|
|
143
|
+
--popover: #1e2732;
|
|
144
|
+
--popover-foreground: #f7f9f9;
|
|
145
|
+
|
|
146
|
+
--primary: #1d9bf0;
|
|
147
|
+
--primary-foreground: #ffffff;
|
|
148
|
+
--secondary: #1e2732;
|
|
149
|
+
--secondary-foreground: #f7f9f9;
|
|
150
|
+
--muted: #1e2732;
|
|
151
|
+
--muted-foreground: #8b98a5;
|
|
152
|
+
--accent: rgba(29, 155, 240, 0.15);
|
|
153
|
+
--accent-foreground: #4db3f5;
|
|
154
|
+
--destructive: #f4212e;
|
|
155
|
+
--destructive-foreground: #ffffff;
|
|
156
|
+
|
|
157
|
+
--border: #38444d;
|
|
158
|
+
--input: #536471;
|
|
159
|
+
--ring: #1d9bf0;
|
|
160
|
+
|
|
161
|
+
--sidebar: transparent;
|
|
162
|
+
--sidebar-foreground: #f7f9f9;
|
|
163
|
+
--sidebar-primary: #1d9bf0;
|
|
164
|
+
--sidebar-primary-foreground: #ffffff;
|
|
165
|
+
--sidebar-accent: rgba(247, 249, 249, 0.1);
|
|
166
|
+
--sidebar-accent-foreground: #f7f9f9;
|
|
167
|
+
--sidebar-border: #38444d;
|
|
168
|
+
--sidebar-ring: #1d9bf0;
|
|
169
|
+
|
|
170
|
+
--danger: #ff5a64;
|
|
171
|
+
--danger-soft: rgba(244, 33, 46, 0.18);
|
|
172
|
+
--warning: #ffd400;
|
|
173
|
+
--warning-soft: rgba(255, 212, 0, 0.16);
|
|
174
|
+
--success: #00ba7c;
|
|
175
|
+
--success-soft: rgba(0, 186, 124, 0.16);
|
|
176
|
+
--info: #4db3f5;
|
|
177
|
+
--info-soft: rgba(29, 155, 240, 0.18);
|
|
178
|
+
--neutral: #8b98a5;
|
|
179
|
+
--neutral-soft: #1e2732;
|
|
180
|
+
|
|
181
|
+
--link: #4db3f5;
|
|
182
|
+
--link-hover: #8dcdf8;
|
|
183
|
+
--inset: #1e2732;
|
|
184
|
+
--inset-foreground: #f7f9f9;
|
|
185
|
+
--brand: #1d9bf0;
|
|
186
|
+
--brand-bright: #4db3f5;
|
|
187
|
+
|
|
188
|
+
--ds-shadow-overlay: 0 0 15px rgba(255, 255, 255, 0.2), 0 0 3px 1px rgba(255, 255, 255, 0.15);
|
|
189
|
+
--ds-shadow-popover: 0 0 15px rgba(255, 255, 255, 0.2), 0 0 3px 1px rgba(255, 255, 255, 0.15);
|
|
190
|
+
|
|
191
|
+
--zt-hover: rgba(247, 249, 249, 0.1);
|
|
192
|
+
--zt-hover-soft: rgba(247, 249, 249, 0.03);
|
|
193
|
+
--zt-line-strong: #536471;
|
|
194
|
+
--zt-ink: #eff3f4;
|
|
195
|
+
--zt-ink-foreground: #0f1419;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ── PERSONALIDAD ────────────────────────────────────────────────────────────
|
|
199
|
+
* Sin capa: gana a las utilidades de los componentes. Solo variables.
|
|
200
|
+
*/
|
|
201
|
+
:root {
|
|
202
|
+
/* Botones: píldora en peso 700; primario en azul; contorno con filete */
|
|
203
|
+
[data-slot='button'] {
|
|
204
|
+
border-radius: 9999px;
|
|
205
|
+
font-weight: 700;
|
|
206
|
+
}
|
|
207
|
+
[data-slot='button'][data-variant='default']:hover:not(:disabled) {
|
|
208
|
+
background-color: var(--link-hover);
|
|
209
|
+
}
|
|
210
|
+
[data-slot='button'][data-variant='secondary'] {
|
|
211
|
+
background: var(--zt-ink);
|
|
212
|
+
color: var(--zt-ink-foreground);
|
|
213
|
+
}
|
|
214
|
+
[data-slot='button'][data-variant='secondary']:hover:not(:disabled) {
|
|
215
|
+
opacity: 0.88;
|
|
216
|
+
}
|
|
217
|
+
[data-slot='button'][data-variant='outline'] {
|
|
218
|
+
background: transparent;
|
|
219
|
+
border: 1px solid var(--zt-line-strong);
|
|
220
|
+
color: var(--foreground);
|
|
221
|
+
}
|
|
222
|
+
[data-slot='button'][data-variant='outline']:hover:not(:disabled),
|
|
223
|
+
[data-slot='button'][data-variant='ghost']:hover:not(:disabled) {
|
|
224
|
+
background: var(--zt-hover);
|
|
225
|
+
}
|
|
226
|
+
[data-slot='button'][data-variant='destructive'] {
|
|
227
|
+
background: var(--destructive);
|
|
228
|
+
color: var(--destructive-foreground);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Tarjetas: planas, con filete, sin elevación */
|
|
232
|
+
[data-slot='card'] {
|
|
233
|
+
border: 1px solid var(--border);
|
|
234
|
+
box-shadow: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Campos: píldora/16px con filete; foco azul lo da el anillo */
|
|
238
|
+
[data-slot='input'],
|
|
239
|
+
[data-slot='textarea'],
|
|
240
|
+
[data-slot='select-trigger'] {
|
|
241
|
+
background: transparent;
|
|
242
|
+
border: 1px solid var(--input);
|
|
243
|
+
}
|
|
244
|
+
[data-slot='textarea'] {
|
|
245
|
+
border-radius: var(--ds-radius-lg);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Etiquetas en píldora */
|
|
249
|
+
[data-slot='badge'] {
|
|
250
|
+
border-radius: 9999px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Pestañas: sin fondo, subrayado de acento en la activa */
|
|
254
|
+
[data-slot='tabs-list'] {
|
|
255
|
+
background: transparent;
|
|
256
|
+
border-bottom: 1px solid var(--border);
|
|
257
|
+
border-radius: 0;
|
|
258
|
+
}
|
|
259
|
+
[data-slot='tabs-trigger'] {
|
|
260
|
+
border-radius: 0;
|
|
261
|
+
background: transparent;
|
|
262
|
+
font-weight: 500;
|
|
263
|
+
}
|
|
264
|
+
[data-slot='tabs-trigger']:hover {
|
|
265
|
+
background: var(--zt-hover-soft);
|
|
266
|
+
}
|
|
267
|
+
[data-slot='tabs-trigger'][data-active] {
|
|
268
|
+
background: transparent;
|
|
269
|
+
box-shadow: inset 0 -4px 0 var(--primary);
|
|
270
|
+
font-weight: 700;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Sidebar: filas grandes en píldora; la activa en negrita, sin relleno */
|
|
274
|
+
[data-sidebar='menu-button'] {
|
|
275
|
+
font-size: 1.125rem;
|
|
276
|
+
border-radius: 9999px;
|
|
277
|
+
}
|
|
278
|
+
[data-sidebar='menu-button']:hover {
|
|
279
|
+
background: var(--zt-hover);
|
|
280
|
+
}
|
|
281
|
+
[data-sidebar='menu-button'][data-active='true'] {
|
|
282
|
+
background: transparent;
|
|
283
|
+
font-weight: 700;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Interruptor y progreso en el azul de marca, planos */
|
|
287
|
+
[data-slot='progress-indicator'] {
|
|
288
|
+
background: var(--primary);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Fuentes del tema twitter. Chirp (la fuente de Twitter) es propietaria y no se
|
|
3
|
+
* puede distribuir: no hay nada que cargar. El tema usa la pila del sistema como
|
|
4
|
+
* respaldo (`-apple-system, Segoe UI, Roboto…`). Si tienes licencia de Chirp, defínela
|
|
5
|
+
* con @font-face en tu app y quedará aplicada.
|
|
6
|
+
*/
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* TEMA twitter — la interfaz de Twitter anterior a X (rediseño de 2021).
|
|
3
|
+
*
|
|
4
|
+
* Personalidad: PLANO y de alto contraste. Sin sombras ni cristal en el contenido;
|
|
5
|
+
* separación por filetes de 1px; botones en píldora con peso 700; tarjetas de 16px
|
|
6
|
+
* sin elevación; sidebar a ras de borde, sin fondo, con filas en píldora y la activa
|
|
7
|
+
* en negrita; pestañas con subrayado de acento. Azul de marca #1D9BF0 (confirmado) con
|
|
8
|
+
* «menos azul»: la acción más importante puede ir en tinta (negro/blanco).
|
|
9
|
+
*
|
|
10
|
+
* VALORES APROXIMADOS: el azul de marca y la fuente (Chirp, propietaria) están
|
|
11
|
+
* documentados; los grises, bordes y los fondos de «Dim» son de memoria y NO se han
|
|
12
|
+
* contrastado con la hoja de estilos real — ajústalos con una captura de referencia.
|
|
13
|
+
* Chirp no se puede distribuir: se usa la pila del sistema como respaldo.
|
|
14
|
+
*
|
|
15
|
+
* Importar DESPUÉS de la estructura. Variables `--zt-*`: privadas de este tema.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* ── VARIABLES · PIEL CLARA ──────────────────────────────────────────────── */
|
|
19
|
+
:root[data-theme='twitter'] {
|
|
20
|
+
--radius: 16px;
|
|
21
|
+
|
|
22
|
+
--ds-font-sans: 'Chirp', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
23
|
+
--ds-font-display: var(--ds-font-sans);
|
|
24
|
+
--ds-font-mono: ui-monospace, 'SF Mono', Menlo, monospace;
|
|
25
|
+
--ds-heading-tracking: normal;
|
|
26
|
+
|
|
27
|
+
/* Color */
|
|
28
|
+
--background: #ffffff;
|
|
29
|
+
--foreground: #0f1419;
|
|
30
|
+
|
|
31
|
+
--card: #ffffff;
|
|
32
|
+
--card-foreground: #0f1419;
|
|
33
|
+
--popover: #ffffff;
|
|
34
|
+
--popover-foreground: #0f1419;
|
|
35
|
+
|
|
36
|
+
--primary: #1d9bf0;
|
|
37
|
+
--primary-foreground: #ffffff;
|
|
38
|
+
--secondary: #eff3f4;
|
|
39
|
+
--secondary-foreground: #0f1419;
|
|
40
|
+
--muted: #f7f9f9;
|
|
41
|
+
--muted-foreground: #536471;
|
|
42
|
+
--accent: rgba(29, 155, 240, 0.1);
|
|
43
|
+
--accent-foreground: #1a8cd8;
|
|
44
|
+
--destructive: #f4212e;
|
|
45
|
+
--destructive-foreground: #ffffff;
|
|
46
|
+
|
|
47
|
+
--border: #eff3f4;
|
|
48
|
+
--input: #cfd9de;
|
|
49
|
+
--ring: #1d9bf0;
|
|
50
|
+
|
|
51
|
+
--chart-1: #1d9bf0;
|
|
52
|
+
--chart-2: #00ba7c;
|
|
53
|
+
--chart-3: #ffd400;
|
|
54
|
+
--chart-4: #f91880;
|
|
55
|
+
--chart-5: #7856ff;
|
|
56
|
+
|
|
57
|
+
--sidebar: transparent;
|
|
58
|
+
--sidebar-foreground: #0f1419;
|
|
59
|
+
--sidebar-primary: #1d9bf0;
|
|
60
|
+
--sidebar-primary-foreground: #ffffff;
|
|
61
|
+
--sidebar-accent: rgba(15, 20, 25, 0.1);
|
|
62
|
+
--sidebar-accent-foreground: #0f1419;
|
|
63
|
+
--sidebar-border: #eff3f4;
|
|
64
|
+
--sidebar-ring: #1d9bf0;
|
|
65
|
+
|
|
66
|
+
--danger: #d4141f;
|
|
67
|
+
--danger-soft: rgba(244, 33, 46, 0.1);
|
|
68
|
+
--warning: #8a6d00;
|
|
69
|
+
--warning-soft: rgba(255, 212, 0, 0.2);
|
|
70
|
+
--success: #00875a;
|
|
71
|
+
--success-soft: rgba(0, 186, 124, 0.12);
|
|
72
|
+
--info: #1a8cd8;
|
|
73
|
+
--info-soft: rgba(29, 155, 240, 0.1);
|
|
74
|
+
--neutral: #536471;
|
|
75
|
+
--neutral-soft: #eff3f4;
|
|
76
|
+
|
|
77
|
+
--link: #1d9bf0;
|
|
78
|
+
--link-hover: #1a8cd8;
|
|
79
|
+
--inset: #f7f9f9;
|
|
80
|
+
--inset-foreground: #0f1419;
|
|
81
|
+
--brand: #1d9bf0;
|
|
82
|
+
--brand-bright: #1d9bf0;
|
|
83
|
+
|
|
84
|
+
/* Formas: píldoras para acciones, 16px para superficies */
|
|
85
|
+
--ds-radius-sm: 8px;
|
|
86
|
+
--ds-radius-md: 12px;
|
|
87
|
+
--ds-radius-lg: 16px;
|
|
88
|
+
--ds-radius-xl: 16px;
|
|
89
|
+
--ds-radius-2xl: 20px;
|
|
90
|
+
--ds-radius-control: 9999px;
|
|
91
|
+
--ds-radius-overlay: 16px;
|
|
92
|
+
|
|
93
|
+
/* Sin elevación: solo los menús flotantes llevan sombra, muy suave */
|
|
94
|
+
--ds-shadow-card: 0 0 #0000;
|
|
95
|
+
--ds-shadow-card-hover: 0 0 #0000;
|
|
96
|
+
--ds-shadow-control: 0 0 #0000;
|
|
97
|
+
--ds-shadow-raised: 0 0 #0000;
|
|
98
|
+
--ds-shadow-overlay: 0 0 15px rgba(101, 119, 134, 0.2), 0 0 3px 1px rgba(101, 119, 134, 0.15);
|
|
99
|
+
--ds-shadow-popover: 0 0 15px rgba(101, 119, 134, 0.2), 0 0 3px 1px rgba(101, 119, 134, 0.15);
|
|
100
|
+
|
|
101
|
+
/* Medidas */
|
|
102
|
+
--ds-control-h-sm: 2rem;
|
|
103
|
+
--ds-control-h-md: 2.25rem;
|
|
104
|
+
--ds-control-h-lg: 3.25rem;
|
|
105
|
+
--ds-button-px-sm: 1rem;
|
|
106
|
+
--ds-button-px-md: 1.25rem;
|
|
107
|
+
--ds-button-px-lg: 2rem;
|
|
108
|
+
--ds-field-px: 1rem;
|
|
109
|
+
--ds-card-spacing: 1rem;
|
|
110
|
+
--ds-card-spacing-sm: 0.75rem;
|
|
111
|
+
|
|
112
|
+
/* Materiales: ninguno (plano) */
|
|
113
|
+
--ds-card-backdrop: none;
|
|
114
|
+
--ds-overlay-backdrop: none;
|
|
115
|
+
--ds-field-backdrop: none;
|
|
116
|
+
--ds-sidebar-backdrop: none;
|
|
117
|
+
--ds-page-backdrop: none;
|
|
118
|
+
|
|
119
|
+
/* Sidebar a ras de borde, sin silueta; filas en píldora grandes */
|
|
120
|
+
--ds-sidebar-pad: 0px;
|
|
121
|
+
--ds-sidebar-radius: 0px;
|
|
122
|
+
--ds-sidebar-shadow: 0 0 #0000;
|
|
123
|
+
--ds-sidebar-ring: 0px;
|
|
124
|
+
--ds-sidebar-edge: 1px solid var(--sidebar-border);
|
|
125
|
+
--ds-sidebar-item-radius: 9999px;
|
|
126
|
+
--ds-sidebar-item-h: 3.25rem;
|
|
127
|
+
|
|
128
|
+
/* Privadas de twitter */
|
|
129
|
+
--zt-hover: rgba(15, 20, 25, 0.1);
|
|
130
|
+
--zt-hover-soft: rgba(15, 20, 25, 0.03);
|
|
131
|
+
--zt-line-strong: #cfd9de;
|
|
132
|
+
--zt-ink: #0f1419;
|
|
133
|
+
--zt-ink-foreground: #ffffff;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* ── VARIABLES · PIEL OSCURA («Dim») ─────────────────────────────────────── */
|
|
137
|
+
:root[data-theme='twitter'].dark {
|
|
138
|
+
--background: #15202b;
|
|
139
|
+
--foreground: #f7f9f9;
|
|
140
|
+
|
|
141
|
+
--card: #15202b;
|
|
142
|
+
--card-foreground: #f7f9f9;
|
|
143
|
+
--popover: #1e2732;
|
|
144
|
+
--popover-foreground: #f7f9f9;
|
|
145
|
+
|
|
146
|
+
--primary: #1d9bf0;
|
|
147
|
+
--primary-foreground: #ffffff;
|
|
148
|
+
--secondary: #1e2732;
|
|
149
|
+
--secondary-foreground: #f7f9f9;
|
|
150
|
+
--muted: #1e2732;
|
|
151
|
+
--muted-foreground: #8b98a5;
|
|
152
|
+
--accent: rgba(29, 155, 240, 0.15);
|
|
153
|
+
--accent-foreground: #4db3f5;
|
|
154
|
+
--destructive: #f4212e;
|
|
155
|
+
--destructive-foreground: #ffffff;
|
|
156
|
+
|
|
157
|
+
--border: #38444d;
|
|
158
|
+
--input: #536471;
|
|
159
|
+
--ring: #1d9bf0;
|
|
160
|
+
|
|
161
|
+
--sidebar: transparent;
|
|
162
|
+
--sidebar-foreground: #f7f9f9;
|
|
163
|
+
--sidebar-primary: #1d9bf0;
|
|
164
|
+
--sidebar-primary-foreground: #ffffff;
|
|
165
|
+
--sidebar-accent: rgba(247, 249, 249, 0.1);
|
|
166
|
+
--sidebar-accent-foreground: #f7f9f9;
|
|
167
|
+
--sidebar-border: #38444d;
|
|
168
|
+
--sidebar-ring: #1d9bf0;
|
|
169
|
+
|
|
170
|
+
--danger: #ff5a64;
|
|
171
|
+
--danger-soft: rgba(244, 33, 46, 0.18);
|
|
172
|
+
--warning: #ffd400;
|
|
173
|
+
--warning-soft: rgba(255, 212, 0, 0.16);
|
|
174
|
+
--success: #00ba7c;
|
|
175
|
+
--success-soft: rgba(0, 186, 124, 0.16);
|
|
176
|
+
--info: #4db3f5;
|
|
177
|
+
--info-soft: rgba(29, 155, 240, 0.18);
|
|
178
|
+
--neutral: #8b98a5;
|
|
179
|
+
--neutral-soft: #1e2732;
|
|
180
|
+
|
|
181
|
+
--link: #4db3f5;
|
|
182
|
+
--link-hover: #8dcdf8;
|
|
183
|
+
--inset: #1e2732;
|
|
184
|
+
--inset-foreground: #f7f9f9;
|
|
185
|
+
--brand: #1d9bf0;
|
|
186
|
+
--brand-bright: #4db3f5;
|
|
187
|
+
|
|
188
|
+
--ds-shadow-overlay: 0 0 15px rgba(255, 255, 255, 0.2), 0 0 3px 1px rgba(255, 255, 255, 0.15);
|
|
189
|
+
--ds-shadow-popover: 0 0 15px rgba(255, 255, 255, 0.2), 0 0 3px 1px rgba(255, 255, 255, 0.15);
|
|
190
|
+
|
|
191
|
+
--zt-hover: rgba(247, 249, 249, 0.1);
|
|
192
|
+
--zt-hover-soft: rgba(247, 249, 249, 0.03);
|
|
193
|
+
--zt-line-strong: #536471;
|
|
194
|
+
--zt-ink: #eff3f4;
|
|
195
|
+
--zt-ink-foreground: #0f1419;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ── PERSONALIDAD ────────────────────────────────────────────────────────────
|
|
199
|
+
* Sin capa: gana a las utilidades de los componentes. Solo variables.
|
|
200
|
+
*/
|
|
201
|
+
:root[data-theme='twitter'] {
|
|
202
|
+
/* Botones: píldora en peso 700; primario en azul; contorno con filete */
|
|
203
|
+
[data-slot='button'] {
|
|
204
|
+
border-radius: 9999px;
|
|
205
|
+
font-weight: 700;
|
|
206
|
+
}
|
|
207
|
+
[data-slot='button'][data-variant='default']:hover:not(:disabled) {
|
|
208
|
+
background-color: var(--link-hover);
|
|
209
|
+
}
|
|
210
|
+
[data-slot='button'][data-variant='secondary'] {
|
|
211
|
+
background: var(--zt-ink);
|
|
212
|
+
color: var(--zt-ink-foreground);
|
|
213
|
+
}
|
|
214
|
+
[data-slot='button'][data-variant='secondary']:hover:not(:disabled) {
|
|
215
|
+
opacity: 0.88;
|
|
216
|
+
}
|
|
217
|
+
[data-slot='button'][data-variant='outline'] {
|
|
218
|
+
background: transparent;
|
|
219
|
+
border: 1px solid var(--zt-line-strong);
|
|
220
|
+
color: var(--foreground);
|
|
221
|
+
}
|
|
222
|
+
[data-slot='button'][data-variant='outline']:hover:not(:disabled),
|
|
223
|
+
[data-slot='button'][data-variant='ghost']:hover:not(:disabled) {
|
|
224
|
+
background: var(--zt-hover);
|
|
225
|
+
}
|
|
226
|
+
[data-slot='button'][data-variant='destructive'] {
|
|
227
|
+
background: var(--destructive);
|
|
228
|
+
color: var(--destructive-foreground);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Tarjetas: planas, con filete, sin elevación */
|
|
232
|
+
[data-slot='card'] {
|
|
233
|
+
border: 1px solid var(--border);
|
|
234
|
+
box-shadow: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Campos: píldora/16px con filete; foco azul lo da el anillo */
|
|
238
|
+
[data-slot='input'],
|
|
239
|
+
[data-slot='textarea'],
|
|
240
|
+
[data-slot='select-trigger'] {
|
|
241
|
+
background: transparent;
|
|
242
|
+
border: 1px solid var(--input);
|
|
243
|
+
}
|
|
244
|
+
[data-slot='textarea'] {
|
|
245
|
+
border-radius: var(--ds-radius-lg);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Etiquetas en píldora */
|
|
249
|
+
[data-slot='badge'] {
|
|
250
|
+
border-radius: 9999px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Pestañas: sin fondo, subrayado de acento en la activa */
|
|
254
|
+
[data-slot='tabs-list'] {
|
|
255
|
+
background: transparent;
|
|
256
|
+
border-bottom: 1px solid var(--border);
|
|
257
|
+
border-radius: 0;
|
|
258
|
+
}
|
|
259
|
+
[data-slot='tabs-trigger'] {
|
|
260
|
+
border-radius: 0;
|
|
261
|
+
background: transparent;
|
|
262
|
+
font-weight: 500;
|
|
263
|
+
}
|
|
264
|
+
[data-slot='tabs-trigger']:hover {
|
|
265
|
+
background: var(--zt-hover-soft);
|
|
266
|
+
}
|
|
267
|
+
[data-slot='tabs-trigger'][data-active] {
|
|
268
|
+
background: transparent;
|
|
269
|
+
box-shadow: inset 0 -4px 0 var(--primary);
|
|
270
|
+
font-weight: 700;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Sidebar: filas grandes en píldora; la activa en negrita, sin relleno */
|
|
274
|
+
[data-sidebar='menu-button'] {
|
|
275
|
+
font-size: 1.125rem;
|
|
276
|
+
border-radius: 9999px;
|
|
277
|
+
}
|
|
278
|
+
[data-sidebar='menu-button']:hover {
|
|
279
|
+
background: var(--zt-hover);
|
|
280
|
+
}
|
|
281
|
+
[data-sidebar='menu-button'][data-active='true'] {
|
|
282
|
+
background: transparent;
|
|
283
|
+
font-weight: 700;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Interruptor y progreso en el azul de marca, planos */
|
|
287
|
+
[data-slot='progress-indicator'] {
|
|
288
|
+
background: var(--primary);
|
|
289
|
+
}
|
|
290
|
+
}
|
package/dist/themes/zyro.css
CHANGED
|
@@ -341,3 +341,41 @@
|
|
|
341
341
|
background: var(--zy-conv-h);
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
|
+
|
|
345
|
+
/* Ajustes de personalidad (vistos en el banco de pruebas) */
|
|
346
|
+
:root {
|
|
347
|
+
/* Grupos de botones: píldora solo en los extremos, el interior recto */
|
|
348
|
+
[data-slot='button-group'] [data-slot='button'] {
|
|
349
|
+
border-radius: 0;
|
|
350
|
+
}
|
|
351
|
+
[data-slot='button-group'] [data-slot='button']:first-child {
|
|
352
|
+
border-start-start-radius: 9999px;
|
|
353
|
+
border-end-start-radius: 9999px;
|
|
354
|
+
}
|
|
355
|
+
[data-slot='button-group'] [data-slot='button']:last-child {
|
|
356
|
+
border-start-end-radius: 9999px;
|
|
357
|
+
border-end-end-radius: 9999px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* Esqueletos: visibles sobre la tarjeta casi blanca */
|
|
361
|
+
[data-slot='skeleton'] {
|
|
362
|
+
background: color-mix(in oklch, var(--foreground) 9%, transparent);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/* Fondo vivo: los degradados derivan despacio (aproximación ligera, sin WebGL de la
|
|
367
|
+
malla original). `prefers-reduced-motion` ya detiene la animación en la estructura. */
|
|
368
|
+
:root {
|
|
369
|
+
body {
|
|
370
|
+
background-size: 160% 160%;
|
|
371
|
+
animation: zy-drift 40s ease-in-out infinite alternate;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
@keyframes zy-drift {
|
|
375
|
+
from {
|
|
376
|
+
background-position: 0% 0%;
|
|
377
|
+
}
|
|
378
|
+
to {
|
|
379
|
+
background-position: 100% 100%;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
@@ -341,3 +341,41 @@
|
|
|
341
341
|
background: var(--zy-conv-h);
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
|
+
|
|
345
|
+
/* Ajustes de personalidad (vistos en el banco de pruebas) */
|
|
346
|
+
:root[data-theme='zyro'] {
|
|
347
|
+
/* Grupos de botones: píldora solo en los extremos, el interior recto */
|
|
348
|
+
[data-slot='button-group'] [data-slot='button'] {
|
|
349
|
+
border-radius: 0;
|
|
350
|
+
}
|
|
351
|
+
[data-slot='button-group'] [data-slot='button']:first-child {
|
|
352
|
+
border-start-start-radius: 9999px;
|
|
353
|
+
border-end-start-radius: 9999px;
|
|
354
|
+
}
|
|
355
|
+
[data-slot='button-group'] [data-slot='button']:last-child {
|
|
356
|
+
border-start-end-radius: 9999px;
|
|
357
|
+
border-end-end-radius: 9999px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* Esqueletos: visibles sobre la tarjeta casi blanca */
|
|
361
|
+
[data-slot='skeleton'] {
|
|
362
|
+
background: color-mix(in oklch, var(--foreground) 9%, transparent);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/* Fondo vivo: los degradados derivan despacio (aproximación ligera, sin WebGL de la
|
|
367
|
+
malla original). `prefers-reduced-motion` ya detiene la animación en la estructura. */
|
|
368
|
+
:root[data-theme='zyro'] {
|
|
369
|
+
body {
|
|
370
|
+
background-size: 160% 160%;
|
|
371
|
+
animation: zy-drift 40s ease-in-out infinite alternate;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
@keyframes zy-drift {
|
|
375
|
+
from {
|
|
376
|
+
background-position: 0% 0%;
|
|
377
|
+
}
|
|
378
|
+
to {
|
|
379
|
+
background-position: 100% 100%;
|
|
380
|
+
}
|
|
381
|
+
}
|
package/docs/CONTRACT.md
CHANGED
|
@@ -84,6 +84,35 @@ Los **materiales** son lo que hace posible un tema de cristal como `zyro`: con v
|
|
|
84
84
|
neutros no hay efecto ni coste; con `blur(28px) saturate(180%)` las superficies se
|
|
85
85
|
vuelven translúcidas.
|
|
86
86
|
|
|
87
|
+
## Capa de marca (`brand.css`): lo que cambia una app, y nunca se pisa
|
|
88
|
+
|
|
89
|
+
Tres capas, de menos a más personal:
|
|
90
|
+
|
|
91
|
+
1. **Estructura y componentes** (paquete): se actualizan.
|
|
92
|
+
2. **Tema y personalidad** (paquete: `qratia`, `zyro`…): formas, sombras, materiales,
|
|
93
|
+
anatomía del sidebar. Se actualizan con versión y changelog.
|
|
94
|
+
3. **Marca** (`src/brand.css`, **en la app**): el grupo estable de variables que una marca
|
|
95
|
+
suele cambiar (`brand.tokens` en `contract.json`: color principal, foco, enlace,
|
|
96
|
+
acento, radio, fuentes). Se importa **después** del tema, así gana, y **ninguna
|
|
97
|
+
actualización lo toca**. Sin fichero, o vacío, se aplica el estándar del tema.
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
@import 'orbital-ds/themes/qratia.css';
|
|
101
|
+
@import './brand.css'; /* tuyo: gana al tema */
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`pnpm exec orbital-ds-init` lo crea la primera vez (con las variables comentadas) y **nunca
|
|
105
|
+
sobrescribe** uno existente.
|
|
106
|
+
|
|
107
|
+
**Por qué una actualización no lo rompe:** los nombres de ese grupo son estables; quitar o
|
|
108
|
+
renombrar uno es versión **mayor**, con aviso antes. Además,
|
|
109
|
+
`orbital-ds-doctor --css src/brand.css` falla si el fichero usa una `--ds-*` que el paquete
|
|
110
|
+
ya no define, para que una renombrada no se ignore en silencio.
|
|
111
|
+
|
|
112
|
+
**Cambiar el color principal:** mueve juntas `primary`, `ring`, `link`, `brand`,
|
|
113
|
+
`sidebar-primary` y `chart-1`, y comprueba el contraste del texto sobre ellas. Nunca edites
|
|
114
|
+
el tema dentro de `node_modules` para personalizar una app.
|
|
115
|
+
|
|
87
116
|
## Reglas de nombres
|
|
88
117
|
|
|
89
118
|
- Todo en **inglés**: tokens, props y valores de variantes.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orbital-ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Sistema de diseño genérico: estructura común + temas con personalidad (qratia, zyro) + ~60 componentes sobre Base UI y Tailwind v4, con contrato verificable y legible por agentes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -19,13 +19,14 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
21
|
"scripts/doctor.mjs",
|
|
22
|
-
"scripts/manifest.mjs",
|
|
23
22
|
"contract.json",
|
|
24
23
|
"components.manifest.json",
|
|
25
24
|
"docs",
|
|
26
25
|
"AGENTS.md",
|
|
27
26
|
"README.md",
|
|
28
|
-
"LICENSE"
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"scripts/init.mjs",
|
|
29
|
+
"scripts/manifest.mjs"
|
|
29
30
|
],
|
|
30
31
|
"exports": {
|
|
31
32
|
"./styles.css": "./dist/styles.css",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
"react-resizable-panels": "^4.14.4"
|
|
134
135
|
},
|
|
135
136
|
"bin": {
|
|
136
|
-
"orbital-ds-doctor": "./scripts/doctor.mjs"
|
|
137
|
+
"orbital-ds-doctor": "./scripts/doctor.mjs",
|
|
138
|
+
"orbital-ds-init": "./scripts/init.mjs"
|
|
137
139
|
}
|
|
138
140
|
}
|
package/scripts/doctor.mjs
CHANGED
|
@@ -65,6 +65,21 @@ function declarations(body) {
|
|
|
65
65
|
return [...top.matchAll(/(^|[;\s])(--[a-z0-9-]+)\s*:\s*([^;]*);?/gi)].map((m) => ({ name: m[2], value: m[3].trim() }));
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/** Variables --ds-* que la estructura del paquete define (las que una app puede usar). */
|
|
69
|
+
function knownDsVars() {
|
|
70
|
+
const f = existsSync(join(ROOT, 'src/styles.css')) ? join(ROOT, 'src/styles.css') : join(ROOT, 'dist/styles.css');
|
|
71
|
+
return new Set([...read(f).matchAll(/(--ds-[a-z0-9-]+)\s*:/g)].map((m) => m[1]));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// El grupo de marca debe ser coherente con el contrato: cada variable, o es del contrato, o es --ds-*.
|
|
75
|
+
for (const t of contract.brand?.tokens ?? []) {
|
|
76
|
+
const inContract =
|
|
77
|
+
contract.root.includes(t.name) ||
|
|
78
|
+
contract.fonts.includes(t.name) ||
|
|
79
|
+
(t.name.startsWith('ds-') && knownDsVars().has(`--${t.name}`));
|
|
80
|
+
if (!inContract) errors.push(`contrato: la variable de marca --${t.name} ni es del contrato ni la define la estructura`);
|
|
81
|
+
}
|
|
82
|
+
|
|
68
83
|
const themeInfo = {}; // nombre → { rootVars:Set, darkVars:Set }
|
|
69
84
|
|
|
70
85
|
function checkTheme(file, name) {
|
|
@@ -141,6 +156,13 @@ if (cssArgIdx > -1 && process.argv[cssArgIdx + 1]) {
|
|
|
141
156
|
const seen = new Map();
|
|
142
157
|
for (const d of declarations(body)) seen.set(d.name, (seen.get(d.name) ?? 0) + 1);
|
|
143
158
|
for (const [v, n] of seen) if (n > 1) errors.push(`app css: ${v} definido ${n} veces en :root (#${idx + 1})`);
|
|
159
|
+
// Una variable --ds-* que el paquete ya no tiene: la marca la ignoraría en silencio.
|
|
160
|
+
const known = knownDsVars();
|
|
161
|
+
for (const d of declarations(body)) {
|
|
162
|
+
if (d.name.startsWith('--ds-') && !known.has(d.name)) {
|
|
163
|
+
errors.push(`app css: ${d.name} no existe en orbital-ds (¿renombrada o retirada? mira docs/CONTRACT.md)`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
144
166
|
});
|
|
145
167
|
}
|
|
146
168
|
|
package/scripts/init.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* orbital-ds-init — crea el fichero de MARCA de una app.
|
|
4
|
+
*
|
|
5
|
+
* pnpm exec orbital-ds-init # crea src/brand.css si no existe
|
|
6
|
+
* pnpm exec orbital-ds-init --out app/brand.css
|
|
7
|
+
*
|
|
8
|
+
* NUNCA sobrescribe un fichero existente. Ese fichero es de la app: ninguna
|
|
9
|
+
* actualización de orbital-ds lo toca, y se importa DESPUÉS del tema para que gane.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { dirname, resolve } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
|
+
const contract = JSON.parse(readFileSync(resolve(ROOT, 'contract.json'), 'utf8'));
|
|
17
|
+
|
|
18
|
+
const outIdx = process.argv.indexOf('--out');
|
|
19
|
+
const out = resolve(outIdx > -1 && process.argv[outIdx + 1] ? process.argv[outIdx + 1] : 'src/brand.css');
|
|
20
|
+
|
|
21
|
+
if (existsSync(out)) {
|
|
22
|
+
console.log(`Ya existe ${out}: no se toca (es de tu app).`);
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const lines = contract.brand.tokens.map(
|
|
27
|
+
(t) => ` /* --${t.name}: ${t.example}; */ /* ${t.about} */`,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const css = `/*
|
|
31
|
+
* MARCA de la app — fichero TUYO.
|
|
32
|
+
*
|
|
33
|
+
* Ninguna actualización de orbital-ds lo toca. Se importa DESPUÉS del tema, así que
|
|
34
|
+
* lo que pongas aquí gana. Si no defines nada, se aplica el valor estándar del tema.
|
|
35
|
+
*
|
|
36
|
+
* Estas variables son el grupo estable de «lo que una marca suele cambiar»: renombrar
|
|
37
|
+
* o quitar una de ellas es una versión MAYOR de orbital-ds, con aviso previo.
|
|
38
|
+
* Descomenta solo lo que necesites y cambia el valor.
|
|
39
|
+
*
|
|
40
|
+
* Cambia el color principal TODO junto: primary, ring, link, brand, sidebar-primary y
|
|
41
|
+
* chart-1 deben ir a la par (y comprueba el contraste del texto sobre ellos).
|
|
42
|
+
*/
|
|
43
|
+
:root {
|
|
44
|
+
${lines.join('\n')}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Piel oscura: solo si tu marca necesita valores distintos en oscuro. */
|
|
48
|
+
.dark {
|
|
49
|
+
/* --primary: ...; */
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
mkdirSync(dirname(out), { recursive: true });
|
|
54
|
+
writeFileSync(out, css);
|
|
55
|
+
console.log(`Creado ${out}.\n\nImpórtalo DESPUÉS del tema, en el CSS de tu app:\n\n @import 'orbital-ds/themes/<tema>.css';\n @import './brand.css';\n`);
|