xertica-ui 2.3.0 → 2.4.1
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 +22 -2
- package/README.md +33 -22
- package/bin/cli.ts +136 -47
- package/bin/language-config.ts +5 -8
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +17 -7
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +1 -3
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +13 -3
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +10 -6
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +1 -3
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +1 -6
- package/components/blocks/card-patterns/ProfileCard.tsx +1 -3
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +1 -6
- package/components/brand/language-selector/language-selector.stories.tsx +1 -4
- package/components/brand/theme-toggle/ThemeToggle.tsx +5 -1
- package/components/brand/xertica-provider/XerticaProvider.tsx +1 -4
- package/components/index.ts +1 -5
- package/components/layout/sidebar/sidebar.tsx +9 -3
- package/components/media/audio-player/AudioPlayer.tsx +4 -2
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/home-content/HomeContent.tsx +55 -55
- package/components/pages/home-page/HomePage.tsx +5 -1
- package/components/pages/login-page/LoginPage.tsx +4 -2
- package/components/pages/reset-password-page/ResetPasswordPage.tsx +7 -3
- package/components/pages/template-content/TemplateContent.tsx +268 -149
- package/components/pages/verify-email-page/VerifyEmailPage.tsx +9 -9
- package/components/shared/error-boundary.stories.tsx +114 -132
- package/components/shared/error-boundary.tsx +150 -154
- package/components/shared/error-fallbacks.tsx +222 -226
- package/components/ui/stats-card/stats-card-skeleton.tsx +1 -3
- package/components/ui/stats-card/stats-card.stories.tsx +18 -0
- package/components/ui/stats-card/stats-card.tsx +18 -2
- package/components.json +512 -892
- package/contexts/AuthContext.tsx +121 -118
- package/contexts/LanguageContext.tsx +1 -2
- package/dist/AssistantChart-BKVtGUKF.js +3383 -0
- package/dist/AssistantChart-WeycT5Pd.cjs +3551 -0
- package/dist/VerifyEmailPage-Bp1XXl3H.cjs +3305 -0
- package/dist/VerifyEmailPage-DGhuIqkb.js +3296 -0
- package/dist/XerticaProvider-BErr83Bg.js +42 -0
- package/dist/XerticaProvider-CwOkHxiT.cjs +44 -0
- package/dist/XerticaXLogo-BX3ueACh.js +255 -0
- package/dist/XerticaXLogo-qBPhwK3g.cjs +260 -0
- package/dist/assistant.cjs.js +1 -1
- package/dist/assistant.es.js +1 -1
- package/dist/brand.cjs.js +2 -2
- package/dist/brand.es.js +2 -2
- package/dist/cli.js +90 -37
- package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/ui/stats-card/stats-card.d.ts +10 -0
- package/dist/index.cjs.js +6 -6
- package/dist/index.es.js +6 -6
- package/dist/layout.cjs.js +1 -1
- package/dist/layout.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/sidebar-B4ZWaMrE.js +792 -0
- package/dist/sidebar-BS1p2V7t.cjs +795 -0
- package/dist/ui.cjs.js +1 -1
- package/dist/ui.es.js +1 -1
- package/dist/xertica-assistant-B1NaSFFj.js +2173 -0
- package/dist/xertica-assistant-CIaUlbIt.cjs +2180 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/architecture-improvements.md +5 -5
- package/docs/architecture.md +16 -10
- package/docs/components/card-patterns.md +19 -17
- package/docs/components/error-boundary.md +201 -191
- package/docs/components/hooks.md +15 -13
- package/docs/components/language-selector.md +20 -16
- package/docs/components/pages.md +323 -309
- package/docs/components/stats-card.md +20 -2
- package/docs/doc-audit.md +12 -11
- package/docs/getting-started.md +41 -28
- package/docs/guidelines.md +14 -12
- package/docs/i18n.md +61 -57
- package/docs/installation.md +268 -267
- package/docs/llms.md +17 -17
- package/docs/state-management.md +17 -17
- package/guidelines/Guidelines.md +17 -14
- package/llms-compact.txt +1 -1
- package/llms-full.txt +11553 -7133
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/styles/xertica/base.css +90 -84
- package/templates/CLAUDE.md +16 -1
- package/templates/guidelines/Guidelines.md +42 -18
- package/templates/package.json +3 -3
- package/templates/src/app/components/AuthGuard.tsx +131 -82
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +1 -3
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +6 -2
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +2 -6
- package/templates/src/features/home/data/mock.ts +41 -35
- package/templates/src/features/home/ui/HomeContent.tsx +62 -64
- package/templates/src/features/template/ui/CrudTemplate.tsx +1 -4
- package/templates/src/features/template/ui/LoginTemplate.tsx +1 -1
- package/templates/src/features/template/ui/TemplateContent.tsx +28 -20
- package/templates/src/locales/en/pages/templates.json +17 -17
- package/templates/src/locales/es/pages/templates.json +17 -17
- package/templates/src/locales/pt-BR/pages/templates.json +17 -17
- package/templates/src/pages/AssistantPage.tsx +26 -20
- package/templates/src/pages/HomePage.tsx +5 -1
- package/templates/src/shared/error-boundary.tsx +150 -154
- package/templates/src/shared/error-fallbacks.tsx +222 -226
- package/templates/vite.config.ts +12 -9
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ImageWithFallback } from 'xertica-ui/ui';
|
|
3
|
-
import { LanguageSelector } from 'xertica-ui/brand';
|
|
4
|
-
|
|
5
|
-
interface AuthPageShellProps {
|
|
6
|
-
imageSrc: string;
|
|
7
|
-
imageAlt: string;
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function AuthPageShell({ imageSrc, imageAlt, children }: AuthPageShellProps) {
|
|
12
|
-
return (
|
|
13
|
-
<div className="
|
|
14
|
-
<div className="hidden lg:flex lg:flex-1 relative overflow-hidden">
|
|
15
|
-
<ImageWithFallback
|
|
16
|
-
src={imageSrc}
|
|
17
|
-
alt={imageAlt}
|
|
18
|
-
className="absolute inset-0 w-full h-full object-cover"
|
|
19
|
-
/>
|
|
20
|
-
<div className="absolute inset-0 bg-[image:var(--gradient-diagonal)] opacity-80" />
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div className="flex-1 flex items-center justify-center px-4 sm:px-6 lg:px-8 lg:flex-none lg:w-1/2 relative bg-muted">
|
|
24
|
-
<div className="absolute top-4 right-4 z-20">
|
|
25
|
-
<LanguageSelector variant="minimal" showIcon={false} />
|
|
26
|
-
</div>
|
|
27
|
-
<div className="absolute inset-0 lg:hidden bg-[image:var(--gradient-diagonal)] opacity-10 dark:opacity-5" />
|
|
28
|
-
<div className="w-full max-w-sm space-y-6 relative z-10">{children}</div>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ImageWithFallback } from 'xertica-ui/ui';
|
|
3
|
+
import { LanguageSelector } from 'xertica-ui/brand';
|
|
4
|
+
|
|
5
|
+
interface AuthPageShellProps {
|
|
6
|
+
imageSrc: string;
|
|
7
|
+
imageAlt: string;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function AuthPageShell({ imageSrc, imageAlt, children }: AuthPageShellProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="h-screen w-full flex overflow-y-auto">
|
|
14
|
+
<div className="hidden lg:flex lg:flex-1 relative overflow-hidden">
|
|
15
|
+
<ImageWithFallback
|
|
16
|
+
src={imageSrc}
|
|
17
|
+
alt={imageAlt}
|
|
18
|
+
className="absolute inset-0 w-full h-full object-cover"
|
|
19
|
+
/>
|
|
20
|
+
<div className="absolute inset-0 bg-[image:var(--gradient-diagonal)] opacity-80" />
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div className="flex-1 flex items-center justify-center px-4 sm:px-6 lg:px-8 lg:flex-none lg:w-1/2 relative bg-muted">
|
|
24
|
+
<div className="absolute top-4 right-4 z-20">
|
|
25
|
+
<LanguageSelector variant="minimal" showIcon={false} />
|
|
26
|
+
</div>
|
|
27
|
+
<div className="absolute inset-0 lg:hidden bg-[image:var(--gradient-diagonal)] opacity-10 dark:opacity-5" />
|
|
28
|
+
<div className="w-full max-w-sm space-y-6 relative z-10">{children}</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -31,9 +31,7 @@ export function ForgotPasswordContent() {
|
|
|
31
31
|
<XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
|
|
32
32
|
</div>
|
|
33
33
|
<h2 className="text-sm text-muted-foreground">{t('forgotPassword.heading')}</h2>
|
|
34
|
-
<p className="mt-2 text-muted-foreground">
|
|
35
|
-
{t('forgotPassword.subheading')}
|
|
36
|
-
</p>
|
|
34
|
+
<p className="mt-2 text-muted-foreground">{t('forgotPassword.subheading')}</p>
|
|
37
35
|
</div>
|
|
38
36
|
|
|
39
37
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
|
@@ -152,13 +152,17 @@ export function ResetPasswordContent() {
|
|
|
152
152
|
<CheckCircle2
|
|
153
153
|
className={`w-4 h-4 ${password.length >= 6 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
154
154
|
/>
|
|
155
|
-
<span className="text-sm text-muted-foreground">
|
|
155
|
+
<span className="text-sm text-muted-foreground">
|
|
156
|
+
{t('resetPassword.requirementMinChars')}
|
|
157
|
+
</span>
|
|
156
158
|
</div>
|
|
157
159
|
<div className="flex items-center gap-2">
|
|
158
160
|
<CheckCircle2
|
|
159
161
|
className={`w-4 h-4 ${password === confirmPassword && password.length > 0 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
160
162
|
/>
|
|
161
|
-
<span className="text-sm text-muted-foreground">
|
|
163
|
+
<span className="text-sm text-muted-foreground">
|
|
164
|
+
{t('resetPassword.requirementMatch')}
|
|
165
|
+
</span>
|
|
162
166
|
</div>
|
|
163
167
|
</div>
|
|
164
168
|
</div>
|
|
@@ -39,16 +39,12 @@ export function VerifyEmailContent() {
|
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
<h2 className="text-sm text-muted-foreground">{t('verifyEmail.heading')}</h2>
|
|
42
|
-
<p className="mt-2 text-muted-foreground">
|
|
43
|
-
{t('verifyEmail.instructionsSent')}
|
|
44
|
-
</p>
|
|
42
|
+
<p className="mt-2 text-muted-foreground">{t('verifyEmail.instructionsSent')}</p>
|
|
45
43
|
<p className="mt-1 text-primary">{email}</p>
|
|
46
44
|
</div>
|
|
47
45
|
|
|
48
46
|
<div className="bg-accent rounded-[var(--radius)] p-4 space-y-3">
|
|
49
|
-
<p className="text-muted-foreground">
|
|
50
|
-
{t('verifyEmail.instructions')}
|
|
51
|
-
</p>
|
|
47
|
+
<p className="text-muted-foreground">{t('verifyEmail.instructions')}</p>
|
|
52
48
|
<div className="flex items-start gap-2 text-muted-foreground">
|
|
53
49
|
<CheckCircle2 className="w-4 h-4 mt-0.5 flex-shrink-0 text-[var(--chart-2)]" />
|
|
54
50
|
<span className="text-sm">{t('verifyEmail.checkSpam')}</span>
|
|
@@ -1,35 +1,41 @@
|
|
|
1
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
-
// features/home/data/mock.ts
|
|
3
|
-
//
|
|
4
|
-
// All mock data for the Home feature lives here.
|
|
5
|
-
// To connect to a real API, replace the fetch functions below with actual
|
|
6
|
-
// HTTP calls — the hooks and components stay unchanged.
|
|
7
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
import i18n from '../../../i18n';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// features/home/data/mock.ts
|
|
3
|
+
//
|
|
4
|
+
// All mock data for the Home feature lives here.
|
|
5
|
+
// To connect to a real API, replace the fetch functions below with actual
|
|
6
|
+
// HTTP calls — the hooks and components stay unchanged.
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
import i18n from '../../../i18n';
|
|
10
|
+
import type { LucideIcon } from 'lucide-react';
|
|
11
|
+
import { FileText } from 'lucide-react';
|
|
12
|
+
|
|
13
|
+
// ── Types ─────────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
export interface FeatureCard {
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
badge?: string;
|
|
20
|
+
href: string;
|
|
21
|
+
Icon: LucideIcon;
|
|
22
|
+
chartColor: string; // CSS variable: '--chart-1' | '--chart-2' | '--chart-3' | '--chart-4' | '--chart-5'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ── Mock API function ─────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
export async function fetchFeatureCards(): Promise<FeatureCard[]> {
|
|
28
|
+
// Replace with: return fetch('/api/home/features').then(r => r.json());
|
|
29
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
id: 'template-cli',
|
|
33
|
+
title: i18n.t('home.templateCliTitle'),
|
|
34
|
+
description: i18n.t('home.templateCliDescription'),
|
|
35
|
+
badge: i18n.t('home.templateClibadge'),
|
|
36
|
+
href: '/template',
|
|
37
|
+
Icon: FileText,
|
|
38
|
+
chartColor: '--chart-1',
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
}
|
|
@@ -11,20 +11,11 @@ import {
|
|
|
11
11
|
} from 'xertica-ui/ui';
|
|
12
12
|
import { Header } from 'xertica-ui/layout';
|
|
13
13
|
import { useLayout } from 'xertica-ui/hooks';
|
|
14
|
-
import { FileText } from 'lucide-react';
|
|
15
14
|
import { useNavigate, Link } from 'react-router-dom';
|
|
16
15
|
import { useTranslation } from 'react-i18next';
|
|
17
16
|
import { useFeatureCards } from '../hooks/useFeatureCards';
|
|
18
17
|
import { SectionErrorBoundary } from '../../../shared/error-boundary';
|
|
19
18
|
|
|
20
|
-
/**
|
|
21
|
-
* Home dashboard content area.
|
|
22
|
-
*
|
|
23
|
-
* All UI strings are translated via `useTranslation()`.
|
|
24
|
-
* Feature cards are fetched via `useFeatureCards` (React Query).
|
|
25
|
-
* To connect to a real API, replace `fetchFeatureCards` in
|
|
26
|
-
* `features/home/data/mock.ts`.
|
|
27
|
-
*/
|
|
28
19
|
export function HomeContent() {
|
|
29
20
|
const { t } = useTranslation();
|
|
30
21
|
const { sidebarExpanded, sidebarWidth } = useLayout();
|
|
@@ -42,11 +33,10 @@ export function HomeContent() {
|
|
|
42
33
|
<Header
|
|
43
34
|
showThemeToggle={true}
|
|
44
35
|
showLanguageSelector={true}
|
|
45
|
-
breadcrumbs={[
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
renderLink={(href: string, props: any) => <Link to={href} {...props} />}
|
|
36
|
+
breadcrumbs={[{ label: t('nav.designSystem'), href: '/home' }, { label: t('nav.home') }]}
|
|
37
|
+
renderLink={(href: string, props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
|
|
38
|
+
<Link to={href} {...props} />
|
|
39
|
+
)}
|
|
50
40
|
/>
|
|
51
41
|
|
|
52
42
|
<main className="flex-1 overflow-hidden bg-muted">
|
|
@@ -54,61 +44,69 @@ export function HomeContent() {
|
|
|
54
44
|
<div className="p-5 sm:p-4 md:p-6">
|
|
55
45
|
<div className="max-w-6xl mx-auto space-y-8">
|
|
56
46
|
<div className="space-y-2">
|
|
57
|
-
<h2>{t('home.welcome')}</h2>
|
|
47
|
+
<h2 className="text-3xl font-bold tracking-tight">{t('home.welcome')}</h2>
|
|
58
48
|
<p className="text-muted-foreground">{t('home.subtitle')}</p>
|
|
59
49
|
</div>
|
|
60
50
|
|
|
61
51
|
<SectionErrorBoundary>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<CardHeader>
|
|
82
|
-
<div className="flex items-center gap-3">
|
|
83
|
-
<div className="p-2 bg-[var(--chart-2)]/20 rounded-[var(--radius)]">
|
|
84
|
-
<FileText className="w-6 h-6 text-[var(--chart-2)]" />
|
|
85
|
-
</div>
|
|
86
|
-
<div className="flex items-center gap-2">
|
|
87
|
-
<CardTitle className="text-sm">{card.title}</CardTitle>
|
|
88
|
-
{card.badge && (
|
|
89
|
-
<Badge variant="default" className="text-xs">
|
|
90
|
-
{card.badge}
|
|
91
|
-
</Badge>
|
|
92
|
-
)}
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
</CardHeader>
|
|
96
|
-
<CardContent className="flex-1">
|
|
97
|
-
<p className="text-muted-foreground">{card.description}</p>
|
|
98
|
-
</CardContent>
|
|
99
|
-
<CardFooter>
|
|
100
|
-
<Button
|
|
101
|
-
variant="outline"
|
|
102
|
-
className="w-full"
|
|
103
|
-
onClick={() => navigate(card.href)}
|
|
52
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
53
|
+
{isLoading
|
|
54
|
+
? Array.from({ length: 3 }).map((_, i) => (
|
|
55
|
+
<Card key={i} className="flex flex-col h-full animate-pulse">
|
|
56
|
+
<CardHeader>
|
|
57
|
+
<div className="h-4 bg-muted-foreground/20 rounded w-2/3" />
|
|
58
|
+
</CardHeader>
|
|
59
|
+
<CardContent className="flex-1">
|
|
60
|
+
<div className="h-3 bg-muted-foreground/10 rounded w-full" />
|
|
61
|
+
</CardContent>
|
|
62
|
+
<CardFooter>
|
|
63
|
+
<div className="h-9 bg-muted-foreground/10 rounded w-full" />
|
|
64
|
+
</CardFooter>
|
|
65
|
+
</Card>
|
|
66
|
+
))
|
|
67
|
+
: featureCards.map(card => (
|
|
68
|
+
<Card
|
|
69
|
+
key={card.id}
|
|
70
|
+
className="hover:shadow-xl transition-shadow duration-200 flex flex-col h-full"
|
|
104
71
|
>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
72
|
+
<CardHeader>
|
|
73
|
+
<div className="flex items-center gap-3">
|
|
74
|
+
<div
|
|
75
|
+
className="p-2 rounded-[var(--radius)]"
|
|
76
|
+
style={{
|
|
77
|
+
background: `color-mix(in srgb, var(${card.chartColor}) 20%, transparent)`,
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
<card.Icon
|
|
81
|
+
className="w-6 h-6"
|
|
82
|
+
style={{ color: `var(${card.chartColor})` }}
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
<div className="flex items-center gap-2">
|
|
86
|
+
<CardTitle className="text-sm">{card.title}</CardTitle>
|
|
87
|
+
{card.badge && (
|
|
88
|
+
<Badge variant="default" className="text-xs">
|
|
89
|
+
{card.badge}
|
|
90
|
+
</Badge>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</CardHeader>
|
|
95
|
+
<CardContent className="flex-1">
|
|
96
|
+
<p className="text-muted-foreground">{card.description}</p>
|
|
97
|
+
</CardContent>
|
|
98
|
+
<CardFooter>
|
|
99
|
+
<Button
|
|
100
|
+
variant="outline"
|
|
101
|
+
className="w-full"
|
|
102
|
+
onClick={() => navigate(card.href)}
|
|
103
|
+
>
|
|
104
|
+
{t('common.view')}
|
|
105
|
+
</Button>
|
|
106
|
+
</CardFooter>
|
|
107
|
+
</Card>
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
112
110
|
</SectionErrorBoundary>
|
|
113
111
|
</div>
|
|
114
112
|
</div>
|
|
@@ -37,10 +37,7 @@ export function CrudTemplate() {
|
|
|
37
37
|
<div className="flex p-4 border-b gap-2">
|
|
38
38
|
<div className="relative w-full max-w-sm">
|
|
39
39
|
<Search className="absolute left-2.5 top-2.5 size-4 text-muted-foreground" />
|
|
40
|
-
<Input
|
|
41
|
-
placeholder={t('crudTemplate.searchPlaceholder')}
|
|
42
|
-
className="w-full h-9 pl-8"
|
|
43
|
-
/>
|
|
40
|
+
<Input placeholder={t('crudTemplate.searchPlaceholder')} className="w-full h-9 pl-8" />
|
|
44
41
|
</div>
|
|
45
42
|
</div>
|
|
46
43
|
|
|
@@ -16,7 +16,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
16
16
|
export function LoginTemplate() {
|
|
17
17
|
const { t } = useTranslation();
|
|
18
18
|
return (
|
|
19
|
-
<div className="flex min-h-
|
|
19
|
+
<div className="flex h-full min-h-0 w-full items-center justify-center bg-muted/30 p-4 overflow-y-auto">
|
|
20
20
|
<Card className="w-full max-w-sm">
|
|
21
21
|
<CardHeader className="text-center">
|
|
22
22
|
<div className="flex justify-center mb-4">
|
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
useStepper,
|
|
69
69
|
} from 'xertica-ui/ui';
|
|
70
70
|
import { Header, Sidebar } from 'xertica-ui/layout';
|
|
71
|
-
import { useLayout } from 'xertica-ui/hooks';
|
|
71
|
+
import { useLayout, useTheme } from 'xertica-ui/hooks';
|
|
72
72
|
import { toast } from 'sonner';
|
|
73
73
|
import { Link } from 'react-router-dom';
|
|
74
74
|
import { Trans, useTranslation } from 'react-i18next';
|
|
@@ -131,6 +131,7 @@ export function TemplateContent() {
|
|
|
131
131
|
},
|
|
132
132
|
];
|
|
133
133
|
const { sidebarExpanded, sidebarWidth } = useLayout();
|
|
134
|
+
const { disableDarkMode } = useTheme();
|
|
134
135
|
const [progress, setProgress] = useState(45);
|
|
135
136
|
const [sliderValue, setSliderValue] = useState([50]);
|
|
136
137
|
const [switchEnabled, setSwitchEnabled] = useState(false);
|
|
@@ -611,17 +612,21 @@ export function TemplateContent() {
|
|
|
611
612
|
<CardDescription>{t('templates.settings.description')}</CardDescription>
|
|
612
613
|
</CardHeader>
|
|
613
614
|
<CardContent className="space-y-6">
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
<
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
615
|
+
{!disableDarkMode && (
|
|
616
|
+
<>
|
|
617
|
+
<div className="flex items-center justify-between">
|
|
618
|
+
<div className="space-y-1">
|
|
619
|
+
<Label>{t('templates.settings.darkMode')}</Label>
|
|
620
|
+
<p className="text-muted-foreground">
|
|
621
|
+
{t('templates.settings.darkModeDescription')}
|
|
622
|
+
</p>
|
|
623
|
+
</div>
|
|
624
|
+
<Switch checked={switchEnabled} onCheckedChange={setSwitchEnabled} />
|
|
625
|
+
</div>
|
|
623
626
|
|
|
624
|
-
|
|
627
|
+
<Separator />
|
|
628
|
+
</>
|
|
629
|
+
)}
|
|
625
630
|
|
|
626
631
|
<div className="flex items-center justify-between">
|
|
627
632
|
<div className="space-y-1">
|
|
@@ -883,9 +888,7 @@ export function TemplateContent() {
|
|
|
883
888
|
</AlertDialogTrigger>
|
|
884
889
|
<AlertDialogContent className="sm:max-w-[425px]">
|
|
885
890
|
<AlertDialogHeader>
|
|
886
|
-
<AlertDialogTitle>
|
|
887
|
-
{t('templates.dialogs.areYouSure')}
|
|
888
|
-
</AlertDialogTitle>
|
|
891
|
+
<AlertDialogTitle>{t('templates.dialogs.areYouSure')}</AlertDialogTitle>
|
|
889
892
|
<AlertDialogDescription>
|
|
890
893
|
{t('templates.dialogs.deleteWarning')}
|
|
891
894
|
</AlertDialogDescription>
|
|
@@ -978,9 +981,7 @@ export function TemplateContent() {
|
|
|
978
981
|
{
|
|
979
982
|
label: t('templates.sidebar.actions.moveActive'),
|
|
980
983
|
onClick: () =>
|
|
981
|
-
toast(
|
|
982
|
-
t('templates.sidebar.actions.moveActiveToast')
|
|
983
|
-
),
|
|
984
|
+
toast(t('templates.sidebar.actions.moveActiveToast')),
|
|
984
985
|
},
|
|
985
986
|
{
|
|
986
987
|
label: t('templates.sidebar.actions.moveMonitoring'),
|
|
@@ -1084,7 +1085,11 @@ export function TemplateContent() {
|
|
|
1084
1085
|
navigate={() => {}}
|
|
1085
1086
|
variant="default"
|
|
1086
1087
|
routes={[
|
|
1087
|
-
{
|
|
1088
|
+
{
|
|
1089
|
+
path: '/home',
|
|
1090
|
+
label: t('templates.sidebar.routes.home'),
|
|
1091
|
+
icon: Home,
|
|
1092
|
+
},
|
|
1088
1093
|
{
|
|
1089
1094
|
path: '/dashboard',
|
|
1090
1095
|
label: t('templates.sidebar.routes.dashboard'),
|
|
@@ -1150,7 +1155,7 @@ export function TemplateContent() {
|
|
|
1150
1155
|
disabled={!canGoPrev}
|
|
1151
1156
|
/>
|
|
1152
1157
|
</PaginationItem>
|
|
1153
|
-
{items.map(
|
|
1158
|
+
{items.map(item =>
|
|
1154
1159
|
item.type === 'ellipsis' ? (
|
|
1155
1160
|
<PaginationItem key={item.key}>
|
|
1156
1161
|
<PaginationEllipsis />
|
|
@@ -1249,7 +1254,10 @@ export function TemplateContent() {
|
|
|
1249
1254
|
aria-label={t('templates.enhanced.treeView.ariaLabel')}
|
|
1250
1255
|
defaultExpanded={['components', 'ui']}
|
|
1251
1256
|
onNodeSelect={node =>
|
|
1252
|
-
console.log(
|
|
1257
|
+
console.log(
|
|
1258
|
+
t('templates.enhanced.treeView.selectedConsoleLog'),
|
|
1259
|
+
node.label
|
|
1260
|
+
)
|
|
1253
1261
|
}
|
|
1254
1262
|
className="max-w-xs border border-border rounded-[var(--radius-lg)] p-2"
|
|
1255
1263
|
/>
|
|
@@ -239,23 +239,23 @@
|
|
|
239
239
|
"next": "Next",
|
|
240
240
|
"finish": "Finish"
|
|
241
241
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
"treeView": {
|
|
243
|
+
"title": "TreeView",
|
|
244
|
+
"description": "Hierarchical navigation with <code>ariaLabel</code>, roving tabindex and WAI-ARIA keyboard (Space expands/collapses, Enter selects).",
|
|
245
|
+
"ariaLabel": "Component structure",
|
|
246
|
+
"selectedConsoleLog": "Selected:",
|
|
247
|
+
"nodes": {
|
|
248
|
+
"components": "Components",
|
|
249
|
+
"ui": "UI",
|
|
250
|
+
"button": "Button",
|
|
251
|
+
"input": "Input",
|
|
252
|
+
"pagination": "Pagination",
|
|
253
|
+
"layout": "Layout",
|
|
254
|
+
"sidebar": "Sidebar",
|
|
255
|
+
"header": "Header",
|
|
256
|
+
"hooks": "Hooks"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
259
|
"richText": {
|
|
260
260
|
"title": "RichTextEditor",
|
|
261
261
|
"description": "Rich text editor with <code>role=\"textbox\"</code>, <code>aria-multiline</code> and counters via <code>useState</code> (without IIFE).",
|
|
@@ -239,23 +239,23 @@
|
|
|
239
239
|
"next": "Siguiente",
|
|
240
240
|
"finish": "Finalizar"
|
|
241
241
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
"treeView": {
|
|
243
|
+
"title": "TreeView",
|
|
244
|
+
"description": "Navegación jerárquica con <code>ariaLabel</code>, roving tabindex y teclado WAI-ARIA (Espacio expande/colapsa, Enter selecciona).",
|
|
245
|
+
"ariaLabel": "Estructura de componentes",
|
|
246
|
+
"selectedConsoleLog": "Seleccionado:",
|
|
247
|
+
"nodes": {
|
|
248
|
+
"components": "Componentes",
|
|
249
|
+
"ui": "UI",
|
|
250
|
+
"button": "Botón",
|
|
251
|
+
"input": "Input",
|
|
252
|
+
"pagination": "Paginación",
|
|
253
|
+
"layout": "Layout",
|
|
254
|
+
"sidebar": "Sidebar",
|
|
255
|
+
"header": "Header",
|
|
256
|
+
"hooks": "Hooks"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
259
|
"richText": {
|
|
260
260
|
"title": "RichTextEditor",
|
|
261
261
|
"description": "Editor rich text con <code>role=\"textbox\"</code>, <code>aria-multiline</code> y contadores via <code>useState</code> (sin IIFE).",
|
|
@@ -239,23 +239,23 @@
|
|
|
239
239
|
"next": "Próximo",
|
|
240
240
|
"finish": "Concluir"
|
|
241
241
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
242
|
+
"treeView": {
|
|
243
|
+
"title": "TreeView",
|
|
244
|
+
"description": "Navegação hierárquica com <code>ariaLabel</code>, roving tabindex e teclado WAI-ARIA (Espaço expande/colapsa, Enter seleciona).",
|
|
245
|
+
"ariaLabel": "Estrutura de componentes",
|
|
246
|
+
"selectedConsoleLog": "Selecionado:",
|
|
247
|
+
"nodes": {
|
|
248
|
+
"components": "Componentes",
|
|
249
|
+
"ui": "UI",
|
|
250
|
+
"button": "Botão",
|
|
251
|
+
"input": "Input",
|
|
252
|
+
"pagination": "Paginação",
|
|
253
|
+
"layout": "Layout",
|
|
254
|
+
"sidebar": "Sidebar",
|
|
255
|
+
"header": "Header",
|
|
256
|
+
"hooks": "Hooks"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
259
|
"richText": {
|
|
260
260
|
"title": "RichTextEditor",
|
|
261
261
|
"description": "Editor rich text com <code>role=\"textbox\"</code>, <code>aria-multiline</code> e contadores via <code>useState</code> (sem IIFE).",
|