@axzydev/axzy_ui_system 1.4.8 → 1.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.
Files changed (223) hide show
  1. package/README.md +2 -11
  2. package/dist/index.cjs +1826 -1351
  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 +115 -14
  7. package/dist/index.d.ts +115 -14
  8. package/dist/index.js +1481 -1010
  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.tsx +30 -28
  39. package/src/components/molecules/time-picker/timePicker.tsx +8 -6
  40. package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
  41. package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
  42. package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
  43. package/src/components/organisms/data-table/dataTable.tsx +31 -25
  44. package/src/components/organisms/dialog/dialog.tsx +3 -0
  45. package/src/components/organisms/drawer/drawer.tsx +3 -0
  46. package/src/components/organisms/dropfile/dropfile.tsx +19 -17
  47. package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
  48. package/src/components/organisms/navbar/navbar.tsx +4 -2
  49. package/src/components/organisms/page-header/page-header.tsx +3 -1
  50. package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
  51. package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
  52. package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
  53. package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
  54. package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
  55. package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
  56. package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
  57. package/src/components/organisms/searchTable/searchTable.tsx +4 -2
  58. package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
  59. package/src/components/organisms/sidebar/sidebar.tsx +9 -4
  60. package/src/components/organisms/toast/toast.tsx +3 -1
  61. package/src/components/organisms/topbar/topbar.tsx +4 -2
  62. package/src/components/templates/page/page.props.ts +4 -4
  63. package/src/components/templates/page/page.tsx +6 -4
  64. package/src/components/theme-provider/themeProvider.tsx +28 -17
  65. package/src/dev.css +61 -2
  66. package/src/global.d.ts +10 -0
  67. package/src/i18n/context.ts +9 -0
  68. package/src/i18n/index.ts +22 -0
  69. package/src/i18n/locales/en.ts +163 -0
  70. package/src/i18n/locales/es.ts +165 -0
  71. package/src/i18n/provider.tsx +44 -0
  72. package/src/i18n/translator.ts +82 -0
  73. package/src/i18n/types.ts +54 -0
  74. package/src/i18n/useITTranslation.ts +20 -0
  75. package/src/index.css +0 -1
  76. package/src/index.ts +7 -1
  77. package/src/sandbox/LandingShowcase.tsx +224 -580
  78. package/src/sandbox/NotFoundShowcase.tsx +51 -36
  79. package/src/sandbox/TopbarSearch.tsx +6 -4
  80. package/src/sandbox/controls.tsx +180 -0
  81. package/src/sandbox/i18n.ts +1939 -0
  82. package/src/sandbox/icons.tsx +25 -0
  83. package/src/sandbox/locale.tsx +72 -0
  84. package/src/sandbox/ui.tsx +474 -0
  85. package/src/sandbox/useHashRoute.ts +46 -10
  86. package/src/showcases/DataShowcases.tsx +103 -87
  87. package/src/showcases/FeedbackShowcases.tsx +37 -30
  88. package/src/showcases/FormShowcases.tsx +303 -215
  89. package/src/showcases/GettingStartedShowcase.tsx +151 -145
  90. package/src/showcases/HelpShowcase.tsx +126 -128
  91. package/src/showcases/HomeShowcase.tsx +678 -482
  92. package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
  93. package/src/showcases/NavigationShowcases.tsx +45 -37
  94. package/src/showcases/PageShowcases.tsx +171 -152
  95. package/src/showcases/ProductoDetalle.tsx +272 -129
  96. package/src/showcases/ShowcaseLayout.tsx +256 -219
  97. package/src/showcases/SizesShowcase.tsx +123 -64
  98. package/src/showcases/StructureShowcases.tsx +203 -138
  99. package/src/showcases/portfolioUi.tsx +153 -0
  100. package/src/showcases/techIcons.ts +3 -0
  101. package/src/utils/table.utils.ts +10 -2
  102. package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
  103. package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
  104. package/src/components/atoms/badget/badget.doc.mdx +0 -46
  105. package/src/components/atoms/badget/badget.stories.tsx +0 -75
  106. package/src/components/atoms/button/button.doc.mdx +0 -59
  107. package/src/components/atoms/button/button.stories.tsx +0 -173
  108. package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
  109. package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
  110. package/src/components/atoms/chip/chip.doc.mdx +0 -47
  111. package/src/components/atoms/chip/chip.stories.tsx +0 -64
  112. package/src/components/atoms/divider/divider.doc.mdx +0 -42
  113. package/src/components/atoms/divider/divider.stories.tsx +0 -33
  114. package/src/components/atoms/flex/flex.doc.mdx +0 -59
  115. package/src/components/atoms/flex/flex.stories.tsx +0 -70
  116. package/src/components/atoms/grid/grid.doc.mdx +0 -54
  117. package/src/components/atoms/grid/grid.stories.tsx +0 -71
  118. package/src/components/atoms/image/image.doc.mdx +0 -44
  119. package/src/components/atoms/image/image.stories.tsx +0 -48
  120. package/src/components/atoms/input/input.doc.mdx +0 -70
  121. package/src/components/atoms/input/input.stories.tsx +0 -113
  122. package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
  123. package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
  124. package/src/components/atoms/loader/loader.doc.mdx +0 -43
  125. package/src/components/atoms/loader/loader.stories.tsx +0 -104
  126. package/src/components/atoms/popover/popover.doc.mdx +0 -53
  127. package/src/components/atoms/popover/popover.stories.tsx +0 -24
  128. package/src/components/atoms/progress/progress.doc.mdx +0 -48
  129. package/src/components/atoms/progress/progress.stories.tsx +0 -39
  130. package/src/components/atoms/radio/radio.doc.mdx +0 -62
  131. package/src/components/atoms/radio/radio.stories.tsx +0 -48
  132. package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
  133. package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
  134. package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
  135. package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
  136. package/src/components/atoms/slide/slide.doc.mdx +0 -46
  137. package/src/components/atoms/slide/slide.stories.tsx +0 -120
  138. package/src/components/atoms/slider/slider.doc.mdx +0 -49
  139. package/src/components/atoms/slider/slider.stories.tsx +0 -29
  140. package/src/components/atoms/stack/stack.doc.mdx +0 -126
  141. package/src/components/atoms/stack/stack.stories.tsx +0 -283
  142. package/src/components/atoms/text/text.doc.mdx +0 -41
  143. package/src/components/atoms/text/text.stories.tsx +0 -66
  144. package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
  145. package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
  146. package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
  147. package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
  148. package/src/components/isolation/isolation.stories.tsx +0 -202
  149. package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
  150. package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
  151. package/src/components/molecules/alert/alert.doc.mdx +0 -48
  152. package/src/components/molecules/alert/alert.stories.tsx +0 -40
  153. package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
  154. package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
  155. package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
  156. package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
  157. package/src/components/molecules/card/card.doc.mdx +0 -54
  158. package/src/components/molecules/card/card.stories.tsx +0 -57
  159. package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
  160. package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
  161. package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
  162. package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
  163. package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
  164. package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
  165. package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
  166. package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
  167. package/src/components/molecules/field/field.doc.mdx +0 -43
  168. package/src/components/molecules/field/field.stories.tsx +0 -42
  169. package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
  170. package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
  171. package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
  172. package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
  173. package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
  174. package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
  175. package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
  176. package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
  177. package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
  178. package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
  179. package/src/components/molecules/select/select.doc.mdx +0 -75
  180. package/src/components/molecules/select/select.stories.tsx +0 -85
  181. package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
  182. package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
  183. package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
  184. package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
  185. package/src/components/molecules/table/table.doc.mdx +0 -140
  186. package/src/components/molecules/table/table.stories.tsx +0 -402
  187. package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
  188. package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
  189. package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
  190. package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
  191. package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
  192. package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
  193. package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
  194. package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -132
  195. package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
  196. package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
  197. package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
  198. package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
  199. package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
  200. package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
  201. package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
  202. package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
  203. package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
  204. package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
  205. package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
  206. package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
  207. package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
  208. package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
  209. package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
  210. package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
  211. package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
  212. package/src/components/organisms/toast/toast.doc.mdx +0 -50
  213. package/src/components/organisms/toast/toast.stories.tsx +0 -137
  214. package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
  215. package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
  216. package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
  217. package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
  218. package/src/components/templates/layout/layout.doc.mdx +0 -53
  219. package/src/components/templates/layout/layout.stories.tsx +0 -113
  220. package/src/components/templates/page/page.doc.mdx +0 -86
  221. package/src/components/templates/page/page.stories.tsx +0 -97
  222. package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
  223. package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
@@ -1,62 +1,140 @@
1
+ /**
2
+ * Marco de las páginas de componente del sandbox (`#ui-system/<grupo>/<item>`).
3
+ *
4
+ * Diseño «documentación viva»: cada ejemplo es un **contenedor con cabecera
5
+ * propia** (número, título y la acción de ver el código siempre a la vista), el
6
+ * código se despliega dentro del mismo contenedor, los controles viven en un
7
+ * grid compacto bajo el demo y la API (props, ejemplos, notas) está **siempre
8
+ * visible** en la columna derecha, sin pestañas.
9
+ *
10
+ * Sigue `DESIGN.md` (AXZY Console): filetes de 1px, mono para metadatos y un
11
+ * solo acento.
12
+ */
13
+
1
14
  import React, { useState } from "react";
2
- import { FaCheck, FaCopy, FaBookOpen, FaCog, FaCode, FaEye } from "react-icons/fa";
15
+ import { FaBookOpen, FaCheck, FaCode, FaCopy, FaEye } from "react-icons/fa";
3
16
  import ITGrid from "../components/atoms/grid/grid";
4
17
  import { useITTheme } from "../components/theme-provider/themeProvider";
18
+ import { ControlSegmentado } from "@/sandbox/controls";
19
+ import {
20
+ BotonCopiar,
21
+ EYEBROW,
22
+ EjemploContenedor,
23
+ FILETE,
24
+ FOCO_CTA,
25
+ } from "@/sandbox/ui";
26
+ import { useITTranslation } from "@/i18n";
5
27
 
28
+ /**
29
+ * Bloque de código con botón de copiar. Fondo tinta, mono y el acento de señal
30
+ * (`cyan-400`) reservado a la etiqueta, como manda el spec.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <CodeViewer code={`<ITButton>Guardar</ITButton>`} compact />
35
+ * ```
36
+ */
6
37
  export const CodeViewer: React.FC<{ code: string; compact?: boolean }> = ({ code, compact }) => {
38
+ const { t } = useITTranslation();
7
39
  const [copied, setCopied] = useState(false);
40
+
8
41
  const handleCopy = () => {
9
- navigator.clipboard.writeText(code);
42
+ navigator.clipboard?.writeText(code);
10
43
  setCopied(true);
11
- setTimeout(() => setCopied(false), 2000);
44
+ window.setTimeout(() => setCopied(false), 2000);
12
45
  };
46
+
13
47
  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>
48
+ <div className="relative overflow-hidden rounded-[10px] border border-slate-800 bg-slate-950 text-slate-200">
49
+ <div className="flex items-center justify-between border-b border-slate-800 px-4 py-2.5">
50
+ <span className="font-mono text-[10px] uppercase tracking-[0.14em] text-cyan-400">
51
+ {t("showcase.layout.jsxCode")}
52
+ </span>
17
53
  <button
54
+ type="button"
18
55
  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"
56
+ 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
57
  >
21
- {copied ? <FaCheck size={11} className="text-emerald-500" /> : <FaCopy size={11} />}
22
- <span>{copied ? "Copied!" : "Copy"}</span>
58
+ {copied ? <FaCheck size={11} className="text-cyan-400" /> : <FaCopy size={11} />}
59
+ <span>{copied ? t("showcase.layout.copied") : t("showcase.layout.copy")}</span>
23
60
  </button>
24
61
  </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`}>
62
+ <pre
63
+ tabIndex={0}
64
+ className={`overflow-x-auto whitespace-pre-wrap p-4 font-mono text-xs leading-relaxed ${
65
+ compact ? "max-h-[420px]" : ""
66
+ } overflow-y-auto`}
67
+ >
26
68
  <code>{code}</code>
27
69
  </pre>
28
70
  </div>
29
71
  );
30
72
  };
31
73
 
74
+ /** Una fila de la tabla de props. */
32
75
  export interface PropDocEntry {
76
+ /** Nombre del prop. */
33
77
  name: string;
78
+ /** Tipo TypeScript. */
34
79
  type: string;
80
+ /** Valor por defecto. */
35
81
  default?: string;
82
+ /** Descripción para el panel de documentación. */
36
83
  description: string;
84
+ /** Marca el prop como obligatorio. */
37
85
  required?: boolean;
38
86
  }
39
87
 
88
+ /** Documentación de un componente, si el showcase la declara. */
40
89
  export interface ComponentDoc {
90
+ /** Resumen de una línea. */
41
91
  summary: string;
92
+ /** Descripción larga opcional. */
42
93
  description?: string;
94
+ /** Ejemplos de uso (código). */
43
95
  examples?: string[];
96
+ /** Tabla de props. */
44
97
  props: PropDocEntry[];
98
+ /** Notas al pie. */
45
99
  notes?: string[];
46
100
  }
47
101
 
102
+ /** Props de `ShowcaseLayout`. */
48
103
  export interface ShowcaseLayoutProps {
104
+ /** Nombre del componente. */
49
105
  title: string;
106
+ /** Descripción corta bajo el título. */
50
107
  description: string;
108
+ /** Demo interactiva. */
51
109
  demo: React.ReactNode;
52
- controls: React.ReactNode;
110
+ /** Controles del ejemplo (lo construye cada showcase). */
111
+ controls?: React.ReactNode;
112
+ /** Código fuente del ejemplo principal. */
53
113
  code: string;
114
+ /** Galería de variaciones y estados. */
54
115
  gallery?: React.ReactNode;
116
+ /** Documentación opcional (columna derecha). */
55
117
  doc?: ComponentDoc;
118
+ /**
119
+ * Ancho mínimo (px) del demo dentro de la vitrina. Los demos que son un layout
120
+ * entero (`ITLayout`, pantallas de ejemplo) lo necesitan: por debajo de ~780px
121
+ * su propio contenido se recorta. La vitrina desplaza en horizontal lo que
122
+ * sobre.
123
+ * @default 0
124
+ */
125
+ demoMinAncho?: number;
56
126
  }
57
127
 
58
- type SandboxView = "preview" | "code";
59
-
128
+ /**
129
+ * Página de un componente del sandbox: cabecera, ejemplo principal con su código,
130
+ * controles en grid, API en la columna derecha y galería de variaciones.
131
+ *
132
+ * @example
133
+ * ```tsx
134
+ * <ShowcaseLayout title="ITButton" description="…" demo={<ITButton>Guardar</ITButton>}
135
+ * controls={<ITSelect … />} code={code} gallery={<Gallery />} doc={doc} />
136
+ * ```
137
+ */
60
138
  export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
61
139
  title,
62
140
  description,
@@ -64,238 +142,197 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
64
142
  controls,
65
143
  code,
66
144
  gallery,
67
- doc
145
+ doc,
146
+ demoMinAncho = 0,
68
147
  }) => {
148
+ const { t } = useITTranslation();
69
149
  const { resolvedTheme } = useITTheme();
70
- const [activeTab, setActiveTab] = useState<"controls" | "docs">("controls");
71
- 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>
150
+ const [sandboxView, setSandboxView] = useState<"preview" | "code">("preview");
82
151
 
152
+ const hayApi = Boolean(doc);
83
153
 
84
- </div>
85
-
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>
100
- </div>
101
-
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
- }`}
122
- >
123
- <FaCode size={10} />
124
- Code
125
- </button>
126
- </div>
127
- </div>
154
+ return (
155
+ <div className="animate-fadeIn pb-4">
156
+ {/* ─── CABECERA ─── */}
157
+ <header className={`border-b pb-6 ${FILETE}`}>
158
+ <p className={EYEBROW}>{t("showcase.layout.eyebrow")}</p>
159
+ <h1 className="mt-2.5 font-display text-[32px] font-bold tracking-[-0.02em] text-slate-900 dark:text-white sm:text-[40px]">
160
+ {title}
161
+ </h1>
162
+ <p className="mt-3 max-w-[70ch] text-[15px] leading-relaxed text-slate-600 dark:text-slate-300">
163
+ {description}
164
+ </p>
165
+ </header>
128
166
 
129
- {/* Sandbox content */}
130
- {sandboxView === "preview" ? (
167
+ <div className="pt-6">
168
+ <ITGrid container columns={12} spacing={8}>
169
+ {/* ── EJEMPLO PRINCIPAL + CONTROLES ── */}
170
+ <ITGrid item xs={12} md={hayApi ? 8 : 12}>
171
+ <EjemploContenedor
172
+ numero="01"
173
+ titulo={t("showcase.layout.sandbox")}
174
+ nota={doc?.summary}
175
+ sangrado
176
+ >
177
+ {/* Barra del ejemplo: vista previa / código, siempre visible */}
131
178
  <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"
179
+ className={`flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 ${FILETE}`}
134
180
  >
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 />
181
+ <span className={EYEBROW}>{t("showcase.layout.preview")}</span>
182
+ <ControlSegmentado
183
+ etiqueta={t("showcase.layout.sandbox")}
184
+ valor={sandboxView}
185
+ onChange={(value) => setSandboxView(value === "code" ? "code" : "preview")}
186
+ opciones={[
187
+ {
188
+ value: "preview",
189
+ label: t("showcase.layout.preview"),
190
+ icono: <FaEye size={10} />,
191
+ },
192
+ { value: "code", label: t("showcase.layout.code"), icono: <FaCode size={10} /> },
193
+ ]}
194
+ />
140
195
  </div>
141
- )}
142
- </div>
143
- </ITGrid>
144
196
 
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
- }`}
197
+ {sandboxView === "preview" ? (
198
+ <div
199
+ data-theme={resolvedTheme}
200
+ tabIndex={0}
201
+ className="flex min-h-[220px] items-center justify-center overflow-x-auto bg-white p-6 dark:bg-slate-950 md:p-8"
202
+ >
203
+ <div
204
+ className="flex w-full justify-center"
205
+ style={demoMinAncho ? { minWidth: `${demoMinAncho}px` } : undefined}
170
206
  >
171
- <FaBookOpen size={11} />
172
- Docs
173
- </button>
207
+ {demo}
208
+ </div>
174
209
  </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>
210
+ ) : (
211
+ <div className="p-4">
212
+ <CodeViewer code={code} compact />
181
213
  </div>
182
214
  )}
215
+ </EjemploContenedor>
183
216
 
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">
217
+ {controls && (
218
+ <section className={`mt-6 overflow-hidden rounded-[10px] border ${FILETE}`}>
219
+ <header
220
+ className={`flex items-center justify-between gap-3 border-b bg-slate-50/70 px-4 py-2.5 dark:bg-slate-950/40 ${FILETE}`}
221
+ >
222
+ <h2 className={EYEBROW}>{t("showcase.layout.controls")}</h2>
223
+ </header>
224
+ <div className="grid gap-4 p-4 sm:grid-cols-2 xl:grid-cols-3">{controls}</div>
225
+ </section>
226
+ )}
227
+ </ITGrid>
228
+
229
+ {/* ── API (siempre visible, sin pestañas) ── */}
230
+ {hayApi && (
231
+ <ITGrid item xs={12} md={4}>
232
+ <div className="md:sticky md:top-4">
233
+ <section className={`overflow-hidden rounded-[10px] border ${FILETE}`}>
234
+ <header
235
+ className={`flex items-center gap-2 border-b bg-slate-50/70 px-4 py-2.5 dark:bg-slate-950/40 ${FILETE}`}
236
+ >
237
+ <FaBookOpen size={11} className="text-primary-700 dark:text-primary-500" />
238
+ <h2 className={EYEBROW}>{t("showcase.layout.api")}</h2>
239
+ </header>
240
+
241
+ <div tabIndex={0} className="max-h-[calc(100vh-220px)] space-y-6 overflow-y-auto p-4">
242
+ {doc?.description && (
243
+ <p className="text-[12.5px] leading-relaxed text-slate-600 dark:text-slate-300">
197
244
  {doc.description}
198
245
  </p>
199
246
  )}
200
- </div>
201
247
 
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">
248
+ {!!doc?.props.length && (
249
+ <div>
250
+ <h3 className={EYEBROW}>{t("showcase.layout.props")}</h3>
251
+ <dl className={`mt-2.5 border-t ${FILETE}`}>
252
+ {doc.props.map((prop) => (
253
+ <div key={prop.name} className={`border-b py-2.5 ${FILETE}`}>
254
+ <dt className="flex flex-wrap items-baseline gap-x-2 font-mono text-[11px] font-semibold text-primary-700 dark:text-primary-500">
225
255
  {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>
256
+ {prop.required ? (
257
+ <span
258
+ className="text-danger-500"
259
+ title={t("showcase.common.required")}
260
+ >
261
+ *
262
+ </span>
263
+ ) : null}
264
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
265
+ {prop.type}
266
+ </span>
267
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
268
+ {`= ${prop.default || "—"}`}
269
+ </span>
270
+ </dt>
271
+ <dd className="mt-1 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300">
272
+ {prop.description}
273
+ </dd>
274
+ </div>
235
275
  ))}
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>
248
- </div>
276
+ </dl>
277
+ </div>
278
+ )}
249
279
 
250
- {/* Usage Examples */}
251
- {doc.examples && doc.examples.length > 0 && (
252
- <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>
280
+ {doc?.examples && doc.examples.length > 0 && (
281
+ <div>
282
+ <h3 className={EYEBROW}>{t("showcase.layout.usageExamples")}</h3>
283
+ <div className="mt-2.5 space-y-2">
284
+ {doc.examples.map((example, i) => (
285
+ <div key={i} className="relative">
286
+ <pre tabIndex={0} className="overflow-x-auto rounded-[10px] border border-slate-800 bg-slate-950 p-3 pr-10 font-mono text-[10px] leading-relaxed text-slate-200">
287
+ <code>{example}</code>
288
+ </pre>
289
+ <span className="absolute right-1.5 top-1.5">
290
+ <BotonCopiar
291
+ texto={example}
292
+ className="text-slate-500 hover:bg-slate-800 hover:text-white dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-white"
293
+ />
294
+ </span>
295
+ </div>
296
+ ))}
261
297
  </div>
262
- ))}
263
- </div>
264
- )}
298
+ </div>
299
+ )}
265
300
 
266
- {/* Notes */}
267
- {doc.notes && doc.notes.length > 0 && (
268
- <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>
278
- ))}
279
- </ul>
280
- </div>
281
- )}
282
- </div>
283
- )}
284
- </div>
285
- </div>
301
+ {doc?.notes && doc.notes.length > 0 && (
302
+ <div>
303
+ <h3 className={EYEBROW}>{t("showcase.layout.notes")}</h3>
304
+ <ul className={`mt-2.5 border-t ${FILETE}`}>
305
+ {doc.notes.map((note, i) => (
306
+ <li
307
+ key={i}
308
+ className={`border-b py-2 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300 ${FILETE}`}
309
+ >
310
+ {note}
311
+ </li>
312
+ ))}
313
+ </ul>
314
+ </div>
315
+ )}
316
+ </div>
317
+ </section>
318
+ </div>
319
+ </ITGrid>
320
+ )}
286
321
  </ITGrid>
287
- </ITGrid>
322
+ </div>
288
323
 
289
- {/* Gallery */}
324
+ {/* ─── MÁS EJEMPLOS ─── */}
290
325
  {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>
326
+ <section
327
+ className={`mt-12 border-t pt-8 ${FILETE}`}
328
+ aria-label={t("showcase.layout.gallery")}
329
+ >
330
+ <p className={EYEBROW}>{t("showcase.layout.gallery")}</p>
331
+ <h2 className="mt-2 font-display text-[22px] font-bold tracking-[-0.02em] text-slate-900 dark:text-white">
332
+ {t("showcase.layout.galleryTitle")}
333
+ </h2>
334
+ <div className="mt-6 space-y-6">{gallery}</div>
335
+ </section>
299
336
  )}
300
337
  </div>
301
338
  );