@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.
Files changed (226) hide show
  1. package/README.md +2 -11
  2. package/dist/index.cjs +2174 -1570
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +1 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.cts +232 -19
  7. package/dist/index.d.ts +232 -19
  8. package/dist/index.js +1838 -1238
  9. package/dist/index.js.map +1 -1
  10. package/dist/layered.css +1 -1
  11. package/package.json +3 -16
  12. package/src/App.tsx +90 -73
  13. package/src/components/atoms/badget/badget.tsx +23 -5
  14. package/src/components/atoms/chip/chip.tsx +3 -1
  15. package/src/components/atoms/image/image.tsx +3 -1
  16. package/src/components/atoms/input/input.tsx +8 -5
  17. package/src/components/atoms/loader/loader.tsx +3 -1
  18. package/src/components/atoms/slide/slide.props.ts +12 -0
  19. package/src/components/atoms/slide/slide.tsx +3 -0
  20. package/src/components/molecules/alert/alert.tsx +3 -1
  21. package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
  22. package/src/components/molecules/calendar/calendar.tsx +9 -6
  23. package/src/components/molecules/card/card.tsx +5 -2
  24. package/src/components/molecules/chip-input/chip-input.tsx +9 -7
  25. package/src/components/molecules/date-picker/datePicker.tsx +9 -9
  26. package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
  27. package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
  28. package/src/components/molecules/field/field.tsx +3 -1
  29. package/src/components/molecules/form-header/form-header.tsx +3 -1
  30. package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
  31. package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
  32. package/src/components/molecules/masked-input/masked-input.tsx +3 -1
  33. package/src/components/molecules/multi-select/multi-select.tsx +12 -9
  34. package/src/components/molecules/pagination/pagination.tsx +11 -5
  35. package/src/components/molecules/search-select/search-select.tsx +11 -9
  36. package/src/components/molecules/select/select.tsx +6 -4
  37. package/src/components/molecules/stepper/stepper.tsx +6 -4
  38. package/src/components/molecules/table/table.props.ts +10 -2
  39. package/src/components/molecules/table/table.tsx +163 -114
  40. package/src/components/molecules/time-picker/timePicker.tsx +8 -6
  41. package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
  42. package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
  43. package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
  44. package/src/components/organisms/data-table/dataTable.props.ts +3 -2
  45. package/src/components/organisms/data-table/dataTable.tsx +149 -81
  46. package/src/components/organisms/dialog/dialog.tsx +3 -0
  47. package/src/components/organisms/drawer/drawer.tsx +3 -0
  48. package/src/components/organisms/dropfile/dropfile.tsx +19 -17
  49. package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
  50. package/src/components/organisms/navbar/navbar.tsx +4 -2
  51. package/src/components/organisms/page-header/page-header.tsx +3 -1
  52. package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
  53. package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
  54. package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
  55. package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
  56. package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
  57. package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
  58. package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
  59. package/src/components/organisms/searchTable/searchTable.tsx +4 -2
  60. package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
  61. package/src/components/organisms/sidebar/sidebar.tsx +9 -4
  62. package/src/components/organisms/toast/toast.tsx +3 -1
  63. package/src/components/organisms/topbar/topbar.tsx +4 -2
  64. package/src/components/templates/page/page.props.ts +4 -4
  65. package/src/components/templates/page/page.tsx +6 -4
  66. package/src/components/theme-provider/themeProvider.tsx +28 -17
  67. package/src/dev.css +77 -2
  68. package/src/global.d.ts +10 -0
  69. package/src/i18n/context.ts +9 -0
  70. package/src/i18n/index.ts +22 -0
  71. package/src/i18n/locales/en.ts +163 -0
  72. package/src/i18n/locales/es.ts +165 -0
  73. package/src/i18n/provider.tsx +44 -0
  74. package/src/i18n/translator.ts +82 -0
  75. package/src/i18n/types.ts +54 -0
  76. package/src/i18n/useITTranslation.ts +20 -0
  77. package/src/index.css +0 -1
  78. package/src/index.ts +9 -3
  79. package/src/sandbox/LandingShowcase.tsx +224 -580
  80. package/src/sandbox/NotFoundShowcase.tsx +51 -36
  81. package/src/sandbox/TopbarSearch.tsx +6 -4
  82. package/src/sandbox/controls.tsx +180 -0
  83. package/src/sandbox/i18n.ts +1929 -0
  84. package/src/sandbox/icons.tsx +25 -0
  85. package/src/sandbox/locale.tsx +72 -0
  86. package/src/sandbox/ui.tsx +377 -0
  87. package/src/sandbox/useHashRoute.ts +46 -10
  88. package/src/showcases/DataShowcases.tsx +201 -80
  89. package/src/showcases/FeedbackShowcases.tsx +37 -30
  90. package/src/showcases/FormShowcases.tsx +302 -214
  91. package/src/showcases/GettingStartedShowcase.tsx +151 -145
  92. package/src/showcases/HelpShowcase.tsx +126 -128
  93. package/src/showcases/HomeShowcase.tsx +678 -482
  94. package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
  95. package/src/showcases/NavigationShowcases.tsx +45 -37
  96. package/src/showcases/PageShowcases.tsx +171 -152
  97. package/src/showcases/ProductoDetalle.tsx +272 -129
  98. package/src/showcases/ShowcaseLayout.tsx +270 -216
  99. package/src/showcases/SizesShowcase.tsx +123 -64
  100. package/src/showcases/StructureShowcases.tsx +157 -131
  101. package/src/showcases/portfolioUi.tsx +153 -0
  102. package/src/showcases/techIcons.ts +3 -0
  103. package/src/types/table.types.ts +110 -0
  104. package/src/utils/table.utils.ts +10 -2
  105. package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
  106. package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
  107. package/src/components/atoms/badget/badget.doc.mdx +0 -46
  108. package/src/components/atoms/badget/badget.stories.tsx +0 -75
  109. package/src/components/atoms/button/button.doc.mdx +0 -59
  110. package/src/components/atoms/button/button.stories.tsx +0 -173
  111. package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
  112. package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
  113. package/src/components/atoms/chip/chip.doc.mdx +0 -47
  114. package/src/components/atoms/chip/chip.stories.tsx +0 -64
  115. package/src/components/atoms/divider/divider.doc.mdx +0 -42
  116. package/src/components/atoms/divider/divider.stories.tsx +0 -33
  117. package/src/components/atoms/flex/flex.doc.mdx +0 -59
  118. package/src/components/atoms/flex/flex.stories.tsx +0 -70
  119. package/src/components/atoms/grid/grid.doc.mdx +0 -54
  120. package/src/components/atoms/grid/grid.stories.tsx +0 -71
  121. package/src/components/atoms/image/image.doc.mdx +0 -44
  122. package/src/components/atoms/image/image.stories.tsx +0 -48
  123. package/src/components/atoms/input/input.doc.mdx +0 -70
  124. package/src/components/atoms/input/input.stories.tsx +0 -113
  125. package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
  126. package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
  127. package/src/components/atoms/loader/loader.doc.mdx +0 -43
  128. package/src/components/atoms/loader/loader.stories.tsx +0 -104
  129. package/src/components/atoms/popover/popover.doc.mdx +0 -53
  130. package/src/components/atoms/popover/popover.stories.tsx +0 -24
  131. package/src/components/atoms/progress/progress.doc.mdx +0 -48
  132. package/src/components/atoms/progress/progress.stories.tsx +0 -39
  133. package/src/components/atoms/radio/radio.doc.mdx +0 -62
  134. package/src/components/atoms/radio/radio.stories.tsx +0 -48
  135. package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
  136. package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
  137. package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
  138. package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
  139. package/src/components/atoms/slide/slide.doc.mdx +0 -46
  140. package/src/components/atoms/slide/slide.stories.tsx +0 -120
  141. package/src/components/atoms/slider/slider.doc.mdx +0 -49
  142. package/src/components/atoms/slider/slider.stories.tsx +0 -29
  143. package/src/components/atoms/stack/stack.doc.mdx +0 -126
  144. package/src/components/atoms/stack/stack.stories.tsx +0 -283
  145. package/src/components/atoms/text/text.doc.mdx +0 -41
  146. package/src/components/atoms/text/text.stories.tsx +0 -66
  147. package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
  148. package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
  149. package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
  150. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
  151. package/src/components/isolation/isolation.stories.tsx +0 -202
  152. package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
  153. package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
  154. package/src/components/molecules/alert/alert.doc.mdx +0 -48
  155. package/src/components/molecules/alert/alert.stories.tsx +0 -40
  156. package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
  157. package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
  158. package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
  159. package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
  160. package/src/components/molecules/card/card.doc.mdx +0 -54
  161. package/src/components/molecules/card/card.stories.tsx +0 -57
  162. package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
  163. package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
  164. package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
  165. package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
  166. package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
  167. package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
  168. package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
  169. package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
  170. package/src/components/molecules/field/field.doc.mdx +0 -43
  171. package/src/components/molecules/field/field.stories.tsx +0 -42
  172. package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
  173. package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
  174. package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
  175. package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
  176. package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
  177. package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
  178. package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
  179. package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
  180. package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
  181. package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
  182. package/src/components/molecules/select/select.doc.mdx +0 -75
  183. package/src/components/molecules/select/select.stories.tsx +0 -85
  184. package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
  185. package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
  186. package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
  187. package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
  188. package/src/components/molecules/table/table.doc.mdx +0 -123
  189. package/src/components/molecules/table/table.stories.tsx +0 -402
  190. package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
  191. package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
  192. package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
  193. package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
  194. package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
  195. package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
  196. package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
  197. package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -115
  198. package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
  199. package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
  200. package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
  201. package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
  202. package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
  203. package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
  204. package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
  205. package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
  206. package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
  207. package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
  208. package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
  209. package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
  210. package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
  211. package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
  212. package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
  213. package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
  214. package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
  215. package/src/components/organisms/toast/toast.doc.mdx +0 -50
  216. package/src/components/organisms/toast/toast.stories.tsx +0 -137
  217. package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
  218. package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
  219. package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
  220. package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
  221. package/src/components/templates/layout/layout.doc.mdx +0 -53
  222. package/src/components/templates/layout/layout.stories.tsx +0 -113
  223. package/src/components/templates/page/page.doc.mdx +0 -86
  224. package/src/components/templates/page/page.stories.tsx +0 -97
  225. package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
  226. package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
@@ -1,62 +1,136 @@
1
+ /**
2
+ * Marco de las páginas de componente del sandbox (`#ui-system/<grupo>/<item>`):
3
+ * cabecera de la hoja, vitrina interactiva (vista previa / código), panel de
4
+ * propiedades y documentación, y galería de variaciones.
5
+ *
6
+ * Sigue `DESIGN.md` (AXZY Console): el bloque lo separan filetes de 1px, no
7
+ * cajas dentro de cajas; los controles vienen del kit compartido
8
+ * (`@/sandbox/ui` y `@/sandbox/controls`) para que el marco no introduzca
9
+ * colores que no pasan AA.
10
+ */
11
+
1
12
  import React, { useState } from "react";
2
- import { FaCheck, FaCopy, FaBookOpen, FaCog, FaCode, FaEye } from "react-icons/fa";
13
+ import { FaBookOpen, FaCheck, FaCode, FaCog, FaCopy, FaEye } from "react-icons/fa";
3
14
  import ITGrid from "../components/atoms/grid/grid";
4
15
  import { useITTheme } from "../components/theme-provider/themeProvider";
16
+ import { ControlSegmentado } from "@/sandbox/controls";
17
+ import { EYEBROW, FILETE, FOCO_CTA } from "@/sandbox/ui";
18
+ import { useITTranslation } from "@/i18n";
5
19
 
20
+ /**
21
+ * Bloque de código con botón de copiar. Fondo tinta, mono y el acento de señal
22
+ * (`cyan-400`) reservado a la etiqueta, como manda el spec.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <CodeViewer code={`<ITButton>Guardar</ITButton>`} compact />
27
+ * ```
28
+ */
6
29
  export const CodeViewer: React.FC<{ code: string; compact?: boolean }> = ({ code, compact }) => {
30
+ const { t } = useITTranslation();
7
31
  const [copied, setCopied] = useState(false);
32
+
8
33
  const handleCopy = () => {
9
- navigator.clipboard.writeText(code);
34
+ navigator.clipboard?.writeText(code);
10
35
  setCopied(true);
11
- setTimeout(() => setCopied(false), 2000);
36
+ window.setTimeout(() => setCopied(false), 2000);
12
37
  };
38
+
13
39
  return (
14
- <div className="relative rounded-xl overflow-hidden bg-slate-950 text-slate-200 border border-slate-800 shadow-inner">
15
- <div className="flex justify-between items-center px-4 py-2 bg-slate-900 border-b border-slate-800">
16
- <span className="text-[10px] uppercase font-bold tracking-wider text-slate-400 font-mono">JSX Code</span>
40
+ <div className="relative overflow-hidden rounded-[10px] border border-slate-800 bg-slate-950 text-slate-200">
41
+ <div className="flex items-center justify-between border-b border-slate-800 px-4 py-2.5">
42
+ <span className="font-mono text-[10px] uppercase tracking-[0.14em] text-cyan-400">
43
+ {t("showcase.layout.jsxCode")}
44
+ </span>
17
45
  <button
46
+ type="button"
18
47
  onClick={handleCopy}
19
- className="text-slate-400 hover:text-white transition-colors flex items-center gap-1.5 text-xs py-1 px-2 rounded hover:bg-slate-800"
48
+ className={`flex items-center gap-1.5 rounded-[6px] px-2 py-1 font-mono text-[10px] uppercase tracking-[0.12em] text-slate-400 transition-colors hover:bg-slate-800 hover:text-white ${FOCO_CTA}`}
20
49
  >
21
- {copied ? <FaCheck size={11} className="text-emerald-500" /> : <FaCopy size={11} />}
22
- <span>{copied ? "Copied!" : "Copy"}</span>
50
+ {copied ? <FaCheck size={11} className="text-cyan-400" /> : <FaCopy size={11} />}
51
+ <span>{copied ? t("showcase.layout.copied") : t("showcase.layout.copy")}</span>
23
52
  </button>
24
53
  </div>
25
- <pre className={`p-4 text-xs font-mono overflow-x-auto leading-relaxed whitespace-pre-wrap ${compact ? "max-h-[420px]" : ""} overflow-y-auto`}>
54
+ <pre
55
+ className={`overflow-x-auto whitespace-pre-wrap p-4 font-mono text-xs leading-relaxed ${
56
+ compact ? "max-h-[420px]" : ""
57
+ } overflow-y-auto`}
58
+ >
26
59
  <code>{code}</code>
27
60
  </pre>
28
61
  </div>
29
62
  );
30
63
  };
31
64
 
65
+ /** Una fila de la tabla de props. */
32
66
  export interface PropDocEntry {
67
+ /** Nombre del prop. */
33
68
  name: string;
69
+ /** Tipo TypeScript. */
34
70
  type: string;
71
+ /** Valor por defecto. */
35
72
  default?: string;
73
+ /** Descripción para el panel de documentación. */
36
74
  description: string;
75
+ /** Marca el prop como obligatorio. */
37
76
  required?: boolean;
38
77
  }
39
78
 
79
+ /** Documentación de un componente, si el showcase la declara. */
40
80
  export interface ComponentDoc {
81
+ /** Resumen de una línea. */
41
82
  summary: string;
83
+ /** Descripción larga opcional. */
42
84
  description?: string;
85
+ /** Ejemplos de uso (código). */
43
86
  examples?: string[];
87
+ /** Tabla de props. */
44
88
  props: PropDocEntry[];
89
+ /** Notas al pie. */
45
90
  notes?: string[];
46
91
  }
47
92
 
93
+ /** Props de `ShowcaseLayout`. */
48
94
  export interface ShowcaseLayoutProps {
95
+ /** Nombre del componente. */
49
96
  title: string;
97
+ /** Descripción corta bajo el título. */
50
98
  description: string;
99
+ /** Demo interactiva. */
51
100
  demo: React.ReactNode;
52
- controls: React.ReactNode;
101
+ /**
102
+ * Panel de controles (lo construye cada showcase). Si se omite, la vitrina
103
+ * ocupa todo el ancho y no se pinta panel: para páginas que solo muestran un
104
+ * ejemplo o una receta.
105
+ */
106
+ controls?: React.ReactNode;
107
+ /** Código fuente que se muestra en la pestaña de código. */
53
108
  code: string;
109
+ /** Galería de variaciones y estados. */
54
110
  gallery?: React.ReactNode;
111
+ /** Documentación opcional (añade la pestaña "Docs"). */
55
112
  doc?: ComponentDoc;
113
+ /**
114
+ * Ancho de la vitrina. `"columna"` (por defecto) la deja en 8/12 columnas con
115
+ * el panel al lado; `"completo"` la lleva a las 12 y baja el panel, para demos
116
+ * que son un layout entero (ITLayout, pantallas de ejemplo) y se recortaban.
117
+ * @default "columna"
118
+ */
119
+ demoAncho?: "columna" | "completo";
56
120
  }
57
121
 
58
122
  type SandboxView = "preview" | "code";
59
123
 
124
+ /**
125
+ * Página de un componente del sandbox: cabecera, vitrina con vista previa y
126
+ * código, panel lateral de propiedades/documentación y galería.
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * <ShowcaseLayout title="ITButton" description="…" demo={<ITButton>Guardar</ITButton>}
131
+ * controls={<ITSelect … />} code={code} gallery={<Gallery />} doc={doc} />
132
+ * ```
133
+ */
60
134
  export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
61
135
  title,
62
136
  description,
@@ -64,238 +138,218 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
64
138
  controls,
65
139
  code,
66
140
  gallery,
67
- doc
141
+ doc,
142
+ demoAncho = "columna",
68
143
  }) => {
144
+ const completo = demoAncho === "completo";
145
+ const { t } = useITTranslation();
69
146
  const { resolvedTheme } = useITTheme();
70
- const [activeTab, setActiveTab] = useState<"controls" | "docs">("controls");
147
+ const [activeTab, setActiveTab] = useState<"controls" | "docs">(controls ? "controls" : "docs");
71
148
  const [sandboxView, setSandboxView] = useState<SandboxView>("preview");
72
- return (
73
- <div className="space-y-6 animate-fadeIn">
74
- {/* Title block */}
75
- <div className="flex flex-col md:flex-row md:items-start justify-between gap-4">
76
- <div className="flex-1 min-w-0">
77
- <h1 className="text-3xl font-extrabold text-slate-800 dark:text-white tracking-tight flex items-center gap-3">
78
- {title}
79
- </h1>
80
- <p className="text-slate-500 dark:text-slate-400 mt-1.5 text-sm md:text-base">{description}</p>
81
- </div>
149
+ // Sin controles la vitrina se queda con todo el ancho.
150
+ const hayPanel = Boolean(controls) || Boolean(doc);
82
151
 
152
+ return (
153
+ <div className="animate-fadeIn pb-4">
154
+ {/* ─── CABECERA DE LA HOJA ─── */}
155
+ <header className={`border-b pb-7 ${FILETE}`}>
156
+ <p className={EYEBROW}>{t("showcase.layout.eyebrow")}</p>
157
+ <h1 className="mt-2.5 font-display text-[32px] font-bold tracking-[-0.02em] text-slate-900 dark:text-white sm:text-[40px]">
158
+ {title}
159
+ </h1>
160
+ <p className="mt-3 max-w-[70ch] text-[15px] leading-relaxed text-slate-600 dark:text-slate-300">
161
+ {description}
162
+ </p>
163
+ </header>
83
164
 
84
- </div>
165
+ <div className="pt-8">
166
+ <ITGrid container columns={12} spacing={8}>
167
+ {/* ── VITRINA ── */}
168
+ <ITGrid item xs={12} md={completo || !hayPanel ? 12 : 8}>
169
+ <section
170
+ aria-label={t("showcase.layout.sandbox")}
171
+ className={`overflow-hidden rounded-[10px] border ${FILETE}`}
172
+ >
173
+ {/* Barra de la vitrina */}
174
+ <div className={`flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 ${FILETE}`}>
175
+ <h2 className={EYEBROW}>{t("showcase.layout.sandbox")}</h2>
85
176
 
86
- <ITGrid container columns={12} spacing={6}>
87
- {/* ── MAIN: Unified Sandbox (Preview / Code tabs) ── */}
88
- <ITGrid item as="main" xs={12} md={8} className="space-y-4">
89
- {/* Unified Sandbox */}
90
- <div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-700 shadow-sm overflow-hidden">
91
- {/* Sandbox header */}
92
- <div className="flex items-center justify-between px-4 py-2 border-b border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50">
93
- <div className="flex items-center gap-2">
94
- <span className="w-2 h-2 rounded-full bg-red-400" />
95
- <span className="w-2 h-2 rounded-full bg-amber-400" />
96
- <span className="w-2 h-2 rounded-full bg-emerald-400" />
97
- <span className="ml-2 text-[10px] font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400">
98
- Interactive Sandbox
99
- </span>
177
+ <ControlSegmentado
178
+ etiqueta={t("showcase.layout.sandbox")}
179
+ valor={sandboxView}
180
+ onChange={(value) => setSandboxView(value === "code" ? "code" : "preview")}
181
+ opciones={[
182
+ {
183
+ value: "preview",
184
+ label: t("showcase.layout.preview"),
185
+ icono: <FaEye size={10} />,
186
+ },
187
+ { value: "code", label: t("showcase.layout.code"), icono: <FaCode size={10} /> },
188
+ ]}
189
+ />
100
190
  </div>
101
191
 
102
- {/* View toggle: Preview / Code */}
103
- <div className="flex items-center gap-1 bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 p-0.5 rounded-lg">
104
- <button
105
- onClick={() => setSandboxView("preview")}
106
- className={`flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-semibold rounded-md transition-all ${
107
- sandboxView === "preview"
108
- ? "bg-primary-100 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300"
109
- : "text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
110
- }`}
111
- >
112
- <FaEye size={10} />
113
- Preview
114
- </button>
115
- <button
116
- onClick={() => setSandboxView("code")}
117
- className={`flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-semibold rounded-md transition-all ${
118
- sandboxView === "code"
119
- ? "bg-primary-100 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300"
120
- : "text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
121
- }`}
192
+ {/* Contenido */}
193
+ {sandboxView === "preview" ? (
194
+ <div
195
+ data-theme={resolvedTheme}
196
+ className="flex min-h-[280px] items-center justify-center overflow-x-auto bg-white p-6 dark:bg-slate-950 md:p-10"
122
197
  >
123
- <FaCode size={10} />
124
- Code
125
- </button>
126
- </div>
127
- </div>
128
-
129
- {/* Sandbox content */}
130
- {sandboxView === "preview" ? (
131
- <div
132
- data-theme={resolvedTheme}
133
- className="p-6 md:p-10 min-h-[320px] flex items-center justify-center transition-all duration-300 bg-white dark:bg-slate-950"
134
- >
135
- <div className="w-full flex justify-center">{demo}</div>
136
- </div>
137
- ) : (
138
- <div className="p-3 bg-slate-50 dark:bg-slate-800/50">
139
- <CodeViewer code={code} compact />
140
- </div>
141
- )}
142
- </div>
143
- </ITGrid>
144
-
145
- {/* ── RIGHT SIDEBAR: Configs / Docs ── */}
146
- <ITGrid item as="aside" xs={12} md={4}>
147
- <div className="md:sticky md:top-4">
148
- <div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-700 shadow-sm overflow-hidden">
149
- {/* Tab bar */}
150
- {doc ? (
151
- <div className="flex border-b border-slate-200 dark:border-slate-700">
152
- <button
153
- onClick={() => setActiveTab("controls")}
154
- className={`flex-1 flex items-center justify-center gap-1.5 py-2.5 text-xs font-semibold transition-colors ${
155
- activeTab === "controls"
156
- ? "text-primary-600 border-b-2 border-primary-600 bg-primary-50/40 dark:bg-primary-950/20 dark:text-primary-400 dark:border-primary-400"
157
- : "text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
158
- }`}
159
- >
160
- <FaCog size={11} />
161
- Properties
162
- </button>
163
- <button
164
- onClick={() => setActiveTab("docs")}
165
- className={`flex-1 flex items-center justify-center gap-1.5 py-2.5 text-xs font-semibold transition-colors ${
166
- activeTab === "docs"
167
- ? "text-primary-600 border-b-2 border-primary-600 bg-primary-50/40 dark:bg-primary-950/20 dark:text-primary-400 dark:border-primary-400"
168
- : "text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
169
- }`}
170
- >
171
- <FaBookOpen size={11} />
172
- Docs
173
- </button>
198
+ <div className="flex w-full justify-center">{demo}</div>
174
199
  </div>
175
- ) : null}
176
-
177
- {/* Controls Tab */}
178
- {activeTab === "controls" && (
179
- <div className="p-4 space-y-4 max-h-[calc(100vh-160px)] overflow-y-auto">
180
- <div className="space-y-4">{controls}</div>
200
+ ) : (
201
+ <div className="p-3">
202
+ <CodeViewer code={code} compact />
181
203
  </div>
182
204
  )}
205
+ </section>
206
+ </ITGrid>
183
207
 
184
- {/* Documentation Tab */}
185
- {doc && activeTab === "docs" && (
186
- <div className="p-4 space-y-5 max-h-[calc(100vh-160px)] overflow-y-auto">
187
- {/* Description */}
188
- <div>
189
- <h3 className="text-[10px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2">
190
- Overview
191
- </h3>
192
- <p className="text-xs text-slate-700 dark:text-slate-300 leading-relaxed">
193
- {doc.summary}
194
- </p>
195
- {doc.description && (
196
- <p className="text-[11px] text-slate-500 dark:text-slate-400 leading-relaxed mt-2">
197
- {doc.description}
198
- </p>
199
- )}
208
+ {/* ── PANEL LATERAL ── */}
209
+ {hayPanel && (
210
+ <ITGrid item xs={12} md={completo ? 12 : 4}>
211
+ <div className={completo ? "" : "md:sticky md:top-4"}>
212
+ <section
213
+ aria-label={t("showcase.layout.properties")}
214
+ className={`overflow-hidden rounded-[10px] border ${FILETE} ${
215
+ completo ? "max-w-[880px]" : ""
216
+ }`}
217
+ >
218
+ {doc ? (
219
+ <div
220
+ role="tablist"
221
+ aria-label={t("showcase.layout.properties")}
222
+ className={`flex items-stretch gap-1 border-b px-2 ${FILETE}`}
223
+ >
224
+ {(
225
+ [
226
+ { id: "controls", label: t("showcase.layout.properties"), icono: <FaCog size={10} /> },
227
+ { id: "docs", label: t("showcase.layout.docs"), icono: <FaBookOpen size={10} /> },
228
+ ] as const
229
+ ).map((tab) => {
230
+ const activa = activeTab === tab.id;
231
+ return (
232
+ <button
233
+ key={tab.id}
234
+ type="button"
235
+ role="tab"
236
+ aria-selected={activa}
237
+ onClick={() => setActiveTab(tab.id)}
238
+ className={`-mb-px inline-flex items-center gap-2 border-b-2 px-3 py-2.5 font-mono text-[10px] font-medium uppercase tracking-[0.14em] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/60 ${
239
+ activa
240
+ ? "border-primary-700 text-primary-700 dark:border-primary-500 dark:text-primary-500"
241
+ : "border-transparent text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
242
+ }`}
243
+ >
244
+ {tab.icono}
245
+ {tab.label}
246
+ </button>
247
+ );
248
+ })}
200
249
  </div>
250
+ ) : null}
201
251
 
202
- {/* Props Table */}
203
- <div>
204
- <h3 className="text-[10px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2">
205
- Props
206
- </h3>
207
- <div className="overflow-x-auto rounded-lg border border-slate-200 dark:border-slate-700">
208
- <table className="w-full text-[11px]">
209
- <thead>
210
- <tr className="bg-slate-50 dark:bg-slate-800">
211
- <th className="text-left px-2 py-1.5 font-semibold text-slate-600 dark:text-slate-300 whitespace-nowrap">Prop</th>
212
- <th className="text-left px-2 py-1.5 font-semibold text-slate-600 dark:text-slate-300 whitespace-nowrap">Type</th>
213
- <th className="text-left px-2 py-1.5 font-semibold text-slate-600 dark:text-slate-300 whitespace-nowrap">Default</th>
214
- </tr>
215
- </thead>
216
- <tbody>
217
- {doc.props.map((prop, i) => (
218
- <tr
219
- key={prop.name}
220
- className={`border-t border-slate-100 dark:border-slate-800 ${
221
- i % 2 === 0 ? "bg-white dark:bg-slate-900" : "bg-slate-50/50 dark:bg-slate-800/50"
222
- }`}
223
- >
224
- <td className="px-2 py-1.5 font-mono font-semibold text-primary-700 dark:text-primary-400 whitespace-nowrap">
225
- {prop.name}
226
- {prop.required ? <span className="text-danger-500 ml-0.5">*</span> : null}
227
- </td>
228
- <td className="px-2 py-1.5 font-mono text-slate-600 dark:text-slate-400 text-[10px]">
229
- {prop.type}
230
- </td>
231
- <td className="px-2 py-1.5 font-mono text-slate-400 dark:text-slate-500 text-[10px]">
232
- {prop.default || "—"}
233
- </td>
234
- </tr>
235
- ))}
236
- </tbody>
237
- </table>
238
- </div>
239
- {/* Detailed descriptions below the compact table */}
240
- <div className="mt-2 space-y-1.5">
241
- {doc.props.map((prop) => (
242
- <div key={prop.name} className="text-[11px]">
243
- <span className="font-mono font-semibold text-primary-700 dark:text-primary-400">{prop.name}</span>
244
- <span className="text-slate-500 dark:text-slate-400"> — {prop.description}</span>
245
- </div>
246
- ))}
247
- </div>
252
+ {activeTab === "controls" && (
253
+ <div
254
+ className={`max-h-[calc(100vh-200px)] space-y-4 overflow-y-auto p-5 ${
255
+ completo ? "it-panel-ancho max-w-[880px]" : ""
256
+ }`}
257
+ >
258
+ {controls}
248
259
  </div>
260
+ )}
249
261
 
250
- {/* Usage Examples */}
251
- {doc.examples && doc.examples.length > 0 && (
262
+ {doc && activeTab === "docs" && (
263
+ <div
264
+ className={`max-h-[calc(100vh-200px)] space-y-6 overflow-y-auto p-5 ${
265
+ completo ? "it-panel-ancho max-w-[880px]" : ""
266
+ }`}
267
+ >
252
268
  <div>
253
- <h3 className="text-[10px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2">
254
- Usage Examples
255
- </h3>
256
- {doc.examples.map((example, i) => (
257
- <div key={i} className="mb-2 last:mb-0">
258
- <pre className="p-2 rounded-lg bg-slate-950 text-slate-200 text-[10px] font-mono overflow-x-auto leading-relaxed">
259
- <code>{example}</code>
260
- </pre>
261
- </div>
262
- ))}
269
+ <h2 className={EYEBROW}>{t("showcase.layout.overview")}</h2>
270
+ <p className="mt-2.5 text-[13px] leading-relaxed text-slate-700 dark:text-slate-300">
271
+ {doc.summary}
272
+ </p>
273
+ {doc.description && (
274
+ <p className="mt-2 text-[12px] leading-relaxed text-slate-500 dark:text-slate-400">
275
+ {doc.description}
276
+ </p>
277
+ )}
263
278
  </div>
264
- )}
265
279
 
266
- {/* Notes */}
267
- {doc.notes && doc.notes.length > 0 && (
268
280
  <div>
269
- <h3 className="text-[10px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 mb-2">
270
- Notes
271
- </h3>
272
- <ul className="space-y-1">
273
- {doc.notes.map((note, i) => (
274
- <li key={i} className="text-[11px] text-slate-600 dark:text-slate-400 flex items-start gap-2">
275
- <span className="text-primary-500 mt-0.5 shrink-0">•</span>
276
- <span>{note}</span>
277
- </li>
281
+ <h2 className={EYEBROW}>{t("showcase.layout.props")}</h2>
282
+ <dl className={`mt-3 border-t ${FILETE}`}>
283
+ {doc.props.map((prop) => (
284
+ <div key={prop.name} className={`border-b py-3 ${FILETE}`}>
285
+ <dt className="flex flex-wrap items-baseline gap-x-2 font-mono text-[11px] font-semibold text-primary-700 dark:text-primary-500">
286
+ {prop.name}
287
+ {prop.required ? (
288
+ <span className="text-danger-500" title={t("showcase.common.required")}>
289
+ *
290
+ </span>
291
+ ) : null}
292
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
293
+ {prop.type}
294
+ </span>
295
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
296
+ {`= ${prop.default || "—"}`}
297
+ </span>
298
+ </dt>
299
+ <dd className="mt-1.5 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300">
300
+ {prop.description}
301
+ </dd>
302
+ </div>
278
303
  ))}
279
- </ul>
304
+ </dl>
280
305
  </div>
281
- )}
282
- </div>
283
- )}
306
+
307
+ {doc.examples && doc.examples.length > 0 && (
308
+ <div>
309
+ <h2 className={EYEBROW}>{t("showcase.layout.usageExamples")}</h2>
310
+ <div className="mt-3 space-y-2">
311
+ {doc.examples.map((example, i) => (
312
+ <pre
313
+ key={i}
314
+ className="overflow-x-auto rounded-[10px] border border-slate-800 bg-slate-950 p-3 font-mono text-[10px] leading-relaxed text-slate-200"
315
+ >
316
+ <code>{example}</code>
317
+ </pre>
318
+ ))}
319
+ </div>
320
+ </div>
321
+ )}
322
+
323
+ {doc.notes && doc.notes.length > 0 && (
324
+ <div>
325
+ <h2 className={EYEBROW}>{t("showcase.layout.notes")}</h2>
326
+ <ul className={`mt-3 border-t ${FILETE}`}>
327
+ {doc.notes.map((note, i) => (
328
+ <li
329
+ key={i}
330
+ className={`border-b py-2.5 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300 ${FILETE}`}
331
+ >
332
+ {note}
333
+ </li>
334
+ ))}
335
+ </ul>
336
+ </div>
337
+ )}
338
+ </div>
339
+ )}
340
+ </section>
284
341
  </div>
285
- </div>
342
+ </ITGrid>
343
+ )}
286
344
  </ITGrid>
287
- </ITGrid>
345
+ </div>
288
346
 
289
- {/* Gallery */}
347
+ {/* ─── GALERÍA ─── */}
290
348
  {gallery && (
291
- <div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-700 shadow-sm overflow-hidden">
292
- <div className="px-4 py-2 border-b border-slate-200 dark:border-slate-700">
293
- <span className="text-[10px] font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400">Variations & States (Gallery)</span>
294
- </div>
295
- <div className="p-4">
296
- {gallery}
297
- </div>
298
- </div>
349
+ <section className={`mt-12 border-t pt-8 ${FILETE}`} aria-label={t("showcase.layout.gallery")}>
350
+ <h2 className={EYEBROW}>{t("showcase.layout.gallery")}</h2>
351
+ <div className="mt-5">{gallery}</div>
352
+ </section>
299
353
  )}
300
354
  </div>
301
355
  );