@axzydev/axzy_ui_system 1.4.7 → 1.5.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/README.md +2 -11
- package/dist/index.cjs +2174 -1570
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +232 -19
- package/dist/index.d.ts +232 -19
- package/dist/index.js +1838 -1238
- package/dist/index.js.map +1 -1
- package/dist/layered.css +1 -1
- package/package.json +3 -16
- package/src/App.tsx +90 -73
- package/src/components/atoms/badget/badget.tsx +23 -5
- package/src/components/atoms/chip/chip.tsx +3 -1
- package/src/components/atoms/image/image.tsx +3 -1
- package/src/components/atoms/input/input.tsx +8 -5
- package/src/components/atoms/loader/loader.tsx +3 -1
- package/src/components/atoms/slide/slide.props.ts +12 -0
- package/src/components/atoms/slide/slide.tsx +3 -0
- package/src/components/molecules/alert/alert.tsx +3 -1
- package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
- package/src/components/molecules/calendar/calendar.tsx +9 -6
- package/src/components/molecules/card/card.tsx +5 -2
- package/src/components/molecules/chip-input/chip-input.tsx +9 -7
- package/src/components/molecules/date-picker/datePicker.tsx +9 -9
- package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
- package/src/components/molecules/field/field.tsx +3 -1
- package/src/components/molecules/form-header/form-header.tsx +3 -1
- package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
- package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
- package/src/components/molecules/masked-input/masked-input.tsx +3 -1
- package/src/components/molecules/multi-select/multi-select.tsx +12 -9
- package/src/components/molecules/pagination/pagination.tsx +11 -5
- package/src/components/molecules/search-select/search-select.tsx +11 -9
- package/src/components/molecules/select/select.tsx +6 -4
- package/src/components/molecules/stepper/stepper.tsx +6 -4
- package/src/components/molecules/table/table.props.ts +10 -2
- package/src/components/molecules/table/table.tsx +163 -114
- package/src/components/molecules/time-picker/timePicker.tsx +8 -6
- package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
- package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
- package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
- package/src/components/organisms/data-table/dataTable.props.ts +3 -2
- package/src/components/organisms/data-table/dataTable.tsx +149 -81
- package/src/components/organisms/dialog/dialog.tsx +3 -0
- package/src/components/organisms/drawer/drawer.tsx +3 -0
- package/src/components/organisms/dropfile/dropfile.tsx +19 -17
- package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
- package/src/components/organisms/navbar/navbar.tsx +4 -2
- package/src/components/organisms/page-header/page-header.tsx +3 -1
- package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
- package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
- package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
- package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
- package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
- package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
- package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
- package/src/components/organisms/searchTable/searchTable.tsx +4 -2
- package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
- package/src/components/organisms/sidebar/sidebar.tsx +9 -4
- package/src/components/organisms/toast/toast.tsx +3 -1
- package/src/components/organisms/topbar/topbar.tsx +4 -2
- package/src/components/templates/page/page.props.ts +4 -4
- package/src/components/templates/page/page.tsx +6 -4
- package/src/components/theme-provider/themeProvider.tsx +28 -17
- package/src/dev.css +77 -2
- package/src/global.d.ts +10 -0
- package/src/i18n/context.ts +9 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/locales/en.ts +163 -0
- package/src/i18n/locales/es.ts +165 -0
- package/src/i18n/provider.tsx +44 -0
- package/src/i18n/translator.ts +82 -0
- package/src/i18n/types.ts +54 -0
- package/src/i18n/useITTranslation.ts +20 -0
- package/src/index.css +0 -1
- package/src/index.ts +9 -3
- package/src/sandbox/LandingShowcase.tsx +224 -580
- package/src/sandbox/NotFoundShowcase.tsx +51 -36
- package/src/sandbox/TopbarSearch.tsx +6 -4
- package/src/sandbox/controls.tsx +180 -0
- package/src/sandbox/i18n.ts +1929 -0
- package/src/sandbox/icons.tsx +25 -0
- package/src/sandbox/locale.tsx +72 -0
- package/src/sandbox/ui.tsx +377 -0
- package/src/sandbox/useHashRoute.ts +46 -10
- package/src/showcases/DataShowcases.tsx +201 -80
- package/src/showcases/FeedbackShowcases.tsx +37 -30
- package/src/showcases/FormShowcases.tsx +302 -214
- package/src/showcases/GettingStartedShowcase.tsx +151 -145
- package/src/showcases/HelpShowcase.tsx +126 -128
- package/src/showcases/HomeShowcase.tsx +678 -482
- package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
- package/src/showcases/NavigationShowcases.tsx +45 -37
- package/src/showcases/PageShowcases.tsx +171 -152
- package/src/showcases/ProductoDetalle.tsx +272 -129
- package/src/showcases/ShowcaseLayout.tsx +270 -216
- package/src/showcases/SizesShowcase.tsx +123 -64
- package/src/showcases/StructureShowcases.tsx +157 -131
- package/src/showcases/portfolioUi.tsx +153 -0
- package/src/showcases/techIcons.ts +3 -0
- package/src/types/table.types.ts +110 -0
- package/src/utils/table.utils.ts +10 -2
- package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
- package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
- package/src/components/atoms/badget/badget.doc.mdx +0 -46
- package/src/components/atoms/badget/badget.stories.tsx +0 -75
- package/src/components/atoms/button/button.doc.mdx +0 -59
- package/src/components/atoms/button/button.stories.tsx +0 -173
- package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
- package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
- package/src/components/atoms/chip/chip.doc.mdx +0 -47
- package/src/components/atoms/chip/chip.stories.tsx +0 -64
- package/src/components/atoms/divider/divider.doc.mdx +0 -42
- package/src/components/atoms/divider/divider.stories.tsx +0 -33
- package/src/components/atoms/flex/flex.doc.mdx +0 -59
- package/src/components/atoms/flex/flex.stories.tsx +0 -70
- package/src/components/atoms/grid/grid.doc.mdx +0 -54
- package/src/components/atoms/grid/grid.stories.tsx +0 -71
- package/src/components/atoms/image/image.doc.mdx +0 -44
- package/src/components/atoms/image/image.stories.tsx +0 -48
- package/src/components/atoms/input/input.doc.mdx +0 -70
- package/src/components/atoms/input/input.stories.tsx +0 -113
- package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
- package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
- package/src/components/atoms/loader/loader.doc.mdx +0 -43
- package/src/components/atoms/loader/loader.stories.tsx +0 -104
- package/src/components/atoms/popover/popover.doc.mdx +0 -53
- package/src/components/atoms/popover/popover.stories.tsx +0 -24
- package/src/components/atoms/progress/progress.doc.mdx +0 -48
- package/src/components/atoms/progress/progress.stories.tsx +0 -39
- package/src/components/atoms/radio/radio.doc.mdx +0 -62
- package/src/components/atoms/radio/radio.stories.tsx +0 -48
- package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
- package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
- package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
- package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
- package/src/components/atoms/slide/slide.doc.mdx +0 -46
- package/src/components/atoms/slide/slide.stories.tsx +0 -120
- package/src/components/atoms/slider/slider.doc.mdx +0 -49
- package/src/components/atoms/slider/slider.stories.tsx +0 -29
- package/src/components/atoms/stack/stack.doc.mdx +0 -126
- package/src/components/atoms/stack/stack.stories.tsx +0 -283
- package/src/components/atoms/text/text.doc.mdx +0 -41
- package/src/components/atoms/text/text.stories.tsx +0 -66
- package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
- package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
- package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
- package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
- package/src/components/isolation/isolation.stories.tsx +0 -202
- package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
- package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
- package/src/components/molecules/alert/alert.doc.mdx +0 -48
- package/src/components/molecules/alert/alert.stories.tsx +0 -40
- package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
- package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
- package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
- package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
- package/src/components/molecules/card/card.doc.mdx +0 -54
- package/src/components/molecules/card/card.stories.tsx +0 -57
- package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
- package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
- package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
- package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
- package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
- package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
- package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
- package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
- package/src/components/molecules/field/field.doc.mdx +0 -43
- package/src/components/molecules/field/field.stories.tsx +0 -42
- package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
- package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
- package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
- package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
- package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
- package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
- package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
- package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
- package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
- package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
- package/src/components/molecules/select/select.doc.mdx +0 -75
- package/src/components/molecules/select/select.stories.tsx +0 -85
- package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
- package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
- package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
- package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
- package/src/components/molecules/table/table.doc.mdx +0 -123
- package/src/components/molecules/table/table.stories.tsx +0 -402
- package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
- package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
- package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
- package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
- package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
- package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
- package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
- package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -115
- package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
- package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
- package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
- package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
- package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
- package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
- package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
- package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
- package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
- package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
- package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
- package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
- package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
- package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
- package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
- package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
- package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
- package/src/components/organisms/toast/toast.doc.mdx +0 -50
- package/src/components/organisms/toast/toast.stories.tsx +0 -137
- package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
- package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
- package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
- package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
- package/src/components/templates/layout/layout.doc.mdx +0 -53
- package/src/components/templates/layout/layout.stories.tsx +0 -113
- package/src/components/templates/page/page.doc.mdx +0 -86
- package/src/components/templates/page/page.stories.tsx +0 -97
- package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
- package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
|
@@ -1,181 +1,324 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import { FaCheck, FaExternalLinkAlt } from "react-icons/fa";
|
|
3
|
-
import ITBadget from "../components/atoms/badget/badget";
|
|
4
|
-
import ITDivider from "../components/atoms/divider/divider";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { FaArrowLeft, FaArrowRight, FaCheck, FaExternalLinkAlt } from "react-icons/fa";
|
|
5
3
|
import ITFlex from "../components/atoms/flex/flex";
|
|
6
|
-
import ITGrid from "../components/atoms/grid/grid";
|
|
7
|
-
import ITStack from "../components/atoms/stack/stack";
|
|
8
4
|
import ITText from "../components/atoms/text/text";
|
|
9
|
-
import ITDialog from "../components/organisms/dialog/dialog";
|
|
10
5
|
import ProductoIcono from "./ProductoIcono";
|
|
11
|
-
import type
|
|
6
|
+
import { PRODUCTOS, type Producto } from "./productos";
|
|
7
|
+
import {
|
|
8
|
+
BotonAccion,
|
|
9
|
+
CHIP,
|
|
10
|
+
ControlesPortafolio,
|
|
11
|
+
EYEBROW,
|
|
12
|
+
EnlaceBoton,
|
|
13
|
+
Etiqueta,
|
|
14
|
+
SaltarContenido,
|
|
15
|
+
} from "./portfolioUi";
|
|
16
|
+
import { useITTranslation } from "@/i18n";
|
|
12
17
|
|
|
13
18
|
interface Props {
|
|
14
19
|
/** Producto que se muestra. */
|
|
15
20
|
producto: Producto;
|
|
16
|
-
/**
|
|
17
|
-
|
|
21
|
+
/** Vuelve al portafolio. */
|
|
22
|
+
onBack: () => void;
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
/** Ancho de la hoja: el mismo que el masthead del portafolio. */
|
|
26
|
+
const HOJA = "mx-auto w-full max-w-[1180px] px-5 sm:px-8 lg:px-10";
|
|
27
|
+
|
|
28
|
+
/** Filete de 1px entre bloques. */
|
|
29
|
+
const FILETE = "border-slate-200 dark:border-slate-800";
|
|
30
|
+
|
|
31
|
+
/** Productos que tienen pantalla de detalle (los que traen capturas). */
|
|
32
|
+
const CON_DETALLE = PRODUCTOS.filter((p) => (p.capturas?.length ?? 0) > 0);
|
|
33
|
+
|
|
20
34
|
/**
|
|
21
|
-
*
|
|
35
|
+
* Página de detalle de un producto del portafolio (`#proyecto/<id>`).
|
|
22
36
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
37
|
+
* Es una **página completa**, no un modal: cabecera propia con volver al
|
|
38
|
+
* portafolio, ficha del producto (qué resuelve y datos técnicos en filas con
|
|
39
|
+
* filete), galería de capturas reales con miniaturas y navegación entre
|
|
40
|
+
* proyectos. La URL es compartible y el botón atrás del navegador funciona.
|
|
26
41
|
*
|
|
27
42
|
* @example
|
|
28
43
|
* ```tsx
|
|
29
|
-
*
|
|
44
|
+
* <ProductoDetalle producto={producto} onBack={() => goToPortfolio()} />
|
|
30
45
|
* ```
|
|
31
46
|
*/
|
|
32
|
-
export default function ProductoDetalle({ producto,
|
|
47
|
+
export default function ProductoDetalle({ producto, onBack }: Props) {
|
|
48
|
+
const { t } = useITTranslation();
|
|
33
49
|
const capturas = producto.capturas ?? [];
|
|
34
50
|
const [activa, setActiva] = useState(capturas[0]);
|
|
35
51
|
const hayGaleria = capturas.length > 0;
|
|
52
|
+
const enlaceExterno = Boolean(producto.enlace && !producto.enlace.startsWith("#"));
|
|
53
|
+
|
|
54
|
+
// Navegación entre proyectos: solo entre los que tienen pantalla de detalle.
|
|
55
|
+
const indice = CON_DETALLE.findIndex((p) => p.id === producto.id);
|
|
56
|
+
const anterior = indice > 0 ? CON_DETALLE[indice - 1] : undefined;
|
|
57
|
+
const siguiente =
|
|
58
|
+
indice >= 0 && indice < CON_DETALLE.length - 1 ? CON_DETALLE[indice + 1] : undefined;
|
|
59
|
+
|
|
60
|
+
// Cada producto entra por arriba y con su primera captura activa.
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
window.scrollTo({ top: 0, behavior: "auto" });
|
|
63
|
+
setActiva(producto.capturas?.[0]);
|
|
64
|
+
}, [producto]);
|
|
36
65
|
|
|
37
66
|
return (
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
<>
|
|
68
|
+
<SaltarContenido />
|
|
69
|
+
|
|
70
|
+
{/* Cabecera: volver + producto + enlace */}
|
|
71
|
+
<header className="sticky top-0 z-[100] border-b border-slate-200 bg-white/85 backdrop-blur-md dark:border-slate-800 dark:bg-[#0b0d10]/85">
|
|
72
|
+
<div className={`${HOJA} flex h-14 items-center gap-3`}>
|
|
73
|
+
<BotonAccion onClick={onBack} icono={<FaArrowLeft size={11} />} className="!px-3 !py-1.5">
|
|
74
|
+
{t("showcase.producto.back")}
|
|
75
|
+
</BotonAccion>
|
|
76
|
+
<span aria-hidden className="text-slate-300 dark:text-slate-700">
|
|
77
|
+
/
|
|
78
|
+
</span>
|
|
79
|
+
<ITText
|
|
80
|
+
as="span"
|
|
81
|
+
className="truncate font-display !text-[13px] !font-bold -tracking-[0.01em] text-slate-900 dark:text-white"
|
|
82
|
+
>
|
|
83
|
+
{producto.nombre}
|
|
84
|
+
</ITText>
|
|
85
|
+
|
|
86
|
+
<div className="ml-auto flex items-center gap-2 sm:gap-3">
|
|
87
|
+
{producto.enlace && (
|
|
88
|
+
<a
|
|
89
|
+
href={producto.enlace}
|
|
90
|
+
{...(enlaceExterno ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
|
91
|
+
className="hidden shrink-0 items-center gap-1.5 font-mono !text-[11px] uppercase !tracking-[0.14em] !text-primary-700 dark:!text-primary-500 sm:inline-flex"
|
|
92
|
+
>
|
|
93
|
+
{enlaceExterno && <FaExternalLinkAlt size={10} />}
|
|
94
|
+
{producto.enlaceTexto ?? t("showcase.home.viewRepo")}
|
|
95
|
+
</a>
|
|
96
|
+
)}
|
|
97
|
+
<ControlesPortafolio />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</header>
|
|
101
|
+
|
|
102
|
+
<main id="contenido">
|
|
103
|
+
{/* ─── FICHA ─── */}
|
|
104
|
+
<div className={`${HOJA} pb-10 pt-10 sm:pt-14`}>
|
|
105
|
+
<ITFlex align="center" gap={3} wrap="wrap">
|
|
106
|
+
<span className="grid h-11 w-11 place-items-center rounded-[10px] border border-slate-200 bg-white text-primary-700 dark:border-slate-800 dark:bg-slate-900 dark:text-primary-500">
|
|
107
|
+
<ProductoIcono icono={producto.icono} size={20} />
|
|
108
|
+
</span>
|
|
109
|
+
<Etiqueta>{producto.tipo}</Etiqueta>
|
|
110
|
+
<ITText as="span" className={EYEBROW}>
|
|
111
|
+
{`${String(indice + 1).padStart(2, "0")} / ${String(CON_DETALLE.length).padStart(2, "0")}`}
|
|
112
|
+
</ITText>
|
|
113
|
+
</ITFlex>
|
|
114
|
+
|
|
115
|
+
<ITText
|
|
116
|
+
as="h1"
|
|
117
|
+
className="font-display !mt-6 !text-[34px] !font-bold !leading-[1.08] -tracking-[0.02em] text-slate-900 dark:text-white sm:!text-[46px]"
|
|
118
|
+
>
|
|
119
|
+
{producto.nombre}
|
|
120
|
+
</ITText>
|
|
121
|
+
|
|
122
|
+
<ITText
|
|
123
|
+
as="p"
|
|
124
|
+
className="!mt-5 max-w-[70ch] !text-[15.5px] !leading-[1.75] text-slate-600 dark:text-slate-300 sm:!text-[16.5px]"
|
|
125
|
+
>
|
|
126
|
+
{producto.detalle ?? producto.descripcion}
|
|
127
|
+
</ITText>
|
|
128
|
+
|
|
129
|
+
<ITFlex gap={1.5} wrap="wrap" className="!mt-6">
|
|
130
|
+
{producto.stack.map((tecnologia) => (
|
|
131
|
+
<span key={tecnologia} className={CHIP}>
|
|
132
|
+
{tecnologia}
|
|
133
|
+
</span>
|
|
134
|
+
))}
|
|
135
|
+
</ITFlex>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{/* ─── GALERÍA ─── */}
|
|
139
|
+
{hayGaleria && activa && (
|
|
140
|
+
<section aria-label={t("showcase.producto.gallery")}>
|
|
141
|
+
<div className={HOJA}>
|
|
142
|
+
<div className={`overflow-hidden rounded-[10px] border bg-slate-950 ${FILETE}`}>
|
|
143
|
+
<img src={activa.src} alt={`${producto.nombre}: ${activa.titulo}`} className="block w-full" />
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
{capturas.length > 1 && (
|
|
147
|
+
<ITFlex gap={2} wrap="wrap" className="!mt-3">
|
|
54
148
|
{capturas.map((captura) => (
|
|
55
149
|
<button
|
|
56
150
|
key={captura.src}
|
|
57
151
|
type="button"
|
|
58
152
|
title={captura.titulo}
|
|
59
153
|
aria-label={captura.titulo}
|
|
154
|
+
aria-pressed={activa.src === captura.src}
|
|
60
155
|
onClick={() => setActiva(captura)}
|
|
61
|
-
className={`h-
|
|
156
|
+
className={`h-16 w-24 shrink-0 overflow-hidden rounded-[8px] border-2 bg-slate-100 transition-all dark:bg-slate-950 ${
|
|
62
157
|
activa.src === captura.src
|
|
63
|
-
? "border-primary-
|
|
64
|
-
: "border-transparent opacity-
|
|
158
|
+
? "border-primary-700 dark:border-primary-500"
|
|
159
|
+
: "border-transparent opacity-60 hover:opacity-100"
|
|
65
160
|
}`}
|
|
66
161
|
>
|
|
67
162
|
<img src={captura.src} alt="" className="h-full w-full object-cover object-top" />
|
|
68
163
|
</button>
|
|
69
164
|
))}
|
|
70
165
|
</ITFlex>
|
|
166
|
+
)}
|
|
71
167
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
168
|
+
<ITText
|
|
169
|
+
as="p"
|
|
170
|
+
className="!mt-3 font-mono !text-[11px] !leading-relaxed text-slate-500 dark:text-slate-400"
|
|
171
|
+
>
|
|
172
|
+
{activa.titulo}
|
|
173
|
+
</ITText>
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
)}
|
|
177
|
+
|
|
178
|
+
{/* ─── QUÉ RESUELVE + FICHA TÉCNICA ─── */}
|
|
179
|
+
<div className={`${HOJA} mt-12 grid gap-10 lg:grid-cols-12`}>
|
|
180
|
+
{!!producto.caracteristicas?.length && (
|
|
181
|
+
<section className="lg:col-span-7">
|
|
182
|
+
<ITText as="h2" className={EYEBROW}>
|
|
183
|
+
{t("showcase.producto.whatItSolves")}
|
|
184
|
+
</ITText>
|
|
185
|
+
<ul className={`mt-4 border-t ${FILETE}`}>
|
|
186
|
+
{producto.caracteristicas.map((caracteristica) => (
|
|
187
|
+
<li key={caracteristica} className={`flex gap-3 border-b py-3.5 ${FILETE}`}>
|
|
188
|
+
<FaCheck
|
|
189
|
+
size={10}
|
|
190
|
+
className="mt-1.5 shrink-0 text-primary-700 dark:text-primary-500"
|
|
191
|
+
/>
|
|
192
|
+
<ITText
|
|
193
|
+
as="span"
|
|
194
|
+
className="!text-[14px] !leading-relaxed text-slate-600 dark:text-slate-300"
|
|
195
|
+
>
|
|
196
|
+
{caracteristica}
|
|
197
|
+
</ITText>
|
|
198
|
+
</li>
|
|
199
|
+
))}
|
|
200
|
+
</ul>
|
|
201
|
+
</section>
|
|
77
202
|
)}
|
|
78
203
|
|
|
79
|
-
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
204
|
+
{!!producto.ficha?.length && (
|
|
205
|
+
<section className="lg:col-span-5">
|
|
206
|
+
<ITText as="h2" className={EYEBROW}>
|
|
207
|
+
{t("showcase.producto.specSheet")}
|
|
208
|
+
</ITText>
|
|
209
|
+
<dl className={`mt-4 border-t ${FILETE}`}>
|
|
210
|
+
{producto.ficha.map((dato) => (
|
|
211
|
+
<div key={dato.etiqueta} className={`border-b py-3.5 ${FILETE}`}>
|
|
212
|
+
<dt className="font-mono text-[11px] uppercase tracking-[0.12em] text-slate-500 dark:text-slate-400">
|
|
213
|
+
{dato.etiqueta}
|
|
214
|
+
</dt>
|
|
215
|
+
<dd className="mt-1.5 text-[13px] leading-relaxed text-slate-700 dark:text-slate-200">
|
|
216
|
+
{dato.valor}
|
|
217
|
+
</dd>
|
|
86
218
|
</div>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
</ITFlex>
|
|
219
|
+
))}
|
|
220
|
+
</dl>
|
|
221
|
+
</section>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
93
224
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
225
|
+
{producto.nota && (
|
|
226
|
+
<div className={HOJA}>
|
|
227
|
+
<ITText
|
|
228
|
+
as="p"
|
|
229
|
+
className="!mt-8 max-w-[74ch] font-mono !text-[11px] !leading-relaxed text-slate-500 dark:text-slate-400"
|
|
230
|
+
>
|
|
231
|
+
{producto.nota}
|
|
232
|
+
</ITText>
|
|
233
|
+
</div>
|
|
234
|
+
)}
|
|
99
235
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
236
|
+
{/* ─── ANTERIOR / SIGUIENTE ─── */}
|
|
237
|
+
{(anterior || siguiente) && (
|
|
238
|
+
<nav aria-label={t("showcase.producto.navLabel")} className={`mt-14 border-t ${FILETE}`}>
|
|
239
|
+
<div className={`${HOJA} grid gap-px sm:grid-cols-2`}>
|
|
240
|
+
{anterior && (
|
|
241
|
+
<a
|
|
242
|
+
href={`#proyecto/${anterior.id}`}
|
|
243
|
+
className={`group flex flex-col gap-1.5 py-6 sm:pr-8 ${
|
|
244
|
+
siguiente ? `sm:border-r ${FILETE}` : ""
|
|
245
|
+
}`}
|
|
246
|
+
>
|
|
247
|
+
<ITText as="span" className={`inline-flex items-center gap-2 ${EYEBROW}`}>
|
|
248
|
+
<FaArrowLeft size={9} aria-hidden />
|
|
249
|
+
{t("showcase.producto.prev")}
|
|
104
250
|
</ITText>
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</div>
|
|
116
|
-
)}
|
|
117
|
-
|
|
118
|
-
<div>
|
|
119
|
-
<ITText as="h3" className="!text-sm !font-bold !mb-2.5">
|
|
120
|
-
Stack
|
|
121
|
-
</ITText>
|
|
122
|
-
<ITFlex gap={2} wrap="wrap">
|
|
123
|
-
{producto.stack.map((tecnologia) => (
|
|
124
|
-
<ITBadget key={tecnologia} label={tecnologia} color="gray" variant="outlined" />
|
|
125
|
-
))}
|
|
126
|
-
</ITFlex>
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
{!!producto.ficha?.length && (
|
|
130
|
-
<>
|
|
131
|
-
<ITDivider />
|
|
132
|
-
|
|
133
|
-
<div>
|
|
134
|
-
<ITText as="h3" className="!text-sm !font-bold !mb-2.5">
|
|
135
|
-
Ficha técnica
|
|
136
|
-
</ITText>
|
|
137
|
-
<ITStack spacing={2.5}>
|
|
138
|
-
{producto.ficha.map((dato) => (
|
|
139
|
-
<ITGrid container spacing={2} key={dato.etiqueta}>
|
|
140
|
-
<ITGrid item xs={4}>
|
|
141
|
-
<ITText as="span" muted className="!text-xs !font-semibold">
|
|
142
|
-
{dato.etiqueta}
|
|
143
|
-
</ITText>
|
|
144
|
-
</ITGrid>
|
|
145
|
-
<ITGrid item xs={8}>
|
|
146
|
-
<ITText as="span" className="!text-xs !leading-relaxed">
|
|
147
|
-
{dato.valor}
|
|
148
|
-
</ITText>
|
|
149
|
-
</ITGrid>
|
|
150
|
-
</ITGrid>
|
|
151
|
-
))}
|
|
152
|
-
</ITStack>
|
|
153
|
-
</div>
|
|
154
|
-
</>
|
|
251
|
+
<ITText
|
|
252
|
+
as="span"
|
|
253
|
+
className="font-display !text-[19px] !font-bold -tracking-[0.02em] text-slate-900 group-hover:text-primary-700 dark:text-white dark:group-hover:text-primary-500"
|
|
254
|
+
>
|
|
255
|
+
{anterior.nombre}
|
|
256
|
+
</ITText>
|
|
257
|
+
<ITText as="span" className="!text-[12px] text-slate-500 dark:text-slate-400">
|
|
258
|
+
{anterior.tipo}
|
|
259
|
+
</ITText>
|
|
260
|
+
</a>
|
|
155
261
|
)}
|
|
156
262
|
|
|
157
|
-
{
|
|
263
|
+
{siguiente && (
|
|
158
264
|
<a
|
|
159
|
-
href={
|
|
160
|
-
{
|
|
161
|
-
?
|
|
162
|
-
|
|
163
|
-
className="!text-xs !font-semibold !text-primary-600 dark:!text-primary-400 inline-flex items-center gap-1.5"
|
|
265
|
+
href={`#proyecto/${siguiente.id}`}
|
|
266
|
+
className={`group flex flex-col gap-1.5 py-6 sm:pl-8 ${
|
|
267
|
+
anterior ? "" : "sm:col-start-2 sm:items-end sm:text-right"
|
|
268
|
+
}`}
|
|
164
269
|
>
|
|
165
|
-
|
|
166
|
-
|
|
270
|
+
<ITText as="span" className={`inline-flex items-center gap-2 ${EYEBROW}`}>
|
|
271
|
+
{t("showcase.producto.next")}
|
|
272
|
+
<FaArrowRight size={9} aria-hidden />
|
|
273
|
+
</ITText>
|
|
274
|
+
<ITText
|
|
275
|
+
as="span"
|
|
276
|
+
className="font-display !text-[19px] !font-bold -tracking-[0.02em] text-slate-900 group-hover:text-primary-700 dark:text-white dark:group-hover:text-primary-500"
|
|
277
|
+
>
|
|
278
|
+
{siguiente.nombre}
|
|
279
|
+
</ITText>
|
|
280
|
+
<ITText as="span" className="!text-[12px] text-slate-500 dark:text-slate-400">
|
|
281
|
+
{siguiente.tipo}
|
|
282
|
+
</ITText>
|
|
167
283
|
</a>
|
|
168
284
|
)}
|
|
285
|
+
</div>
|
|
286
|
+
</nav>
|
|
287
|
+
)}
|
|
288
|
+
|
|
289
|
+
{/* ─── CIERRE ─── */}
|
|
290
|
+
<section className={`border-t ${FILETE}`}>
|
|
291
|
+
<div
|
|
292
|
+
className={`${HOJA} flex flex-col gap-6 py-12 sm:flex-row sm:items-center sm:justify-between`}
|
|
293
|
+
>
|
|
294
|
+
<div>
|
|
295
|
+
<ITText as="p" className={EYEBROW}>
|
|
296
|
+
{t("showcase.home.eyebrowNext")}
|
|
297
|
+
</ITText>
|
|
298
|
+
<ITText
|
|
299
|
+
as="h2"
|
|
300
|
+
className="font-display !mt-2.5 !text-[24px] !font-bold -tracking-[0.02em] text-slate-900 dark:text-white sm:!text-[30px]"
|
|
301
|
+
>
|
|
302
|
+
{t("showcase.producto.cta")}
|
|
303
|
+
</ITText>
|
|
304
|
+
</div>
|
|
169
305
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
306
|
+
<ITFlex gap={3} wrap="wrap" align="center" className="shrink-0">
|
|
307
|
+
<BotonAccion onClick={onBack} icono={<FaArrowLeft size={11} />}>
|
|
308
|
+
{t("showcase.producto.back")}
|
|
309
|
+
</BotonAccion>
|
|
310
|
+
{producto.enlace && (
|
|
311
|
+
<EnlaceBoton
|
|
312
|
+
href={producto.enlace}
|
|
313
|
+
icono={enlaceExterno ? <FaExternalLinkAlt size={11} /> : undefined}
|
|
314
|
+
>
|
|
315
|
+
{producto.enlaceTexto ?? t("showcase.home.viewRepo")}
|
|
316
|
+
</EnlaceBoton>
|
|
174
317
|
)}
|
|
175
|
-
</
|
|
176
|
-
</
|
|
177
|
-
</
|
|
178
|
-
</
|
|
179
|
-
|
|
318
|
+
</ITFlex>
|
|
319
|
+
</div>
|
|
320
|
+
</section>
|
|
321
|
+
</main>
|
|
322
|
+
</>
|
|
180
323
|
);
|
|
181
324
|
}
|