@edc-motor/admin-kit 0.2.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.
@@ -0,0 +1,329 @@
1
+ @use "tokens" as *;
2
+
3
+ // Piezas compartidas por los gestores del admin (previews y PDF).
4
+ // Mobile-first: todo funciona en una columna estrecha; la rejilla pasa a dos
5
+ // columnas según el ancho del contenedor `content` (el área de contenido del
6
+ // AdminLayout), no del viewport.
7
+
8
+ .manager-container {
9
+ display: grid;
10
+ gap: $space-5;
11
+ // Deja aire bajo las migas y esquiva el asa del panel derecho.
12
+ margin-top: $space-4;
13
+ }
14
+
15
+ .manager-bar {
16
+ display: flex;
17
+ justify-content: flex-end;
18
+ gap: $space-2;
19
+ flex-wrap: wrap;
20
+ }
21
+
22
+ .manager-grid {
23
+ display: grid;
24
+ grid-template-columns: minmax(0, 1fr);
25
+ gap: $space-4;
26
+ align-items: start;
27
+
28
+ @container content (min-width: #{$bp-md}) {
29
+ grid-template-columns: repeat(2, minmax(0, 1fr));
30
+ }
31
+ }
32
+
33
+ .manager-card {
34
+ background: $surface;
35
+ border: 1px solid $border;
36
+ border-radius: $radius-lg;
37
+ box-shadow: $shadow-sm;
38
+ overflow: hidden;
39
+ min-width: 0;
40
+ cursor: pointer; // TODA la tarjeta selecciona (menos sus controles)
41
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
42
+ // La tarjeta es su propio contenedor `content`: los botones con icono se
43
+ // apilan según el ancho de la TARJETA, no de la página (patrón kontuan).
44
+ container-name: content;
45
+ container-type: inline-size;
46
+
47
+ &:hover {
48
+ border-color: $border-strong;
49
+ box-shadow: $shadow-md;
50
+
51
+ .manager-card__hint { color: $accent-500; }
52
+ }
53
+
54
+ &:focus-visible {
55
+ outline: 2px solid $accent-500;
56
+ outline-offset: 2px;
57
+ }
58
+
59
+ &.is-active {
60
+ border-color: $accent-500;
61
+ }
62
+
63
+ &__head {
64
+ display: flex;
65
+ align-items: center;
66
+ gap: $space-2;
67
+ color: $text-1;
68
+ padding: $space-3 $space-4;
69
+ min-width: 0;
70
+ }
71
+
72
+ &__title {
73
+ font-size: $fs-16;
74
+ font-weight: $k-fw-semibold;
75
+ min-width: 0;
76
+ }
77
+
78
+ // El aspecto lo pone el .chip unificado (@edc-motor/ui); aquí solo la posición.
79
+ &__chip {
80
+ margin-left: auto;
81
+ flex: 0 0 auto;
82
+ }
83
+
84
+ &__hint {
85
+ flex: 0 0 auto;
86
+ color: $text-3;
87
+
88
+ // Sin chip, el icono se va al borde derecho.
89
+ &:first-of-type { margin-left: auto; }
90
+ .manager-card__chip + & { margin-left: 0; }
91
+ }
92
+
93
+ &__meta {
94
+ display: flex;
95
+ flex-wrap: wrap;
96
+ align-items: center;
97
+ gap: $space-1 $space-3;
98
+ padding: 0 $space-4 $space-3;
99
+ }
100
+
101
+ &__body {
102
+ border-top: 1px solid $border;
103
+ background: $surface-2;
104
+ padding: $space-3 $space-4;
105
+ display: grid;
106
+ gap: $space-3;
107
+ }
108
+
109
+ &__actions {
110
+ display: flex;
111
+ flex-wrap: wrap;
112
+ align-items: center;
113
+ justify-content: flex-end;
114
+ gap: $space-2;
115
+ border-top: 1px solid $border;
116
+ padding: $space-3 $space-4;
117
+ }
118
+ }
119
+
120
+ .manager-stat {
121
+ font-size: $fs-13;
122
+ color: $text-2;
123
+
124
+ strong { color: $text-1; }
125
+ &.is-ok strong { color: $success; }
126
+ &.is-warn strong { color: $warning; }
127
+ }
128
+
129
+ // ---------------------------------------------------------------------------
130
+ // Contenido del panel derecho de los gestores: selector con buscador +
131
+ // detalle del elemento elegido.
132
+ // ---------------------------------------------------------------------------
133
+
134
+ .manager-panel {
135
+ display: grid;
136
+ gap: $space-3;
137
+
138
+ &__empty {
139
+ color: $text-3;
140
+ font-size: $fs-13;
141
+ margin: 0;
142
+ }
143
+
144
+ &__kicker {
145
+ color: $text-3;
146
+ font-size: $fs-12;
147
+ text-transform: uppercase;
148
+ letter-spacing: 0.04em;
149
+ margin: 0;
150
+ }
151
+
152
+ // Separador entre bloques del panel (acciones | sección | sección…):
153
+ // TODOS los paneles derechos siguen el mismo orden.
154
+ &__divider {
155
+ border: none;
156
+ border-top: 1px solid $border;
157
+ margin: $space-1 0;
158
+ width: 100%;
159
+ }
160
+ }
161
+
162
+ .manager-detail {
163
+ display: grid;
164
+ gap: $space-3;
165
+ border-top: 1px dashed $border;
166
+ padding-top: $space-3;
167
+
168
+ &__title {
169
+ margin: 0;
170
+ font-size: $fs-16;
171
+ overflow-wrap: anywhere;
172
+ }
173
+
174
+ &__row {
175
+ display: flex;
176
+ flex-wrap: wrap;
177
+ align-items: center;
178
+ gap: $space-1;
179
+ }
180
+
181
+ &__meta {
182
+ color: $text-2;
183
+ font-size: $fs-13;
184
+ margin: 0;
185
+ }
186
+
187
+ &__error {
188
+ color: $danger;
189
+ font-size: $fs-13;
190
+ margin: 0;
191
+ overflow-wrap: anywhere;
192
+ }
193
+
194
+ &__figures {
195
+ display: grid;
196
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
197
+ gap: $space-2;
198
+ }
199
+
200
+ &__figure {
201
+ margin: 0;
202
+ display: grid;
203
+ gap: $space-1;
204
+ justify-items: center;
205
+
206
+ img,
207
+ .manager-detail__hole {
208
+ width: 100%;
209
+ border-radius: $radius-sm;
210
+ border: 1px solid $border;
211
+ background: $surface-2;
212
+ }
213
+
214
+ figcaption {
215
+ color: $text-3;
216
+ font-size: $fs-12;
217
+ }
218
+
219
+ &.is-missing figcaption { color: $warning; }
220
+ }
221
+
222
+ &__hole {
223
+ display: flex;
224
+ align-items: center;
225
+ justify-content: center;
226
+ min-height: 72px;
227
+ color: $text-3;
228
+ }
229
+
230
+ &__actions {
231
+ display: flex;
232
+ flex-wrap: wrap;
233
+ gap: $space-2;
234
+
235
+ // Botones de acción del panel: TODOS con su color, en CONTORNO — borde
236
+ // y texto/stroke del color de la acción; en hover el color pasa al
237
+ // fondo y el texto al color de texto normal.
238
+ @each $variant, $color in (
239
+ primary: $accent-500,
240
+ info: $info,
241
+ warning: $warning,
242
+ success: $success,
243
+ danger: $danger,
244
+ ) {
245
+ .edc-button--#{$variant} {
246
+ background: transparent;
247
+ border-color: $color;
248
+ color: $color;
249
+
250
+ &:hover:not(:disabled) {
251
+ background: $color;
252
+ border-color: $color;
253
+ color: $text-1;
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ // Listado compacto del panel (p.ej. bloques de la página seleccionada):
260
+ // cada fila es UNA línea, con el resto truncado.
261
+ &__rows {
262
+ list-style: none;
263
+ margin: 0;
264
+ padding: 0;
265
+ display: grid;
266
+ gap: $space-2;
267
+ }
268
+
269
+ &__row-line {
270
+ display: flex;
271
+ align-items: baseline;
272
+ gap: $space-2;
273
+ min-width: 0;
274
+ font-size: $fs-13;
275
+
276
+ strong {
277
+ flex: 0 0 auto;
278
+ color: $text-1;
279
+ }
280
+ }
281
+
282
+ &__row-text {
283
+ color: $text-3;
284
+ min-width: 0;
285
+ overflow: hidden;
286
+ text-overflow: ellipsis;
287
+ white-space: nowrap;
288
+ }
289
+
290
+ // Campos del bloque seleccionado: etiqueta + valor; los valores largos se
291
+ // recortan a unas pocas líneas.
292
+ &__field {
293
+ display: grid;
294
+ gap: 2px;
295
+ min-width: 0;
296
+ font-size: $fs-13;
297
+
298
+ dt {
299
+ color: $text-3;
300
+ font-size: $fs-12;
301
+ text-transform: uppercase;
302
+ letter-spacing: 0.04em;
303
+ }
304
+
305
+ dd {
306
+ margin: 0;
307
+ color: $text-2;
308
+ overflow-wrap: anywhere;
309
+ display: -webkit-box;
310
+ -webkit-box-orient: vertical;
311
+ -webkit-line-clamp: 4;
312
+ line-clamp: 4;
313
+ overflow: hidden;
314
+ }
315
+ }
316
+
317
+ &__fields {
318
+ margin: 0;
319
+ display: grid;
320
+ gap: $space-2;
321
+ }
322
+
323
+ &__thumb {
324
+ max-width: 120px;
325
+ border-radius: $radius-sm;
326
+ border: 1px solid $border;
327
+ background: $surface-2;
328
+ }
329
+ }
@@ -0,0 +1,179 @@
1
+ @use "tokens" as *;
2
+
3
+ // Gestor de bloques de una página (PageBlocks) + renderer del DSL de campos.
4
+ .page-blocks {
5
+ display: grid;
6
+ gap: $space-3;
7
+
8
+ &__bar {
9
+ display: flex;
10
+ justify-content: flex-end;
11
+ }
12
+
13
+ &__palette { position: relative; }
14
+
15
+ &__menu {
16
+ position: absolute;
17
+ top: calc(100% + #{$space-1});
18
+ right: 0;
19
+ z-index: 40;
20
+ min-width: 220px;
21
+ background: $surface;
22
+ border: 1px solid $border-strong;
23
+ border-radius: $radius-md;
24
+ box-shadow: $shadow-md;
25
+ padding: $space-1;
26
+ display: grid;
27
+ gap: 1px;
28
+ }
29
+
30
+ &__menu-item {
31
+ background: none;
32
+ border: 0;
33
+ border-radius: $radius-sm;
34
+ color: $text-1;
35
+ cursor: pointer;
36
+ padding: $space-2 $space-3;
37
+ text-align: left;
38
+ font-size: $fs-13;
39
+
40
+ &:hover { background: $surface-2; }
41
+ // Los bloques con-datos del juego, marcados.
42
+ &.is-data { color: $accent-500; }
43
+ }
44
+
45
+ &__empty { color: $text-3; margin: 0; }
46
+
47
+ &__list {
48
+ display: grid;
49
+ gap: $space-2;
50
+ }
51
+
52
+ // Fila de bloque: SIN wrap por elemento — en estrecho TODAS las filas
53
+ // cambian a la vez a un layout apilado (grid-areas por container query).
54
+ &__item {
55
+ display: grid;
56
+ grid-template-columns: auto minmax(0, 1fr) auto;
57
+ grid-template-areas:
58
+ "grip type buttons"
59
+ "grip summary summary"
60
+ "grip flags flags";
61
+ align-items: center;
62
+ gap: $space-1 $space-2;
63
+ border: 1px solid $border;
64
+ border-radius: $radius-md;
65
+ background: $surface;
66
+ padding: $space-2 $space-3;
67
+ min-width: 0;
68
+ cursor: pointer; // toda la fila selecciona (panel derecho)
69
+ transition: border-color 0.15s ease;
70
+
71
+ @container content (min-width: 640px) {
72
+ grid-template-columns: auto auto minmax(0, 1fr) auto auto;
73
+ grid-template-areas: "grip type summary flags buttons";
74
+ }
75
+
76
+ &:hover { border-color: $border-strong; }
77
+ &.is-active { border-color: $accent-500; }
78
+ }
79
+
80
+ &__grip {
81
+ grid-area: grip;
82
+ display: inline-flex;
83
+ color: $text-3;
84
+ cursor: grab;
85
+
86
+ &:active { cursor: grabbing; }
87
+ }
88
+
89
+ &__type { grid-area: type; font-weight: $k-fw-semibold; white-space: nowrap; }
90
+
91
+ &__summary {
92
+ grid-area: summary;
93
+ min-width: 0;
94
+ color: $text-3;
95
+ font-size: $fs-13;
96
+ overflow: hidden;
97
+ text-overflow: ellipsis;
98
+ white-space: nowrap;
99
+ }
100
+
101
+ &__flags { grid-area: flags; display: flex; gap: $space-1; }
102
+
103
+ &__buttons {
104
+ grid-area: buttons;
105
+ margin-left: auto;
106
+ display: flex;
107
+ gap: $space-1;
108
+ }
109
+
110
+ &__common {
111
+ border-top: 1px dashed $border;
112
+ padding-top: $space-3;
113
+
114
+ summary {
115
+ cursor: pointer;
116
+ color: $text-2;
117
+ font-size: $fs-13;
118
+ margin-bottom: $space-3;
119
+ }
120
+
121
+ display: grid;
122
+ gap: $space-3;
123
+ }
124
+ }
125
+
126
+ .schema-fields {
127
+ display: grid;
128
+ gap: $space-4;
129
+
130
+ &__color,
131
+ &__image {
132
+ display: grid;
133
+ gap: $space-1;
134
+ }
135
+
136
+ // Anidados del DSL: group (fieldset) y repeater (filas numeradas con
137
+ // añadir/quitar/reordenar).
138
+ &__group,
139
+ &__row {
140
+ margin: 0;
141
+ border: 1px dashed $border;
142
+ border-radius: $radius-md;
143
+ padding: $space-3;
144
+ display: grid;
145
+ gap: $space-3;
146
+ min-width: 0;
147
+
148
+ legend {
149
+ padding: 0 $space-1;
150
+ }
151
+ }
152
+
153
+ &__repeater {
154
+ display: grid;
155
+ gap: $space-2;
156
+ justify-items: start;
157
+
158
+ > .form-field__label { justify-self: stretch; }
159
+ }
160
+
161
+ &__row { width: 100%; }
162
+
163
+ &__row-bar {
164
+ display: flex;
165
+ align-items: center;
166
+ gap: $space-1;
167
+ justify-content: flex-end;
168
+ }
169
+
170
+ &__row-index {
171
+ margin-right: auto;
172
+ color: $text-3;
173
+ font-size: $fs-12;
174
+ font-weight: 600;
175
+ }
176
+ }
177
+
178
+ // Item fantasma del drag (vue-draggable-plus / SortableJS).
179
+ .sortable-ghost { opacity: 0.4; }
@@ -0,0 +1,46 @@
1
+ @use "tokens" as *;
2
+
3
+ // Gestor de PDF (PdfManager), sobre .manager-card / .manager-grid y el panel
4
+ // derecho (ver _manager-card.scss). Cada PDF del panel es una entrada
5
+ // compacta: idioma + estado + acciones, con fecha o error debajo.
6
+
7
+ .pdf-entry {
8
+ border: 1px solid $border;
9
+ border-radius: $radius-md;
10
+ background: $surface;
11
+ padding: $space-2 $space-3;
12
+ display: grid;
13
+ gap: $space-1;
14
+
15
+ &__head {
16
+ display: flex;
17
+ flex-wrap: wrap;
18
+ align-items: center;
19
+ gap: $space-1 $space-2;
20
+ }
21
+
22
+ &__locale {
23
+ font-weight: $k-fw-bold;
24
+ min-width: 2.5em;
25
+ }
26
+
27
+ &__buttons {
28
+ margin-left: auto;
29
+ display: flex;
30
+ gap: $space-1;
31
+ align-items: center;
32
+ }
33
+
34
+ &__meta {
35
+ color: $text-3;
36
+ font-size: $fs-12;
37
+ margin: 0;
38
+ }
39
+
40
+ &__error {
41
+ color: $danger;
42
+ font-size: $fs-12;
43
+ margin: 0;
44
+ overflow-wrap: anywhere;
45
+ }
46
+ }
@@ -0,0 +1,5 @@
1
+ @use "tokens" as *;
2
+
3
+ // Gestor de previews PNG (PreviewManager): tarjetas fijas con estadísticas
4
+ // (ver _manager-card.scss) y selector + detalle en el panel derecho. Aquí no
5
+ // queda nada específico: todo vive en las piezas compartidas (.manager-*).
@@ -0,0 +1,152 @@
1
+ @use "tokens" as *;
2
+
3
+ // Panel lateral derecho contextual (portado de kontuan): lo registra cada
4
+ // vista con useRightSidebar() y lo pinta <RightSidebar />, montado una vez
5
+ // por AdminLayout. El comportamiento móvil usa la clase `is-mobile` que el
6
+ // layout pone en su raíz.
7
+
8
+ // En estrecho, con el drawer IZQUIERDO abierto, la barra derecha (panel,
9
+ // asa y overlay) se esconde: nunca conviven los dos laterales superpuestos.
10
+ .app-layout.left-drawer-open {
11
+ .right-sidebar,
12
+ .right-sidebar-handle,
13
+ .right-sidebar-overlay {
14
+ display: none;
15
+ }
16
+ }
17
+
18
+ .right-sidebar {
19
+ width: 320px;
20
+ flex-shrink: 0;
21
+ background: $surface;
22
+ border-left: 1px solid $border;
23
+ display: flex;
24
+ flex-direction: column;
25
+ overflow: hidden;
26
+ transition: width 0.2s ease, transform 0.25s ease;
27
+
28
+ &--collapsed {
29
+ width: 0;
30
+ border-left: 0;
31
+ }
32
+ }
33
+
34
+ .right-sidebar__header {
35
+ display: flex;
36
+ align-items: center;
37
+ padding: 0;
38
+ height: 48px;
39
+ width: 100%;
40
+ border-bottom: 1px solid $border;
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ .right-sidebar__toggle {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ align-self: stretch;
49
+ width: 48px;
50
+ padding: 0;
51
+ background: transparent;
52
+ border: none;
53
+ border-right: 1px solid $border;
54
+ color: $accent-500;
55
+ cursor: pointer;
56
+ flex-shrink: 0;
57
+ transition: background-color 0.15s ease;
58
+
59
+ &:hover {
60
+ background: $surface-2;
61
+ color: $accent-600;
62
+ }
63
+ }
64
+
65
+ .right-sidebar__title {
66
+ flex: 1;
67
+ font-size: $fs-14;
68
+ font-weight: $k-fw-semibold;
69
+ color: $text-1;
70
+ margin: 0;
71
+ padding: 0 $space-3;
72
+ overflow: hidden;
73
+ text-overflow: ellipsis;
74
+ white-space: nowrap;
75
+ }
76
+
77
+ .right-sidebar__body {
78
+ flex: 1;
79
+ overflow-y: auto;
80
+ padding: $space-3;
81
+ // Contenedor `content`: los botones con icono pasan a modo vertical
82
+ // (mini-etiqueta bajo el icono) en el ancho del panel.
83
+ container-type: inline-size;
84
+ container-name: content;
85
+ }
86
+
87
+ .right-sidebar-handle {
88
+ position: fixed;
89
+ top: 64px;
90
+ right: 0;
91
+ z-index: 95;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ width: 28px;
96
+ height: 48px;
97
+ padding: 0;
98
+ background: $surface;
99
+ border: 1px solid $accent-500;
100
+ border-right: none;
101
+ border-radius: $radius-md 0 0 $radius-md;
102
+ color: $accent-500;
103
+ cursor: pointer;
104
+ transition: background-color 0.15s ease, color 0.15s ease;
105
+
106
+ &:hover {
107
+ background: $surface-2;
108
+ color: $accent-600;
109
+ }
110
+
111
+ &--flash {
112
+ animation: right-sidebar-handle-flash 1.1s ease-in-out;
113
+ }
114
+ }
115
+
116
+ @keyframes right-sidebar-handle-flash {
117
+ 0%, 50%, 100% {
118
+ background: $surface;
119
+ color: $accent-500;
120
+ }
121
+ 25%, 75% {
122
+ background: $accent-500;
123
+ color: white;
124
+ }
125
+ }
126
+
127
+ .right-sidebar-overlay {
128
+ position: fixed;
129
+ top: 56px;
130
+ left: 0;
131
+ right: 0;
132
+ bottom: 0;
133
+ background: rgb(0 0 0 / 40%);
134
+ z-index: 90;
135
+ }
136
+
137
+ // Modo drawer (por debajo del umbral del componente): superpuesto al
138
+ // contenido para que el main nunca quede más estrecho que las barras.
139
+ .right-sidebar--drawer {
140
+ position: fixed;
141
+ top: 56px;
142
+ right: 0;
143
+ bottom: 0;
144
+ height: auto;
145
+ z-index: 100;
146
+ width: min(320px, 100vw);
147
+ transform: translateX(100%);
148
+
149
+ &.right-sidebar--drawer-open {
150
+ transform: translateX(0);
151
+ }
152
+ }