@edc-motor/ui 0.4.25 → 0.4.27
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/package.json +1 -1
- package/scss/_tokens.scss +1 -1
- package/scss/components/_block-related.scss +8 -4
- package/scss/components/_blocks.scss +139 -45
- package/scss/components/_modal.scss +8 -0
- package/scss/components/_rich-content.scss +12 -5
- package/src/blocks/BlockCta.vue +3 -1
- package/src/blocks/BlockIndex.vue +25 -5
- package/src/blocks/BlockShell.vue +9 -2
- package/src/blocks/BlockTextCard.vue +7 -1
- package/src/components/BaseModal.vue +1 -1
- package/src/components/EditModal.vue +10 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edc-motor/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.27",
|
|
4
4
|
"description": "EdC Motor — componentes públicos Vue 3 + tokens SCSS para webs de juegos de mesa (paquete fuente: lo compila el consumidor con Vite)",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"type": "module",
|
package/scss/_tokens.scss
CHANGED
|
@@ -38,7 +38,7 @@ $k-fw-bold: 700;
|
|
|
38
38
|
$k-lh-tight: 1.15;
|
|
39
39
|
$k-lh-ui: 1.35;
|
|
40
40
|
$k-lh-body: 1.55;
|
|
41
|
-
$fs-11: 11px; $fs-12: 12px; $fs-13: 13px; $fs-14: 14px; $fs-16: 16px; $fs-18: 18px; $fs-20: 20px; $fs-24: 24px; $fs-28: 28px; $fs-32: 32px;
|
|
41
|
+
$fs-11: 11px; $fs-12: 12px; $fs-13: 13px; $fs-14: 14px; $fs-16: 16px; $fs-18: 18px; $fs-20: 20px; $fs-24: 24px; $fs-28: 28px; $fs-32: 32px; $fs-36: 36px; $fs-40: 40px;
|
|
42
42
|
|
|
43
43
|
// Espaciado (px, como kontuan)
|
|
44
44
|
$space-0: 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@use "tokens" as *;
|
|
2
2
|
|
|
3
3
|
// Bloque `related` (BlockRelated.vue): cabecera en rejilla (títulos + botón
|
|
4
|
-
// al índice a la derecha en ≥
|
|
4
|
+
// al índice a la derecha en ≥600, patrón del relateds de CDL) sobre una
|
|
5
5
|
// PreviewGrid compacta.
|
|
6
6
|
.block--related {
|
|
7
7
|
.block__related-header {
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
grid-template-columns: 1fr;
|
|
10
10
|
gap: $space-4;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// 600px es un umbral PROPIO de esta cabecera (sin token: no encaja en
|
|
13
|
+
// $bp-sm/$bp-md) — por debajo, título + subtítulo + botón caen en TRES
|
|
14
|
+
// filas (una columna); container query sobre `content` (el ancho real
|
|
15
|
+
// del bloque), coherente con el resto de bloques con imagen.
|
|
16
|
+
@container content (min-width: 600px) {
|
|
13
17
|
grid-template-columns: 1fr auto;
|
|
14
18
|
align-items: center;
|
|
15
19
|
}
|
|
@@ -24,14 +28,14 @@
|
|
|
24
28
|
.block__related-button {
|
|
25
29
|
justify-self: center; // estrecho: los botones de bloque van centrados
|
|
26
30
|
|
|
27
|
-
@
|
|
31
|
+
@container content (min-width: 600px) {
|
|
28
32
|
justify-self: end;
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
// Centrado/derecha del campo común `align`: la cabecera acompaña.
|
|
33
37
|
&.block--align-center .block__related-header {
|
|
34
|
-
@
|
|
38
|
+
@container content (min-width: 600px) {
|
|
35
39
|
grid-template-columns: 1fr;
|
|
36
40
|
}
|
|
37
41
|
}
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// Bloques públicos del CRM (doc 03): estilos base, cada juego los ajusta.
|
|
4
4
|
.block {
|
|
5
|
-
// Aire vertical entre bloques (CDL usa 4rem; aquí algo más contenido).
|
|
5
|
+
// Aire vertical entre bloques (CDL usa 4rem; aquí algo más contenido). En
|
|
6
|
+
// estrecho (contenedor `content') baja un poco: los bloques respiran
|
|
7
|
+
// menos apretados en pantallas pequeñas.
|
|
6
8
|
padding-block: $space-8 + $space-6; // 56px
|
|
9
|
+
|
|
10
|
+
@container content (max-width: #{$bp-sm - 1px}) {
|
|
11
|
+
padding-block: $space-8 + $space-2; // 40px
|
|
12
|
+
}
|
|
7
13
|
background: var(--block-bg, transparent);
|
|
8
14
|
|
|
9
15
|
&__inner {
|
|
@@ -15,18 +21,47 @@
|
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
// Anchura del contenido (campo común `width`): coherente entre bloques.
|
|
18
|
-
&--w-narrow .block__inner { max-width:
|
|
24
|
+
&--w-narrow .block__inner { max-width: 880px; }
|
|
19
25
|
&--w-full .block__inner { max-width: none; padding-inline: $space-6; }
|
|
20
26
|
|
|
21
|
-
//
|
|
22
|
-
//
|
|
27
|
+
// Las tarjetas (CTA, tarjeta de texto y cita) son algo más angostas que el
|
|
28
|
+
// resto en cada preset (wide/narrow), con la diferencia PROPORCIONAL (no
|
|
29
|
+
// un recorte fijo que desaparece de golpe): min(tope, 90%) — 90% ≈ la
|
|
30
|
+
// relación 1080/1200 del preset ancho, así que en pantallas grandes manda
|
|
31
|
+
// el tope (120px/100px más angosto que el resto) y, según se estrecha,
|
|
32
|
+
// manda el porcentaje y la diferencia decrece sin saltos. "Ancho
|
|
33
|
+
// completo" no lleva tope: full es full.
|
|
34
|
+
&--cta.block--w-wide .block__inner,
|
|
35
|
+
&--text-card.block--w-wide .block__inner,
|
|
36
|
+
&--quote.block--w-wide .block__inner { max-width: min(1080px, 90%); }
|
|
37
|
+
&--cta.block--w-narrow .block__inner,
|
|
38
|
+
&--text-card.block--w-narrow .block__inner,
|
|
39
|
+
&--quote.block--w-narrow .block__inner { max-width: min(780px, 90%); }
|
|
40
|
+
|
|
41
|
+
// Tipografía de bloque: texto BASE $fs-16 (el mismo cuerpo que el wysiwyg
|
|
42
|
+
// por defecto — sin override aquí), subtítulo $fs-24 (entre el título y
|
|
43
|
+
// la base), título $fs-32 (la cabecera sube a 40/28). Los títulos nunca
|
|
44
|
+
// se justifican.
|
|
23
45
|
// width 100%: en grids con justify-items start (el cuerpo del CTA) el
|
|
24
46
|
// elemento encoge a su contenido y el text-align no se vería.
|
|
25
|
-
&__title { margin: 0; font-size: $fs-
|
|
47
|
+
&__title { margin: 0; font-size: $fs-32; width: 100%; }
|
|
26
48
|
// pre-line: el subtítulo es un textarea — sus saltos de línea cuentan.
|
|
27
|
-
&__subtitle { margin: 0; color: $text-2; font-size: $fs-
|
|
49
|
+
&__subtitle { margin: 0; color: $text-2; font-size: $fs-24; white-space: pre-line; width: 100%; }
|
|
28
50
|
&__text { color: $text-1; font-size: $fs-16; }
|
|
29
51
|
|
|
52
|
+
// Alineación del bloque (campo común `align`): por CLASE (BlockShell ya
|
|
53
|
+
// no la mete como style en línea) para poder pisarla en estrecho.
|
|
54
|
+
&--align-left { text-align: left; }
|
|
55
|
+
&--align-center { text-align: center; }
|
|
56
|
+
&--align-right { text-align: right; }
|
|
57
|
+
&--align-justify { text-align: justify; }
|
|
58
|
+
|
|
59
|
+
// Justificado, a la IZQUIERDA por debajo de $bp-sm — mismo criterio (y
|
|
60
|
+
// mismo mecanismo, @media de viewport) que título/subtítulo, más abajo.
|
|
61
|
+
@media (max-width: $bp-sm - 1px) {
|
|
62
|
+
&--align-justify { text-align: left; }
|
|
63
|
+
}
|
|
64
|
+
|
|
30
65
|
&--align-justify &__title,
|
|
31
66
|
&--align-justify &__subtitle { text-align: left; }
|
|
32
67
|
|
|
@@ -52,17 +87,20 @@
|
|
|
52
87
|
&--subtitle-right &__subtitle { text-align: right; }
|
|
53
88
|
}
|
|
54
89
|
|
|
90
|
+
// Etiqueta de la tarjeta de texto: SIN chip — solo texto coloreado de
|
|
91
|
+
// acento, con alineación propia (campo label_align del bloque).
|
|
55
92
|
&__label {
|
|
56
|
-
display:
|
|
57
|
-
|
|
58
|
-
font-size: $fs-
|
|
93
|
+
display: block;
|
|
94
|
+
width: 100%;
|
|
95
|
+
font-size: $fs-13;
|
|
59
96
|
font-weight: $k-fw-semibold;
|
|
60
97
|
text-transform: uppercase;
|
|
61
98
|
letter-spacing: 0.05em;
|
|
62
99
|
color: $accent-500;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
100
|
+
|
|
101
|
+
&--left { text-align: left; }
|
|
102
|
+
&--center { text-align: center; }
|
|
103
|
+
&--right { text-align: right; }
|
|
66
104
|
}
|
|
67
105
|
|
|
68
106
|
&__card {
|
|
@@ -80,8 +118,8 @@
|
|
|
80
118
|
.edc-button { justify-self: start; text-decoration: none; }
|
|
81
119
|
}
|
|
82
120
|
|
|
83
|
-
&--header .block__title { font-size: $fs-
|
|
84
|
-
&--header .block__subtitle { font-size: $fs-
|
|
121
|
+
&--header .block__title { font-size: $fs-40; }
|
|
122
|
+
&--header .block__subtitle { font-size: $fs-28; }
|
|
85
123
|
|
|
86
124
|
&__media-layout { display: grid; gap: $space-4; }
|
|
87
125
|
&__image {
|
|
@@ -90,9 +128,11 @@
|
|
|
90
128
|
justify-self: center;
|
|
91
129
|
}
|
|
92
130
|
|
|
131
|
+
// Columnas solo de $bp-md (768) para arriba: por debajo el bloque pasa a
|
|
132
|
+
// VERTICAL y la imagen va SIEMPRE encima del texto (regla más abajo).
|
|
93
133
|
&--image-left .block__media-layout,
|
|
94
134
|
&--image-right .block__media-layout {
|
|
95
|
-
@container content (min-width: #{$bp-
|
|
135
|
+
@container content (min-width: #{$bp-md}) {
|
|
96
136
|
// Reparto izquierda:derecha del campo image_columns (--img-cols).
|
|
97
137
|
grid-template-columns: var(--img-cols, minmax(0, 2fr) minmax(0, 3fr));
|
|
98
138
|
align-items: stretch;
|
|
@@ -102,8 +142,21 @@
|
|
|
102
142
|
&--image-right .block__media-layout .block__image { order: 2; }
|
|
103
143
|
&--image-bottom .block__media-layout .block__image { order: 2; }
|
|
104
144
|
|
|
105
|
-
//
|
|
106
|
-
//
|
|
145
|
+
// En vertical (contenedor < 768) la imagen SIEMPRE encima del texto, da
|
|
146
|
+
// igual su posición configurada (derecha/abajo incluidas). Después de las
|
|
147
|
+
// reglas de order de arriba para ganarles el empate.
|
|
148
|
+
@container content (max-width: #{$bp-md}) {
|
|
149
|
+
&[class*="block--image-"] .block__media-layout > .block__image,
|
|
150
|
+
&[class*="block--image-"] .block__media-layout > .block__image-frame {
|
|
151
|
+
order: -1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Marco de la imagen en columnas: por defecto (cubrir/rellenar) el ALTO
|
|
156
|
+
// lo marca el texto de al lado (la imagen absoluta no aporta altura) y el
|
|
157
|
+
// modo de escalado hace el resto — object-position top: con el marco
|
|
158
|
+
// estirado, "cubrir" centraba la imagen en vertical, SIEMPRE anclada
|
|
159
|
+
// arriba.
|
|
107
160
|
&__image-frame {
|
|
108
161
|
position: relative;
|
|
109
162
|
min-height: 200px; // que no colapse con textos muy cortos
|
|
@@ -116,13 +169,32 @@
|
|
|
116
169
|
max-width: none;
|
|
117
170
|
}
|
|
118
171
|
}
|
|
119
|
-
|
|
120
|
-
&--fit-contain &__image-frame .block__image { object-fit: contain; }
|
|
121
|
-
&--fit-cover &__image-frame .block__image { object-fit: cover; }
|
|
172
|
+
&--fit-cover &__image-frame .block__image { object-fit: cover; object-position: top; }
|
|
122
173
|
&--fit-fill &__image-frame .block__image { object-fit: fill; }
|
|
123
174
|
|
|
124
|
-
//
|
|
125
|
-
|
|
175
|
+
// "Contener" es la excepción: la imagen respeta su tamaño NATURAL — ancho
|
|
176
|
+
// de columna, alto según su propia proporción — sin ampliarse ni
|
|
177
|
+
// encogerse para casar con el marco (si es más alta que el texto la fila
|
|
178
|
+
// crece; si es más baja, queda aire debajo). Por eso escapa del marco
|
|
179
|
+
// absoluto: vuelve al flujo normal, anclada arriba (align-self) del grid
|
|
180
|
+
// de columnas.
|
|
181
|
+
&--fit-contain &__image-frame {
|
|
182
|
+
@container content (min-width: #{$bp-md}) {
|
|
183
|
+
position: static;
|
|
184
|
+
min-height: 0;
|
|
185
|
+
align-self: start;
|
|
186
|
+
|
|
187
|
+
.block__image {
|
|
188
|
+
position: static;
|
|
189
|
+
width: 100%;
|
|
190
|
+
height: auto;
|
|
191
|
+
max-width: none;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// En una columna (vertical, < 768) la imagen vuelve al flujo normal.
|
|
197
|
+
@container content (max-width: #{$bp-md}) {
|
|
126
198
|
&__image-frame {
|
|
127
199
|
position: static;
|
|
128
200
|
min-height: 0;
|
|
@@ -137,7 +209,9 @@
|
|
|
137
209
|
}
|
|
138
210
|
|
|
139
211
|
// Imagen flotada: el texto la rodea y sigue por debajo (cleartext, como
|
|
140
|
-
// CDL)
|
|
212
|
+
// CDL), con un margen de $space-4 (16px) hacia el texto por los lados que
|
|
213
|
+
// lo tocan. En vertical (< 768) la imagen va arriba a lo ancho, sin
|
|
214
|
+
// flotar.
|
|
141
215
|
&--image-clear-left .block__media-layout,
|
|
142
216
|
&--image-clear-right .block__media-layout {
|
|
143
217
|
display: block;
|
|
@@ -145,20 +219,24 @@
|
|
|
145
219
|
// Clearfix: el bloque no se corta si la imagen es más alta que el texto.
|
|
146
220
|
&::after { content: ""; display: table; clear: both; }
|
|
147
221
|
|
|
148
|
-
.block__image { margin-bottom: $space-
|
|
222
|
+
.block__image { margin-bottom: $space-4; }
|
|
149
223
|
}
|
|
150
224
|
&--image-clear-left .block__media-layout .block__image {
|
|
151
|
-
@container content (min-width: #{$bp-
|
|
225
|
+
@container content (min-width: #{$bp-md}) {
|
|
152
226
|
float: left;
|
|
153
227
|
max-width: 50%;
|
|
154
|
-
|
|
228
|
+
// Respiro de $space-4 (16px) por arriba, abajo y hacia el texto
|
|
229
|
+
// (derecha); pegada a su lado exterior (izquierda, sin margen).
|
|
230
|
+
margin: $space-4 $space-4 $space-4 0;
|
|
231
|
+
vertical-align: top;
|
|
155
232
|
}
|
|
156
233
|
}
|
|
157
234
|
&--image-clear-right .block__media-layout .block__image {
|
|
158
|
-
@container content (min-width: #{$bp-
|
|
235
|
+
@container content (min-width: #{$bp-md}) {
|
|
159
236
|
float: right;
|
|
160
237
|
max-width: 50%;
|
|
161
|
-
margin
|
|
238
|
+
margin: $space-4 0 $space-4 $space-4;
|
|
239
|
+
vertical-align: top;
|
|
162
240
|
}
|
|
163
241
|
}
|
|
164
242
|
|
|
@@ -204,18 +282,20 @@
|
|
|
204
282
|
}
|
|
205
283
|
|
|
206
284
|
// La imagen del CTA sangra hasta el borde de la tarjeta según su posición:
|
|
207
|
-
// en columnas toca arriba, abajo y su lateral
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
|
|
285
|
+
// en columnas toca TODA la altura (arriba, abajo y su lateral — título y
|
|
286
|
+
// subtítulo viven dentro de `.block__cta-body`, junto al texto, en la
|
|
287
|
+
// columna de contenido); arriba/abajo toca los laterales. Esquinas
|
|
288
|
+
// siguiendo el radio de la tarjeta.
|
|
289
|
+
// Las tarjetas del CTA y de la tarjeta de texto llevan un halo SUTIL del
|
|
290
|
+
// acento, igual por los cuatro bordes, además de su sombra normal.
|
|
291
|
+
&--cta .block__card,
|
|
292
|
+
&--text-card .block__card {
|
|
213
293
|
box-shadow: $shadow-sm, 0 0 18px color-mix(in srgb, $accent-500 30%, transparent);
|
|
214
294
|
}
|
|
215
295
|
|
|
216
296
|
&--cta.block--image-right .block__media-layout .block__image-frame,
|
|
217
297
|
&--cta.block--image-left .block__media-layout .block__image-frame {
|
|
218
|
-
@container content (min-width: #{$bp-
|
|
298
|
+
@container content (min-width: #{$bp-md}) {
|
|
219
299
|
overflow: hidden;
|
|
220
300
|
min-height: 0;
|
|
221
301
|
|
|
@@ -223,13 +303,13 @@
|
|
|
223
303
|
}
|
|
224
304
|
}
|
|
225
305
|
&--cta.block--image-right .block__media-layout .block__image-frame {
|
|
226
|
-
@container content (min-width: #{$bp-
|
|
306
|
+
@container content (min-width: #{$bp-md}) {
|
|
227
307
|
margin: (-$space-8) (-$space-8) (-$space-8) 0;
|
|
228
308
|
border-radius: 0 $radius-lg $radius-lg 0;
|
|
229
309
|
}
|
|
230
310
|
}
|
|
231
311
|
&--cta.block--image-left .block__media-layout .block__image-frame {
|
|
232
|
-
@container content (min-width: #{$bp-
|
|
312
|
+
@container content (min-width: #{$bp-md}) {
|
|
233
313
|
margin: (-$space-8) 0 (-$space-8) (-$space-8);
|
|
234
314
|
border-radius: $radius-lg 0 0 $radius-lg;
|
|
235
315
|
}
|
|
@@ -250,11 +330,11 @@
|
|
|
250
330
|
border-radius: 0 0 $radius-lg $radius-lg;
|
|
251
331
|
}
|
|
252
332
|
|
|
253
|
-
// CTA con imagen en
|
|
254
|
-
// ARRIBA, a sangre por los laterales de la tarjeta y con
|
|
255
|
-
// (recortada, no deformada). Va DESPUÉS de las reglas por
|
|
256
|
-
// ganarles en el empate de especificidad.
|
|
257
|
-
@container content (max-width: #{$bp-
|
|
333
|
+
// CTA con imagen en VERTICAL (< 768): da igual la posición elegida — la
|
|
334
|
+
// imagen va ARRIBA, a sangre por los laterales de la tarjeta y con
|
|
335
|
+
// proporción 2:1 (recortada, no deformada). Va DESPUÉS de las reglas por
|
|
336
|
+
// posición para ganarles en el empate de especificidad.
|
|
337
|
+
@container content (max-width: #{$bp-md}) {
|
|
258
338
|
&--cta[class*="block--image-"] .block__card .block__media-layout {
|
|
259
339
|
> .block__image,
|
|
260
340
|
> .block__image-frame {
|
|
@@ -297,8 +377,8 @@
|
|
|
297
377
|
}
|
|
298
378
|
}
|
|
299
379
|
|
|
300
|
-
// Cita: sin adorno de borde, en GRANDE ($fs-32, el
|
|
301
|
-
//
|
|
380
|
+
// Cita: sin adorno de borde, en GRANDE ($fs-32, el mismo tamaño que un
|
|
381
|
+
// título de bloque) y del color de acento.
|
|
302
382
|
&--quote .block__quote {
|
|
303
383
|
margin: 0;
|
|
304
384
|
// Fuente "especial" de la configuración de la web (doc 10); las fuentes
|
|
@@ -337,7 +417,21 @@
|
|
|
337
417
|
a { color: $accent-500; text-decoration: none; }
|
|
338
418
|
a:hover { text-decoration: underline; }
|
|
339
419
|
|
|
340
|
-
//
|
|
420
|
+
// Numerado: la numeración anidada (1, 1.1, 1.2.1…) la pinta el
|
|
421
|
+
// componente — fuera los números nativos del ol.
|
|
422
|
+
&--numbered {
|
|
423
|
+
list-style: none;
|
|
424
|
+
padding-left: 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.block__index-number {
|
|
428
|
+
margin-right: $space-2;
|
|
429
|
+
color: $text-2;
|
|
430
|
+
font-variant-numeric: tabular-nums;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Tamaño por nivel: 24 → 22 (no hay token entre 20 y 24) → 20 (el 3
|
|
434
|
+
// agrupa "3 o más").
|
|
341
435
|
.block__index-level-1 { font-size: $fs-24; }
|
|
342
436
|
.block__index-level-2 { font-size: 22px; }
|
|
343
437
|
.block__index-level-3 { font-size: $fs-20; }
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
&--sm { max-width: 380px; }
|
|
27
27
|
&--md { max-width: 560px; }
|
|
28
28
|
&--lg { max-width: 820px; }
|
|
29
|
+
// Formularios con más columnas (el modal de bloque, EditModal): más ancho
|
|
30
|
+
// que el resto, pero sin llegar a ocupar toda la pantalla.
|
|
31
|
+
&--wide { max-width: 940px; }
|
|
29
32
|
|
|
30
33
|
&__header {
|
|
31
34
|
flex-shrink: 0;
|
|
@@ -50,11 +53,16 @@
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
// El cuerpo es la única zona que scrollea (cabecera y pie quedan fijos).
|
|
56
|
+
// Contenedor con nombre (container query, no viewport): los formularios de
|
|
57
|
+
// dentro (SchemaFields/PageBlocks) apilan sus filas de dos columnas según
|
|
58
|
+
// el ANCHO REAL del modal, no el del viewport.
|
|
53
59
|
&__body {
|
|
54
60
|
flex: 1 1 auto;
|
|
55
61
|
min-height: 0;
|
|
56
62
|
overflow-y: auto;
|
|
57
63
|
padding: $space-5;
|
|
64
|
+
container-type: inline-size;
|
|
65
|
+
container-name: modal-body;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
&__footer {
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
font-size: $fs-16;
|
|
8
8
|
line-height: $k-lh-body;
|
|
9
9
|
|
|
10
|
+
// Las NEGRITAS del wysiwyg, en el color de acento.
|
|
11
|
+
strong,
|
|
12
|
+
b {
|
|
13
|
+
color: $accent-500;
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// Aire entre TODOS los elementos del wysiwyg (párrafos, listas, títulos…).
|
|
11
17
|
p,
|
|
12
18
|
ul,
|
|
@@ -28,12 +34,13 @@
|
|
|
28
34
|
> :first-child { margin-block-start: 0; }
|
|
29
35
|
> :last-child { margin-block-end: 0; }
|
|
30
36
|
|
|
31
|
-
// Escala del wysiwyg: h2
|
|
32
|
-
|
|
37
|
+
// Escala del wysiwyg: h2 32 (el mismo tamaño que un título de bloque) ·
|
|
38
|
+
// h3 24 · h4 22 (no hay token entre 20 y 24) · h5 20 · h6 18.
|
|
39
|
+
h2 { font-size: $fs-32; }
|
|
33
40
|
h3 { font-size: $fs-24; }
|
|
34
|
-
h4 { font-size:
|
|
35
|
-
h5 { font-size: $fs-
|
|
36
|
-
h6 { font-size: $fs-
|
|
41
|
+
h4 { font-size: 22px; }
|
|
42
|
+
h5 { font-size: $fs-20; }
|
|
43
|
+
h6 { font-size: $fs-18; }
|
|
37
44
|
|
|
38
45
|
ul,
|
|
39
46
|
ol {
|
package/src/blocks/BlockCta.vue
CHANGED
|
@@ -28,7 +28,9 @@ const layoutStyle = computed(() => {
|
|
|
28
28
|
>
|
|
29
29
|
<div class="block__card">
|
|
30
30
|
<!-- En columnas, título y subtítulo viajan a la columna de texto para
|
|
31
|
-
que la imagen pueda sangrar a TODA la altura de la tarjeta
|
|
31
|
+
que la imagen pueda sangrar a TODA la altura de la tarjeta (a
|
|
32
|
+
todo ancho, en todos los anchos de pantalla: es una decisión de
|
|
33
|
+
plantilla por settings, no por el ancho del contenedor). -->
|
|
32
34
|
<template v-if="!inColumns">
|
|
33
35
|
<h2 v-if="settings.title" class="block__title">{{ settings.title }}</h2>
|
|
34
36
|
<p v-if="settings.subtitle" class="block__subtitle">{{ settings.subtitle }}</p>
|
|
@@ -1,24 +1,43 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
2
3
|
import BlockShell from './BlockShell.vue'
|
|
3
4
|
|
|
4
5
|
// Índice automático: enlaces de ancla a los bloques posteriores de la
|
|
5
6
|
// página, con sangría por nivel (sin límite de profundidad: la escribe
|
|
6
7
|
// IndexBlock::resolveData subiendo por la cadena de padres del bloque).
|
|
7
|
-
defineProps<{
|
|
8
|
+
const props = defineProps<{
|
|
8
9
|
settings: Record<string, unknown>
|
|
9
10
|
data: { items?: { id: number; label: string; depth?: number }[] }
|
|
10
11
|
}>()
|
|
12
|
+
|
|
13
|
+
// Numeración ANIDADA del modo numerado (1, 1.1, 1.2, 1.2.1…): la lista
|
|
14
|
+
// llega plana en preorden con `depth`, así que basta una pila de contadores.
|
|
15
|
+
const numbered = computed(() => {
|
|
16
|
+
const counters: number[] = []
|
|
17
|
+
return (props.data.items ?? []).map((item) => {
|
|
18
|
+
const depth = item.depth ?? 0
|
|
19
|
+
counters.length = depth + 1
|
|
20
|
+
counters[depth] = (counters[depth] ?? 0) + 1
|
|
21
|
+
return { ...item, number: counters.join('.') }
|
|
22
|
+
})
|
|
23
|
+
})
|
|
11
24
|
</script>
|
|
12
25
|
|
|
13
26
|
<template>
|
|
14
27
|
<BlockShell :settings="settings" class="block--index">
|
|
15
28
|
<h2 v-if="settings.title" class="block__title">{{ settings.title }}</h2>
|
|
16
29
|
<p v-if="settings.subtitle" class="block__subtitle">{{ settings.subtitle }}</p>
|
|
17
|
-
<component
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
<component
|
|
31
|
+
:is="settings.numbered ? 'ol' : 'ul'"
|
|
32
|
+
class="block__index"
|
|
33
|
+
:class="{ 'block__index--numbered': settings.numbered }"
|
|
34
|
+
>
|
|
35
|
+
<!-- Tamaño por nivel (el 3 agrupa "3 o más"); la SANGRÍA, en cambio,
|
|
36
|
+
escala con la profundidad real (--depth, sin tope). Numerado: la
|
|
37
|
+
numeración es ANIDADA (1, 1.1, 1.2.1…), calculada aquí — el ol
|
|
38
|
+
nativo no sabe numerar una lista plana con profundidades. -->
|
|
20
39
|
<li
|
|
21
|
-
v-for="item in
|
|
40
|
+
v-for="item in numbered"
|
|
22
41
|
:key="item.id"
|
|
23
42
|
:style="{ '--depth': item.depth ?? 0 }"
|
|
24
43
|
:class="[
|
|
@@ -26,6 +45,7 @@ defineProps<{
|
|
|
26
45
|
{ 'block__index-child': (item.depth ?? 0) > 0 },
|
|
27
46
|
]"
|
|
28
47
|
>
|
|
48
|
+
<span v-if="settings.numbered" class="block__index-number">{{ item.number }}</span>
|
|
29
49
|
<a :href="`#block-${item.id}`">{{ item.label }}</a>
|
|
30
50
|
</li>
|
|
31
51
|
</component>
|
|
@@ -19,13 +19,15 @@ const headingAlign = (key: 'title_align' | 'subtitle_align', prefix: string) =>
|
|
|
19
19
|
return value && value !== 'inherit' ? `block--${prefix}-${value}` : ''
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// La alineación va por CLASE (block--align-*, _blocks.scss), no por style en
|
|
23
|
+
// línea: un style inline no se puede pisar desde CSS (bloqueaba el cambio a
|
|
24
|
+
// izquierda del justificado en estrecho, DC-03 ampliado).
|
|
22
25
|
const style = computed<CSSProperties>(() => {
|
|
23
26
|
const background = props.settings.background as string | undefined
|
|
24
27
|
return {
|
|
25
28
|
'--block-bg': background
|
|
26
29
|
? `color-mix(in srgb, ${background} var(--block-tint, 15%), transparent)`
|
|
27
30
|
: 'transparent',
|
|
28
|
-
textAlign: ((props.settings.align as string) || 'justify') as CSSProperties['textAlign'],
|
|
29
31
|
}
|
|
30
32
|
})
|
|
31
33
|
</script>
|
|
@@ -33,7 +35,12 @@ const style = computed<CSSProperties>(() => {
|
|
|
33
35
|
<template>
|
|
34
36
|
<section
|
|
35
37
|
class="block"
|
|
36
|
-
:class="[
|
|
38
|
+
:class="[
|
|
39
|
+
width,
|
|
40
|
+
align,
|
|
41
|
+
headingAlign('title_align', 'title'),
|
|
42
|
+
headingAlign('subtitle_align', 'subtitle'),
|
|
43
|
+
]"
|
|
37
44
|
:style="style"
|
|
38
45
|
>
|
|
39
46
|
<div class="block__inner">
|
|
@@ -12,7 +12,13 @@ defineProps<{ settings: Record<string, unknown>; data?: Record<string, unknown>
|
|
|
12
12
|
:class="settings.image ? `block--image-${settings.image_position || 'top'}` : ''"
|
|
13
13
|
>
|
|
14
14
|
<div class="block__card">
|
|
15
|
-
<span
|
|
15
|
+
<span
|
|
16
|
+
v-if="settings.label"
|
|
17
|
+
class="block__label"
|
|
18
|
+
:class="`block__label--${settings.label_align || 'left'}`"
|
|
19
|
+
>
|
|
20
|
+
{{ settings.label }}
|
|
21
|
+
</span>
|
|
16
22
|
<h2 v-if="settings.title" class="block__title">{{ settings.title }}</h2>
|
|
17
23
|
<p v-if="settings.subtitle" class="block__subtitle">{{ settings.subtitle }}</p>
|
|
18
24
|
<div class="block__media-layout">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
2
3
|
import BaseModal from './BaseModal.vue'
|
|
3
4
|
import { Save, X } from '@lucide/vue'
|
|
4
5
|
import BaseButton from './BaseButton.vue'
|
|
@@ -11,7 +12,8 @@ const props = withDefaults(
|
|
|
11
12
|
defineProps<{
|
|
12
13
|
modelValue: boolean
|
|
13
14
|
title: string
|
|
14
|
-
|
|
15
|
+
/** 'wide' para formularios con más columnas (el modal de bloque). */
|
|
16
|
+
size?: 'normal' | 'wide'
|
|
15
17
|
loading?: boolean
|
|
16
18
|
submitLabel?: string
|
|
17
19
|
cancelLabel?: string
|
|
@@ -20,7 +22,7 @@ const props = withDefaults(
|
|
|
20
22
|
localeSwitchLabel?: string
|
|
21
23
|
}>(),
|
|
22
24
|
{
|
|
23
|
-
size: '
|
|
25
|
+
size: 'normal',
|
|
24
26
|
loading: false,
|
|
25
27
|
submitLabel: 'Guardar',
|
|
26
28
|
cancelLabel: 'Cancelar',
|
|
@@ -29,6 +31,11 @@ const props = withDefaults(
|
|
|
29
31
|
},
|
|
30
32
|
)
|
|
31
33
|
|
|
34
|
+
// EditModal tiene su propia escala de tamaño (normal/wide, sobre el
|
|
35
|
+
// contenido del FORMULARIO); BaseModal sigue con la suya (sm/md/lg/wide,
|
|
36
|
+
// genérica) — normal se apoya en su 'md' por defecto.
|
|
37
|
+
const modalSize = computed(() => (props.size === 'wide' ? 'wide' : 'md'))
|
|
38
|
+
|
|
32
39
|
const emit = defineEmits<{ 'update:modelValue': [boolean]; submit: [] }>()
|
|
33
40
|
|
|
34
41
|
// Locale global del formulario: los campos traducibles del slot (Translatable*
|
|
@@ -46,7 +53,7 @@ function close() {
|
|
|
46
53
|
<BaseModal
|
|
47
54
|
:model-value="modelValue"
|
|
48
55
|
:title="title"
|
|
49
|
-
:size="
|
|
56
|
+
:size="modalSize"
|
|
50
57
|
@update:model-value="(v) => !loading && emit('update:modelValue', v)"
|
|
51
58
|
>
|
|
52
59
|
<!-- Cabecera propia: título + selector de locale global (si hay campos
|