@edc-motor/ui 0.5.0 → 0.5.1
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/ui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
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",
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
@use "../tokens" as *;
|
|
2
2
|
|
|
3
|
-
// Paginación compacta de listados (BasePagination.vue)
|
|
3
|
+
// Paginación compacta de listados (BasePagination.vue): anterior /
|
|
4
|
+
// números de página (con elisión «…») / siguiente.
|
|
4
5
|
.base-pagination {
|
|
5
6
|
display: flex;
|
|
6
7
|
align-items: center;
|
|
7
8
|
justify-content: center;
|
|
8
9
|
gap: $space-2;
|
|
9
10
|
|
|
11
|
+
// Anterior/siguiente: fondo SEMIOPACO + borde; el chevron (lucide,
|
|
12
|
+
// stroke: currentColor) hereda el color del TEXTO del botón — nunca el
|
|
13
|
+
// acento.
|
|
10
14
|
&__button {
|
|
11
15
|
display: inline-flex;
|
|
12
16
|
align-items: center;
|
|
@@ -15,15 +19,15 @@
|
|
|
15
19
|
// de los controles de formulario.
|
|
16
20
|
width: 32px;
|
|
17
21
|
height: 32px;
|
|
18
|
-
background:
|
|
22
|
+
background: color-mix(in srgb, $surface 65%, transparent);
|
|
19
23
|
border: 1px solid $border;
|
|
20
24
|
border-radius: $radius-sm;
|
|
21
25
|
color: $text-2;
|
|
22
26
|
transition: color 0.15s ease, border-color 0.15s ease;
|
|
23
27
|
|
|
24
28
|
&:not(:disabled):hover {
|
|
25
|
-
color: $
|
|
26
|
-
border-color: $
|
|
29
|
+
color: $text-1;
|
|
30
|
+
border-color: $border-strong;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
&:disabled {
|
|
@@ -32,10 +36,40 @@
|
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
// Números de página clicables; el actual, marcado con aria-current.
|
|
40
|
+
&__number {
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
min-width: 32px;
|
|
45
|
+
height: 32px;
|
|
46
|
+
padding: 0 $space-1;
|
|
47
|
+
background: none;
|
|
48
|
+
border: 1px solid transparent;
|
|
49
|
+
border-radius: $radius-sm;
|
|
37
50
|
color: $text-2;
|
|
38
|
-
|
|
51
|
+
font-size: $fs-13;
|
|
52
|
+
font-variant-numeric: tabular-nums;
|
|
53
|
+
transition: color 0.15s ease, border-color 0.15s ease;
|
|
54
|
+
|
|
55
|
+
&:hover {
|
|
56
|
+
color: $text-1;
|
|
57
|
+
border-color: $border;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&[aria-current="page"] {
|
|
61
|
+
background: $accent-500;
|
|
62
|
+
border-color: $accent-500;
|
|
63
|
+
@include contrast-text($accent-500);
|
|
64
|
+
cursor: default;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&__ellipsis {
|
|
69
|
+
min-width: 20px;
|
|
39
70
|
text-align: center;
|
|
71
|
+
color: $text-3;
|
|
72
|
+
font-size: $fs-13;
|
|
73
|
+
user-select: none;
|
|
40
74
|
}
|
|
41
75
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@use "tokens" as *;
|
|
2
2
|
|
|
3
3
|
// Rejilla de previews del catálogo público (PreviewGrid.vue). Mobile-first:
|
|
4
|
-
//
|
|
4
|
+
// 1 columna → 2 → 3 → 4 (patrón CDL). Media queries y no container queries:
|
|
5
5
|
// también se monta fuera de las páginas del CRM (índices, singles).
|
|
6
6
|
.preview-grid {
|
|
7
7
|
display: grid;
|
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
&__grid {
|
|
11
11
|
display: grid;
|
|
12
|
-
grid-template-columns:
|
|
12
|
+
grid-template-columns: minmax(0, 1fr);
|
|
13
13
|
gap: $space-4;
|
|
14
14
|
|
|
15
|
+
@media (min-width: $bp-sm) {
|
|
16
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
@media (min-width: $bp-md) {
|
|
16
20
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
17
21
|
}
|
|
@@ -33,7 +37,8 @@
|
|
|
33
37
|
min-width: 0;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
// Tarjeta (enlace o div):
|
|
40
|
+
// Tarjeta (enlace o div): al pasar, SOLO una sombra muy sutil (sin
|
|
41
|
+
// desplazarse). El foco por teclado conserva su halo de acento.
|
|
37
42
|
&__item {
|
|
38
43
|
display: block;
|
|
39
44
|
width: 100%;
|
|
@@ -41,12 +46,14 @@
|
|
|
41
46
|
text-decoration: none;
|
|
42
47
|
border-radius: $radius-md;
|
|
43
48
|
overflow: hidden;
|
|
44
|
-
transition: box-shadow 0.2s ease
|
|
49
|
+
transition: box-shadow 0.2s ease;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
a.preview-grid__item:hover {
|
|
53
|
+
box-shadow: $shadow-sm;
|
|
45
54
|
}
|
|
46
55
|
|
|
47
|
-
a.preview-grid__item:hover,
|
|
48
56
|
a.preview-grid__item:focus-visible {
|
|
49
|
-
transform: translateY(-2px);
|
|
50
57
|
box-shadow: 0 0 0 2px color-mix(in srgb, $accent-500 55%, transparent), $shadow-md;
|
|
51
58
|
outline: none;
|
|
52
59
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
2
3
|
import { ChevronLeft, ChevronRight } from '@lucide/vue'
|
|
3
4
|
|
|
4
|
-
// Paginación compacta para listados (admin y web): anterior /
|
|
5
|
-
// siguiente. Con una sola página no pinta nada.
|
|
6
|
-
// textos por prop, defaults en castellano
|
|
5
|
+
// Paginación compacta para listados (admin y web): anterior / números de
|
|
6
|
+
// página clicables / siguiente. Con una sola página no pinta nada.
|
|
7
|
+
// Agnóstica de i18n (DC-29): textos por prop, defaults en castellano (los
|
|
8
|
+
// números no necesitan traducción).
|
|
7
9
|
const props = withDefaults(
|
|
8
10
|
defineProps<{
|
|
9
11
|
page: number
|
|
@@ -18,6 +20,24 @@ const props = withDefaults(
|
|
|
18
20
|
|
|
19
21
|
const emit = defineEmits<{ 'update:page': [page: number] }>()
|
|
20
22
|
|
|
23
|
+
// Números visibles entre anterior/siguiente: patrón clásico de elisión —
|
|
24
|
+
// primera + vecinas de la actual + última, con «…» en los tramos omitidos
|
|
25
|
+
// (1 … 4 5 6 … 20). Hasta 7 páginas caben todas (elidir no ahorraría
|
|
26
|
+
// hueco).
|
|
27
|
+
const items = computed<(number | '…')[]>(() => {
|
|
28
|
+
const { page, pages } = props
|
|
29
|
+
if (pages <= 7) return Array.from({ length: pages }, (_, i) => i + 1)
|
|
30
|
+
const start = Math.max(2, page - 1)
|
|
31
|
+
const end = Math.min(pages - 1, page + 1)
|
|
32
|
+
return [
|
|
33
|
+
1,
|
|
34
|
+
...(start > 2 ? ['…' as const] : []),
|
|
35
|
+
...Array.from({ length: end - start + 1 }, (_, i) => start + i),
|
|
36
|
+
...(end < pages - 1 ? ['…' as const] : []),
|
|
37
|
+
pages,
|
|
38
|
+
]
|
|
39
|
+
})
|
|
40
|
+
|
|
21
41
|
function go(page: number) {
|
|
22
42
|
if (page < 1 || page > props.pages || page === props.page) return
|
|
23
43
|
emit('update:page', page)
|
|
@@ -40,7 +60,18 @@ function status(): string {
|
|
|
40
60
|
>
|
|
41
61
|
<ChevronLeft :size="16" />
|
|
42
62
|
</button>
|
|
43
|
-
<
|
|
63
|
+
<template v-for="(item, index) in items" :key="`${item}-${index}`">
|
|
64
|
+
<span v-if="item === '…'" class="base-pagination__ellipsis" aria-hidden="true">…</span>
|
|
65
|
+
<button
|
|
66
|
+
v-else
|
|
67
|
+
type="button"
|
|
68
|
+
class="base-pagination__number"
|
|
69
|
+
:aria-current="item === page ? 'page' : undefined"
|
|
70
|
+
@click="go(item)"
|
|
71
|
+
>
|
|
72
|
+
{{ item }}
|
|
73
|
+
</button>
|
|
74
|
+
</template>
|
|
44
75
|
<button
|
|
45
76
|
type="button"
|
|
46
77
|
class="base-pagination__button"
|