anima-ds-nucleus 1.0.0 → 1.0.3

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.
@@ -0,0 +1,346 @@
1
+ import { useState } from 'react';
2
+ import { Icon } from '../../Atoms/Icon/Icon';
3
+ import { Typography } from '../../Atoms/Typography/Typography';
4
+
5
+ // Mock data con 2 títulos y 2 secciones
6
+ const MOCK_SECTIONS = [
7
+ {
8
+ title: 'PERSONAS',
9
+ items: [
10
+ { id: 'empleados', label: 'Empleados', icon: 'UserGroupIcon' },
11
+ { id: 'organizacion', label: 'Organización', icon: 'BuildingOfficeIcon' },
12
+ ],
13
+ },
14
+ {
15
+ title: 'TALENTO',
16
+ items: [
17
+ { id: 'reclutamiento', label: 'Reclutamiento', icon: 'UserPlusIcon' },
18
+ { id: 'desarrollo', label: 'Desarrollo', icon: 'AcademicCapIcon' },
19
+ ],
20
+ },
21
+ ];
22
+
23
+ export const SidebarCore = ({
24
+ sections = MOCK_SECTIONS,
25
+ activeItem,
26
+ onItemClick,
27
+ defaultCollapsed = false,
28
+ companyName = 'HEXA Core',
29
+ companyLogo,
30
+ onCompanyClick,
31
+ nucleusName = 'Nucleus AR',
32
+ nucleusLogo,
33
+ onNucleusClick,
34
+ itemBadges = {}, // Objeto con { itemId: number } para los badges
35
+ className = '',
36
+ ...props
37
+ }) => {
38
+ const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
39
+
40
+ const toggleCollapse = () => {
41
+ setIsCollapsed(!isCollapsed);
42
+ };
43
+
44
+ return (
45
+ <aside
46
+ className={`bg-white border-r border-gray-200 transition-all duration-300 ease-in-out ${
47
+ isCollapsed ? 'w-20' : 'w-64'
48
+ } ${className}`}
49
+ {...props}
50
+ >
51
+ <nav className="h-full flex flex-col overflow-hidden">
52
+ {/* Barra superior con HEXA Core */}
53
+ {!isCollapsed && (
54
+ <div className="p-4 border-b border-gray-200">
55
+ <button
56
+ onClick={onCompanyClick}
57
+ className="w-full bg-white rounded-lg px-3 py-2.5
58
+ flex items-center justify-between hover:bg-gray-50 transition-colors"
59
+ >
60
+ <div className="flex items-center space-x-3">
61
+ {/* Icono cuadrado oscuro con H */}
62
+ {companyLogo ? (
63
+ <img
64
+ src={companyLogo}
65
+ alt={companyName}
66
+ className="w-8 h-8 rounded"
67
+ />
68
+ ) : (
69
+ <div className="w-8 h-8 bg-gray-700 rounded flex items-center justify-center">
70
+ <Typography
71
+ variant="body-md"
72
+ className="color-white font-bold"
73
+ >
74
+ H
75
+ </Typography>
76
+ </div>
77
+ )}
78
+ {/* Nombre de la empresa */}
79
+ <Typography
80
+ variant="body-md"
81
+ className="color-gray-900 font-medium"
82
+ >
83
+ {companyName}
84
+ </Typography>
85
+ </div>
86
+ </button>
87
+ </div>
88
+ )}
89
+ {/* Botón Nucleus AR */}
90
+ {!isCollapsed && (
91
+ <div className="bg-gray-100 py-4 w-full">
92
+ <div className="px-4">
93
+ <button
94
+ onClick={onNucleusClick}
95
+ className="w-full flex items-center px-4 py-2.5 rounded-lg
96
+ transition-all duration-200 color-gray-700 hover:bg-gray-200
97
+ justify-between"
98
+ >
99
+ <div className="flex items-center">
100
+ <Icon
101
+ name="BuildingOfficeIcon"
102
+ variant="24-outline"
103
+ size={20}
104
+ className="mr-3 color-teal"
105
+ />
106
+ <Typography
107
+ variant="body-md"
108
+ className="font-medium color-gray-700"
109
+ >
110
+ {nucleusName}
111
+ </Typography>
112
+ </div>
113
+ {/* Chevron hacia abajo */}
114
+ <Icon
115
+ name="ChevronDownIcon"
116
+ variant="24-outline"
117
+ size={16}
118
+ className="color-teal"
119
+ />
120
+ </button>
121
+ </div>
122
+ </div>
123
+ )}
124
+
125
+ {/* Botón de colapsar/expandir - Solo visible cuando está expandido */}
126
+ {!isCollapsed && (
127
+ <div className="px-4 pb-2 flex justify-end">
128
+ <button
129
+ onClick={toggleCollapse}
130
+ className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
131
+ aria-label="Colapsar sidebar"
132
+ style={{ marginRight: '10px' }}
133
+ >
134
+ <Icon
135
+ name="ChevronDoubleLeftIcon"
136
+ variant="24-outline"
137
+ size={20}
138
+ className="color-teal"
139
+ />
140
+ </button>
141
+ </div>
142
+ )}
143
+
144
+ {/* Logo H cuando está colapsado */}
145
+ {isCollapsed && (
146
+ <div className="p-4 border-b border-gray-200 flex justify-center">
147
+ {companyLogo ? (
148
+ <img
149
+ src={companyLogo}
150
+ alt={companyName}
151
+ className="w-8 h-8 rounded"
152
+ />
153
+ ) : (
154
+ <div className="w-8 h-8 bg-gray-700 rounded flex items-center justify-center">
155
+ <Typography
156
+ variant="body-md"
157
+ className="color-white font-bold"
158
+ >
159
+ H
160
+ </Typography>
161
+ </div>
162
+ )}
163
+ </div>
164
+ )}
165
+
166
+ {/* Botón Nucleus AR cuando está colapsado */}
167
+ {isCollapsed && (
168
+ <div className="bg-gray-100 py-4 w-full">
169
+ <div className="px-4 flex justify-center">
170
+ <button
171
+ onClick={onNucleusClick}
172
+ className="flex items-center justify-center p-2.5 rounded-lg
173
+ transition-all duration-200 color-gray-700 hover:bg-gray-200"
174
+ >
175
+ <Icon
176
+ name="BuildingOfficeIcon"
177
+ variant="24-outline"
178
+ size={20}
179
+ className="color-teal"
180
+ />
181
+ <Icon
182
+ name="ChevronDownIcon"
183
+ variant="24-outline"
184
+ size={16}
185
+ className="ml-1 color-teal"
186
+ />
187
+ </button>
188
+ </div>
189
+ </div>
190
+ )}
191
+
192
+ {/* Botón para expandir - Solo visible cuando está colapsado */}
193
+ {isCollapsed && (
194
+ <div className="px-4 pb-2 flex justify-center">
195
+ <button
196
+ onClick={toggleCollapse}
197
+ className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
198
+ aria-label="Expandir sidebar"
199
+ >
200
+ <Icon
201
+ name="ChevronDoubleRightIcon"
202
+ variant="24-outline"
203
+ size={20}
204
+ className="color-teal"
205
+ />
206
+ </button>
207
+ </div>
208
+ )}
209
+
210
+ {/* Contenido del sidebar */}
211
+ <div className="flex-1 overflow-y-auto py-4">
212
+ {/* Item "Inicio" destacado */}
213
+ <div className="px-4 mb-4">
214
+ <button
215
+ onClick={() => onItemClick && onItemClick('inicio')}
216
+ className={`w-full flex items-center ${
217
+ isCollapsed ? 'justify-center px-2' : 'px-4 justify-between'
218
+ } py-2.5 rounded-lg transition-all duration-200 ${
219
+ activeItem === 'inicio'
220
+ ? ''
221
+ : 'color-gray-700 hover:bg-gray-100'
222
+ }`}
223
+ style={
224
+ activeItem === 'inicio'
225
+ ? { backgroundColor: '#2D5C63' }
226
+ : {}
227
+ }
228
+ >
229
+ <div className="flex items-center">
230
+ <Icon
231
+ name="HomeIcon"
232
+ variant="24-outline"
233
+ size={20}
234
+ className={`${isCollapsed ? '' : 'mr-3'} ${
235
+ activeItem === 'inicio' ? 'color-white' : 'color-gray-700'
236
+ }`}
237
+ />
238
+ {!isCollapsed && (
239
+ <Typography
240
+ variant="body-md"
241
+ className={`font-medium ${
242
+ activeItem === 'inicio' ? 'color-white' : 'color-gray-700'
243
+ }`}
244
+ >
245
+ Inicio
246
+ </Typography>
247
+ )}
248
+ </div>
249
+ {!isCollapsed && itemBadges['inicio'] !== undefined && itemBadges['inicio'] > 0 && (
250
+ <span
251
+ className="px-2 py-0.5 min-w-[20px] h-5
252
+ text-white rounded-full flex items-center justify-center
253
+ text-body-sm font-medium"
254
+ style={{
255
+ backgroundColor: '#6D3856',
256
+ borderRadius: '12px'
257
+ }}
258
+ >
259
+ {itemBadges['inicio'] > 9 ? '9+' : itemBadges['inicio']}
260
+ </span>
261
+ )}
262
+ </button>
263
+ </div>
264
+
265
+ {/* Secciones */}
266
+ {sections.map((section, sectionIndex) => (
267
+ <div key={sectionIndex} className="mb-6">
268
+ {/* Título de la sección */}
269
+ {!isCollapsed && (
270
+ <div className="px-4 mb-2">
271
+ <Typography
272
+ variant="body-sm"
273
+ className="color-gray-500 uppercase font-medium tracking-wider"
274
+ >
275
+ {section.title}
276
+ </Typography>
277
+ </div>
278
+ )}
279
+
280
+ {/* Items de la sección */}
281
+ <div className="space-y-1">
282
+ {section.items.map((item) => (
283
+ <div key={item.id} className="px-4">
284
+ <button
285
+ onClick={() => onItemClick && onItemClick(item.id)}
286
+ className={`w-full flex items-center ${
287
+ isCollapsed ? 'justify-center px-2' : 'px-4 justify-between'
288
+ } py-2.5 rounded-lg transition-all duration-200 ${
289
+ activeItem === item.id
290
+ ? ''
291
+ : 'color-gray-700 hover:bg-gray-100'
292
+ }`}
293
+ style={
294
+ activeItem === item.id
295
+ ? { backgroundColor: '#2D5C63' }
296
+ : {}
297
+ }
298
+ title={isCollapsed ? item.label : ''}
299
+ >
300
+ <div className="flex items-center">
301
+ <Icon
302
+ name={item.icon}
303
+ variant="24-outline"
304
+ size={20}
305
+ className={`${isCollapsed ? '' : 'mr-3'} ${
306
+ activeItem === item.id ? 'color-white' : 'color-gray-700'
307
+ }`}
308
+ />
309
+ {!isCollapsed && (
310
+ <Typography
311
+ variant="body-md"
312
+ className={`font-medium ${
313
+ activeItem === item.id ? 'color-white' : 'color-gray-700'
314
+ }`}
315
+ >
316
+ {item.label}
317
+ </Typography>
318
+ )}
319
+ </div>
320
+ {!isCollapsed && ((itemBadges[item.id] !== undefined && itemBadges[item.id] > 0) || (item.id === 'empleados' && 2)) && (
321
+ <span
322
+ className="px-2 py-0.5 min-w-[20px] h-5
323
+ text-white rounded-full flex items-center justify-center
324
+ text-body-sm font-medium"
325
+ style={{
326
+ backgroundColor: '#6D3856',
327
+ borderRadius: '12px'
328
+ }}
329
+ >
330
+ {item.id === 'empleados' ? 2 : (itemBadges[item.id] > 9 ? '9+' : itemBadges[item.id])}
331
+ </span>
332
+ )}
333
+ </button>
334
+ </div>
335
+ ))}
336
+ </div>
337
+ </div>
338
+ ))}
339
+ </div>
340
+ </nav>
341
+ </aside>
342
+ );
343
+ };
344
+
345
+ export default SidebarCore;
346
+
@@ -0,0 +1,92 @@
1
+ import { useState } from 'react';
2
+ import { SidebarCore } from './SidebarCore';
3
+
4
+ export default {
5
+ title: 'Layout/SidebarCore',
6
+ component: SidebarCore,
7
+ tags: ['autodocs'],
8
+ };
9
+
10
+ // Mock data con 2 títulos y 2 secciones
11
+ const mockSections = [
12
+ {
13
+ title: 'PERSONAS',
14
+ items: [
15
+ { id: 'empleados', label: 'Empleados', icon: 'UserGroupIcon' },
16
+ { id: 'organizacion', label: 'Organización', icon: 'BuildingOfficeIcon' },
17
+ ],
18
+ },
19
+ {
20
+ title: 'TALENTO',
21
+ items: [
22
+ { id: 'reclutamiento', label: 'Reclutamiento', icon: 'UserPlusIcon' },
23
+ { id: 'desarrollo', label: 'Desarrollo', icon: 'AcademicCapIcon' },
24
+ ],
25
+ },
26
+ ];
27
+
28
+ export const Default = {
29
+ render: () => {
30
+ const [activeItem, setActiveItem] = useState('inicio');
31
+ return (
32
+ <div className="h-screen bg-gray-100">
33
+ <SidebarCore
34
+ sections={mockSections}
35
+ activeItem={activeItem}
36
+ onItemClick={setActiveItem}
37
+ companyName="HEXA Core"
38
+ onCompanyClick={() => console.log('Company clicked')}
39
+ />
40
+ </div>
41
+ );
42
+ },
43
+ };
44
+
45
+ export const Colapsado = {
46
+ render: () => {
47
+ const [activeItem, setActiveItem] = useState('inicio');
48
+ return (
49
+ <div className="h-screen bg-gray-100">
50
+ <SidebarCore
51
+ sections={mockSections}
52
+ activeItem={activeItem}
53
+ onItemClick={setActiveItem}
54
+ defaultCollapsed={true}
55
+ />
56
+ </div>
57
+ );
58
+ },
59
+ };
60
+
61
+ export const ConSeccionesPersonalizadas = {
62
+ render: () => {
63
+ const [activeItem, setActiveItem] = useState('item1');
64
+ const customSections = [
65
+ {
66
+ title: 'ADMINISTRACIÓN',
67
+ items: [
68
+ { id: 'item1', label: 'Usuarios', icon: 'UserIcon' },
69
+ { id: 'item2', label: 'Roles', icon: 'ShieldCheckIcon' },
70
+ ],
71
+ },
72
+ {
73
+ title: 'REPORTES',
74
+ items: [
75
+ { id: 'item3', label: 'Analíticas', icon: 'ChartBarIcon' },
76
+ { id: 'item4', label: 'Exportar', icon: 'ArrowDownTrayIcon' },
77
+ ],
78
+ },
79
+ ];
80
+ return (
81
+ <div className="h-screen bg-gray-100">
82
+ <SidebarCore
83
+ sections={customSections}
84
+ activeItem={activeItem}
85
+ onItemClick={setActiveItem}
86
+ />
87
+ </div>
88
+ );
89
+ },
90
+ };
91
+
92
+