siesa-ui-kit 1.0.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 (198) hide show
  1. package/README.md +89 -0
  2. package/bin/install.cjs +502 -0
  3. package/bin/prepare-publish.cjs +28 -0
  4. package/bin/restore-folders.cjs +28 -0
  5. package/claude/agents/siesa-ui-kit-specialist.md +2401 -0
  6. package/claude/prompts/component-template.md +121 -0
  7. package/claude/settings.local.json +61 -0
  8. package/docs/border-radius.md +1261 -0
  9. package/docs/colors.md +832 -0
  10. package/docs/dark-mode-guide.md +1426 -0
  11. package/docs/filters.md +1243 -0
  12. package/docs/icons.md +1283 -0
  13. package/docs/shadows.md +1377 -0
  14. package/docs/spacing.md +1684 -0
  15. package/docs/typography.md +1268 -0
  16. package/package.json +83 -0
  17. package/postcss.config.cjs +6 -0
  18. package/public/,Business Logo.png +0 -0
  19. package/public/.Siesa Logo.png +0 -0
  20. package/public/bg_siesa.png +0 -0
  21. package/public/siesa_logo_mobile.png +0 -0
  22. package/public/vite.svg +1 -0
  23. package/src/App.css +42 -0
  24. package/src/App.tsx +8 -0
  25. package/src/ButtonTest.tsx +147 -0
  26. package/src/assets/fonts/README.md +261 -0
  27. package/src/assets/fonts/SiesaBT/SiesaBT-Bold.otf +0 -0
  28. package/src/assets/fonts/SiesaBT/SiesaBT-Light.otf +0 -0
  29. package/src/assets/fonts/SiesaBT/SiesaBT-Regular.otf +0 -0
  30. package/src/assets/react.svg +1 -0
  31. package/src/components/Alert/Alert.stories.tsx +332 -0
  32. package/src/components/Alert/Alert.tsx +106 -0
  33. package/src/components/Alert/Alert.types.ts +54 -0
  34. package/src/components/Avatar/Avatar.stories.tsx +494 -0
  35. package/src/components/Avatar/Avatar.tsx +143 -0
  36. package/src/components/Avatar/Avatar.types.ts +53 -0
  37. package/src/components/Badge/Badge.stories.tsx +339 -0
  38. package/src/components/Badge/Badge.tsx +278 -0
  39. package/src/components/Badge/Badge.types.ts +58 -0
  40. package/src/components/Button/Button.stories.tsx +950 -0
  41. package/src/components/Button/Button.tsx +337 -0
  42. package/src/components/Button/Button.types.ts +180 -0
  43. package/src/components/Button/icons.tsx +87 -0
  44. package/src/components/Button/index.ts +3 -0
  45. package/src/components/Checkbox/Checkbox.stories.tsx +453 -0
  46. package/src/components/Checkbox/Checkbox.tsx +208 -0
  47. package/src/components/Checkbox/Checkbox.types.ts +61 -0
  48. package/src/components/DescriptionList/DescriptionList.stories.tsx +250 -0
  49. package/src/components/DescriptionList/DescriptionList.tsx +96 -0
  50. package/src/components/DescriptionList/DescriptionList.types.ts +29 -0
  51. package/src/components/Divider/Divider.stories.tsx +263 -0
  52. package/src/components/Divider/Divider.tsx +80 -0
  53. package/src/components/Divider/Divider.types.ts +24 -0
  54. package/src/components/Dropdown/Dropdown.stories.tsx +552 -0
  55. package/src/components/Dropdown/Dropdown.tsx +422 -0
  56. package/src/components/Dropdown/Dropdown.types.ts +146 -0
  57. package/src/components/Dropdown/README.md +266 -0
  58. package/src/components/Dropdown/icons.tsx +72 -0
  59. package/src/components/Dropdown/index.ts +8 -0
  60. package/src/components/Input/Input.stories.tsx +583 -0
  61. package/src/components/Input/Input.tsx +204 -0
  62. package/src/components/Input/Input.types.ts +80 -0
  63. package/src/components/Input/icons.tsx +145 -0
  64. package/src/components/Input/index.ts +2 -0
  65. package/src/components/LoginView/LoginView.stories.tsx +148 -0
  66. package/src/components/LoginView/LoginView.tsx +426 -0
  67. package/src/components/LoginView/LoginView.types.ts +52 -0
  68. package/src/components/LoginView/README.md +396 -0
  69. package/src/components/LoginView/icons.tsx +85 -0
  70. package/src/components/LoginView/index.ts +3 -0
  71. package/src/components/Navbar/Navbar.stories.tsx +810 -0
  72. package/src/components/Navbar/Navbar.tsx +755 -0
  73. package/src/components/Navbar/Navbar.types.ts +219 -0
  74. package/src/components/Navbar/README.md +279 -0
  75. package/src/components/Navbar/icons.tsx +102 -0
  76. package/src/components/Navbar/index.ts +8 -0
  77. package/src/components/NavigationBar/NavigationBar.stories.tsx +406 -0
  78. package/src/components/NavigationBar/NavigationBar.tsx +246 -0
  79. package/src/components/NavigationBar/NavigationBar.types.ts +74 -0
  80. package/src/components/NavigationBar/README.md +469 -0
  81. package/src/components/NavigationBar/index.ts +2 -0
  82. package/src/components/NavigationRail/NavigationRail.stories.tsx +417 -0
  83. package/src/components/NavigationRail/NavigationRail.tsx +418 -0
  84. package/src/components/NavigationRail/NavigationRail.types.ts +109 -0
  85. package/src/components/NavigationRail/README.md +224 -0
  86. package/src/components/NavigationRail/index.ts +2 -0
  87. package/src/components/Notification/Notification.stories.tsx +513 -0
  88. package/src/components/Notification/Notification.tsx +145 -0
  89. package/src/components/Notification/Notification.types.ts +142 -0
  90. package/src/components/Notification/README.md +409 -0
  91. package/src/components/Notification/index.ts +3 -0
  92. package/src/components/POSConvention/POSConvention.stories.tsx +235 -0
  93. package/src/components/POSConvention/POSConvention.tsx +129 -0
  94. package/src/components/POSConvention/POSConvention.types.ts +38 -0
  95. package/src/components/POSConvention/README.md +123 -0
  96. package/src/components/POSConvention/icons.tsx +45 -0
  97. package/src/components/POSConvention/index.ts +3 -0
  98. package/src/components/POSLocationButton/POSLocationButton.stories.tsx +531 -0
  99. package/src/components/POSLocationButton/POSLocationButton.tsx +247 -0
  100. package/src/components/POSLocationButton/POSLocationButton.types.ts +87 -0
  101. package/src/components/POSLocationButton/README.md +253 -0
  102. package/src/components/POSLocationButton/icons.tsx +120 -0
  103. package/src/components/POSLocationButton/index.ts +14 -0
  104. package/src/components/POSNumberButton/POSNumberButton.stories.tsx +415 -0
  105. package/src/components/POSNumberButton/POSNumberButton.tsx +179 -0
  106. package/src/components/POSNumberButton/POSNumberButton.types.ts +51 -0
  107. package/src/components/POSNumberButton/README.md +321 -0
  108. package/src/components/POSNumberButton/index.ts +3 -0
  109. package/src/components/POSProductButton/POSProductButton.stories.tsx +318 -0
  110. package/src/components/POSProductButton/POSProductButton.tsx +152 -0
  111. package/src/components/POSProductButton/POSProductButton.types.ts +46 -0
  112. package/src/components/POSProductButton/README.md +269 -0
  113. package/src/components/POSProductButton/index.ts +2 -0
  114. package/src/components/POSProductCard/POSProductCard.stories.tsx +642 -0
  115. package/src/components/POSProductCard/POSProductCard.tsx +208 -0
  116. package/src/components/POSProductCard/POSProductCard.types.ts +76 -0
  117. package/src/components/POSProductCard/README.md +179 -0
  118. package/src/components/POSProductCard/icons.tsx +26 -0
  119. package/src/components/POSProductCard/index.ts +2 -0
  120. package/src/components/POSProductSidebarItems/POSProductSidebarItems.stories.tsx +753 -0
  121. package/src/components/POSProductSidebarItems/POSProductSidebarItems.tsx +332 -0
  122. package/src/components/POSProductSidebarItems/POSProductSidebarItems.types.ts +119 -0
  123. package/src/components/POSProductSidebarItems/README.md +198 -0
  124. package/src/components/POSProductSidebarItems/icons.tsx +21 -0
  125. package/src/components/POSProductSidebarItems/index.ts +3 -0
  126. package/src/components/POSTable/POSTable.stories.tsx +737 -0
  127. package/src/components/POSTable/POSTable.tsx +401 -0
  128. package/src/components/POSTable/POSTable.types.ts +83 -0
  129. package/src/components/POSTable/README.md +286 -0
  130. package/src/components/POSTable/index.ts +7 -0
  131. package/src/components/Pagination/Pagination.stories.tsx +555 -0
  132. package/src/components/Pagination/Pagination.tsx +286 -0
  133. package/src/components/Pagination/Pagination.types.ts +93 -0
  134. package/src/components/Pagination/README.md +298 -0
  135. package/src/components/Pagination/icons.tsx +47 -0
  136. package/src/components/Pagination/index.ts +3 -0
  137. package/src/components/Quantity/Quantity.stories.tsx +457 -0
  138. package/src/components/Quantity/Quantity.tsx +289 -0
  139. package/src/components/Quantity/Quantity.types.ts +70 -0
  140. package/src/components/Radio/Radio.stories.tsx +523 -0
  141. package/src/components/Radio/Radio.tsx +170 -0
  142. package/src/components/Radio/Radio.types.ts +122 -0
  143. package/src/components/Select/README.md +299 -0
  144. package/src/components/Select/Select.stories.tsx +673 -0
  145. package/src/components/Select/Select.tsx +454 -0
  146. package/src/components/Select/Select.types.ts +148 -0
  147. package/src/components/Select/icons.tsx +50 -0
  148. package/src/components/Select/index.ts +3 -0
  149. package/src/components/SignUpView/SignUpView.stories.tsx +129 -0
  150. package/src/components/SignUpView/SignUpView.tsx +503 -0
  151. package/src/components/SignUpView/SignUpView.types.ts +58 -0
  152. package/src/components/SignUpView/icons.tsx +71 -0
  153. package/src/components/SignUpView/index.ts +3 -0
  154. package/src/components/Switch/README.md +112 -0
  155. package/src/components/Switch/Switch.stories.tsx +550 -0
  156. package/src/components/Switch/Switch.tsx +246 -0
  157. package/src/components/Switch/Switch.types.ts +67 -0
  158. package/src/components/Table/README.md +369 -0
  159. package/src/components/Table/Table.stories.tsx +805 -0
  160. package/src/components/Table/Table.tsx +688 -0
  161. package/src/components/Table/Table.types.ts +204 -0
  162. package/src/components/Table/index.ts +9 -0
  163. package/src/components/Tabs/README.md +201 -0
  164. package/src/components/Tabs/Tabs.stories.tsx +580 -0
  165. package/src/components/Tabs/Tabs.tsx +356 -0
  166. package/src/components/Tabs/Tabs.types.ts +127 -0
  167. package/src/components/Tabs/icons.tsx +129 -0
  168. package/src/components/Tabs/index.ts +11 -0
  169. package/src/components/Textarea/Textarea.stories.tsx +535 -0
  170. package/src/components/Textarea/Textarea.tsx +188 -0
  171. package/src/components/Textarea/Textarea.types.ts +54 -0
  172. package/src/context/ThemeContext.tsx +99 -0
  173. package/src/context/index.ts +1 -0
  174. package/src/index.css +29 -0
  175. package/src/index.ts +39 -0
  176. package/src/main.tsx +10 -0
  177. package/src/views/ProductsView/ProductsView.stories.tsx +344 -0
  178. package/src/views/ProductsView/ProductsView.tsx +480 -0
  179. package/src/views/ProductsView/ProductsView.types.ts +238 -0
  180. package/src/views/ProductsView/README.md +312 -0
  181. package/src/views/ProductsView/icons.tsx +38 -0
  182. package/src/views/ProductsView/index.ts +8 -0
  183. package/src/views/RecoverPasswordView/README.md +269 -0
  184. package/src/views/RecoverPasswordView/RecoverPasswordView.stories.tsx +131 -0
  185. package/src/views/RecoverPasswordView/RecoverPasswordView.tsx +376 -0
  186. package/src/views/RecoverPasswordView/RecoverPasswordView.types.ts +56 -0
  187. package/src/views/RecoverPasswordView/icons.tsx +17 -0
  188. package/src/views/RecoverPasswordView/index.ts +2 -0
  189. package/src/views/TableLayoutView/README.md +268 -0
  190. package/src/views/TableLayoutView/TableLayoutView.stories.tsx +235 -0
  191. package/src/views/TableLayoutView/TableLayoutView.tsx +461 -0
  192. package/src/views/TableLayoutView/TableLayoutView.types.ts +209 -0
  193. package/src/views/TableLayoutView/icons.tsx +113 -0
  194. package/src/views/TableLayoutView/index.ts +6 -0
  195. package/storybook/main.ts +20 -0
  196. package/storybook/preview.tsx +84 -0
  197. package/storybook/vitest.setup.ts +7 -0
  198. package/tailwind.config.js +128 -0
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # 🎨 Siesa UI Kit
2
+
3
+ Sistema de componentes de interfaz moderno con React, TypeScript y Tailwind CSS. Construido con un sistema de diseño completo que incluye dark mode, tokens consistentes y documentación interactiva.
4
+
5
+ ## 🚀 Inicio Rápido
6
+
7
+ ```bash
8
+ # Instalar dependencias
9
+ npm install
10
+
11
+ # Iniciar Storybook (documentación interactiva)
12
+ npm run storybook
13
+
14
+ # Construir para producción
15
+ npm run build
16
+
17
+ # Construir Storybook para producción
18
+ npm run build-storybook
19
+ ```
20
+
21
+ ## 🛠️ Tecnologías
22
+
23
+ - **React 19** - Framework UI
24
+ - **TypeScript 5** - Tipado estático
25
+ - **Tailwind CSS 3.4** - Sistema de estilos
26
+ - **Storybook 10** - Documentación de componentes
27
+ - **Vite 7** - Build tool
28
+
29
+ ## 📖 Storybook
30
+
31
+ Este proyecto utiliza **Storybook** como herramienta principal para:
32
+
33
+ - 📦 Desarrollar componentes de forma aislada
34
+ - 🎨 Visualizar todos los estados y variantes
35
+ - 📝 Documentar props y ejemplos de uso
36
+ - 🧪 Probar componentes interactivamente
37
+ - 🌓 Verificar dark mode y accesibilidad
38
+
39
+ Accede a Storybook ejecutando `npm run storybook` y abriendo http://localhost:6006
40
+
41
+ ## 🤖 Desarrollo con IA
42
+
43
+ Este proyecto fue construido utilizando **Claude (Sonnet 4.5)** con un agente especializado:
44
+
45
+ ### Agente Especializado
46
+ - **Ubicación**: `.claude/agents/siesa-ui-kit-specialist.md`
47
+ - **Propósito**: Crear y mantener componentes siguiendo el sistema de diseño
48
+ - **Características**:
49
+ - Extrae specs de Figma automáticamente
50
+ - Aplica tokens del sistema consistentemente
51
+ - Garantiza dark mode completo
52
+ - Genera documentación y Storybook stories
53
+
54
+ ### Prompts Templates
55
+ Ubicados en `.claude/prompts/component-template.md`:
56
+
57
+ 1. **Crear Componente Nuevo** - Genera componente completo desde cero
58
+ 2. **Corregir Componente Existente** - Actualiza componentes con mejoras
59
+ 3. **Crear Vista Completa** - Compone páginas usando componentes del sistema
60
+
61
+ Cada template incluye un checklist obligatorio que garantiza:
62
+ - ✅ Todos los archivos necesarios (.tsx, .types.ts, .stories.tsx, README.md)
63
+ - ✅ JSDoc completo con referencias
64
+ - ✅ Dark mode en todos los estados
65
+ - ✅ Focus rings adaptativos
66
+ - ✅ Tokens del sistema (sin colores hardcodeados)
67
+ - ✅ Build sin errores
68
+ - ✅ Stories con ejemplos completos
69
+
70
+ ## 📚 Documentación del Sistema
71
+
72
+ En la carpeta `docs/` encontrarás guías detalladas sobre:
73
+
74
+ - `colors.md` - Paleta de colores y tokens
75
+ - `typography.md` - Sistema tipográfico
76
+ - `spacing.md` - Escala de espaciado
77
+ - `shadows.md` - Elevaciones y sombras
78
+ - `dark-mode-guide.md` - Implementación de dark mode
79
+ - `icons.md` - Sistema de íconos
80
+ - `filters.md` - Filtros y efectos
81
+ - `border-radius.md` - Bordes redondeados
82
+
83
+ ## 🎨 Diseño
84
+
85
+ - [Figma Design System](https://www.figma.com/design/5XNqf2YTxvwemxwo1LMQ6j/Siesa-UI-Kit)
86
+
87
+ ---
88
+
89
+ © 2025 Siesa
@@ -0,0 +1,502 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const readline = require('readline');
6
+
7
+ class SiesaUIKitInstaller {
8
+ constructor() {
9
+ // Definir las carpetas primero (nombres en el paquete vs nombres finales)
10
+ this.folderMappings = [
11
+ { source: 'claude', target: '.claude' },
12
+ { source: 'storybook', target: '.storybook' },
13
+ { source: 'docs', target: 'docs' },
14
+ { source: 'src', target: 'src' },
15
+ { source: 'public', target: 'public' }
16
+ ];
17
+
18
+ // Lista de archivos que se preservan automáticamente (no se crean backups)
19
+ this.ignoredFiles = [];
20
+
21
+ this.targetDir = process.cwd();
22
+ // Intentar múltiples ubicaciones posibles para el paquete
23
+ this.packageDir = this.findPackageDir();
24
+
25
+ // Almacenamiento temporal para contenido de archivos ignorados
26
+ this.preservedContent = new Map();
27
+ }
28
+
29
+ showBanner() {
30
+ console.log('\n');
31
+ console.log('███████╗██╗███████╗███████╗ █████╗ ██╗ ██╗██╗ ██╗ ██╗██╗████████╗');
32
+ console.log('██╔════╝██║██╔════╝██╔════╝██╔══██╗ ██║ ██║██║ ██║ ██╔╝██║╚══██╔══╝');
33
+ console.log('███████╗██║█████╗ ███████╗███████║ ██║ ██║██║ █████╔╝ ██║ ██║ ');
34
+ console.log('╚════██║██║██╔══╝ ╚════██║██╔══██║ ██║ ██║██║ ██╔═██╗ ██║ ██║ ');
35
+ console.log('███████║██║███████╗███████║██║ ██║ ╚██████╔╝██║ ██║ ██╗██║ ██║ ');
36
+ console.log('╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ');
37
+ console.log('');
38
+ }
39
+
40
+ findPackageDir() {
41
+ // Opción 1: directorio padre del bin (instalación normal)
42
+ let packageDir = path.dirname(__dirname);
43
+
44
+ // Opción 2: si estamos en npx, buscar en node_modules
45
+ if (!this.hasRequiredFolders(packageDir)) {
46
+ // Para npm 6.14+ y npx, intentar ubicaciones alternativas
47
+ const possiblePaths = [
48
+ path.join(__dirname, '..'), // bin -> paquete
49
+ path.resolve(__dirname, '..'), // alternativa con resolve
50
+ path.resolve(__dirname, '..', '..', 'siesa-ui-kit'), // desde node_modules
51
+ // Intentar buscar basado en __dirname específicamente para npx
52
+ path.resolve(__dirname.replace(/\\bin$|\/bin$/, '')),
53
+ process.cwd(), // directorio actual como último recurso
54
+ ];
55
+
56
+ for (const possiblePath of possiblePaths) {
57
+ if (this.hasRequiredFolders(possiblePath)) {
58
+ packageDir = possiblePath;
59
+ break;
60
+ }
61
+ }
62
+ }
63
+
64
+ return packageDir;
65
+ }
66
+
67
+ hasRequiredFolders(dir) {
68
+ return this.folderMappings.some(mapping => {
69
+ const folderPath = path.join(dir, mapping.source);
70
+ return fs.existsSync(folderPath);
71
+ });
72
+ }
73
+
74
+ async install() {
75
+ this.showBanner();
76
+ console.log(' Instalando SIESA UI Kit...');
77
+
78
+ try {
79
+ // Verificar si ya existe una instalación
80
+ const hasExistingInstallation = this.checkExistingInstallation();
81
+
82
+ if (hasExistingInstallation) {
83
+ console.log('🔄 Instalación existente detectada. Actualizando...');
84
+ await this.update();
85
+ } else {
86
+ console.log('✨ Nueva instalación...');
87
+ await this.performInstallation();
88
+ }
89
+
90
+ console.log('✅ SIESA UI Kit instalado correctamente!');
91
+ this.showPostInstallMessage();
92
+
93
+ } catch (error) {
94
+ console.error('❌ Error durante la instalación:', error.message);
95
+ process.exit(1);
96
+ }
97
+ }
98
+
99
+ checkExistingInstallation() {
100
+ return this.folderMappings.some(mapping => {
101
+ const targetPath = path.join(this.targetDir, mapping.target);
102
+ return fs.existsSync(targetPath);
103
+ });
104
+ }
105
+
106
+ async checkModifiedFiles() {
107
+ const modifiedFiles = [];
108
+
109
+ for (const mapping of this.folderMappings) {
110
+ const sourcePath = path.join(this.packageDir, mapping.source);
111
+ const targetPath = path.join(this.targetDir, mapping.target);
112
+
113
+ if (!fs.existsSync(sourcePath) || !fs.existsSync(targetPath)) {
114
+ continue;
115
+ }
116
+
117
+ // Obtener todos los archivos recursivamente
118
+ const sourceFiles = await this.getAllFiles(sourcePath);
119
+
120
+ for (const sourceFile of sourceFiles) {
121
+ const relativePath = path.relative(sourcePath, sourceFile);
122
+ const targetFile = path.join(targetPath, relativePath);
123
+
124
+ if (fs.existsSync(targetFile)) {
125
+ try {
126
+ // Comparar contenido de archivos
127
+ const sourceContent = await fs.readFile(sourceFile, 'utf8');
128
+ const targetContent = await fs.readFile(targetFile, 'utf8');
129
+
130
+ if (sourceContent !== targetContent) {
131
+ modifiedFiles.push({
132
+ folder: mapping.target,
133
+ file: relativePath,
134
+ fullPath: targetFile,
135
+ is_ignored: this.ignoredFiles.includes(relativePath)
136
+ });
137
+ }
138
+ } catch (error) {
139
+ // Si no se puede leer como texto, comparar como buffer (archivos binarios)
140
+ const sourceBuffer = await fs.readFile(sourceFile);
141
+ const targetBuffer = await fs.readFile(targetFile);
142
+
143
+ if (!sourceBuffer.equals(targetBuffer)) {
144
+ modifiedFiles.push({
145
+ folder: mapping.target,
146
+ file: relativePath,
147
+ fullPath: targetFile,
148
+ is_ignored: this.ignoredFiles.includes(relativePath)
149
+ });
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ return modifiedFiles;
157
+ }
158
+
159
+ async getAllFiles(dir) {
160
+ const files = [];
161
+ const items = await fs.readdir(dir);
162
+
163
+ for (const item of items) {
164
+ const fullPath = path.join(dir, item);
165
+ const stat = await fs.stat(fullPath);
166
+
167
+ if (stat.isDirectory()) {
168
+ const subFiles = await this.getAllFiles(fullPath);
169
+ files.push(...subFiles);
170
+ } else {
171
+ files.push(fullPath);
172
+ }
173
+ }
174
+
175
+ return files;
176
+ }
177
+
178
+ async promptUser(modifiedFiles) {
179
+
180
+ const hasNonIgnoredFiles = modifiedFiles.some(file => file.is_ignored == false)
181
+ if (!hasNonIgnoredFiles) return '2'
182
+
183
+ console.log('\n⚠️ Se detectaron archivos modificados:');
184
+
185
+ // Agrupar por carpeta
186
+ const filesByFolder = {};
187
+ modifiedFiles.forEach(item => {
188
+ if (!filesByFolder[item.folder]) {
189
+ filesByFolder[item.folder] = [];
190
+ }
191
+ filesByFolder[item.folder].push(item.file);
192
+ });
193
+
194
+ // Mostrar archivos modificados por carpeta
195
+ Object.keys(filesByFolder).forEach(folder => {
196
+ console.log(`\n📁 ${folder}:`);
197
+ filesByFolder[folder].forEach(file => {
198
+ console.log(` - ${file}`);
199
+ });
200
+ });
201
+
202
+ console.log('\n¿Qué deseas hacer?');
203
+ console.log('1. Reemplazar todos los archivos (se perderán las modificaciones)');
204
+ console.log('2. Hacer backup de archivos modificados (se agregarán con sufijo _bk)');
205
+
206
+ const rl = readline.createInterface({
207
+ input: process.stdin,
208
+ output: process.stdout
209
+ });
210
+
211
+ return new Promise((resolve) => {
212
+ rl.question('\nElige una opción (1 o 2): ', (answer) => {
213
+ rl.close();
214
+ resolve(answer.trim());
215
+ });
216
+ });
217
+ }
218
+
219
+ async backupModifiedFiles(modifiedFiles) {
220
+ console.log('\n🔄 Creando backup de archivos modificados...');
221
+
222
+ for (const item of modifiedFiles) {
223
+ // No crear backup de archivos ignorados
224
+ if (item.is_ignored) {
225
+ console.log(`✓ Preservando: ${item.file} (sin backup)`);
226
+ continue;
227
+ }
228
+
229
+ const originalPath = item.fullPath;
230
+ const backupPath = this.getBackupPath(originalPath);
231
+
232
+ try {
233
+ await fs.copy(originalPath, backupPath);
234
+
235
+ // Determinar tipo de backup para mostrar mensaje apropiado
236
+ const backupName = path.basename(backupPath);
237
+ const isVersionedBackup = backupName.includes('_bk_');
238
+
239
+ if (isVersionedBackup) {
240
+ console.log(`✓ Backup versionado: ${path.relative(this.targetDir, backupPath)}`);
241
+ } else {
242
+ console.log(`✓ Backup creado: ${path.relative(this.targetDir, backupPath)}`);
243
+ }
244
+ } catch (error) {
245
+ console.warn(`⚠️ Error creando backup de ${item.file}: ${error.message}`);
246
+ }
247
+ }
248
+ }
249
+
250
+ getBackupPath(filePath) {
251
+ const dir = path.dirname(filePath);
252
+ const ext = path.extname(filePath);
253
+ const name = path.basename(filePath, ext);
254
+
255
+ // Primer intento: archivo_bk.ext
256
+ const basicBackupPath = path.join(dir, `${name}_bk${ext}`);
257
+
258
+ // Si no existe, usar el nombre básico
259
+ if (!fs.existsSync(basicBackupPath)) {
260
+ return basicBackupPath;
261
+ }
262
+
263
+ // Si ya existe _bk, crear versión con timestamp
264
+ const now = new Date();
265
+ const timestamp = now.getFullYear().toString() +
266
+ (now.getMonth() + 1).toString().padStart(2, '0') +
267
+ now.getDate().toString().padStart(2, '0') + '_' +
268
+ now.getHours().toString().padStart(2, '0') +
269
+ now.getMinutes().toString().padStart(2, '0') +
270
+ now.getSeconds().toString().padStart(2, '0');
271
+
272
+ return path.join(dir, `${name}_bk_${timestamp}${ext}`);
273
+ }
274
+
275
+ async performUpdateWithBackups() {
276
+ for (const mapping of this.folderMappings) {
277
+ const sourcePath = path.join(this.packageDir, mapping.source);
278
+ const targetPath = path.join(this.targetDir, mapping.target);
279
+
280
+ if (fs.existsSync(sourcePath)) {
281
+ // Copiar archivos selectivamente, preservando los _bk
282
+ await this.copyWithBackupPreservation(sourcePath, targetPath);
283
+ } else {
284
+ console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
285
+ }
286
+ }
287
+ }
288
+
289
+ async copyWithBackupPreservation(sourcePath, targetPath) {
290
+ // Obtener todos los archivos backup existentes
291
+ const backupFiles = await this.findBackupFiles(targetPath);
292
+
293
+ // Copiar la carpeta
294
+ await fs.copy(sourcePath, targetPath, {
295
+ overwrite: true,
296
+ recursive: true,
297
+ filter: (src) => {
298
+ const relativePath = path.relative(sourcePath, src);
299
+ // No sobrescribir archivos ignorados si ya existen
300
+ if (this.ignoredFiles.includes(relativePath)) {
301
+ const targetFile = path.join(targetPath, relativePath);
302
+ return !fs.existsSync(targetFile);
303
+ }
304
+ return true;
305
+ }
306
+ });
307
+
308
+ // Restaurar los archivos backup
309
+ for (const backupFile of backupFiles) {
310
+ const backupSourcePath = backupFile.tempPath;
311
+ const backupTargetPath = backupFile.originalPath;
312
+
313
+ try {
314
+ await fs.copy(backupSourcePath, backupTargetPath);
315
+ // Limpiar archivo temporal
316
+ await fs.remove(backupSourcePath);
317
+ } catch (error) {
318
+ console.warn(`⚠️ Error restaurando backup ${backupFile.relativePath}: ${error.message}`);
319
+ }
320
+ }
321
+ }
322
+
323
+ async findBackupFiles(targetPath) {
324
+ if (!fs.existsSync(targetPath)) {
325
+ return [];
326
+ }
327
+
328
+ const backupFiles = [];
329
+ const allFiles = await this.getAllFiles(targetPath);
330
+
331
+ for (const filePath of allFiles) {
332
+ const fileName = path.basename(filePath);
333
+ // Detectar archivos _bk y _bk_timestamp
334
+ if (fileName.includes('_bk')) {
335
+ const tempPath = path.join(require('os').tmpdir(), `backup_${Date.now()}_${fileName}`);
336
+ const relativePath = path.relative(targetPath, filePath);
337
+
338
+ // Crear copia temporal del backup
339
+ await fs.copy(filePath, tempPath);
340
+
341
+ backupFiles.push({
342
+ originalPath: filePath,
343
+ tempPath: tempPath,
344
+ relativePath: relativePath
345
+ });
346
+ }
347
+ }
348
+
349
+ return backupFiles;
350
+ }
351
+
352
+ async performInstallation() {
353
+ for (const mapping of this.folderMappings) {
354
+ const sourcePath = path.join(this.packageDir, mapping.source);
355
+ const targetPath = path.join(this.targetDir, mapping.target);
356
+
357
+ if (fs.existsSync(sourcePath)) {
358
+ await fs.copy(sourcePath, targetPath, {
359
+ overwrite: true,
360
+ recursive: true,
361
+ filter: (src) => {
362
+ const relativePath = path.relative(sourcePath, src);
363
+ // No sobrescribir archivos ignorados si ya existen
364
+ if (this.ignoredFiles.includes(relativePath)) {
365
+ const targetFile = path.join(targetPath, relativePath);
366
+ return !fs.existsSync(targetFile);
367
+ }
368
+ return true;
369
+ }
370
+ });
371
+ console.log(` ✓ ${mapping.target} instalado`);
372
+ } else {
373
+ console.warn(`⚠️ Carpeta ${mapping.source} no encontrada en el paquete`);
374
+ }
375
+ }
376
+ }
377
+
378
+ async update() {
379
+ // Verificar archivos modificados
380
+ console.log('🔍 Verificando archivos modificados...');
381
+ const modifiedFiles = await this.checkModifiedFiles();
382
+
383
+ let hasBackups = false;
384
+ if (modifiedFiles.length > 0) {
385
+ const userChoice = await this.promptUser(modifiedFiles);
386
+
387
+ if (userChoice === '2') {
388
+ // Crear backup de archivos modificados
389
+ await this.backupModifiedFiles(modifiedFiles);
390
+ hasBackups = true;
391
+ } else if (userChoice !== '1') {
392
+ console.log('❌ Opción no válida. Cancelando actualización.');
393
+ return;
394
+ }
395
+
396
+ console.log('\n🔄 Procediendo con la actualización...');
397
+ } else {
398
+ console.log('✓ No se detectaron archivos modificados.');
399
+ }
400
+
401
+ // Si hay backups, hacer actualización preservando backups
402
+ if (hasBackups) {
403
+ await this.performUpdateWithBackups();
404
+ } else {
405
+ // Si no hay backups, hacer actualización normal (remover y copiar)
406
+ // Pero primero preservar archivos ignorados
407
+ await this.preserveIgnoredFiles();
408
+
409
+ for (const mapping of this.folderMappings) {
410
+ const targetPath = path.join(this.targetDir, mapping.target);
411
+
412
+ if (fs.existsSync(targetPath)) {
413
+ await fs.remove(targetPath);
414
+ }
415
+ }
416
+
417
+ // Realizar instalación nueva
418
+ await this.performInstallation();
419
+
420
+ // Restaurar archivos ignorados
421
+ await this.restoreIgnoredFiles();
422
+ }
423
+ }
424
+
425
+ async preserveIgnoredFiles() {
426
+ if (this.ignoredFiles.length === 0) return;
427
+
428
+ console.log('🔒 Preservando archivos de configuración...');
429
+
430
+ for (const mapping of this.folderMappings) {
431
+ const targetFolderPath = path.join(this.targetDir, mapping.target);
432
+
433
+ if (!fs.existsSync(targetFolderPath)) {
434
+ continue;
435
+ }
436
+
437
+ for (const ignoredFile of this.ignoredFiles) {
438
+ const filePath = path.join(targetFolderPath, ignoredFile);
439
+
440
+ if (fs.existsSync(filePath)) {
441
+ try {
442
+ const content = await fs.readFile(filePath, 'utf8');
443
+ const key = `${mapping.target}/${ignoredFile}`;
444
+ this.preservedContent.set(key, content);
445
+ console.log(`✓ Preservando: ${ignoredFile}`);
446
+ } catch (error) {
447
+ console.warn(`⚠️ Error leyendo ${ignoredFile}: ${error.message}`);
448
+ }
449
+ }
450
+ }
451
+ }
452
+ }
453
+
454
+ async restoreIgnoredFiles() {
455
+ if (this.preservedContent.size === 0) {
456
+ return;
457
+ }
458
+
459
+ console.log('🔄 Restaurando archivos de configuración...');
460
+
461
+ for (const [key, content] of this.preservedContent) {
462
+ const [targetFolder, ...filePathParts] = key.split('/');
463
+ const filePath = path.join(this.targetDir, targetFolder, ...filePathParts);
464
+
465
+ try {
466
+ // Asegurar que el directorio existe
467
+ await fs.ensureDir(path.dirname(filePath));
468
+
469
+ // Restaurar el contenido
470
+ await fs.writeFile(filePath, content, 'utf8');
471
+ console.log(`✓ Restaurado: ${filePathParts.join('/')}`);
472
+ } catch (error) {
473
+ console.warn(`⚠️ Error restaurando ${filePathParts.join('/')}: ${error.message}`);
474
+ }
475
+ }
476
+
477
+ // Limpiar el mapa después de restaurar
478
+ this.preservedContent.clear();
479
+ }
480
+
481
+ showPostInstallMessage() {
482
+ console.log('\n📚 Carpetas instaladas:');
483
+ this.folderMappings.forEach(mapping => {
484
+ const targetPath = path.join(this.targetDir, mapping.target);
485
+ if (fs.existsSync(targetPath)) {
486
+ console.log(` ✓ ${mapping.target}`);
487
+ }
488
+ });
489
+
490
+ console.log('\n🎉 ¡Instalación completada!');
491
+ console.log('💡 Las carpetas han sido instaladas en tu directorio actual.');
492
+ console.log('🔧 Puedes ejecutar "npx siesa-ui-kit" nuevamente para actualizar.');
493
+ }
494
+ }
495
+
496
+ // Ejecutar instalación si el script es llamado directamente
497
+ if (require.main === module) {
498
+ const installer = new SiesaUIKitInstaller();
499
+ installer.install();
500
+ }
501
+
502
+ module.exports = SiesaUIKitInstaller;
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+
6
+ const rootDir = path.dirname(__dirname);
7
+
8
+ // Renombrar carpetas que empiezan con punto para que npm las incluya
9
+ const folderMappings = [
10
+ { from: '.claude', to: 'claude' },
11
+ { from: '.storybook', to: 'storybook' }
12
+ ];
13
+
14
+ console.log('📦 Preparando carpetas para publicación (siesa-ui-kit)...');
15
+
16
+ for (const mapping of folderMappings) {
17
+ const fromPath = path.join(rootDir, mapping.from);
18
+ const toPath = path.join(rootDir, mapping.to);
19
+
20
+ if (fs.existsSync(fromPath)) {
21
+ console.log(`📁 Renombrando ${mapping.from} -> ${mapping.to}`);
22
+ fs.moveSync(fromPath, toPath, { overwrite: true });
23
+ } else {
24
+ console.warn(`⚠️ Carpeta ${mapping.from} no encontrada, omitiendo...`);
25
+ }
26
+ }
27
+
28
+ console.log('✅ Carpetas preparadas para publicación');
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+
6
+ const rootDir = path.dirname(__dirname);
7
+
8
+ // Restaurar nombres originales de las carpetas
9
+ const folderMappings = [
10
+ { from: 'claude', to: '.claude' },
11
+ { from: 'storybook', to: '.storybook' }
12
+ ];
13
+
14
+ console.log('🔄 Restaurando nombres originales de carpetas...');
15
+
16
+ for (const mapping of folderMappings) {
17
+ const fromPath = path.join(rootDir, mapping.from);
18
+ const toPath = path.join(rootDir, mapping.to);
19
+
20
+ if (fs.existsSync(fromPath)) {
21
+ console.log(`📁 Restaurando ${mapping.from} -> ${mapping.to}`);
22
+ fs.moveSync(fromPath, toPath, { overwrite: true });
23
+ } else {
24
+ console.warn(`⚠️ Carpeta ${mapping.from} no encontrada, omitiendo...`);
25
+ }
26
+ }
27
+
28
+ console.log('✅ Carpetas restauradas');