xertica-ui 2.1.2 → 2.1.4
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/CHANGELOG.md +46 -0
- package/README.md +1 -1
- package/bin/cli.ts +1 -1
- package/bin/generate-tokens.ts +13 -7
- package/components/assistant/xertica-assistant/index.ts +2 -0
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +97 -0
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -0
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -0
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +86 -0
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +77 -0
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +573 -0
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +65 -0
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -0
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +98 -0
- package/components/assistant/xertica-assistant/parts/index.ts +16 -0
- package/components/assistant/xertica-assistant/types.ts +139 -0
- package/components/assistant/xertica-assistant/use-assistant.ts +559 -0
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +200 -0
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +198 -1460
- package/components/brand/theme-toggle/ThemeToggle.tsx +8 -27
- package/components/hooks/index.ts +3 -0
- package/components/hooks/use-layout-shortcuts.ts +46 -0
- package/components/layout/sidebar/index.ts +2 -0
- package/components/layout/sidebar/sidebar.stories.tsx +160 -8
- package/components/layout/sidebar/sidebar.tsx +606 -497
- package/components/layout/sidebar/use-sidebar.ts +104 -0
- package/components/media/audio-player/AudioPlayer.tsx +131 -206
- package/components/media/audio-player/use-audio-player.ts +298 -0
- package/components/pages/home-page/HomePage.tsx +1 -1
- package/components/pages/template-content/TemplateContent.tsx +5 -5
- package/components/pages/template-page/TemplatePage.tsx +5 -5
- package/components/shared/CustomTooltipContent.tsx +52 -0
- package/components/shared/layout-constants.ts +1 -1
- package/components/ui/chart/chart.stories.tsx +966 -7
- package/components/ui/chart/chart.tsx +918 -45
- package/components/ui/file-upload/file-upload.stories.tsx +100 -0
- package/components/ui/file-upload/file-upload.tsx +14 -74
- package/components/ui/file-upload/index.ts +1 -0
- package/components/ui/file-upload/use-file-upload.ts +181 -0
- package/components/ui/pagination/index.ts +2 -0
- package/components/ui/pagination/pagination.stories.tsx +94 -0
- package/components/ui/pagination/use-pagination.ts +194 -0
- package/components/ui/rich-text-editor/index.ts +2 -0
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +129 -1
- package/components/ui/rich-text-editor/rich-text-editor.tsx +86 -305
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +439 -0
- package/components/ui/stepper/index.ts +3 -1
- package/components/ui/stepper/stepper.stories.tsx +116 -0
- package/components/ui/stepper/stepper.tsx +4 -4
- package/components/ui/stepper/use-stepper.ts +137 -0
- package/components/ui/tree-view/index.ts +4 -1
- package/components/ui/tree-view/tree-view.stories.tsx +110 -4
- package/components/ui/tree-view/tree-view.tsx +17 -125
- package/components/ui/tree-view/use-tree-view.ts +229 -0
- package/contexts/AssistenteContext.tsx +17 -54
- package/contexts/BrandColorsContext.tsx +6 -17
- package/contexts/LayoutContext.tsx +5 -31
- package/dist/AssistantChart-BAudAfne.cjs +3591 -0
- package/dist/AssistantChart-BP8upjMk.js +3565 -0
- package/dist/AudioPlayer-1ypwE2Wh.cjs +936 -0
- package/dist/AudioPlayer-DuKXrCfy.js +937 -0
- package/dist/CustomTooltipContent-DHjkY0ww.js +40 -0
- package/dist/CustomTooltipContent-c_K-DWRr.cjs +56 -0
- package/dist/LanguageContext-BwhwC3G2.js +657 -0
- package/dist/LanguageContext-DvUt5jBg.cjs +656 -0
- package/dist/LayoutContext-BDmcZfMH.cjs +84 -0
- package/dist/LayoutContext-dbQvdC4O.js +85 -0
- package/dist/ThemeContext-RTy1m2Uq.js +82 -0
- package/dist/ThemeContext-bSzuOit2.cjs +81 -0
- package/dist/VerifyEmailPage-C_ihbcth.js +2828 -0
- package/dist/VerifyEmailPage-Dt7zgA4w.cjs +2827 -0
- package/dist/XerticaProvider-CW9hpCdF.cjs +39 -0
- package/dist/XerticaProvider-siSt9uG2.js +40 -0
- package/dist/XerticaXLogo-D8jf0SNv.cjs +214 -0
- package/dist/XerticaXLogo-fAJMy3H4.js +215 -0
- package/dist/assistant.cjs.js +2 -1
- package/dist/assistant.es.js +3 -2
- package/dist/brand.cjs.js +2 -2
- package/dist/brand.es.js +2 -2
- package/dist/cli.js +14 -8
- package/dist/components/assistant/xertica-assistant/index.d.ts +2 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +19 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +11 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +29 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +4 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/index.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/types.d.ts +106 -0
- package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +125 -0
- package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +8 -97
- package/dist/components/hooks/index.d.ts +3 -0
- package/dist/components/hooks/use-layout-shortcuts.d.ts +22 -0
- package/dist/components/layout/sidebar/index.d.ts +2 -0
- package/dist/components/layout/sidebar/sidebar.d.ts +80 -0
- package/dist/components/layout/sidebar/use-sidebar.d.ts +22 -0
- package/dist/components/media/audio-player/AudioPlayer.d.ts +4 -1
- package/dist/components/media/audio-player/use-audio-player.d.ts +72 -0
- package/dist/components/shared/CustomTooltipContent.d.ts +20 -0
- package/dist/components/shared/layout-constants.d.ts +1 -1
- package/dist/components/ui/alert/alert.d.ts +1 -1
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/button/button.d.ts +2 -2
- package/dist/components/ui/chart/chart.d.ts +162 -5
- package/dist/components/ui/file-upload/file-upload.d.ts +2 -0
- package/dist/components/ui/file-upload/index.d.ts +1 -0
- package/dist/components/ui/file-upload/use-file-upload.d.ts +49 -0
- package/dist/components/ui/pagination/index.d.ts +2 -0
- package/dist/components/ui/pagination/use-pagination.d.ts +78 -0
- package/dist/components/ui/rich-text-editor/index.d.ts +2 -0
- package/dist/components/ui/rich-text-editor/use-rich-text-editor.d.ts +107 -0
- package/dist/components/ui/stepper/index.d.ts +3 -1
- package/dist/components/ui/stepper/stepper.d.ts +2 -2
- package/dist/components/ui/stepper/use-stepper.d.ts +60 -0
- package/dist/components/ui/tree-view/index.d.ts +4 -1
- package/dist/components/ui/tree-view/tree-view.d.ts +4 -6
- package/dist/components/ui/tree-view/use-tree-view.d.ts +60 -0
- package/dist/contexts/AssistenteContext.d.ts +10 -49
- package/dist/hooks.cjs.js +30 -10
- package/dist/hooks.es.js +25 -4
- package/dist/index.cjs.js +20 -9
- package/dist/index.es.js +38 -27
- package/dist/layout.cjs.js +82 -1
- package/dist/layout.es.js +83 -2
- package/dist/media.cjs.js +1 -1
- package/dist/media.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/rich-text-editor-BmsjY03B.js +2949 -0
- package/dist/rich-text-editor-GS2kpTAK.cjs +2966 -0
- package/dist/sidebar-CVUGHOS_.cjs +756 -0
- package/dist/sidebar-CmvwjnVb.js +757 -0
- package/dist/ui.cjs.js +12 -2
- package/dist/ui.es.js +24 -14
- package/dist/use-audio-player-Bkh23vQ3.js +177 -0
- package/dist/use-audio-player-Dn1NR9xN.cjs +176 -0
- package/dist/utils/color-utils.d.ts +51 -0
- package/dist/xertica-assistant-BMqdyRVi.js +2082 -0
- package/dist/xertica-assistant-Bj3vBCq_.cjs +2081 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/ai-usage.md +28 -10
- package/docs/architecture-improvements.md +463 -0
- package/docs/architecture.md +77 -1
- package/docs/components/assistant-chart.md +1 -1
- package/docs/components/assistant.md +159 -0
- package/docs/components/audio-player.md +46 -0
- package/docs/components/branding.md +251 -0
- package/docs/components/chart.md +354 -39
- package/docs/components/code-block.md +108 -0
- package/docs/components/file-upload.md +119 -2
- package/docs/components/formatted-document.md +113 -0
- package/docs/components/hooks.md +430 -0
- package/docs/components/image-with-fallback.md +106 -0
- package/docs/components/map-layers.md +140 -0
- package/docs/components/modern-chat-input.md +163 -0
- package/docs/components/pages.md +351 -0
- package/docs/components/pagination.md +187 -0
- package/docs/components/rich-text-editor.md +164 -0
- package/docs/components/sidebar.md +153 -4
- package/docs/components/stepper.md +157 -12
- package/docs/components/tree-view.md +164 -6
- package/docs/doc-audit.md +223 -0
- package/docs/getting-started.md +155 -1
- package/docs/guidelines.md +14 -8
- package/docs/layout.md +2 -2
- package/docs/llms.md +29 -9
- package/docs/patterns/detail-page.md +276 -0
- package/docs/patterns/settings.md +346 -0
- package/docs/patterns/wizard.md +217 -0
- package/guidelines/Guidelines.md +5 -3
- package/llms.txt +1 -1
- package/package.json +10 -10
- package/styles/xertica/tokens.css +41 -12
- package/templates/CLAUDE.md +16 -6
- package/templates/guidelines/Guidelines.md +16 -4
- package/templates/package.json +3 -3
- package/templates/src/styles/xertica/tokens.css +39 -10
- package/utils/color-utils.ts +72 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Page Templates — Xertica UI
|
|
2
|
+
|
|
3
|
+
Xertica UI ships 8 ready-to-use page templates covering authentication flows, the main dashboard shell, and a fully-featured component showcase. All templates are exported from `xertica-ui/pages`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import {
|
|
11
|
+
LoginPage,
|
|
12
|
+
ForgotPasswordPage,
|
|
13
|
+
ResetPasswordPage,
|
|
14
|
+
VerifyEmailPage,
|
|
15
|
+
HomePage,
|
|
16
|
+
HomeContent,
|
|
17
|
+
TemplatePage,
|
|
18
|
+
TemplateContent,
|
|
19
|
+
} from 'xertica-ui/pages';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Authentication Pages
|
|
25
|
+
|
|
26
|
+
### `LoginPage`
|
|
27
|
+
|
|
28
|
+
A complete, responsive login screen with a hero image side-panel (desktop) and a focused authentication form.
|
|
29
|
+
|
|
30
|
+
**Features:**
|
|
31
|
+
- Email + password form with validation
|
|
32
|
+
- Loading state during submission
|
|
33
|
+
- Error message display
|
|
34
|
+
- Social/SSO provider placeholders (Google, MT Login, gov.br)
|
|
35
|
+
- Language selector (`LanguageSelector`)
|
|
36
|
+
- Xertica logo
|
|
37
|
+
- Link to forgot-password flow (via `react-router-dom`)
|
|
38
|
+
|
|
39
|
+
**Props:**
|
|
40
|
+
|
|
41
|
+
| Prop | Type | Description |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `onLogin` | `(email: string, password: string) => boolean` | Authentication handler. Return `true` on success, `false` to show an error. |
|
|
44
|
+
|
|
45
|
+
**Usage:**
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { LoginPage } from 'xertica-ui/pages';
|
|
49
|
+
import { useNavigate } from 'react-router-dom';
|
|
50
|
+
|
|
51
|
+
function AuthRoute() {
|
|
52
|
+
const navigate = useNavigate();
|
|
53
|
+
|
|
54
|
+
const handleLogin = (email: string, password: string): boolean => {
|
|
55
|
+
if (!email || !password) return false;
|
|
56
|
+
// call your auth API here
|
|
57
|
+
navigate('/home');
|
|
58
|
+
return true;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return <LoginPage onLogin={handleLogin} />;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### `ForgotPasswordPage`
|
|
68
|
+
|
|
69
|
+
A password recovery form where users enter their email to receive a reset link.
|
|
70
|
+
|
|
71
|
+
**Features:**
|
|
72
|
+
- Email input with validation
|
|
73
|
+
- Success state (shows confirmation message after submission)
|
|
74
|
+
- Back-to-login navigation link
|
|
75
|
+
- Xertica logo + hero image
|
|
76
|
+
|
|
77
|
+
**Props:**
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Description |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `onSubmit` | `(email: string) => void` | Called when the user submits the recovery form |
|
|
82
|
+
|
|
83
|
+
**Usage:**
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { ForgotPasswordPage } from 'xertica-ui/pages';
|
|
87
|
+
|
|
88
|
+
<ForgotPasswordPage
|
|
89
|
+
onSubmit={(email) => {
|
|
90
|
+
// send password reset email
|
|
91
|
+
console.log('Reset requested for:', email);
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### `ResetPasswordPage`
|
|
99
|
+
|
|
100
|
+
A new-password form for users arriving via a password reset link.
|
|
101
|
+
|
|
102
|
+
**Features:**
|
|
103
|
+
- New password + confirm password fields
|
|
104
|
+
- Password match validation
|
|
105
|
+
- Success state after reset
|
|
106
|
+
|
|
107
|
+
**Props:**
|
|
108
|
+
|
|
109
|
+
| Prop | Type | Description |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `onReset` | `(password: string) => void` | Called with the new password when the form is submitted |
|
|
112
|
+
|
|
113
|
+
**Usage:**
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import { ResetPasswordPage } from 'xertica-ui/pages';
|
|
117
|
+
|
|
118
|
+
<ResetPasswordPage
|
|
119
|
+
onReset={(newPassword) => {
|
|
120
|
+
// call your reset API with the token from the URL
|
|
121
|
+
console.log('New password:', newPassword);
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### `VerifyEmailPage`
|
|
129
|
+
|
|
130
|
+
An email verification confirmation screen shown after registration.
|
|
131
|
+
|
|
132
|
+
**Features:**
|
|
133
|
+
- Confirmation message with email address display
|
|
134
|
+
- "Resend email" action
|
|
135
|
+
- Back-to-login link
|
|
136
|
+
|
|
137
|
+
**Props:**
|
|
138
|
+
|
|
139
|
+
| Prop | Type | Description |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `email` | `string` | The email address to display in the confirmation message |
|
|
142
|
+
| `onResend` | `() => void` | Called when the user clicks "Resend verification email" |
|
|
143
|
+
|
|
144
|
+
**Usage:**
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { VerifyEmailPage } from 'xertica-ui/pages';
|
|
148
|
+
|
|
149
|
+
<VerifyEmailPage
|
|
150
|
+
email="user@example.com"
|
|
151
|
+
onResend={() => {
|
|
152
|
+
// resend verification email
|
|
153
|
+
}}
|
|
154
|
+
/>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Dashboard Pages
|
|
160
|
+
|
|
161
|
+
### `HomePage`
|
|
162
|
+
|
|
163
|
+
The root dashboard page. Assembles `Sidebar`, `HomeContent`, and `XerticaAssistant` into a full-screen layout.
|
|
164
|
+
|
|
165
|
+
**Features:**
|
|
166
|
+
- Full-screen `h-screen` layout with sidebar + main content + assistant
|
|
167
|
+
- Integrates `LayoutContext` for synchronized sidebar/assistant state
|
|
168
|
+
- Falls back to local state if `LayoutContext` is not available (standalone usage)
|
|
169
|
+
- Pre-configured `XerticaAssistant` in demo mode with sample suggestions
|
|
170
|
+
|
|
171
|
+
**Props:**
|
|
172
|
+
|
|
173
|
+
| Prop | Type | Description |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| `user` | `{ email: string } \| null` | Currently logged-in user |
|
|
176
|
+
| `onLogout` | `() => void` | Logout handler passed to the Sidebar footer |
|
|
177
|
+
|
|
178
|
+
**Usage:**
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { HomePage } from 'xertica-ui/pages';
|
|
182
|
+
|
|
183
|
+
<HomePage
|
|
184
|
+
user={{ email: 'user@example.com' }}
|
|
185
|
+
onLogout={() => {
|
|
186
|
+
// clear session and redirect to login
|
|
187
|
+
navigate('/login');
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
> **Note**: `HomePage` uses `react-router-dom` hooks internally. It must be rendered inside a `<BrowserRouter>` (or equivalent).
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### `HomeContent`
|
|
197
|
+
|
|
198
|
+
The main content area of the dashboard — used inside `HomePage`. Can also be used standalone to build custom page shells.
|
|
199
|
+
|
|
200
|
+
**Features:**
|
|
201
|
+
- `Header` with breadcrumbs, user menu, and actions
|
|
202
|
+
- Stats cards row
|
|
203
|
+
- Charts section
|
|
204
|
+
- Recent activity table
|
|
205
|
+
|
|
206
|
+
**Props:**
|
|
207
|
+
|
|
208
|
+
| Prop | Type | Description |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `user` | `{ email: string } \| null` | User object for the header |
|
|
211
|
+
| `onLogout` | `() => void` | Logout handler |
|
|
212
|
+
| `sidebarExpanded` | `boolean` | Controls header left padding |
|
|
213
|
+
| `sidebarWidth` | `number` | Sidebar width in pixels |
|
|
214
|
+
| `onToggleSidebar` | `() => void` | Sidebar toggle callback |
|
|
215
|
+
| `onToggleAssistant` | `() => void` | Assistant toggle callback |
|
|
216
|
+
|
|
217
|
+
**Usage:**
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { HomeContent } from 'xertica-ui/pages';
|
|
221
|
+
import { useLayout } from 'xertica-ui/hooks';
|
|
222
|
+
|
|
223
|
+
function MyDashboard({ user, onLogout }) {
|
|
224
|
+
const { sidebarExpanded, sidebarWidth, toggleSidebar, toggleAssistente } = useLayout();
|
|
225
|
+
return (
|
|
226
|
+
<HomeContent
|
|
227
|
+
user={user}
|
|
228
|
+
onLogout={onLogout}
|
|
229
|
+
sidebarExpanded={sidebarExpanded}
|
|
230
|
+
sidebarWidth={sidebarWidth}
|
|
231
|
+
onToggleSidebar={toggleSidebar}
|
|
232
|
+
onToggleAssistant={toggleAssistente}
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### `TemplatePage`
|
|
241
|
+
|
|
242
|
+
A complete layout shell identical to `HomePage` but with `TemplateContent` as the main area. Use this as the **primary reference** for building new pages in a Xertica UI project.
|
|
243
|
+
|
|
244
|
+
**Features:**
|
|
245
|
+
- Full-screen layout: Sidebar + TemplateContent + XerticaAssistant
|
|
246
|
+
- Synchronized layout state via `LayoutContext`
|
|
247
|
+
- Demonstrates all major layout patterns
|
|
248
|
+
|
|
249
|
+
**Props:**
|
|
250
|
+
|
|
251
|
+
| Prop | Type | Description |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| `user` | `{ email: string } \| null` | Currently logged-in user |
|
|
254
|
+
| `onLogout` | `() => void` | Logout handler |
|
|
255
|
+
|
|
256
|
+
**Usage:**
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
import { TemplatePage } from 'xertica-ui/pages';
|
|
260
|
+
|
|
261
|
+
// Use as a starting point for new feature pages
|
|
262
|
+
<TemplatePage
|
|
263
|
+
user={currentUser}
|
|
264
|
+
onLogout={handleLogout}
|
|
265
|
+
/>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
### `TemplateContent`
|
|
271
|
+
|
|
272
|
+
The main content area of `TemplatePage`. Contains a comprehensive showcase of all Xertica UI components — useful as a living reference during development.
|
|
273
|
+
|
|
274
|
+
**Features:**
|
|
275
|
+
- `Header` with full breadcrumb, user menu, and action buttons
|
|
276
|
+
- All form elements (Input, Select, Checkbox, Switch, Slider, etc.)
|
|
277
|
+
- Data display components (Table, Chart, StatsCard, Timeline, TreeView)
|
|
278
|
+
- Overlay components (Dialog, Sheet, Drawer, Popover, Tooltip)
|
|
279
|
+
- Media components (AudioPlayer, VideoPlayer)
|
|
280
|
+
- AI components (XerticaAssistant in full-page mode)
|
|
281
|
+
|
|
282
|
+
**Props:**
|
|
283
|
+
|
|
284
|
+
| Prop | Type | Description |
|
|
285
|
+
|---|---|---|
|
|
286
|
+
| `user` | `{ email: string } \| null` | User object for the header |
|
|
287
|
+
| `onLogout` | `() => void` | Logout handler |
|
|
288
|
+
| `sidebarExpanded` | `boolean` | Controls header left padding |
|
|
289
|
+
| `sidebarWidth` | `number` | Sidebar width in pixels |
|
|
290
|
+
| `onToggleSidebar` | `() => void` | Sidebar toggle callback |
|
|
291
|
+
| `onToggleAssistant` | `() => void` | Assistant toggle callback |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Page Architecture Pattern
|
|
296
|
+
|
|
297
|
+
All dashboard pages follow the same three-column layout pattern:
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
┌─────────────────────────────────────────────────────┐
|
|
301
|
+
│ Sidebar │ Main Content │Assistant │
|
|
302
|
+
│ (fixed) │ Header + scrollable body │ (fixed) │
|
|
303
|
+
└─────────────────────────────────────────────────────┘
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
// Standard page shell pattern
|
|
308
|
+
function MyPage({ user, onLogout }) {
|
|
309
|
+
const { sidebarExpanded, sidebarWidth, assistenteExpanded,
|
|
310
|
+
toggleSidebar, toggleAssistente } = useLayout();
|
|
311
|
+
const location = useLocation();
|
|
312
|
+
const navigate = useNavigate();
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<div className="h-screen flex bg-muted overflow-hidden relative">
|
|
316
|
+
<Sidebar
|
|
317
|
+
expanded={sidebarExpanded}
|
|
318
|
+
width={sidebarWidth}
|
|
319
|
+
onToggle={toggleSidebar}
|
|
320
|
+
user={user}
|
|
321
|
+
onLogout={onLogout}
|
|
322
|
+
location={location}
|
|
323
|
+
navigate={navigate}
|
|
324
|
+
routes={routes}
|
|
325
|
+
/>
|
|
326
|
+
<MyContent
|
|
327
|
+
sidebarExpanded={sidebarExpanded}
|
|
328
|
+
sidebarWidth={sidebarWidth}
|
|
329
|
+
onToggleSidebar={toggleSidebar}
|
|
330
|
+
onToggleAssistant={toggleAssistente}
|
|
331
|
+
/>
|
|
332
|
+
<XerticaAssistant
|
|
333
|
+
isExpanded={assistenteExpanded}
|
|
334
|
+
onToggle={toggleAssistente}
|
|
335
|
+
mode="demo"
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## AI Rules
|
|
345
|
+
|
|
346
|
+
> [!IMPORTANT]
|
|
347
|
+
> - **Use `TemplatePage` as the reference**: When building a new page, copy the structure from `TemplatePage` — it demonstrates the correct three-column layout with synchronized state.
|
|
348
|
+
> - **Router dependency**: All dashboard pages use `useLocation` and `useNavigate` from `react-router-dom`. They must be rendered inside a `<BrowserRouter>`.
|
|
349
|
+
> - **`LayoutContext` is optional**: Pages use `useOptionalLayout()` and fall back to local state if the context is not available. This allows standalone usage in Storybook or tests.
|
|
350
|
+
> - **Authentication pages are standalone**: `LoginPage`, `ForgotPasswordPage`, `ResetPasswordPage`, and `VerifyEmailPage` do not use `LayoutContext` and can be rendered without `XerticaProvider`.
|
|
351
|
+
> - **Do not add business logic to page shells**: Page components (`HomePage`, `TemplatePage`) are layout containers. Business logic belongs in content components (`HomeContent`, `TemplateContent`) or custom feature components.
|
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
A navigation control for moving through pages of a large dataset. Renders Previous/Next buttons, numbered page buttons, and ellipsis for large page counts. Use it below data tables to control which page of records is displayed.
|
|
6
6
|
|
|
7
|
+
The package also exports a **headless `usePagination` hook** that computes the full page item list (numbers + ellipsis) and exposes navigation helpers — use it when you need full control over the pagination UI.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Exports
|
|
12
|
+
|
|
13
|
+
| Export | Description |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `Pagination` | Root nav wrapper |
|
|
16
|
+
| `PaginationContent` | Flex container for all items |
|
|
17
|
+
| `PaginationItem` | Individual item wrapper |
|
|
18
|
+
| `PaginationLink` | Numbered page button |
|
|
19
|
+
| `PaginationPrevious` | "Previous" button with left arrow |
|
|
20
|
+
| `PaginationNext` | "Next" button with right arrow |
|
|
21
|
+
| `PaginationEllipsis` | "..." indicator for skipped pages |
|
|
22
|
+
| `usePagination` | Headless hook — all logic, no UI |
|
|
23
|
+
| `UsePaginationProps` | TypeScript props type for the hook |
|
|
24
|
+
| `UsePaginationReturn` | TypeScript return type for the hook |
|
|
25
|
+
| `PaginationPageItem` | Union type for page items returned by the hook |
|
|
26
|
+
|
|
7
27
|
---
|
|
8
28
|
|
|
9
29
|
## When to Use
|
|
@@ -108,11 +128,178 @@ const totalPages = 10;
|
|
|
108
128
|
|
|
109
129
|
---
|
|
110
130
|
|
|
131
|
+
## `usePagination` Hook
|
|
132
|
+
|
|
133
|
+
A headless hook that computes the full page item list (page numbers + ellipsis markers) and exposes navigation helpers. Supports both **uncontrolled** (internal state) and **controlled** (external `page` prop) modes.
|
|
134
|
+
|
|
135
|
+
### Props
|
|
136
|
+
|
|
137
|
+
| Prop | Type | Default | Description |
|
|
138
|
+
|---|---|---|---|
|
|
139
|
+
| `totalItems` | `number` | — | **Required.** Total number of items across all pages |
|
|
140
|
+
| `pageSize` | `number` | `10` | Number of items per page |
|
|
141
|
+
| `initialPage` | `number` | `1` | Initial page (uncontrolled mode only) |
|
|
142
|
+
| `page` | `number` | — | Controlled current page — when provided, the hook uses this value instead of internal state |
|
|
143
|
+
| `onPageChange` | `(page: number) => void` | — | Called whenever the page changes |
|
|
144
|
+
| `siblingCount` | `number` | `1` | Number of page buttons to show on each side of the current page |
|
|
145
|
+
|
|
146
|
+
### Return Value
|
|
147
|
+
|
|
148
|
+
| Property | Type | Description |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `currentPage` | `number` | The currently active page (1-indexed) |
|
|
151
|
+
| `totalPages` | `number` | Total number of pages |
|
|
152
|
+
| `startIndex` | `number` | Zero-based index of the first item on the current page |
|
|
153
|
+
| `endIndex` | `number` | Zero-based index of the last item on the current page (exclusive) |
|
|
154
|
+
| `canGoPrev` | `boolean` | Whether navigating to the previous page is possible |
|
|
155
|
+
| `canGoNext` | `boolean` | Whether navigating to the next page is possible |
|
|
156
|
+
| `isFirstPage` | `boolean` | Whether the current page is the first page |
|
|
157
|
+
| `isLastPage` | `boolean` | Whether the current page is the last page |
|
|
158
|
+
| `items` | `PaginationPageItem[]` | Ordered list of page items to render (see below) |
|
|
159
|
+
| `goTo` | `(page: number) => void` | Navigate to a specific page number |
|
|
160
|
+
| `next` | `() => void` | Navigate to the next page |
|
|
161
|
+
| `prev` | `() => void` | Navigate to the previous page |
|
|
162
|
+
| `first` | `() => void` | Navigate to the first page |
|
|
163
|
+
| `last` | `() => void` | Navigate to the last page |
|
|
164
|
+
|
|
165
|
+
### `PaginationPageItem` Type
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
type PaginationPageItem =
|
|
169
|
+
| { type: 'page'; page: number }
|
|
170
|
+
| { type: 'ellipsis'; key: string };
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The `items` array is ready to render directly — map over it and render `<PaginationLink>` for `type: 'page'` items and `<PaginationEllipsis>` for `type: 'ellipsis'` items.
|
|
174
|
+
|
|
175
|
+
### Uncontrolled Example
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
import {
|
|
179
|
+
usePagination,
|
|
180
|
+
Pagination,
|
|
181
|
+
PaginationContent,
|
|
182
|
+
PaginationItem,
|
|
183
|
+
PaginationLink,
|
|
184
|
+
PaginationPrevious,
|
|
185
|
+
PaginationNext,
|
|
186
|
+
PaginationEllipsis,
|
|
187
|
+
} from 'xertica-ui/ui';
|
|
188
|
+
|
|
189
|
+
function MyTable({ data }: { data: Record<string, unknown>[] }) {
|
|
190
|
+
const {
|
|
191
|
+
currentPage,
|
|
192
|
+
totalPages,
|
|
193
|
+
startIndex,
|
|
194
|
+
endIndex,
|
|
195
|
+
canGoPrev,
|
|
196
|
+
canGoNext,
|
|
197
|
+
items,
|
|
198
|
+
next,
|
|
199
|
+
prev,
|
|
200
|
+
} = usePagination({ totalItems: data.length, pageSize: 10 });
|
|
201
|
+
|
|
202
|
+
const pageData = data.slice(startIndex, endIndex);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div className="space-y-4">
|
|
206
|
+
<table>
|
|
207
|
+
{/* render pageData rows */}
|
|
208
|
+
</table>
|
|
209
|
+
|
|
210
|
+
<Pagination>
|
|
211
|
+
<PaginationContent>
|
|
212
|
+
<PaginationItem>
|
|
213
|
+
<PaginationPrevious onClick={prev} aria-disabled={!canGoPrev} />
|
|
214
|
+
</PaginationItem>
|
|
215
|
+
|
|
216
|
+
{items.map((item) =>
|
|
217
|
+
item.type === 'ellipsis' ? (
|
|
218
|
+
<PaginationItem key={item.key}>
|
|
219
|
+
<PaginationEllipsis />
|
|
220
|
+
</PaginationItem>
|
|
221
|
+
) : (
|
|
222
|
+
<PaginationItem key={item.page}>
|
|
223
|
+
<PaginationLink
|
|
224
|
+
isActive={item.page === currentPage}
|
|
225
|
+
onClick={() => goTo(item.page)}
|
|
226
|
+
>
|
|
227
|
+
{item.page}
|
|
228
|
+
</PaginationLink>
|
|
229
|
+
</PaginationItem>
|
|
230
|
+
)
|
|
231
|
+
)}
|
|
232
|
+
|
|
233
|
+
<PaginationItem>
|
|
234
|
+
<PaginationNext onClick={next} aria-disabled={!canGoNext} />
|
|
235
|
+
</PaginationItem>
|
|
236
|
+
</PaginationContent>
|
|
237
|
+
</Pagination>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Controlled Example (API-driven pagination)
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import { usePagination } from 'xertica-ui/ui';
|
|
247
|
+
import { useState } from 'react';
|
|
248
|
+
|
|
249
|
+
function ServerPaginatedTable({ totalItems }: { totalItems: number }) {
|
|
250
|
+
const [page, setPage] = useState(1);
|
|
251
|
+
|
|
252
|
+
const { items, canGoPrev, canGoNext, next, prev, goTo, currentPage } =
|
|
253
|
+
usePagination({
|
|
254
|
+
totalItems,
|
|
255
|
+
pageSize: 20,
|
|
256
|
+
page, // controlled
|
|
257
|
+
onPageChange: setPage,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// fetch data for `page` from your API...
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<Pagination>
|
|
264
|
+
<PaginationContent>
|
|
265
|
+
<PaginationItem>
|
|
266
|
+
<PaginationPrevious onClick={prev} aria-disabled={!canGoPrev} />
|
|
267
|
+
</PaginationItem>
|
|
268
|
+
{items.map((item) =>
|
|
269
|
+
item.type === 'ellipsis' ? (
|
|
270
|
+
<PaginationItem key={item.key}><PaginationEllipsis /></PaginationItem>
|
|
271
|
+
) : (
|
|
272
|
+
<PaginationItem key={item.page}>
|
|
273
|
+
<PaginationLink
|
|
274
|
+
isActive={item.page === currentPage}
|
|
275
|
+
onClick={() => goTo(item.page)}
|
|
276
|
+
>
|
|
277
|
+
{item.page}
|
|
278
|
+
</PaginationLink>
|
|
279
|
+
</PaginationItem>
|
|
280
|
+
)
|
|
281
|
+
)}
|
|
282
|
+
<PaginationItem>
|
|
283
|
+
<PaginationNext onClick={next} aria-disabled={!canGoNext} />
|
|
284
|
+
</PaginationItem>
|
|
285
|
+
</PaginationContent>
|
|
286
|
+
</Pagination>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
111
293
|
## AI Rules
|
|
112
294
|
|
|
113
295
|
- Place Pagination below the `<Table>` inside the same `<Card>` wrapping both.
|
|
114
296
|
- Use `isActive` on the currently selected page link.
|
|
115
297
|
- For controlled pagination (API-driven), use `onClick` instead of `href` on `PaginationLink`.
|
|
298
|
+
- When using `usePagination`, use `startIndex` and `endIndex` to slice client-side data arrays: `data.slice(startIndex, endIndex)`.
|
|
299
|
+
- For server-side pagination, pass `page` and `onPageChange` to `usePagination` to use controlled mode — the hook will not manage internal state.
|
|
300
|
+
- Always render `PaginationEllipsis` for `item.type === 'ellipsis'` items from the `items` array — never skip them.
|
|
301
|
+
- `totalItems` is the count of **all** records, not just the current page.
|
|
302
|
+
- Pages are **1-indexed** — the first page is `1`, not `0`.
|
|
116
303
|
|
|
117
304
|
---
|
|
118
305
|
|