@edc-motor/admin-kit 0.5.3 → 0.5.5
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edc-motor/admin-kit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "EdC Motor — kit del panel de administración: layout, gestores CRUD, imágenes, PDF, páginas, configuración, usuarios y copias (paquete fuente: lo compila el consumidor con Vite)",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@edc-motor/ui": "^0.5.
|
|
36
|
+
"@edc-motor/ui": "^0.5.5",
|
|
37
37
|
"axios": "^1.7.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
@@ -368,40 +368,50 @@
|
|
|
368
368
|
|
|
369
369
|
// Campos del bloque seleccionado: etiqueta + valor; los valores largos se
|
|
370
370
|
// recortan a unas pocas líneas.
|
|
371
|
-
// Campo del panel de bloque: «Label: valor»
|
|
372
|
-
//
|
|
371
|
+
// Campo del panel de bloque: «Label: valor» como UN ÚNICO PÁRRAFO corrido
|
|
372
|
+
// — dt y dd van en línea, el valor arranca tras los dos puntos y, al
|
|
373
|
+
// envolver, ocupa el ancho completo bajo el label (nada de dos columnas).
|
|
374
|
+
// El clamp de líneas vive ahora en el PÁRRAFO entero (el -webkit-box no
|
|
375
|
+
// convive con hijos inline sueltos, así que recorta label+valor juntos:
|
|
376
|
+
// con labels de una palabra, en la práctica es el mismo recorte de antes).
|
|
377
|
+
// Las imágenes van apiladas (is-stacked), con la miniatura bajo el label.
|
|
373
378
|
&__field {
|
|
374
|
-
display: flex;
|
|
375
|
-
align-items: baseline;
|
|
376
|
-
gap: $space-1;
|
|
377
379
|
min-width: 0;
|
|
378
380
|
font-size: $fs-13;
|
|
381
|
+
overflow-wrap: anywhere;
|
|
382
|
+
display: -webkit-box;
|
|
383
|
+
-webkit-box-orient: vertical;
|
|
384
|
+
-webkit-line-clamp: 4;
|
|
385
|
+
line-clamp: 4;
|
|
386
|
+
overflow: hidden;
|
|
379
387
|
|
|
380
388
|
dt {
|
|
381
|
-
|
|
389
|
+
display: inline;
|
|
382
390
|
color: $text-3;
|
|
383
391
|
font-size: $fs-12;
|
|
384
392
|
text-transform: uppercase;
|
|
385
393
|
letter-spacing: 0.04em;
|
|
386
394
|
|
|
387
|
-
|
|
395
|
+
// El hueco tras los dos puntos va en margen: Vue condensa el
|
|
396
|
+
// whitespace entre <dt> y <dd> y en línea quedarían pegados.
|
|
397
|
+
&::after {
|
|
398
|
+
content: ':';
|
|
399
|
+
margin-inline-end: 0.4em;
|
|
400
|
+
}
|
|
388
401
|
}
|
|
389
402
|
|
|
390
403
|
dd {
|
|
404
|
+
display: inline;
|
|
391
405
|
margin: 0;
|
|
392
|
-
min-width: 0;
|
|
393
406
|
color: $text-2;
|
|
394
|
-
overflow-wrap: anywhere;
|
|
395
|
-
display: -webkit-box;
|
|
396
|
-
-webkit-box-orient: vertical;
|
|
397
|
-
-webkit-line-clamp: 4;
|
|
398
|
-
line-clamp: 4;
|
|
399
|
-
overflow: hidden;
|
|
400
407
|
}
|
|
401
408
|
|
|
402
409
|
&.is-stacked {
|
|
403
410
|
display: grid;
|
|
404
411
|
gap: 2px;
|
|
412
|
+
-webkit-line-clamp: none;
|
|
413
|
+
line-clamp: none;
|
|
414
|
+
overflow: visible;
|
|
405
415
|
|
|
406
416
|
dt::after { content: none; }
|
|
407
417
|
}
|
|
@@ -208,6 +208,20 @@
|
|
|
208
208
|
// cortarse (180px sobraba de aire).
|
|
209
209
|
&__field-align { flex: 0 0 140px; }
|
|
210
210
|
|
|
211
|
+
// Fila declarada en el esquema (Field::row): el grupo baja por recursión
|
|
212
|
+
// como un .schema-fields anidado — aquí solo se reparte en columnas
|
|
213
|
+
// iguales MIENTRAS QUEPAN (auto-fit: con poco ancho van cayendo solas);
|
|
214
|
+
// el checkbox se centra en vertical junto a sus compañeros de fila.
|
|
215
|
+
&__field--pair > .schema-fields {
|
|
216
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
217
|
+
gap: $space-3;
|
|
218
|
+
align-items: start;
|
|
219
|
+
|
|
220
|
+
> .schema-fields__field:has(> .schema-fields__field-main > .checkbox) {
|
|
221
|
+
align-self: center;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
211
225
|
// Imagen a dos columnas: el input a la izquierda, sus ajustes (posición,
|
|
212
226
|
// escalado, reparto de columnas) apilados a la derecha. `stretch` para que
|
|
213
227
|
// la columna de la imagen llene el alto de la fila; el cuadro de arrastre
|
|
@@ -253,6 +267,9 @@
|
|
|
253
267
|
&__field-align { flex-basis: auto; }
|
|
254
268
|
|
|
255
269
|
&__field--image-group { grid-template-columns: 1fr; }
|
|
270
|
+
|
|
271
|
+
// Las filas declaradas (Field::row) apilan en el modal angosto.
|
|
272
|
+
&__field--pair > .schema-fields { grid-template-columns: 1fr; }
|
|
256
273
|
}
|
|
257
274
|
|
|
258
275
|
&__color,
|
|
@@ -43,6 +43,8 @@ export interface FieldSchema {
|
|
|
43
43
|
fields?: FieldSchema[] | null
|
|
44
44
|
/** Para entity: endpoint de opciones del admin. */
|
|
45
45
|
options_url?: string | null
|
|
46
|
+
/** Fila declarada en el esquema (Field::row): mismo nombre = misma fila. */
|
|
47
|
+
row?: string | null
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
const props = withDefaults(
|
|
@@ -76,6 +78,13 @@ const emit = defineEmits<{ 'update:modelValue': [value: Record<string, unknown>]
|
|
|
76
78
|
// (`image_position`, `image_fit`, `image_columns`) en la misma lista se
|
|
77
79
|
// agrupa con ellos — columna 1 la imagen, columna 2 los ajustes
|
|
78
80
|
// apilados.
|
|
81
|
+
// 3) Filas DECLARADAS en el esquema (Field::row('nombre')): los campos que
|
|
82
|
+
// comparten `row` van juntos en una fila de columnas iguales mientras
|
|
83
|
+
// quepan (auto-fit; en un modal angosto apilan). Se pintan por RECURSIÓN
|
|
84
|
+
// sobre este mismo componente (los compañeros pierden su `row` al bajar,
|
|
85
|
+
// para no re-agrupar en bucle). La fila declarada es intención EXPLÍCITA
|
|
86
|
+
// del esquema: gana a las convenciones 1 y 2 — un campo con `row` queda
|
|
87
|
+
// fuera del emparejado implícito (tanto de origen como de destino).
|
|
79
88
|
const IMAGE_SETTING_KEYS = ['image_position', 'image_fit', 'image_columns']
|
|
80
89
|
|
|
81
90
|
interface LayoutItem {
|
|
@@ -84,6 +93,8 @@ interface LayoutItem {
|
|
|
84
93
|
align?: FieldSchema
|
|
85
94
|
/** Ajustes de imagen (image_position/fit/columns) que viajan con `field`. */
|
|
86
95
|
imageSettings?: FieldSchema[]
|
|
96
|
+
/** Campos de una fila declarada (Field::row), este incluido y sin `row`. */
|
|
97
|
+
rowFields?: FieldSchema[]
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
const layout = computed<LayoutItem[]>(() => {
|
|
@@ -92,32 +103,52 @@ const layout = computed<LayoutItem[]>(() => {
|
|
|
92
103
|
const consumed = new Set<string>() // claves ya emparejadas con otro campo
|
|
93
104
|
|
|
94
105
|
for (const field of props.fields) {
|
|
95
|
-
if (field.type !== 'select' || !field.key.endsWith('_align')) continue
|
|
106
|
+
if (field.type !== 'select' || !field.key.endsWith('_align') || field.row) continue
|
|
96
107
|
const base = field.key.slice(0, -'_align'.length)
|
|
97
108
|
if (!base) continue // el "align" general no tiene prefijo
|
|
98
109
|
const baseKey = byKey.has(base) ? base : byKey.has(`${base}_text`) ? `${base}_text` : null
|
|
99
|
-
if (!baseKey) continue
|
|
110
|
+
if (!baseKey || byKey.get(baseKey)?.row) continue // el base va en fila declarada
|
|
100
111
|
alignOf.set(baseKey, field)
|
|
101
112
|
consumed.add(field.key)
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
const imageSettingsOf = new Map<string, FieldSchema[]>()
|
|
105
116
|
for (const field of props.fields) {
|
|
106
|
-
if (field.key !== 'image' || field.type !== 'image') continue
|
|
117
|
+
if (field.key !== 'image' || field.type !== 'image' || field.row) continue
|
|
107
118
|
const settings = IMAGE_SETTING_KEYS.map((key) => byKey.get(key)).filter(
|
|
108
|
-
(f): f is FieldSchema => !!f,
|
|
119
|
+
(f): f is FieldSchema => !!f && !f.row,
|
|
109
120
|
)
|
|
110
121
|
if (!settings.length) continue
|
|
111
122
|
imageSettingsOf.set(field.key, settings)
|
|
112
123
|
settings.forEach((f) => consumed.add(f.key))
|
|
113
124
|
}
|
|
114
125
|
|
|
126
|
+
// Filas declaradas: agrupa por nombre de fila los campos aún libres (sin
|
|
127
|
+
// pareja de align/imagen). El grupo se pinta donde va su PRIMER campo.
|
|
128
|
+
const rowGroups = new Map<string, FieldSchema[]>()
|
|
129
|
+
for (const field of props.fields) {
|
|
130
|
+
if (!field.row) continue
|
|
131
|
+
const group = rowGroups.get(field.row) ?? []
|
|
132
|
+
group.push(field)
|
|
133
|
+
rowGroups.set(field.row, group)
|
|
134
|
+
}
|
|
135
|
+
const rowFieldsOf = new Map<string, FieldSchema[]>()
|
|
136
|
+
for (const group of rowGroups.values()) {
|
|
137
|
+
if (group.length < 2) continue // solo, se pinta como siempre
|
|
138
|
+
rowFieldsOf.set(
|
|
139
|
+
group[0].key,
|
|
140
|
+
group.map((f) => ({ ...f, row: null })),
|
|
141
|
+
)
|
|
142
|
+
group.slice(1).forEach((f) => consumed.add(f.key))
|
|
143
|
+
}
|
|
144
|
+
|
|
115
145
|
return props.fields
|
|
116
146
|
.filter((f) => !consumed.has(f.key))
|
|
117
147
|
.map((f) => ({
|
|
118
148
|
field: f,
|
|
119
149
|
align: alignOf.get(f.key),
|
|
120
150
|
imageSettings: imageSettingsOf.get(f.key),
|
|
151
|
+
rowFields: rowFieldsOf.get(f.key),
|
|
121
152
|
}))
|
|
122
153
|
})
|
|
123
154
|
|
|
@@ -211,8 +242,23 @@ function addLabel(): string {
|
|
|
211
242
|
|
|
212
243
|
<template>
|
|
213
244
|
<div class="schema-fields">
|
|
214
|
-
<template v-for="{ field, align, imageSettings } in layout" :key="field.key">
|
|
245
|
+
<template v-for="{ field, align, imageSettings, rowFields } in layout" :key="field.key">
|
|
246
|
+
<!-- Fila declarada (Field::row): los campos del grupo por recursión,
|
|
247
|
+
en columnas iguales (los compañeros bajan sin `row`) -->
|
|
248
|
+
<div v-if="rowFields" class="schema-fields__field schema-fields__field--pair">
|
|
249
|
+
<SchemaFields
|
|
250
|
+
:fields="rowFields"
|
|
251
|
+
:model-value="modelValue"
|
|
252
|
+
:locales="locales"
|
|
253
|
+
:api="api"
|
|
254
|
+
:icons="icons"
|
|
255
|
+
:rich-labels="richLabels"
|
|
256
|
+
:translate="translate"
|
|
257
|
+
@update:model-value="(v) => emit('update:modelValue', v)"
|
|
258
|
+
/>
|
|
259
|
+
</div>
|
|
215
260
|
<div
|
|
261
|
+
v-else
|
|
216
262
|
class="schema-fields__field"
|
|
217
263
|
:class="{
|
|
218
264
|
'schema-fields__field--row': !!align,
|