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.
- package/README.md +89 -0
- package/bin/install.cjs +502 -0
- package/bin/prepare-publish.cjs +28 -0
- package/bin/restore-folders.cjs +28 -0
- package/claude/agents/siesa-ui-kit-specialist.md +2401 -0
- package/claude/prompts/component-template.md +121 -0
- package/claude/settings.local.json +61 -0
- package/docs/border-radius.md +1261 -0
- package/docs/colors.md +832 -0
- package/docs/dark-mode-guide.md +1426 -0
- package/docs/filters.md +1243 -0
- package/docs/icons.md +1283 -0
- package/docs/shadows.md +1377 -0
- package/docs/spacing.md +1684 -0
- package/docs/typography.md +1268 -0
- package/package.json +83 -0
- package/postcss.config.cjs +6 -0
- package/public/,Business Logo.png +0 -0
- package/public/.Siesa Logo.png +0 -0
- package/public/bg_siesa.png +0 -0
- package/public/siesa_logo_mobile.png +0 -0
- package/public/vite.svg +1 -0
- package/src/App.css +42 -0
- package/src/App.tsx +8 -0
- package/src/ButtonTest.tsx +147 -0
- package/src/assets/fonts/README.md +261 -0
- package/src/assets/fonts/SiesaBT/SiesaBT-Bold.otf +0 -0
- package/src/assets/fonts/SiesaBT/SiesaBT-Light.otf +0 -0
- package/src/assets/fonts/SiesaBT/SiesaBT-Regular.otf +0 -0
- package/src/assets/react.svg +1 -0
- package/src/components/Alert/Alert.stories.tsx +332 -0
- package/src/components/Alert/Alert.tsx +106 -0
- package/src/components/Alert/Alert.types.ts +54 -0
- package/src/components/Avatar/Avatar.stories.tsx +494 -0
- package/src/components/Avatar/Avatar.tsx +143 -0
- package/src/components/Avatar/Avatar.types.ts +53 -0
- package/src/components/Badge/Badge.stories.tsx +339 -0
- package/src/components/Badge/Badge.tsx +278 -0
- package/src/components/Badge/Badge.types.ts +58 -0
- package/src/components/Button/Button.stories.tsx +950 -0
- package/src/components/Button/Button.tsx +337 -0
- package/src/components/Button/Button.types.ts +180 -0
- package/src/components/Button/icons.tsx +87 -0
- package/src/components/Button/index.ts +3 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +453 -0
- package/src/components/Checkbox/Checkbox.tsx +208 -0
- package/src/components/Checkbox/Checkbox.types.ts +61 -0
- package/src/components/DescriptionList/DescriptionList.stories.tsx +250 -0
- package/src/components/DescriptionList/DescriptionList.tsx +96 -0
- package/src/components/DescriptionList/DescriptionList.types.ts +29 -0
- package/src/components/Divider/Divider.stories.tsx +263 -0
- package/src/components/Divider/Divider.tsx +80 -0
- package/src/components/Divider/Divider.types.ts +24 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +552 -0
- package/src/components/Dropdown/Dropdown.tsx +422 -0
- package/src/components/Dropdown/Dropdown.types.ts +146 -0
- package/src/components/Dropdown/README.md +266 -0
- package/src/components/Dropdown/icons.tsx +72 -0
- package/src/components/Dropdown/index.ts +8 -0
- package/src/components/Input/Input.stories.tsx +583 -0
- package/src/components/Input/Input.tsx +204 -0
- package/src/components/Input/Input.types.ts +80 -0
- package/src/components/Input/icons.tsx +145 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/LoginView/LoginView.stories.tsx +148 -0
- package/src/components/LoginView/LoginView.tsx +426 -0
- package/src/components/LoginView/LoginView.types.ts +52 -0
- package/src/components/LoginView/README.md +396 -0
- package/src/components/LoginView/icons.tsx +85 -0
- package/src/components/LoginView/index.ts +3 -0
- package/src/components/Navbar/Navbar.stories.tsx +810 -0
- package/src/components/Navbar/Navbar.tsx +755 -0
- package/src/components/Navbar/Navbar.types.ts +219 -0
- package/src/components/Navbar/README.md +279 -0
- package/src/components/Navbar/icons.tsx +102 -0
- package/src/components/Navbar/index.ts +8 -0
- package/src/components/NavigationBar/NavigationBar.stories.tsx +406 -0
- package/src/components/NavigationBar/NavigationBar.tsx +246 -0
- package/src/components/NavigationBar/NavigationBar.types.ts +74 -0
- package/src/components/NavigationBar/README.md +469 -0
- package/src/components/NavigationBar/index.ts +2 -0
- package/src/components/NavigationRail/NavigationRail.stories.tsx +417 -0
- package/src/components/NavigationRail/NavigationRail.tsx +418 -0
- package/src/components/NavigationRail/NavigationRail.types.ts +109 -0
- package/src/components/NavigationRail/README.md +224 -0
- package/src/components/NavigationRail/index.ts +2 -0
- package/src/components/Notification/Notification.stories.tsx +513 -0
- package/src/components/Notification/Notification.tsx +145 -0
- package/src/components/Notification/Notification.types.ts +142 -0
- package/src/components/Notification/README.md +409 -0
- package/src/components/Notification/index.ts +3 -0
- package/src/components/POSConvention/POSConvention.stories.tsx +235 -0
- package/src/components/POSConvention/POSConvention.tsx +129 -0
- package/src/components/POSConvention/POSConvention.types.ts +38 -0
- package/src/components/POSConvention/README.md +123 -0
- package/src/components/POSConvention/icons.tsx +45 -0
- package/src/components/POSConvention/index.ts +3 -0
- package/src/components/POSLocationButton/POSLocationButton.stories.tsx +531 -0
- package/src/components/POSLocationButton/POSLocationButton.tsx +247 -0
- package/src/components/POSLocationButton/POSLocationButton.types.ts +87 -0
- package/src/components/POSLocationButton/README.md +253 -0
- package/src/components/POSLocationButton/icons.tsx +120 -0
- package/src/components/POSLocationButton/index.ts +14 -0
- package/src/components/POSNumberButton/POSNumberButton.stories.tsx +415 -0
- package/src/components/POSNumberButton/POSNumberButton.tsx +179 -0
- package/src/components/POSNumberButton/POSNumberButton.types.ts +51 -0
- package/src/components/POSNumberButton/README.md +321 -0
- package/src/components/POSNumberButton/index.ts +3 -0
- package/src/components/POSProductButton/POSProductButton.stories.tsx +318 -0
- package/src/components/POSProductButton/POSProductButton.tsx +152 -0
- package/src/components/POSProductButton/POSProductButton.types.ts +46 -0
- package/src/components/POSProductButton/README.md +269 -0
- package/src/components/POSProductButton/index.ts +2 -0
- package/src/components/POSProductCard/POSProductCard.stories.tsx +642 -0
- package/src/components/POSProductCard/POSProductCard.tsx +208 -0
- package/src/components/POSProductCard/POSProductCard.types.ts +76 -0
- package/src/components/POSProductCard/README.md +179 -0
- package/src/components/POSProductCard/icons.tsx +26 -0
- package/src/components/POSProductCard/index.ts +2 -0
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.stories.tsx +753 -0
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.tsx +332 -0
- package/src/components/POSProductSidebarItems/POSProductSidebarItems.types.ts +119 -0
- package/src/components/POSProductSidebarItems/README.md +198 -0
- package/src/components/POSProductSidebarItems/icons.tsx +21 -0
- package/src/components/POSProductSidebarItems/index.ts +3 -0
- package/src/components/POSTable/POSTable.stories.tsx +737 -0
- package/src/components/POSTable/POSTable.tsx +401 -0
- package/src/components/POSTable/POSTable.types.ts +83 -0
- package/src/components/POSTable/README.md +286 -0
- package/src/components/POSTable/index.ts +7 -0
- package/src/components/Pagination/Pagination.stories.tsx +555 -0
- package/src/components/Pagination/Pagination.tsx +286 -0
- package/src/components/Pagination/Pagination.types.ts +93 -0
- package/src/components/Pagination/README.md +298 -0
- package/src/components/Pagination/icons.tsx +47 -0
- package/src/components/Pagination/index.ts +3 -0
- package/src/components/Quantity/Quantity.stories.tsx +457 -0
- package/src/components/Quantity/Quantity.tsx +289 -0
- package/src/components/Quantity/Quantity.types.ts +70 -0
- package/src/components/Radio/Radio.stories.tsx +523 -0
- package/src/components/Radio/Radio.tsx +170 -0
- package/src/components/Radio/Radio.types.ts +122 -0
- package/src/components/Select/README.md +299 -0
- package/src/components/Select/Select.stories.tsx +673 -0
- package/src/components/Select/Select.tsx +454 -0
- package/src/components/Select/Select.types.ts +148 -0
- package/src/components/Select/icons.tsx +50 -0
- package/src/components/Select/index.ts +3 -0
- package/src/components/SignUpView/SignUpView.stories.tsx +129 -0
- package/src/components/SignUpView/SignUpView.tsx +503 -0
- package/src/components/SignUpView/SignUpView.types.ts +58 -0
- package/src/components/SignUpView/icons.tsx +71 -0
- package/src/components/SignUpView/index.ts +3 -0
- package/src/components/Switch/README.md +112 -0
- package/src/components/Switch/Switch.stories.tsx +550 -0
- package/src/components/Switch/Switch.tsx +246 -0
- package/src/components/Switch/Switch.types.ts +67 -0
- package/src/components/Table/README.md +369 -0
- package/src/components/Table/Table.stories.tsx +805 -0
- package/src/components/Table/Table.tsx +688 -0
- package/src/components/Table/Table.types.ts +204 -0
- package/src/components/Table/index.ts +9 -0
- package/src/components/Tabs/README.md +201 -0
- package/src/components/Tabs/Tabs.stories.tsx +580 -0
- package/src/components/Tabs/Tabs.tsx +356 -0
- package/src/components/Tabs/Tabs.types.ts +127 -0
- package/src/components/Tabs/icons.tsx +129 -0
- package/src/components/Tabs/index.ts +11 -0
- package/src/components/Textarea/Textarea.stories.tsx +535 -0
- package/src/components/Textarea/Textarea.tsx +188 -0
- package/src/components/Textarea/Textarea.types.ts +54 -0
- package/src/context/ThemeContext.tsx +99 -0
- package/src/context/index.ts +1 -0
- package/src/index.css +29 -0
- package/src/index.ts +39 -0
- package/src/main.tsx +10 -0
- package/src/views/ProductsView/ProductsView.stories.tsx +344 -0
- package/src/views/ProductsView/ProductsView.tsx +480 -0
- package/src/views/ProductsView/ProductsView.types.ts +238 -0
- package/src/views/ProductsView/README.md +312 -0
- package/src/views/ProductsView/icons.tsx +38 -0
- package/src/views/ProductsView/index.ts +8 -0
- package/src/views/RecoverPasswordView/README.md +269 -0
- package/src/views/RecoverPasswordView/RecoverPasswordView.stories.tsx +131 -0
- package/src/views/RecoverPasswordView/RecoverPasswordView.tsx +376 -0
- package/src/views/RecoverPasswordView/RecoverPasswordView.types.ts +56 -0
- package/src/views/RecoverPasswordView/icons.tsx +17 -0
- package/src/views/RecoverPasswordView/index.ts +2 -0
- package/src/views/TableLayoutView/README.md +268 -0
- package/src/views/TableLayoutView/TableLayoutView.stories.tsx +235 -0
- package/src/views/TableLayoutView/TableLayoutView.tsx +461 -0
- package/src/views/TableLayoutView/TableLayoutView.types.ts +209 -0
- package/src/views/TableLayoutView/icons.tsx +113 -0
- package/src/views/TableLayoutView/index.ts +6 -0
- package/storybook/main.ts +20 -0
- package/storybook/preview.tsx +84 -0
- package/storybook/vitest.setup.ts +7 -0
- 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
|
package/bin/install.cjs
ADDED
|
@@ -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');
|