anima-ds-nucleus 1.0.5 → 1.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anima-ds-nucleus",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Anima Design System - A comprehensive React component library",
5
5
  "author": "Nucleus Labs <ipvasallo@nucleus.com.ar>",
6
6
  "license": "UNLICENSED",
@@ -1,113 +1,359 @@
1
- import { Typography } from '../../Atoms/Typography/Typography';
1
+ import { useState } from 'react';
2
2
  import { Icon } from '../../Atoms/Icon/Icon';
3
- import { LogoHexa } from '../../Atoms/LogoHexa/LogoHexa';
3
+ import { Avatar } from '../../Atoms/Avatar/Avatar';
4
+ import { Typography } from '../../Atoms/Typography/Typography';
4
5
 
5
6
  export const HeaderPoint = ({
6
- logo,
7
- companyName = 'Point',
8
- date,
9
- pointLabel = 'HEXA Core',
10
- onPointClick,
11
- backgroundColor,
12
- borderColor,
13
- verticalLineColor = '#9CA3AF',
14
- logoBackgroundColor = '#FFFFFF',
15
- logoIconColor,
16
- companyNameColor,
17
- dateColor = '#6B7280',
18
- buttonBackgroundColor = '#000000',
19
- buttonBorderColor = '#FFFFFF',
20
- buttonTextColor = '#FFFFFF',
7
+ searchPlaceholder = 'Buscar empleados, reportes, configuraciones...',
8
+ userName,
9
+ userAvatar,
10
+ notificationCount = 0,
11
+ onSearch,
12
+ onNotificationClick,
13
+ onUserClick,
21
14
  className = '',
22
15
  ...props
23
16
  }) => {
24
- // Formatear fecha si no se proporciona
25
- const formattedDate = date || new Date().toLocaleDateString('es-AR', {
26
- weekday: 'long',
27
- year: 'numeric',
28
- month: 'long',
29
- day: 'numeric',
30
- });
17
+ const [searchValue, setSearchValue] = useState('');
18
+
19
+ const handleSearchChange = (e) => {
20
+ const value = e.target.value;
21
+ setSearchValue(value);
22
+ if (onSearch) {
23
+ onSearch(value);
24
+ }
25
+ };
31
26
 
32
- // Capitalizar primera letra de la fecha
33
- const capitalizedDate = formattedDate.charAt(0).toUpperCase() + formattedDate.slice(1);
27
+ const handleSearchSubmit = (e) => {
28
+ e.preventDefault();
29
+ if (onSearch) {
30
+ onSearch(searchValue);
31
+ }
32
+ };
34
33
 
35
- // Determinar colores del logo
36
- const logoBgColor = logoBackgroundColor;
37
- const logoIconStrokeColor = logoIconColor || backgroundColor || '#2D5C63';
38
-
39
34
  return (
40
35
  <header
41
- className={`${className}`}
42
- style={{
43
- backgroundColor: backgroundColor || '#FFFFFF',
44
- borderBottom: borderColor ? `1px solid ${borderColor}` : '1px solid #E5E7EB'
45
- }}
36
+ className={`bg-white border-b border-gray-200 header-point-mobile ${className}`}
46
37
  {...props}
47
38
  >
48
- <div className="w-full">
49
- <div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
50
- {/* Lado izquierdo: logo y nombre */}
51
- <div className="flex items-center space-x-2">
52
- {/* Logo hexagonal */}
53
- {logo ? (
54
- <img
55
- src={logo}
56
- alt={companyName}
57
- className="w-8 h-8"
39
+ <style>{`
40
+ .header-search-input {
41
+ border-color: #9ca3af;
42
+ }
43
+ .header-search-input::placeholder {
44
+ color: #9ca3af !important;
45
+ opacity: 1 !important;
46
+ }
47
+ .header-search-icon-container {
48
+ border-color: #9ca3af;
49
+ }
50
+ .header-search-form:focus-within .header-search-input {
51
+ border-color: #3b82f6 !important;
52
+ box-shadow: 0 0 0 1px #3b82f6;
53
+ }
54
+ .header-search-form:focus-within .header-search-icon-container {
55
+ border-color: #3b82f6 !important;
56
+ box-shadow: 0 0 0 1px #3b82f6;
57
+ }
58
+ @media (max-width: 768px) {
59
+ .header-point-mobile {
60
+ background-color: transparent !important;
61
+ border-bottom: none !important;
62
+ }
63
+ .header-mobile-layout {
64
+ display: block;
65
+ position: relative;
66
+ }
67
+ .header-mobile-top-row {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: space-between;
71
+ padding: 8px 4px;
72
+ min-height: 48px;
73
+ }
74
+ .header-mobile-layout::after {
75
+ content: '';
76
+ position: absolute;
77
+ top: 0;
78
+ left: 0;
79
+ right: 0;
80
+ height: calc(48px + 16px + 4px + 20px);
81
+ background-color: var(--color-main);
82
+ z-index: -1;
83
+ border-bottom: 1px solid var(--color-main-800);
84
+ }
85
+ .header-mobile-search-row {
86
+ display: block;
87
+ padding: 4px 4px 8px 4px;
88
+ }
89
+ .header-desktop-layout {
90
+ display: none !important;
91
+ }
92
+ .header-mobile-layout .header-search-input {
93
+ font-size: 12px !important;
94
+ padding-left: 8px !important;
95
+ padding-right: 8px !important;
96
+ }
97
+ .header-mobile-layout .header-search-icon-container {
98
+ width: 36px !important;
99
+ }
100
+ .header-mobile-menu-icon {
101
+ color: var(--color-neutrals-white) !important;
102
+ }
103
+ .header-mobile-notification-icon {
104
+ color: var(--color-neutrals-white) !important;
105
+ }
106
+ .header-mobile-point-text {
107
+ color: var(--color-neutrals-white) !important;
108
+ }
109
+ }
110
+ @media (min-width: 769px) {
111
+ .header-mobile-layout {
112
+ display: none;
113
+ }
114
+ }
115
+ `}</style>
116
+
117
+ <div className="w-full" style={{ paddingLeft: '4px', paddingRight: '4px' }}>
118
+ {/* Layout Desktop (más de 768px) */}
119
+ <div className="header-desktop-layout flex items-center justify-between h-16">
120
+ {/* Barra de búsqueda con icono a la derecha */}
121
+ <div className="flex-1 mr-2 md:mr-4" style={{ maxWidth: 'none', minWidth: '0' }}>
122
+ <form onSubmit={handleSearchSubmit} className="header-search-form flex items-center w-full">
123
+ {/* Input de búsqueda */}
124
+ <input
125
+ type="text"
126
+ value={searchValue}
127
+ onChange={handleSearchChange}
128
+ placeholder={searchPlaceholder}
129
+ className="header-search-input flex-1 pl-2 md:pl-4 pr-2 md:pr-4 py-2 md:py-2.5 bg-white border border-gray-400 rounded-l-lg
130
+ focus:outline-none text-sm md:text-base"
131
+ style={{
132
+ height: '40px',
133
+ borderRight: 'none',
134
+ borderTopRightRadius: '0',
135
+ borderBottomRightRadius: '0',
136
+ color: '#374151',
137
+ fontFamily: 'IBM Plex Sans',
138
+ fontWeight: 400,
139
+ fontStyle: 'italic',
140
+ fontSize: '14px',
141
+ lineHeight: '20px',
142
+ letterSpacing: '0px'
143
+ }}
58
144
  />
59
- ) : (
60
- <LogoHexa
61
- width={36}
62
- height={40}
63
- />
64
- )}
65
-
66
- {/* Nombre de la empresa */}
67
- <Typography
68
- variant="body-md"
69
- className="font-bold"
70
- style={{ color: companyNameColor }}
71
- >
72
- {companyName}
73
- </Typography>
145
+
146
+ {/* Recuadro con icono de buscar a la derecha */}
147
+ <div
148
+ className="header-search-icon-container flex items-center justify-center border border-gray-400 rounded-r-lg bg-white"
149
+ style={{
150
+ width: '40px',
151
+ height: '40px',
152
+ borderTopLeftRadius: '0',
153
+ borderBottomLeftRadius: '0'
154
+ }}
155
+ >
156
+ <Icon
157
+ name="MagnifyingGlassIcon"
158
+ variant="24-outline"
159
+ size={20}
160
+ className="color-gray-600"
161
+ />
162
+ </div>
163
+ </form>
74
164
  </div>
75
165
 
76
- {/* Centro: Fecha */}
77
- <div className="flex-1 flex justify-center">
78
- <Typography
79
- variant="body-md"
80
- style={{ color: dateColor }}
81
- >
82
- {capitalizedDate}
83
- </Typography>
166
+ {/* Notificaciones y Perfil */}
167
+ <div className="flex items-center space-x-3 md:space-x-6 flex-shrink-0" style={{ marginLeft: 'auto', paddingRight: '0px' }}>
168
+ {/* Icono de notificaciones */}
169
+ {notificationCount !== undefined && (
170
+ <button
171
+ onClick={onNotificationClick}
172
+ className="relative p-2 hover:bg-gray-100 rounded-lg transition-colors"
173
+ aria-label="Notificaciones"
174
+ >
175
+ <Icon
176
+ name="BellIcon"
177
+ variant="24-outline"
178
+ size={24}
179
+ className="color-gray-600"
180
+ />
181
+ {notificationCount > 0 && (
182
+ <span
183
+ className="absolute -top-1 -right-1 px-1.5 py-0.5 min-w-[20px] h-5
184
+ text-white rounded-full flex items-center justify-center
185
+ text-body-sm font-medium"
186
+ style={{
187
+ backgroundColor: '#6D3856',
188
+ borderRadius: '12px'
189
+ }}
190
+ >
191
+ {notificationCount > 9 ? '9+' : notificationCount}
192
+ </span>
193
+ )}
194
+ </button>
195
+ )}
196
+
197
+ {/* Perfil de usuario */}
198
+ {userName && (
199
+ <button
200
+ onClick={onUserClick}
201
+ className="flex items-center space-x-3 hover:bg-gray-50
202
+ rounded-lg px-2 py-1.5 transition-colors"
203
+ aria-label="Perfil de usuario"
204
+ >
205
+ <Avatar
206
+ src={userAvatar}
207
+ name={userName}
208
+ size="medium"
209
+ variant="circle"
210
+ />
211
+ <Typography
212
+ variant="body-lg"
213
+ className="color-gray-700 hidden md:block"
214
+ style={{
215
+ fontFamily: 'IBM Plex Sans',
216
+ fontWeight: 400,
217
+ fontStyle: 'normal',
218
+ fontSize: '16px',
219
+ lineHeight: '24px',
220
+ letterSpacing: '0%',
221
+ verticalAlign: 'middle'
222
+ }}
223
+ >
224
+ {userName}
225
+ </Typography>
226
+ <Icon
227
+ name="ChevronDownIcon"
228
+ variant="24-outline"
229
+ size={20}
230
+ className="color-gray-500"
231
+ />
232
+ </button>
233
+ )}
84
234
  </div>
235
+ </div>
85
236
 
86
- {/* Lado derecho: Botón HEXA Core */}
87
- <div className="flex items-center">
88
- <button
89
- onClick={onPointClick}
90
- className="px-4 py-2 border rounded-lg
91
- transition-colors flex items-center space-x-2"
237
+ {/* Layout Mobile (768px o menos) */}
238
+ <div className="header-mobile-layout">
239
+ {/* Primera fila: Menú, Point (centrado), Notificaciones */}
240
+ <div className="header-mobile-top-row" style={{ position: 'relative' }}>
241
+ {/* Lado izquierdo: Menú hamburguesa */}
242
+ <div className="flex items-center">
243
+ <button
244
+ className="p-2 hover:bg-gray-100 rounded-lg transition-colors header-mobile-menu-button"
245
+ style={{ cursor: 'pointer' }}
246
+ aria-label="Menú"
247
+ >
248
+ <Icon
249
+ name="Bars3Icon"
250
+ variant="24-outline"
251
+ size={24}
252
+ className="header-mobile-menu-icon"
253
+ />
254
+ </button>
255
+ </div>
256
+
257
+ {/* Centro: Texto "Point" */}
258
+ <div
92
259
  style={{
93
- borderColor: buttonBorderColor,
94
- backgroundColor: buttonBackgroundColor,
95
- color: buttonTextColor
260
+ position: 'absolute',
261
+ left: '50%',
262
+ transform: 'translateX(-50%)'
96
263
  }}
97
264
  >
98
265
  <Typography
99
- variant="body-md"
100
- style={{ color: buttonTextColor }}
266
+ variant="h6"
267
+ className="header-mobile-point-text"
268
+ style={{
269
+ fontSize: '24px',
270
+ fontFamily: 'IBM Plex Sans',
271
+ fontWeight: 600,
272
+ lineHeight: '1.2',
273
+ margin: 0
274
+ }}
101
275
  >
102
- {pointLabel}
276
+ Point
103
277
  </Typography>
104
- <Icon
105
- name="ArrowUpRightIcon"
106
- variant="24-outline"
107
- size={16}
108
- style={{ color: buttonTextColor }}
278
+ </div>
279
+
280
+ {/* Lado derecho: Notificaciones */}
281
+ <div className="flex items-center ml-auto">
282
+ {notificationCount !== undefined && (
283
+ <button
284
+ onClick={onNotificationClick}
285
+ className="relative p-2 hover:bg-gray-100 rounded-lg transition-colors header-mobile-notification-button"
286
+ style={{ cursor: 'pointer' }}
287
+ aria-label="Notificaciones"
288
+ >
289
+ <Icon
290
+ name="BellIcon"
291
+ variant="24-outline"
292
+ size={24}
293
+ className="header-mobile-notification-icon"
294
+ />
295
+ {notificationCount > 0 && (
296
+ <span
297
+ className="absolute -top-1 -right-1 px-1.5 py-0.5 min-w-[20px] h-5
298
+ text-white rounded-full flex items-center justify-center
299
+ text-body-sm font-medium"
300
+ style={{
301
+ backgroundColor: '#6D3856',
302
+ borderRadius: '12px'
303
+ }}
304
+ >
305
+ {notificationCount > 9 ? '9+' : notificationCount}
306
+ </span>
307
+ )}
308
+ </button>
309
+ )}
310
+ </div>
311
+ </div>
312
+
313
+ {/* Segunda fila: Barra de búsqueda */}
314
+ <div className="header-mobile-search-row">
315
+ <form onSubmit={handleSearchSubmit} className="header-search-form flex items-center w-full">
316
+ {/* Input de búsqueda */}
317
+ <input
318
+ type="text"
319
+ value={searchValue}
320
+ onChange={handleSearchChange}
321
+ placeholder={searchPlaceholder}
322
+ className="header-search-input flex-1 pl-3 pr-3 py-2 bg-white border border-gray-400 rounded-l-lg
323
+ focus:outline-none text-sm"
324
+ style={{
325
+ height: '40px',
326
+ borderRight: 'none',
327
+ borderTopRightRadius: '0',
328
+ borderBottomRightRadius: '0',
329
+ color: '#374151',
330
+ fontFamily: 'IBM Plex Sans',
331
+ fontWeight: 400,
332
+ fontStyle: 'italic',
333
+ fontSize: '14px',
334
+ lineHeight: '20px',
335
+ letterSpacing: '0px'
336
+ }}
109
337
  />
110
- </button>
338
+
339
+ {/* Recuadro con icono de buscar a la derecha */}
340
+ <div
341
+ className="header-search-icon-container flex items-center justify-center border border-gray-400 rounded-r-lg bg-white"
342
+ style={{
343
+ width: '40px',
344
+ height: '40px',
345
+ borderTopLeftRadius: '0',
346
+ borderBottomLeftRadius: '0'
347
+ }}
348
+ >
349
+ <Icon
350
+ name="MagnifyingGlassIcon"
351
+ variant="24-outline"
352
+ size={20}
353
+ className="color-gray-600"
354
+ />
355
+ </div>
356
+ </form>
111
357
  </div>
112
358
  </div>
113
359
  </div>
@@ -116,5 +362,3 @@ export const HeaderPoint = ({
116
362
  };
117
363
 
118
364
  export default HeaderPoint;
119
-
120
-
@@ -9,102 +9,44 @@ export default {
9
9
  export const Default = {
10
10
  render: () => (
11
11
  <HeaderPoint
12
- backgroundColor="#2D5C63"
13
- borderColor="#1F4549"
14
- verticalLineColor="#4A8A92"
15
- logoIconColor="#2D5C63"
16
- companyNameColor="#FFFFFF"
17
- dateColor="#E5E7EB"
18
- buttonBackgroundColor="#2D5C63"
19
- buttonBorderColor="#FFFFFF"
20
- buttonTextColor="#FFFFFF"
21
- date="Martes, 20 de octubre de 2023"
22
- onPointClick={() => console.log('HEXA Core clickeado')}
12
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
13
+ userName="Maria García Alonso"
14
+ userAvatar="https://i.pravatar.cc/150?img=12"
15
+ notificationCount={7}
16
+ onSearch={(value) => console.log('Búsqueda:', value)}
17
+ onNotificationClick={() => console.log('Notificaciones clickeadas')}
18
+ onUserClick={() => console.log('Usuario clickeado')}
23
19
  />
24
20
  ),
25
21
  };
26
22
 
27
- export const ConFechaAutomatica = {
23
+ export const SinNotificaciones = {
28
24
  render: () => (
29
25
  <HeaderPoint
30
- backgroundColor="#2D5C63"
31
- borderColor="#1F4549"
32
- verticalLineColor="#4A8A92"
33
- logoIconColor="#2D5C63"
34
- companyNameColor="#FFFFFF"
35
- dateColor="#E5E7EB"
36
- buttonBackgroundColor="#2D5C63"
37
- buttonBorderColor="#FFFFFF"
38
- buttonTextColor="#FFFFFF"
26
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
27
+ userName="Juan Pérez"
28
+ userAvatar="https://i.pravatar.cc/150?img=33"
29
+ notificationCount={0}
39
30
  />
40
31
  ),
41
32
  };
42
33
 
43
- export const ConLogoPersonalizado = {
34
+ export const ConMuchasNotificaciones = {
44
35
  render: () => (
45
36
  <HeaderPoint
46
- companyName="Mi Empresa"
47
- logo="https://via.placeholder.com/32"
48
- date="Lunes, 15 de enero de 2024"
49
- pointLabel="Mi Punto"
37
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
38
+ userName="Ana Martínez"
39
+ userAvatar="https://i.pravatar.cc/150?img=47"
40
+ notificationCount={15}
50
41
  />
51
42
  ),
52
43
  };
53
44
 
54
- export const ConLabelsPersonalizados = {
45
+ export const SinUsuario = {
55
46
  render: () => (
56
47
  <HeaderPoint
57
- companyName="ACME Corp"
58
- date="Viernes, 25 de diciembre de 2024"
59
- pointLabel="ACME Hub"
48
+ searchPlaceholder="Buscar empleados, reportes, configuraciones..."
49
+ notificationCount={3}
60
50
  />
61
51
  ),
62
52
  };
63
-
64
- export const ConFondoNegro = {
65
- render: () => (
66
- <HeaderPoint
67
- backgroundColor="#000000"
68
- borderColor="#333333"
69
- verticalLineColor="#666666"
70
- logoIconColor="#000000"
71
- companyNameColor="#FFFFFF"
72
- dateColor="#CCCCCC"
73
- date="Martes, 20 de octubre de 2023"
74
- onPointClick={() => console.log('HEXA Core clickeado')}
75
- />
76
- ),
77
- };
78
-
79
- export const ConBotonesPersonalizados = {
80
- render: () => (
81
- <HeaderPoint
82
- backgroundColor="#000000"
83
- buttonBackgroundColor="#FF5733"
84
- buttonBorderColor="#FFFFFF"
85
- buttonTextColor="#FFFFFF"
86
- date="Martes, 20 de octubre de 2023"
87
- onPointClick={() => console.log('HEXA Core clickeado')}
88
- />
89
- ),
90
- };
91
-
92
- export const ConTodosLosColoresPersonalizados = {
93
- render: () => (
94
- <HeaderPoint
95
- backgroundColor="#1A1A1A"
96
- borderColor="#333333"
97
- verticalLineColor="#666666"
98
- logoBackgroundColor="#FFFFFF"
99
- logoIconColor="#1A1A1A"
100
- companyNameColor="#FFFFFF"
101
- dateColor="#CCCCCC"
102
- buttonBackgroundColor="#FF5733"
103
- buttonBorderColor="#FFFFFF"
104
- buttonTextColor="#FFFFFF"
105
- date="Martes, 20 de octubre de 2023"
106
- onPointClick={() => console.log('HEXA Core clickeado')}
107
- />
108
- ),
109
- };
110
-
@@ -15,14 +15,54 @@ export const NavPoint = ({
15
15
  className = '',
16
16
  ...props
17
17
  }) => {
18
+ const shouldCompress = items.length >= 5;
19
+
18
20
  return (
19
21
  <nav
20
- className={`fixed bottom-0 left-0 right-0 z-50 md:hidden bg-white rounded-t-lg shadow-md overflow-hidden ${className}`}
22
+ className={`fixed bottom-0 left-0 right-0 z-50 md:hidden bg-white rounded-t-lg shadow-md overflow-hidden nav-point ${shouldCompress ? 'compressed' : ''} ${className}`}
21
23
  style={{
22
24
  boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.1)'
23
25
  }}
24
26
  {...props}
25
27
  >
28
+ <style>{`
29
+ .nav-point-text {
30
+ display: block;
31
+ transition: opacity 0.2s, max-height 0.2s;
32
+ overflow: hidden;
33
+ white-space: nowrap !important;
34
+ text-overflow: ellipsis;
35
+ width: 100%;
36
+ text-align: center;
37
+ }
38
+ .nav-point-item {
39
+ min-width: 0;
40
+ }
41
+ /* Ocultar textos solo cuando hay muchos items (5+) y pantalla pequeña para evitar desorden */
42
+ @media (max-width: 480px) {
43
+ .nav-point.compressed .nav-point-text {
44
+ display: none !important;
45
+ max-height: 0;
46
+ opacity: 0;
47
+ }
48
+ .nav-point.compressed .nav-point-item {
49
+ padding-left: 0.5rem !important;
50
+ padding-right: 0.5rem !important;
51
+ }
52
+ }
53
+ /* Ocultar textos solo en pantallas muy pequeñas (< 320px) donde definitivamente no caben */
54
+ @media (max-width: 320px) {
55
+ .nav-point-text {
56
+ display: none !important;
57
+ max-height: 0;
58
+ opacity: 0;
59
+ }
60
+ .nav-point-item {
61
+ padding-left: 0.5rem !important;
62
+ padding-right: 0.5rem !important;
63
+ }
64
+ }
65
+ `}</style>
26
66
  <div className="flex items-stretch">
27
67
  {items.map((item, index) => {
28
68
  const isActive = activeItem === item.id;
@@ -32,7 +72,7 @@ export const NavPoint = ({
32
72
  <button
33
73
  key={item.id}
34
74
  onClick={() => onItemClick && onItemClick(item.id)}
35
- className="flex flex-col items-center justify-center px-4 py-3 transition-all duration-200 cursor-pointer flex-1 relative"
75
+ className="flex flex-col items-center justify-center px-4 py-3 transition-all duration-200 cursor-pointer flex-1 relative nav-point-item"
36
76
  style={{
37
77
  backgroundColor: isActive ? '#2D5C63' : 'transparent',
38
78
  borderRadius: isActive
@@ -48,8 +88,14 @@ export const NavPoint = ({
48
88
  />
49
89
  <Typography
50
90
  variant="body-sm"
51
- className="mt-1 font-medium"
52
- style={{ color: isActive ? '#FFFFFF' : '#374151' }}
91
+ className="mt-1 font-medium nav-point-text"
92
+ style={{
93
+ color: isActive ? '#FFFFFF' : '#374151',
94
+ whiteSpace: 'nowrap',
95
+ overflow: 'hidden',
96
+ textOverflow: 'ellipsis',
97
+ width: '100%'
98
+ }}
53
99
  >
54
100
  {item.label}
55
101
  </Typography>