@axzydev/axzy_ui_system 1.2.6 → 1.2.8
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/dist/index.cjs +777 -535
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +1470 -87
- package/dist/index.d.ts +1470 -87
- package/dist/index.js +799 -555
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/App.tsx +19 -54
- package/src/components/alert/alert.doc.mdx +48 -0
- package/src/components/alert/alert.props.ts +7 -0
- package/src/components/alert/alert.tsx +8 -0
- package/src/components/avatar/avatar.doc.mdx +48 -0
- package/src/components/avatar/avatar.props.ts +8 -0
- package/src/components/avatar/avatar.tsx +25 -5
- package/src/components/badget/badget.doc.mdx +46 -0
- package/src/components/badget/badget.props.ts +6 -0
- package/src/components/badget/badget.tsx +11 -0
- package/src/components/breadcrumbs/breadcrumbs.doc.mdx +57 -0
- package/src/components/breadcrumbs/breadcrumbs.props.ts +6 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +12 -0
- package/src/components/button/button.doc.mdx +59 -0
- package/src/components/button/button.props.ts +12 -0
- package/src/components/button/button.tsx +11 -0
- package/src/components/calendar/calendar.doc.mdx +75 -0
- package/src/components/calendar/calendar.props.ts +27 -7
- package/src/components/calendar/calendar.tsx +13 -0
- package/src/components/card/card.doc.mdx +54 -0
- package/src/components/card/card.props.ts +11 -0
- package/src/components/card/card.tsx +13 -0
- package/src/components/checkbox/checkbox.doc.mdx +54 -0
- package/src/components/checkbox/checkbox.props.ts +7 -0
- package/src/components/checkbox/checkbox.tsx +9 -0
- package/src/components/confirm-dialog/confirm-dialog.doc.mdx +60 -0
- package/src/components/confirm-dialog/confirm-dialog.props.ts +9 -0
- package/src/components/confirm-dialog/confirm-dialog.tsx +19 -0
- package/src/components/data-table/ITDataTable.doc.mdx +59 -0
- package/src/components/data-table/dataTable.props.ts +15 -0
- package/src/components/data-table/dataTable.tsx +178 -73
- package/src/components/date-picker/date-picker.doc.mdx +65 -0
- package/src/components/date-picker/date-picker.props.ts +17 -0
- package/src/components/date-picker/datePicker.tsx +31 -1
- package/src/components/dialog/dialog.doc.mdx +54 -0
- package/src/components/dialog/dialog.props.ts +7 -0
- package/src/components/dialog/dialog.tsx +26 -0
- package/src/components/divider/divider.doc.mdx +42 -0
- package/src/components/divider/divider.props.ts +5 -0
- package/src/components/divider/divider.tsx +16 -0
- package/src/components/drawer/drawer.doc.mdx +59 -0
- package/src/components/drawer/drawer.props.ts +9 -0
- package/src/components/drawer/drawer.tsx +20 -0
- package/src/components/dropfile/dropfile.doc.mdx +59 -0
- package/src/components/dropfile/dropfile.props.ts +41 -0
- package/src/components/dropfile/dropfile.tsx +21 -33
- package/src/components/empty-state/empty-state.doc.mdx +50 -0
- package/src/components/empty-state/empty-state.props.ts +5 -0
- package/src/components/empty-state/empty-state.tsx +16 -0
- package/src/components/flex/flex.doc.mdx +59 -0
- package/src/components/flex/flex.props.ts +13 -0
- package/src/components/flex/flex.tsx +15 -0
- package/src/components/form-builder/fieldRenderer.tsx +52 -2
- package/src/components/form-builder/formBuilder.doc.mdx +124 -0
- package/src/components/form-builder/formBuilder.props.ts +12 -2
- package/src/components/form-builder/formBuilder.tsx +31 -0
- package/src/components/form-header/form-header.doc.mdx +38 -0
- package/src/components/form-header/form-header.props.ts +3 -0
- package/src/components/form-header/form-header.stories.tsx +53 -0
- package/src/components/form-header/form-header.tsx +11 -0
- package/src/components/grid/grid.doc.mdx +54 -0
- package/src/components/grid/grid.props.ts +13 -0
- package/src/components/grid/grid.tsx +26 -2
- package/src/components/image/image.doc.mdx +44 -0
- package/src/components/image/image.props.ts +5 -0
- package/src/components/image/image.stories.tsx +49 -0
- package/src/components/image/image.tsx +19 -0
- package/src/components/input/input.doc.mdx +70 -0
- package/src/components/input/input.props.ts +34 -2
- package/src/components/input/input.tsx +29 -0
- package/src/components/layout/layout.doc.mdx +51 -0
- package/src/components/layout/layout.props.ts +5 -0
- package/src/components/layout/layout.tsx +41 -17
- package/src/components/loader/loader.doc.mdx +43 -0
- package/src/components/loader/loader.props.ts +4 -0
- package/src/components/loader/loader.tsx +17 -0
- package/src/components/navbar/navbar.doc.mdx +77 -0
- package/src/components/navbar/navbar.props.ts +37 -1
- package/src/components/navbar/navbar.stories.tsx +84 -0
- package/src/components/navbar/navbar.tsx +78 -46
- package/src/components/page/page.doc.mdx +80 -0
- package/src/components/page/page.props.ts +25 -0
- package/src/components/page/page.tsx +35 -7
- package/src/components/page-header/page-header.doc.mdx +54 -0
- package/src/components/page-header/page-header.props.ts +11 -0
- package/src/components/page-header/page-header.stories.tsx +14 -0
- package/src/components/page-header/page-header.tsx +50 -15
- package/src/components/pagination/pagination.doc.mdx +62 -0
- package/src/components/pagination/pagination.props.ts +11 -32
- package/src/components/pagination/pagination.tsx +17 -0
- package/src/components/popover/popover.doc.mdx +53 -0
- package/src/components/popover/popover.props.ts +8 -0
- package/src/components/popover/popover.tsx +13 -0
- package/src/components/progress/progress.doc.mdx +48 -0
- package/src/components/progress/progress.props.ts +8 -0
- package/src/components/progress/progress.tsx +9 -0
- package/src/components/radio/radio.doc.mdx +62 -0
- package/src/components/radio/radio.props.ts +11 -0
- package/src/components/radio/radio.tsx +18 -0
- package/src/components/search-select/search-select.doc.mdx +72 -0
- package/src/components/search-select/search-select.props.ts +23 -18
- package/src/components/search-select/search-select.tsx +27 -2
- package/src/components/searchTable/searchTable.doc.mdx +79 -0
- package/src/components/searchTable/searchTable.props.ts +42 -3
- package/src/components/searchTable/searchTable.stories.tsx +74 -0
- package/src/components/searchTable/searchTable.tsx +23 -0
- package/src/components/segmented-control/segmented-control.doc.mdx +60 -0
- package/src/components/segmented-control/segmented-control.props.ts +12 -0
- package/src/components/segmented-control/segmented-control.tsx +15 -0
- package/src/components/select/select.doc.mdx +75 -0
- package/src/components/select/select.props.ts +22 -0
- package/src/components/select/select.tsx +2 -5
- package/src/components/sidebar/sidebar.doc.mdx +86 -0
- package/src/components/sidebar/sidebar.props.ts +22 -0
- package/src/components/sidebar/sidebar.tsx +22 -0
- package/src/components/skeleton/skeleton.doc.mdx +43 -0
- package/src/components/skeleton/skeleton.props.ts +8 -0
- package/src/components/skeleton/skeleton.tsx +10 -0
- package/src/components/slide/slide.doc.mdx +46 -0
- package/src/components/slide/slide.props.ts +11 -24
- package/src/components/slide/slide.tsx +10 -1
- package/src/components/slider/slider.doc.mdx +49 -0
- package/src/components/slider/slider.props.ts +9 -0
- package/src/components/slider/slider.tsx +15 -0
- package/src/components/stack/stack.doc.mdx +126 -0
- package/src/components/stack/stack.props.ts +18 -0
- package/src/components/stack/stack.stories.tsx +221 -16
- package/src/components/stack/stack.tsx +21 -0
- package/src/components/stat-card/stat-card.doc.mdx +48 -0
- package/src/components/stat-card/stat-card.props.ts +9 -0
- package/src/components/stat-card/stat-card.tsx +10 -0
- package/src/components/stepper/stepper.doc.mdx +54 -0
- package/src/components/stepper/stepper.props.ts +11 -1
- package/src/components/stepper/stepper.tsx +15 -0
- package/src/components/table/table.doc.mdx +58 -0
- package/src/components/table/table.props.ts +17 -0
- package/src/components/table/table.tsx +199 -84
- package/src/components/tabs/tabs.doc.mdx +52 -0
- package/src/components/tabs/tabs.props.ts +11 -0
- package/src/components/tabs/tabs.tsx +14 -0
- package/src/components/text/text.doc.mdx +41 -0
- package/src/components/text/text.props.ts +5 -0
- package/src/components/text/text.stories.tsx +67 -0
- package/src/components/text/text.tsx +10 -0
- package/src/components/textarea/textarea.doc.mdx +64 -0
- package/src/components/textarea/textarea.props.ts +11 -0
- package/src/components/textarea/textarea.tsx +16 -0
- package/src/components/theme-provider/themeProvider.doc.mdx +75 -0
- package/src/components/theme-provider/themeProvider.props.ts +3 -0
- package/src/components/theme-provider/themeProvider.stories.tsx +59 -0
- package/src/components/theme-provider/themeProvider.tsx +14 -0
- package/src/components/time-picker/timePicker.doc.mdx +68 -0
- package/src/components/time-picker/timePicker.props.ts +14 -0
- package/src/components/time-picker/timePicker.tsx +22 -1
- package/src/components/toast/toast.doc.mdx +50 -0
- package/src/components/toast/toast.props.ts +5 -0
- package/src/components/toast/toast.tsx +21 -0
- package/src/components/tooltip/tooltip.doc.mdx +47 -0
- package/src/components/tooltip/tooltip.props.ts +6 -0
- package/src/components/tooltip/tooltip.tsx +19 -0
- package/src/components/topbar/topbar.doc.mdx +69 -0
- package/src/components/topbar/topbar.props.ts +15 -0
- package/src/components/topbar/topbar.tsx +38 -0
- package/src/components/triple-filter/tripleFilter.doc.mdx +62 -0
- package/src/components/triple-filter/tripleFilter.props.ts +7 -0
- package/src/components/triple-filter/tripleFilter.tsx +32 -0
- package/src/index.css +17 -0
- package/src/showcases/DataShowcases.tsx +529 -45
- package/src/showcases/FormShowcases.tsx +399 -29
- package/src/showcases/HomeShowcase.tsx +252 -272
- package/src/showcases/LayoutPrimitivesShowcases.tsx +1224 -248
- package/src/showcases/PageShowcases.tsx +868 -151
- package/src/showcases/ShowcaseLayout.tsx +237 -73
- package/src/showcases/StructureShowcases.tsx +1039 -97
- package/src/types/table.types.ts +1 -1
- package/src/utils/styles.ts +2 -1
|
@@ -3,7 +3,35 @@ import { useRef, useState } from "react";
|
|
|
3
3
|
import { FaChevronDown, FaChevronRight, FaUserCircle } from "react-icons/fa";
|
|
4
4
|
import { ITNavbarProps, ITNavigationItem } from "./navbar.props";
|
|
5
5
|
import ITText from "@/components/text/text";
|
|
6
|
+
import { theme } from "@/theme/theme";
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Full sidebar navigation shell with collapsible submenus, user menu dropdown, and themed styling.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <ITNavbar
|
|
14
|
+
* logo={<LogoIcon />}
|
|
15
|
+
* logoText="My App"
|
|
16
|
+
* navigationItems={[
|
|
17
|
+
* { id: 'home', label: 'Home', icon: <FaHome />, isActive: true },
|
|
18
|
+
* {
|
|
19
|
+
* id: 'settings',
|
|
20
|
+
* label: 'Settings',
|
|
21
|
+
* icon: <FaCog />,
|
|
22
|
+
* subitems: [{ id: 'profile', label: 'Profile', action: () => {} }],
|
|
23
|
+
* },
|
|
24
|
+
* ]}
|
|
25
|
+
* userMenu={{
|
|
26
|
+
* userName: 'John Doe',
|
|
27
|
+
* userEmail: 'john@example.com',
|
|
28
|
+
* menuItems: [{ label: 'Logout', onClick: () => {} }],
|
|
29
|
+
* }}
|
|
30
|
+
* >
|
|
31
|
+
* <ITPage title="Dashboard">...</ITPage>
|
|
32
|
+
* </ITNavbar>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
7
35
|
export default function ITNavbar({
|
|
8
36
|
logo,
|
|
9
37
|
logoText,
|
|
@@ -139,15 +167,21 @@ export default function ITNavbar({
|
|
|
139
167
|
}
|
|
140
168
|
|
|
141
169
|
// New sidebar design
|
|
170
|
+
const sidebar = theme.sidebar;
|
|
171
|
+
const topbar = theme.topbar;
|
|
172
|
+
|
|
142
173
|
return (
|
|
143
|
-
<div className="flex h-screen font-sans" style={{ backgroundColor:
|
|
174
|
+
<div className="flex h-screen font-sans" style={{ backgroundColor: theme.layout.backgroundColor }}>
|
|
144
175
|
{/* Sidebar */}
|
|
145
|
-
<aside
|
|
176
|
+
<aside
|
|
177
|
+
className="w-72 shadow-xl flex flex-col transition-all duration-300 ease-in-out"
|
|
178
|
+
style={{ backgroundColor: sidebar.backgroundColor, borderRight: `1px solid ${sidebar.borderColor}` }}
|
|
179
|
+
>
|
|
146
180
|
{/* Logo Section */}
|
|
147
|
-
<div className="p-6 flex items-center gap-3" style={{ borderBottom:
|
|
181
|
+
<div className="p-6 flex items-center gap-3" style={{ borderBottom: `1px solid ${sidebar.borderColor}` }}>
|
|
148
182
|
{logo && <div className="h-8 w-auto object-contain transition-transform hover:scale-105">{logo}</div>}
|
|
149
183
|
{logoText && (
|
|
150
|
-
<ITText as="span" className="text-lg font-bold tracking-wide" style={{ color:
|
|
184
|
+
<ITText as="span" className="text-lg font-bold tracking-wide" style={{ color: sidebar.active.color }}>
|
|
151
185
|
{logoText}
|
|
152
186
|
</ITText>
|
|
153
187
|
)}
|
|
@@ -160,46 +194,42 @@ export default function ITNavbar({
|
|
|
160
194
|
<li key={item.id}>
|
|
161
195
|
<div
|
|
162
196
|
className={`group flex items-center justify-between px-4 py-3 rounded-xl cursor-pointer transition-all duration-200 border-l-4 ${
|
|
163
|
-
item.isActive
|
|
164
|
-
? 'shadow-sm'
|
|
197
|
+
item.isActive
|
|
198
|
+
? 'shadow-sm'
|
|
165
199
|
: 'hover:shadow-sm'
|
|
166
200
|
}`}
|
|
167
201
|
onClick={() => handleItemClick(item)}
|
|
168
202
|
style={{
|
|
169
|
-
backgroundColor: item.isActive ?
|
|
170
|
-
borderColor: item.isActive ?
|
|
171
|
-
color: item.isActive ?
|
|
203
|
+
backgroundColor: item.isActive ? sidebar.active.backgroundColor : "transparent",
|
|
204
|
+
borderColor: item.isActive ? sidebar.active.iconColor : "transparent",
|
|
205
|
+
color: item.isActive ? sidebar.active.color : sidebar.label.color
|
|
172
206
|
}}
|
|
173
207
|
onMouseEnter={(e) => {
|
|
174
208
|
if (!item.isActive) {
|
|
175
|
-
e.currentTarget.style.backgroundColor =
|
|
176
|
-
e.currentTarget.style.color =
|
|
209
|
+
e.currentTarget.style.backgroundColor = sidebar.hover.backgroundColor;
|
|
210
|
+
e.currentTarget.style.color = sidebar.active.color;
|
|
177
211
|
}
|
|
178
212
|
}}
|
|
179
213
|
onMouseLeave={(e) => {
|
|
180
214
|
if (!item.isActive) {
|
|
181
215
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
182
|
-
e.currentTarget.style.color =
|
|
216
|
+
e.currentTarget.style.color = sidebar.label.color;
|
|
183
217
|
}
|
|
184
218
|
}}
|
|
185
219
|
>
|
|
186
220
|
<div className="flex items-center gap-3">
|
|
187
|
-
{/* Icon */}
|
|
188
221
|
{item.icon && (
|
|
189
222
|
<div className="text-xl transition-colors" style={{
|
|
190
|
-
color: item.isActive ?
|
|
223
|
+
color: item.isActive ? sidebar.active.iconColor : sidebar.icon.color
|
|
191
224
|
}}>
|
|
192
225
|
{item.icon}
|
|
193
226
|
</div>
|
|
194
227
|
)}
|
|
195
|
-
|
|
196
|
-
{/* Label */}
|
|
197
228
|
<ITText as="span" className={`font-medium text-sm ${item.isActive ? 'font-semibold' : ''}`}>{item.label}</ITText>
|
|
198
229
|
</div>
|
|
199
230
|
|
|
200
|
-
{/* Chevron for expandable items */}
|
|
201
231
|
{item.subitems && item.subitems.length > 0 && (
|
|
202
|
-
<div className="transition-transform" style={{ color:
|
|
232
|
+
<div className="transition-transform" style={{ color: sidebar.icon.color }}>
|
|
203
233
|
{expandedItems.has(item.id) ? (
|
|
204
234
|
<FaChevronDown className="w-3 h-3" />
|
|
205
235
|
) : (
|
|
@@ -209,23 +239,22 @@ export default function ITNavbar({
|
|
|
209
239
|
)}
|
|
210
240
|
</div>
|
|
211
241
|
|
|
212
|
-
{
|
|
213
|
-
|
|
214
|
-
item.subitems.length > 0 &&
|
|
242
|
+
{item.subitems &&
|
|
243
|
+
item.subitems.length > 0 &&
|
|
215
244
|
expandedItems.has(item.id) && (
|
|
216
|
-
<ul className="mt-1 ml-4 pl-4 space-y-1" style={{ borderLeft:
|
|
245
|
+
<ul className="mt-1 ml-4 pl-4 space-y-1" style={{ borderLeft: `1px solid ${sidebar.borderColor}` }}>
|
|
217
246
|
{item.subitems.map((subitem) => (
|
|
218
247
|
<li key={subitem.id}>
|
|
219
248
|
<button
|
|
220
249
|
onClick={subitem.action}
|
|
221
250
|
className="block w-full text-left px-4 py-2.5 rounded-lg text-sm transition-all duration-200"
|
|
222
251
|
style={{
|
|
223
|
-
color: subitem.isActive ?
|
|
224
|
-
backgroundColor: subitem.isActive ?
|
|
252
|
+
color: subitem.isActive ? sidebar.active.color : sidebar.label.color,
|
|
253
|
+
backgroundColor: subitem.isActive ? sidebar.active.backgroundColor : "transparent"
|
|
225
254
|
}}
|
|
226
255
|
onMouseEnter={(e) => {
|
|
227
256
|
if (!subitem.isActive) {
|
|
228
|
-
e.currentTarget.style.backgroundColor =
|
|
257
|
+
e.currentTarget.style.backgroundColor = sidebar.hover.backgroundColor;
|
|
229
258
|
}
|
|
230
259
|
}}
|
|
231
260
|
onMouseLeave={(e) => {
|
|
@@ -247,14 +276,14 @@ export default function ITNavbar({
|
|
|
247
276
|
|
|
248
277
|
{/* User Menu */}
|
|
249
278
|
{userMenu && (
|
|
250
|
-
<div className="p-4" style={{ borderTop:
|
|
279
|
+
<div className="p-4" style={{ borderTop: `1px solid ${sidebar.borderColor}` }}>
|
|
251
280
|
<div className="relative">
|
|
252
281
|
<button
|
|
253
282
|
type="button"
|
|
254
283
|
className="flex items-center gap-3 w-full p-3 rounded-xl transition-colors duration-200 group"
|
|
255
|
-
style={{ color:
|
|
256
|
-
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor =
|
|
257
|
-
onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = "transparent"; e.currentTarget.style.color =
|
|
284
|
+
style={{ color: sidebar.label.color }}
|
|
285
|
+
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = sidebar.hover.backgroundColor; e.currentTarget.style.color = sidebar.active.color; }}
|
|
286
|
+
onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = "transparent"; e.currentTarget.style.color = sidebar.label.color; }}
|
|
258
287
|
onClick={toggleUserMenu}
|
|
259
288
|
>
|
|
260
289
|
{userMenu.userImage ? (
|
|
@@ -262,37 +291,40 @@ export default function ITNavbar({
|
|
|
262
291
|
className="w-10 h-10 rounded-full border-2 transition-colors"
|
|
263
292
|
src={userMenu.userImage}
|
|
264
293
|
alt="user photo"
|
|
265
|
-
style={{ borderColor:
|
|
294
|
+
style={{ borderColor: sidebar.borderColor }}
|
|
266
295
|
/>
|
|
267
296
|
) : (
|
|
268
|
-
<div
|
|
269
|
-
|
|
297
|
+
<div
|
|
298
|
+
className="w-10 h-10 rounded-full flex items-center justify-center transition-colors"
|
|
299
|
+
style={{ backgroundColor: sidebar.hover.backgroundColor, color: sidebar.icon.color }}
|
|
300
|
+
>
|
|
301
|
+
<FaUserCircle className="w-6 h-6" />
|
|
270
302
|
</div>
|
|
271
303
|
)}
|
|
272
304
|
<div className="flex-1 text-left overflow-hidden">
|
|
273
|
-
<ITText as="div" className="font-medium text-sm truncate" style={{ color:
|
|
305
|
+
<ITText as="div" className="font-medium text-sm truncate" style={{ color: sidebar.active.color }}>
|
|
274
306
|
{userMenu.userName}
|
|
275
307
|
</ITText>
|
|
276
|
-
<ITText as="div" className="text-xs truncate" style={{ color:
|
|
308
|
+
<ITText as="div" className="text-xs truncate" style={{ color: sidebar.label.color }}>
|
|
277
309
|
{userMenu.userEmail}
|
|
278
310
|
</ITText>
|
|
279
311
|
</div>
|
|
280
|
-
<FaChevronRight className="w-3 h-3" style={{ color:
|
|
312
|
+
<FaChevronRight className="w-3 h-3" style={{ color: sidebar.icon.color }} />
|
|
281
313
|
</button>
|
|
282
314
|
|
|
283
315
|
{isUserMenuOpen && (
|
|
284
316
|
<div
|
|
285
317
|
ref={userMenuRef}
|
|
286
318
|
className="absolute bottom-full left-0 mb-3 w-full rounded-xl shadow-2xl overflow-hidden transform transition-all duration-200 origin-bottom"
|
|
287
|
-
style={{ backgroundColor:
|
|
319
|
+
style={{ backgroundColor: topbar.userMenu.dropdown.backgroundColor, border: `1px solid ${topbar.userMenu.dropdown.borderColor}` }}
|
|
288
320
|
>
|
|
289
|
-
<div className="px-4 py-3" style={{ backgroundColor:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
321
|
+
<div className="px-4 py-3" style={{ backgroundColor: topbar.userMenu.backgroundColor, borderBottom: `1px solid ${topbar.userMenu.dropdown.borderColor}` }}>
|
|
322
|
+
<ITText as="span" className="block text-sm font-semibold" style={{ color: topbar.userMenu.textColor }}>
|
|
323
|
+
{userMenu.userName}
|
|
324
|
+
</ITText>
|
|
325
|
+
<ITText as="span" className="block text-xs truncate" style={{ color: topbar.userMenu.subtitleColor }}>
|
|
326
|
+
{userMenu.userEmail}
|
|
327
|
+
</ITText>
|
|
296
328
|
</div>
|
|
297
329
|
<ul className="py-1">
|
|
298
330
|
{userMenu.menuItems.map((item, index) => (
|
|
@@ -303,8 +335,8 @@ export default function ITNavbar({
|
|
|
303
335
|
setIsUserMenuOpen(false);
|
|
304
336
|
}}
|
|
305
337
|
className="flex items-center w-full px-4 py-2.5 text-sm transition-colors"
|
|
306
|
-
style={{ color:
|
|
307
|
-
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor =
|
|
338
|
+
style={{ color: topbar.userMenu.textColor }}
|
|
339
|
+
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = topbar.userMenu.dropdown.itemHoverBackground; }}
|
|
308
340
|
onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = "transparent"; }}
|
|
309
341
|
>
|
|
310
342
|
<ITText as="span">{item.label}</ITText>
|
|
@@ -320,7 +352,7 @@ export default function ITNavbar({
|
|
|
320
352
|
</aside>
|
|
321
353
|
|
|
322
354
|
{/* Main Content */}
|
|
323
|
-
<main className="flex-1 overflow-y-auto relative" style={{ backgroundColor:
|
|
355
|
+
<main className="flex-1 overflow-y-auto relative" style={{ backgroundColor: theme.layout.backgroundColor }}>
|
|
324
356
|
{children}
|
|
325
357
|
</main>
|
|
326
358
|
</div>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './page.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITPage
|
|
7
|
+
|
|
8
|
+
A page template component that wraps an ITPageHeader with content area and built-in state handling for loading, error, and empty states. Provides automatic skeleton placeholders during loading, an error boundary with retry action, and a customizable empty state with action.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `title` | `string` | `undefined` | Page title passed to the header. |
|
|
15
|
+
| `description` | `string` | `undefined` | Description text shown below the title. |
|
|
16
|
+
| `breadcrumbs` | `ITBreadcrumbItem[]` | `undefined` | Breadcrumb navigation items. |
|
|
17
|
+
| `actions` | `ReactNode` | `undefined` | Action buttons rendered in the header. |
|
|
18
|
+
| `backAction` | `() => void` | `undefined` | Callback for the back button. |
|
|
19
|
+
| `icon` | `ReactNode` | `undefined` | Icon displayed next to the title. |
|
|
20
|
+
| `iconColor` | `string` | `undefined` | Custom color for the icon. |
|
|
21
|
+
| `loading` | `boolean` | `false` | When true, shows skeleton placeholders instead of content. |
|
|
22
|
+
| `error` | `string \| null` | `null` | Error message. When provided, shows an error state with retry button. |
|
|
23
|
+
| `errorTitle` | `string` | `'Error'` | Custom title for the error state. |
|
|
24
|
+
| `errorActionLabel` | `string` | `'Reintentar'` | Label for the retry button in the error state. |
|
|
25
|
+
| `onRetry` | `() => void` | `undefined` | Callback when the retry button is clicked. |
|
|
26
|
+
| `empty` | `boolean` | `false` | When true, shows an empty state placeholder. |
|
|
27
|
+
| `emptyTitle` | `string` | `'Sin datos'` | Custom title for the empty state. |
|
|
28
|
+
| `emptyDescription` | `string` | `undefined` | Custom description for the empty state. |
|
|
29
|
+
| `emptyAction` | `ReactNode` | `undefined` | Custom action element for the empty state. |
|
|
30
|
+
| `children` | `ReactNode` | required | Content rendered when no special state (loading/error/empty) is active. |
|
|
31
|
+
| `maxWidth` | `'2xl' \| '3xl' \| '4xl' \| '5xl' \| '6xl' \| '7xl'` | `'7xl'` | Maximum width of the page content container. |
|
|
32
|
+
| `noPadding` | `boolean` | `false` | When true, removes default padding from the page wrapper. |
|
|
33
|
+
| `className` | `string` | `undefined` | Additional CSS classes for the page wrapper. |
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { ITPage } from '@axzydev/axzy_ui_system';
|
|
39
|
+
|
|
40
|
+
<ITPage title="Users" description="Manage system users" actions={<ITButton label="Add" />}>
|
|
41
|
+
<p>Your page content</p>
|
|
42
|
+
</ITPage>
|
|
43
|
+
|
|
44
|
+
<ITPage title="Dashboard" loading>
|
|
45
|
+
<p>Content not shown while loading</p>
|
|
46
|
+
</ITPage>
|
|
47
|
+
|
|
48
|
+
<ITPage
|
|
49
|
+
title="Orders"
|
|
50
|
+
error="Failed to load orders"
|
|
51
|
+
onRetry={() => refetch()}
|
|
52
|
+
>
|
|
53
|
+
<p>Content not shown while error</p>
|
|
54
|
+
</ITPage>
|
|
55
|
+
|
|
56
|
+
<ITPage
|
|
57
|
+
title="Notifications"
|
|
58
|
+
empty
|
|
59
|
+
emptyTitle="No notifications"
|
|
60
|
+
emptyAction={<ITButton label="Refresh" />}
|
|
61
|
+
>
|
|
62
|
+
<p>Content not shown while empty</p>
|
|
63
|
+
</ITPage>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Notes
|
|
67
|
+
|
|
68
|
+
- State priority: `error` > `loading` > `empty` > `children`.
|
|
69
|
+
- The loading state renders animated skeleton blocks matching common page patterns.
|
|
70
|
+
- The error state renders a centered error icon, message, and a retry button.
|
|
71
|
+
- The empty state renders a centered placeholder with optional title, description, and action.
|
|
72
|
+
- All header props (`title`, `description`, `breadcrumbs`, `actions`, `backAction`, `icon`) are forwarded to ITPageHeader.
|
|
73
|
+
- Content maximum width is controlled by Tailwind max-width classes via `maxWidth`.
|
|
74
|
+
- `noPadding` is useful for full-bleed layouts like dashboards.
|
|
75
|
+
|
|
76
|
+
## Stories
|
|
77
|
+
|
|
78
|
+
<Primary />
|
|
79
|
+
<Controls />
|
|
80
|
+
<Stories />
|
|
@@ -1,21 +1,46 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { ITBreadcrumbItem } from "../breadcrumbs/breadcrumbs.props";
|
|
3
3
|
|
|
4
|
+
/** Props for the ITPage component. */
|
|
4
5
|
export interface ITPageProps {
|
|
6
|
+
/** Page title passed to the header. */
|
|
5
7
|
title?: string;
|
|
8
|
+
/** Description text shown below the title. */
|
|
6
9
|
description?: string;
|
|
10
|
+
/** Array of breadcrumb items for navigation context. */
|
|
7
11
|
breadcrumbs?: ITBreadcrumbItem[];
|
|
12
|
+
/** Action buttons rendered in the header. */
|
|
8
13
|
actions?: ReactNode;
|
|
14
|
+
/** Callback fired when the back button is clicked. */
|
|
9
15
|
backAction?: () => void;
|
|
16
|
+
/** Optional icon displayed next to the title. */
|
|
17
|
+
icon?: ReactNode;
|
|
18
|
+
/** Custom color for the icon. Accepts any valid CSS color value. */
|
|
19
|
+
iconColor?: string;
|
|
20
|
+
/** Whether the page is in a loading state. Shows skeleton placeholders when true. */
|
|
10
21
|
loading?: boolean;
|
|
22
|
+
/** Error message to display. Shows an error state with retry button when provided. */
|
|
11
23
|
error?: string | null;
|
|
24
|
+
/** Custom title for the error state. Default: "Error". */
|
|
12
25
|
errorTitle?: string;
|
|
26
|
+
/** Label for the retry button in the error state. Default: "Reintentar". */
|
|
13
27
|
errorActionLabel?: string;
|
|
28
|
+
/** Callback fired when the retry button is clicked in the error state. */
|
|
14
29
|
onRetry?: () => void;
|
|
30
|
+
/** Whether the page is in an empty state. Shows a placeholder when true. */
|
|
15
31
|
empty?: boolean;
|
|
32
|
+
/** Custom title for the empty state. Default: "Sin datos". */
|
|
16
33
|
emptyTitle?: string;
|
|
34
|
+
/** Custom description for the empty state. */
|
|
17
35
|
emptyDescription?: string;
|
|
36
|
+
/** Custom action element for the empty state. */
|
|
18
37
|
emptyAction?: ReactNode;
|
|
38
|
+
/** Additional CSS classes for the page wrapper. */
|
|
19
39
|
className?: string;
|
|
40
|
+
/** Content rendered inside the page wrapper. */
|
|
20
41
|
children: ReactNode;
|
|
42
|
+
/** Maximum width of the page content. Options: "2xl", "3xl", "4xl", "5xl", "6xl", "7xl". Default: "7xl". */
|
|
43
|
+
maxWidth?: "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "7xl";
|
|
44
|
+
/** Whether to remove default padding from the page wrapper. */
|
|
45
|
+
noPadding?: boolean;
|
|
21
46
|
}
|
|
@@ -7,7 +7,7 @@ import ITButton from "../button/button";
|
|
|
7
7
|
import ITStack from "../stack/stack";
|
|
8
8
|
|
|
9
9
|
const hasHeader = (props: ITPageProps) =>
|
|
10
|
-
!!(props.title || props.description || props.breadcrumbs || props.actions || props.backAction);
|
|
10
|
+
!!(props.title || props.description || props.breadcrumbs || props.actions || props.backAction || props.icon);
|
|
11
11
|
|
|
12
12
|
const renderHeader = (props: ITPageProps) => {
|
|
13
13
|
if (!hasHeader(props)) return null;
|
|
@@ -18,10 +18,30 @@ const renderHeader = (props: ITPageProps) => {
|
|
|
18
18
|
breadcrumbs={props.breadcrumbs}
|
|
19
19
|
actions={props.actions}
|
|
20
20
|
backAction={props.backAction}
|
|
21
|
+
icon={props.icon}
|
|
22
|
+
iconColor={props.iconColor}
|
|
21
23
|
/>
|
|
22
24
|
);
|
|
23
25
|
};
|
|
24
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Page template combining a page header and content area with built-in states for loading, error, and empty.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <ITPage
|
|
33
|
+
* title="Dashboard"
|
|
34
|
+
* description="Overview of your account"
|
|
35
|
+
* breadcrumbs={[{ label: 'Home' }, { label: 'Dashboard' }]}
|
|
36
|
+
* actions={<ITButton label="Refresh" />}
|
|
37
|
+
* loading={isLoading}
|
|
38
|
+
* error={errorMessage}
|
|
39
|
+
* onRetry={fetchData}
|
|
40
|
+
* >
|
|
41
|
+
* <ITCard>Dashboard content</ITCard>
|
|
42
|
+
* </ITPage>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
25
45
|
export default function ITPage(props: ITPageProps) {
|
|
26
46
|
const {
|
|
27
47
|
loading = false,
|
|
@@ -35,18 +55,26 @@ export default function ITPage(props: ITPageProps) {
|
|
|
35
55
|
emptyAction,
|
|
36
56
|
className,
|
|
37
57
|
children,
|
|
58
|
+
maxWidth = "7xl",
|
|
59
|
+
noPadding = false,
|
|
38
60
|
} = props;
|
|
39
61
|
|
|
40
|
-
const wrapperClass = clsx(
|
|
62
|
+
const wrapperClass = clsx(
|
|
63
|
+
"mx-auto w-full",
|
|
64
|
+
!noPadding && "px-4 sm:px-6 lg:px-8 py-6",
|
|
65
|
+
`max-w-${maxWidth}`,
|
|
66
|
+
"space-y-8",
|
|
67
|
+
className
|
|
68
|
+
);
|
|
41
69
|
|
|
42
70
|
if (loading) {
|
|
43
71
|
return (
|
|
44
72
|
<div className={wrapperClass}>
|
|
45
73
|
{renderHeader(props)}
|
|
46
|
-
<ITStack spacing={
|
|
47
|
-
<ITSkeleton variant="rectangular" height={40} width="40%" />
|
|
48
|
-
<ITSkeleton variant="rectangular" height={200} />
|
|
49
|
-
<ITSkeleton variant="rectangular" height={200} />
|
|
74
|
+
<ITStack spacing={6}>
|
|
75
|
+
<ITSkeleton variant="rectangular" height={40} width="40%" className="rounded-lg" />
|
|
76
|
+
<ITSkeleton variant="rectangular" height={200} className="rounded-lg" />
|
|
77
|
+
<ITSkeleton variant="rectangular" height={200} className="rounded-lg" />
|
|
50
78
|
</ITStack>
|
|
51
79
|
</div>
|
|
52
80
|
);
|
|
@@ -92,4 +120,4 @@ export default function ITPage(props: ITPageProps) {
|
|
|
92
120
|
{children}
|
|
93
121
|
</div>
|
|
94
122
|
);
|
|
95
|
-
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Meta, Title, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './page-header.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# ITPageHeader
|
|
7
|
+
|
|
8
|
+
A page title bar component that displays a heading with optional breadcrumbs, description text, action buttons, and a back navigation button. Designed to sit at the top of page content for consistent page-level navigation.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
|------|------|---------|-------------|
|
|
14
|
+
| `title` | `string` | required | Page title displayed as the main heading. |
|
|
15
|
+
| `description` | `string` | `undefined` | Optional description text shown below the title. |
|
|
16
|
+
| `breadcrumbs` | `ITBreadcrumbItem[]` | `undefined` | Breadcrumb navigation items above the title. |
|
|
17
|
+
| `actions` | `ReactNode` | `undefined` | Action buttons or elements rendered on the right side. |
|
|
18
|
+
| `backAction` | `() => void` | `undefined` | Callback fired when the back button is clicked. |
|
|
19
|
+
| `icon` | `ReactNode` | `undefined` | Optional icon displayed next to the title. |
|
|
20
|
+
| `iconColor` | `string` | `undefined` | Custom CSS color value for the icon. |
|
|
21
|
+
| `className` | `string` | `undefined` | Additional CSS classes for the container. |
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { ITPageHeader } from '@axzydev/axzy_ui_system';
|
|
27
|
+
import { FaUsers } from 'react-icons/fa';
|
|
28
|
+
|
|
29
|
+
<ITPageHeader
|
|
30
|
+
title="Users"
|
|
31
|
+
description="Manage system users"
|
|
32
|
+
breadcrumbs={[{ label: 'Dashboard', href: '#' }, { label: 'Users' }]}
|
|
33
|
+
actions={<ITButton label="Add User" />}
|
|
34
|
+
/>
|
|
35
|
+
<ITPageHeader
|
|
36
|
+
title="Edit User"
|
|
37
|
+
backAction={() => navigate(-1)}
|
|
38
|
+
breadcrumbs={[{ label: 'Users', href: '/users' }, { label: 'Edit' }]}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Notes
|
|
43
|
+
|
|
44
|
+
- Breadcrumbs render above the title using the ITBreadcrumbs component.
|
|
45
|
+
- `backAction` renders a left-arrow button before the content; breadcrumbs shift to the right of the back button.
|
|
46
|
+
- The `icon` slot places an icon beside the title, colored by `iconColor` or the primary theme color.
|
|
47
|
+
- Actions area accepts any React nodes; typically ITButton components with `small` sizing.
|
|
48
|
+
- The component uses a flex layout: breadcrumbs + back button on the left, actions on the right.
|
|
49
|
+
|
|
50
|
+
## Stories
|
|
51
|
+
|
|
52
|
+
<Primary />
|
|
53
|
+
<Controls />
|
|
54
|
+
<Stories />
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { ITBreadcrumbItem } from "../breadcrumbs/breadcrumbs.props";
|
|
3
3
|
|
|
4
|
+
/** Props for the ITPageHeader component. */
|
|
4
5
|
export interface ITPageHeaderProps {
|
|
6
|
+
/** Page title displayed as the main heading. */
|
|
5
7
|
title: string;
|
|
8
|
+
/** Optional description text shown below the title. */
|
|
6
9
|
description?: string;
|
|
10
|
+
/** Array of breadcrumb items for navigation context. */
|
|
7
11
|
breadcrumbs?: ITBreadcrumbItem[];
|
|
12
|
+
/** Action buttons or elements rendered on the right side. */
|
|
8
13
|
actions?: ReactNode;
|
|
14
|
+
/** Callback fired when the back button is clicked. */
|
|
9
15
|
backAction?: () => void;
|
|
16
|
+
/** Optional icon displayed next to the title. */
|
|
17
|
+
icon?: ReactNode;
|
|
18
|
+
/** Custom color for the icon. Accepts any valid CSS color value. */
|
|
19
|
+
iconColor?: string;
|
|
20
|
+
/** Additional CSS classes for the container. */
|
|
10
21
|
className?: string;
|
|
11
22
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { FaUsers } from "react-icons/fa";
|
|
2
3
|
import ITPageHeader from "./page-header";
|
|
3
4
|
import ITButton from "../button/button";
|
|
4
5
|
|
|
@@ -59,3 +60,16 @@ export const WithBackAction: Story = {
|
|
|
59
60
|
actions: <ITButton label="Editar" size="small" />,
|
|
60
61
|
},
|
|
61
62
|
};
|
|
63
|
+
|
|
64
|
+
export const WithIcon: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
title: "Usuarios",
|
|
67
|
+
description: "Gestiona los usuarios del sistema",
|
|
68
|
+
icon: <FaUsers size={20} />,
|
|
69
|
+
iconColor: "#6366f1",
|
|
70
|
+
breadcrumbs: [
|
|
71
|
+
{ label: "Inicio", href: "#" },
|
|
72
|
+
{ label: "Usuarios" },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
};
|