xertica-ui 2.6.0 → 2.7.0

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.
Files changed (100) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/components/assistant/xertica-assistant/use-assistant.ts +5 -6
  4. package/{templates/src/features/auth/ui → components/blocks/auth}/AuthPageShell.tsx +8 -3
  5. package/components/blocks/auth/PasswordStrengthMeter.tsx +41 -0
  6. package/components/blocks/auth/SocialLoginButtons.tsx +95 -0
  7. package/components/blocks/auth/index.ts +11 -0
  8. package/components/blocks/auth/usePasswordStrength.ts +13 -0
  9. package/components/blocks/index.ts +1 -0
  10. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +45 -139
  11. package/components/pages/login-page/LoginPage.tsx +52 -145
  12. package/components/pages/reset-password-page/ResetPasswordPage.tsx +79 -169
  13. package/components/pages/verify-email-page/VerifyEmailPage.tsx +48 -150
  14. package/dist/AssistantChart-CImCNLfD.cjs +3551 -0
  15. package/dist/AssistantChart-DfdIfmQr.js +3383 -0
  16. package/dist/FeatureCard-BhpfmPPx.js +485 -0
  17. package/dist/FeatureCard-D-5yS_OD.cjs +497 -0
  18. package/dist/ImageWithFallback-CfkAkctC.cjs +122 -0
  19. package/dist/ImageWithFallback-bw-CxxDc.js +98 -0
  20. package/dist/LanguageContext-CX_zdxre.js +1912 -0
  21. package/dist/LanguageContext-CjhSSqJT.cjs +1917 -0
  22. package/dist/LanguageSelector-BR3Ss0k_.js +46 -0
  23. package/dist/LanguageSelector-CHOLPmHr.cjs +48 -0
  24. package/dist/PasswordStrengthMeter-C8irs0G1.js +173 -0
  25. package/dist/PasswordStrengthMeter-MLzhax-d.cjs +179 -0
  26. package/dist/ThemeContext-CEY9pCn-.cjs +86 -0
  27. package/dist/ThemeContext-Dk3tH7Ym.js +83 -0
  28. package/dist/ThemeToggle-BpM_iHh8.js +215 -0
  29. package/dist/ThemeToggle-CZRlv0d4.cjs +219 -0
  30. package/dist/VerifyEmailPage-BKiaw2YK.js +2954 -0
  31. package/dist/VerifyEmailPage-Beaicc6V.cjs +2963 -0
  32. package/dist/VerifyEmailPage-BehPBp0F.cjs +2963 -0
  33. package/dist/VerifyEmailPage-Djb6hthM.js +2954 -0
  34. package/dist/XerticaProvider-BijpC_py.cjs +46 -0
  35. package/dist/XerticaProvider-C2wDRQhT.js +44 -0
  36. package/dist/alert-dialog-BzIcTKn_.cjs +872 -0
  37. package/dist/alert-dialog-kty5pxQp.js +819 -0
  38. package/dist/assistant.cjs.js +1 -1
  39. package/dist/assistant.es.js +1 -1
  40. package/dist/blocks.cjs.js +7 -3
  41. package/dist/blocks.es.js +2 -2
  42. package/dist/brand.cjs.js +7 -6
  43. package/dist/brand.es.js +3 -2
  44. package/dist/components/blocks/auth/AuthPageShell.d.ts +12 -0
  45. package/dist/components/blocks/auth/PasswordStrengthMeter.d.ts +7 -0
  46. package/dist/components/blocks/auth/SocialLoginButtons.d.ts +8 -0
  47. package/dist/components/blocks/auth/index.d.ts +8 -0
  48. package/dist/components/blocks/auth/usePasswordStrength.d.ts +3 -0
  49. package/dist/components/blocks/index.d.ts +1 -0
  50. package/dist/components/pages/reset-password-page/ResetPasswordPage.d.ts +1 -1
  51. package/dist/hooks.cjs.js +5 -4
  52. package/dist/hooks.es.js +2 -1
  53. package/dist/index.cjs.js +29 -24
  54. package/dist/index.es.js +12 -11
  55. package/dist/layout.cjs.js +1 -1
  56. package/dist/layout.es.js +1 -1
  57. package/dist/pages.cjs.js +1 -1
  58. package/dist/pages.es.js +1 -1
  59. package/dist/sidebar-B7YzwAp3.js +1151 -0
  60. package/dist/sidebar-Cb0U7NsV.cjs +1154 -0
  61. package/dist/ui.cjs.js +7 -7
  62. package/dist/ui.es.js +3 -3
  63. package/dist/xertica-assistant-8fh8KA2K.js +2173 -0
  64. package/dist/xertica-assistant-BjfG3zyL.cjs +2180 -0
  65. package/docs/i18n.md +2 -0
  66. package/package.json +1 -1
  67. package/templates/package.json +2 -2
  68. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +1 -2
  69. package/templates/src/features/auth/ui/LoginContent.tsx +1 -2
  70. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +3 -57
  71. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +1 -2
  72. package/templates/src/features/home/index.ts +0 -10
  73. package/templates/src/features/home/ui/HomeContent.tsx +21 -75
  74. package/templates/src/features/template/index.ts +0 -4
  75. package/templates/src/features/template/ui/TemplateContent.tsx +26 -1279
  76. package/templates/src/locales/en/pages/templates.json +5 -313
  77. package/templates/src/locales/es/pages/templates.json +5 -313
  78. package/templates/src/locales/pt-BR/pages/templates.json +5 -313
  79. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +0 -78
  80. package/templates/src/features/home/data/mock.ts +0 -41
  81. package/templates/src/features/home/hooks/useFeatureCards.ts +0 -20
  82. package/templates/src/features/home/store/dashboardStore.ts +0 -25
  83. package/templates/src/features/template/ui/CrudTemplate.tsx +0 -112
  84. package/templates/src/features/template/ui/DashboardTemplate.tsx +0 -110
  85. package/templates/src/features/template/ui/FormTemplate.tsx +0 -117
  86. package/templates/src/features/template/ui/LoginTemplate.tsx +0 -59
  87. package/templates/src/locales/en/pages/crudTemplate.json +0 -25
  88. package/templates/src/locales/en/pages/dashboardTemplate.json +0 -20
  89. package/templates/src/locales/en/pages/formTemplate.json +0 -16
  90. package/templates/src/locales/en/pages/loginTemplate.json +0 -9
  91. package/templates/src/locales/es/pages/crudTemplate.json +0 -25
  92. package/templates/src/locales/es/pages/dashboardTemplate.json +0 -20
  93. package/templates/src/locales/es/pages/formTemplate.json +0 -16
  94. package/templates/src/locales/es/pages/loginTemplate.json +0 -9
  95. package/templates/src/locales/pt-BR/pages/crudTemplate.json +0 -25
  96. package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +0 -20
  97. package/templates/src/locales/pt-BR/pages/formTemplate.json +0 -16
  98. package/templates/src/locales/pt-BR/pages/loginTemplate.json +0 -9
  99. package/templates/vite.config.d.ts +0 -2
  100. package/templates/vite.config.js +0 -20
package/CHANGELOG.md CHANGED
@@ -11,6 +11,24 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
11
11
 
12
12
  ---
13
13
 
14
+ ## [2.7.0] — 2026-07-07
15
+
16
+ ### Added
17
+
18
+ - **`xertica-ui/blocks` ganha um novo namespace `auth`** — `AuthPageShell` (layout de imagem hero + seletor de idioma + painel de formulário centralizado), `SocialLoginButtons` (com prop `providers` configurável, default `['google', 'mtLogin', 'govBr']`, para projetos que não usam todos os provedores de login social), `usePasswordStrength` e `PasswordStrengthMeter`. Extraídos da duplicação entre `components/pages/{login,forgot-password,reset-password,verify-email}-page/*` e `templates/src/features/auth/ui/*`, que agora consomem a mesma fonte via `xertica-ui/blocks`.
19
+
20
+ ### Fixed
21
+
22
+ - **Assistente de IA — clique numa sugestão inicial rolava a página e deslocava o header** — o efeito de auto-scroll de `use-assistant.ts` media `messagesEndRef.current.parentElement` (uma `<div>` sem overflow próprio) em vez do viewport real do `ScrollArea` do Radix, fazendo a checagem "está perto do fim da rolagem" ser sempre verdadeira — inclusive na primeira mensagem, na transição da tela de boas-vindas para a conversa. Sem `block: 'nearest'`, o `scrollIntoView` podia rolar a janela inteira. Corrigido para medir o `[data-radix-scroll-area-viewport]` correto e conter o scroll dentro dele.
23
+ - **`components/pages/forgot-password-page/ForgotPasswordPage.tsx` tinha texto hardcoded em português**, sem passar por `useTranslation()` como as demais páginas de auth. Convertido para `t('forgotPassword.xxx')`, com as chaves adicionadas em `locales/*/pages/forgotPassword.json` (en/es/pt-BR) na raiz.
24
+
25
+ ### Changed
26
+
27
+ - **`templates/src/features/home` e `templates/src/features/template` reduzidos a placeholders mínimos** — esse conteúdo é vitrine de exemplo, feito para ser substituído pelo consumidor do `npx xertica-ui init`, não para ficar sincronizado com a lib. Removido código morto (`CrudTemplate`, `DashboardTemplate`, `FormTemplate`, `LoginTemplate`, `dashboardStore`, `mock.ts`, `useFeatureCards`) e os locales órfãos correspondentes nos 3 idiomas.
28
+ - Removidos `templates/vite.config.js`/`vite.config.d.ts` — artefatos de build obsoletos e versionados por engano desde a v2.1.0, que faziam o Vite carregar uma versão desatualizada da config (sem os aliases de desenvolvimento do monorepo) em vez do `vite.config.ts` atual.
29
+
30
+ ---
31
+
14
32
  ## [2.6.0] — 2026-07-06
15
33
 
16
34
  ### Security
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Enterprise-grade React design system** built on Tailwind CSS v4, Radix UI, and Lucide Icons — with a robust AI-first documentation layer for precise LLM-driven composition and autonomous agent interaction.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-2.6.0-blue)](https://www.npmjs.com/package/xertica-ui)
5
+ [![npm version](https://img.shields.io/badge/npm-2.7.0-blue)](https://www.npmjs.com/package/xertica-ui)
6
6
  [![license](https://img.shields.io/badge/license-proprietary-red)](./LICENSE)
7
7
 
8
8
  ---
@@ -257,15 +257,14 @@ export function useAssistant({
257
257
  // Auto-scroll on new messages (condicional ≤ 120px)
258
258
  useEffect(() => {
259
259
  if (messagesEndRef.current && abaSelecionada === 'chat') {
260
- const container = messagesEndRef.current.parentElement;
261
- if (!container) {
262
- messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
263
- return;
264
- }
260
+ const container = messagesEndRef.current.closest<HTMLElement>(
261
+ '[data-radix-scroll-area-viewport]'
262
+ );
263
+ if (!container) return;
265
264
  const distanceFromBottom =
266
265
  container.scrollHeight - container.scrollTop - container.clientHeight;
267
266
  if (distanceFromBottom < 120) {
268
- messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
267
+ messagesEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
269
268
  }
270
269
  }
271
270
  }, [mensagens, abaSelecionada]);
@@ -1,13 +1,18 @@
1
1
  import React from 'react';
2
- import { ImageWithFallback } from 'xertica-ui/ui';
3
- import { LanguageSelector } from 'xertica-ui/brand';
2
+ import { ImageWithFallback } from '../../figma/ImageWithFallback';
3
+ import { LanguageSelector } from '../../brand/language-selector';
4
4
 
5
- interface AuthPageShellProps {
5
+ export interface AuthPageShellProps {
6
6
  imageSrc: string;
7
7
  imageAlt: string;
8
8
  children: React.ReactNode;
9
9
  }
10
10
 
11
+ /**
12
+ * Shared two-column shell used by every auth page (Login, ForgotPassword,
13
+ * ResetPassword, VerifyEmail): hero image on the left, centered form panel
14
+ * with a language selector on the right.
15
+ */
11
16
  export function AuthPageShell({ imageSrc, imageAlt, children }: AuthPageShellProps) {
12
17
  return (
13
18
  <div className="h-screen w-full flex overflow-y-auto">
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import type { PasswordStrength } from './usePasswordStrength';
4
+
5
+ export interface PasswordStrengthMeterProps {
6
+ strength: PasswordStrength;
7
+ }
8
+
9
+ const BAR_WIDTH: Record<Exclude<PasswordStrength, null>, string> = {
10
+ weak: 'w-1/3 bg-destructive',
11
+ medium: 'w-2/3 bg-[var(--chart-3)]',
12
+ strong: 'w-full bg-[var(--chart-2)]',
13
+ };
14
+
15
+ const TEXT_COLOR: Record<Exclude<PasswordStrength, null>, string> = {
16
+ weak: 'text-destructive',
17
+ medium: 'text-[var(--chart-3)]',
18
+ strong: 'text-[var(--chart-2)]',
19
+ };
20
+
21
+ const LABEL_KEY: Record<Exclude<PasswordStrength, null>, string> = {
22
+ weak: 'resetPassword.strengthWeak',
23
+ medium: 'resetPassword.strengthMedium',
24
+ strong: 'resetPassword.strengthStrong',
25
+ };
26
+
27
+ /** Progress bar + label shown under the new-password field on reset/create-password screens. */
28
+ export function PasswordStrengthMeter({ strength }: PasswordStrengthMeterProps) {
29
+ const { t } = useTranslation();
30
+
31
+ if (!strength) return null;
32
+
33
+ return (
34
+ <div className="flex items-center gap-2">
35
+ <div className="flex-1 h-1 bg-muted rounded-full overflow-hidden">
36
+ <div className={`h-full transition-all duration-300 ${BAR_WIDTH[strength]}`} />
37
+ </div>
38
+ <span className={`text-small ${TEXT_COLOR[strength]}`}>{t(LABEL_KEY[strength])}</span>
39
+ </div>
40
+ );
41
+ }
@@ -0,0 +1,95 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Lock } from 'lucide-react';
4
+ import { Button } from '../../ui/button';
5
+
6
+ export type SocialProvider = 'google' | 'mtLogin' | 'govBr';
7
+
8
+ export interface SocialLoginButtonsProps {
9
+ onSocialLogin: (provider: string) => void;
10
+ /** Which SSO providers to render — projects without gov.br/MT Login can pass a smaller list. */
11
+ providers?: SocialProvider[];
12
+ }
13
+
14
+ const DEFAULT_PROVIDERS: SocialProvider[] = ['google', 'mtLogin', 'govBr'];
15
+
16
+ export function SocialLoginButtons({
17
+ onSocialLogin,
18
+ providers = DEFAULT_PROVIDERS,
19
+ }: SocialLoginButtonsProps) {
20
+ const { t } = useTranslation();
21
+
22
+ if (providers.length === 0) return null;
23
+
24
+ return (
25
+ <>
26
+ <div className="relative">
27
+ <div className="absolute inset-0 flex items-center">
28
+ <div className="w-full border-t border-border" />
29
+ </div>
30
+ <div className="relative flex justify-center text-sm">
31
+ <span className="bg-muted px-2 text-muted-foreground">{t('login.orContinueWith')}</span>
32
+ </div>
33
+ </div>
34
+
35
+ <div className="space-y-3">
36
+ {providers.includes('google') && (
37
+ <Button
38
+ type="button"
39
+ variant="outline"
40
+ className="w-full justify-center"
41
+ onClick={() => onSocialLogin('Google')}
42
+ >
43
+ <svg className="w-5 h-5 mr-2" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
44
+ <path
45
+ fill="#EA4335"
46
+ d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
47
+ />
48
+ <path
49
+ fill="#4285F4"
50
+ d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"
51
+ />
52
+ <path
53
+ fill="#FBBC05"
54
+ d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"
55
+ />
56
+ <path
57
+ fill="#34A853"
58
+ d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"
59
+ />
60
+ <path fill="none" d="M0 0h48v48H0z" />
61
+ </svg>
62
+ <span>{t('login.signInWithGoogle')}</span>
63
+ </Button>
64
+ )}
65
+
66
+ {providers.includes('mtLogin') && (
67
+ <Button
68
+ type="button"
69
+ variant="outline"
70
+ className="w-full justify-center"
71
+ onClick={() => onSocialLogin('MT Login')}
72
+ >
73
+ <Lock className="w-5 h-5 mr-2 text-[var(--chart-4)]" />
74
+ <span>{t('login.signInWithMTLogin')}</span>
75
+ </Button>
76
+ )}
77
+
78
+ {providers.includes('govBr') && (
79
+ <Button
80
+ type="button"
81
+ variant="outline"
82
+ className="w-full justify-center font-normal"
83
+ onClick={() => onSocialLogin('gov.br')}
84
+ >
85
+ <span>
86
+ {t('login.signInWithGovBr').split('gov.br')[0]}
87
+ <strong className="font-semibold">gov.br</strong>
88
+ {t('login.signInWithGovBr').split('gov.br')[1] || ''}
89
+ </span>
90
+ </Button>
91
+ )}
92
+ </div>
93
+ </>
94
+ );
95
+ }
@@ -0,0 +1,11 @@
1
+ export { AuthPageShell } from './AuthPageShell';
2
+ export type { AuthPageShellProps } from './AuthPageShell';
3
+
4
+ export { SocialLoginButtons } from './SocialLoginButtons';
5
+ export type { SocialLoginButtonsProps, SocialProvider } from './SocialLoginButtons';
6
+
7
+ export { usePasswordStrength } from './usePasswordStrength';
8
+ export type { PasswordStrength } from './usePasswordStrength';
9
+
10
+ export { PasswordStrengthMeter } from './PasswordStrengthMeter';
11
+ export type { PasswordStrengthMeterProps } from './PasswordStrengthMeter';
@@ -0,0 +1,13 @@
1
+ import { useMemo } from 'react';
2
+
3
+ export type PasswordStrength = 'weak' | 'medium' | 'strong' | null;
4
+
5
+ /** Length-based password strength heuristic shared by every reset/create-password screen. */
6
+ export function usePasswordStrength(password: string): PasswordStrength {
7
+ return useMemo(() => {
8
+ if (password.length === 0) return null;
9
+ if (password.length < 6) return 'weak';
10
+ if (password.length < 10) return 'medium';
11
+ return 'strong';
12
+ }, [password]);
13
+ }
@@ -1 +1,2 @@
1
1
  export * from './card-patterns';
2
+ export * from './auth';
@@ -3,10 +3,10 @@ import { Button } from '../../ui/button';
3
3
  import { Input } from '../../ui/input';
4
4
  import { Label } from '../../ui/label';
5
5
  import { XerticaLogo } from '../../brand/xertica-logo';
6
- import { ImageWithFallback } from '../../figma/ImageWithFallback';
7
- import { LanguageSelector } from '../../brand/language-selector';
8
- import { ArrowLeft, Lock } from 'lucide-react';
6
+ import { AuthPageShell, SocialLoginButtons } from '../../blocks/auth';
7
+ import { ArrowLeft } from 'lucide-react';
9
8
  import { useNavigate } from 'react-router-dom';
9
+ import { useTranslation } from 'react-i18next';
10
10
 
11
11
  /**
12
12
  * Forgot Password Page component.
@@ -22,6 +22,7 @@ import { useNavigate } from 'react-router-dom';
22
22
  */
23
23
  export function ForgotPasswordPage() {
24
24
  const navigate = useNavigate();
25
+ const { t } = useTranslation();
25
26
  const [email, setEmail] = useState('');
26
27
  const [isLoading, setIsLoading] = useState(false);
27
28
 
@@ -43,146 +44,51 @@ export function ForgotPasswordPage() {
43
44
  };
44
45
 
45
46
  return (
46
- <div className="h-screen w-full flex overflow-y-auto">
47
- {/* Left side - Full background image */}
48
- <div className="hidden lg:flex lg:flex-1 relative overflow-hidden">
49
- {/* Background image filling all space */}
50
- <ImageWithFallback
51
- src="https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop&auto=format"
52
- alt="Segurança e tecnologia"
53
- className="absolute inset-0 w-full h-full object-cover"
54
- />
55
-
56
- {/* Gradient overlay */}
57
- <div className="absolute inset-0 bg-[image:var(--gradient-diagonal)] opacity-80" />
47
+ <AuthPageShell
48
+ imageSrc="https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop&auto=format"
49
+ imageAlt={t('forgotPassword.heroImageAlt')}
50
+ >
51
+ <div className="text-center">
52
+ <div className="flex items-center justify-center mb-4">
53
+ <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
54
+ </div>
55
+ <h2 className="text-sm text-muted-foreground">{t('forgotPassword.heading')}</h2>
56
+ <p className="mt-2 text-muted-foreground">{t('forgotPassword.subheading')}</p>
58
57
  </div>
59
58
 
60
- {/* Right side - Form */}
61
- <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">
62
- {/* Language selector in the top right corner */}
63
- <div className="absolute top-4 right-4 z-20">
64
- <LanguageSelector variant="minimal" showIcon={false} />
59
+ <form className="space-y-6" onSubmit={handleSubmit}>
60
+ <div className="form-group space-y-2">
61
+ <Label htmlFor="email">{t('forgotPassword.emailLabel')}</Label>
62
+ <Input
63
+ id="email"
64
+ name="email"
65
+ type="email"
66
+ required
67
+ className="w-full"
68
+ placeholder={t('forgotPassword.emailPlaceholder')}
69
+ value={email}
70
+ onChange={e => setEmail(e.target.value)}
71
+ />
65
72
  </div>
66
73
 
67
- {/* Mobile background gradient */}
68
- <div className="absolute inset-0 lg:hidden bg-[image:var(--gradient-diagonal)] opacity-10 dark:opacity-5" />
69
-
70
- <div className="w-full max-w-sm space-y-6 relative z-10">
71
- {/* Form header */}
72
- <div className="text-center">
73
- <div className="flex items-center justify-center mb-4">
74
- <XerticaLogo
75
- className="h-12 w-auto text-primary dark:text-foreground"
76
- variant="theme"
77
- />
78
- </div>
79
- <h2 className="text-sm text-muted-foreground">Recuperar senha</h2>
80
- <p className="mt-2 text-muted-foreground">
81
- Digite seu e-mail e enviaremos as instruções para redefinir sua senha
82
- </p>
83
- </div>
84
-
85
- {/* Form */}
86
- <form className="space-y-6" onSubmit={handleSubmit}>
87
- <div className="form-group space-y-2">
88
- <Label htmlFor="email" className="form-label">
89
- E-mail
90
- </Label>
91
- <Input
92
- id="email"
93
- name="email"
94
- type="email"
95
- required
96
- className="w-full"
97
- placeholder="seu@email.com"
98
- value={email}
99
- onChange={e => setEmail(e.target.value)}
100
- />
101
- </div>
102
-
103
- <div className="space-y-3">
104
- <Button type="submit" className="w-full" disabled={isLoading}>
105
- {isLoading ? 'Enviando...' : 'Enviar instruções'}
106
- </Button>
107
-
108
- <Button
109
- type="button"
110
- onClick={() => navigate('/login')}
111
- variant="outline"
112
- className="w-full text-muted-foreground hover:text-foreground"
113
- >
114
- <ArrowLeft className="w-4 h-4 mr-2" />
115
- Voltar para o login
116
- </Button>
117
- </div>
118
- </form>
119
-
120
- {/* Divider */}
121
- <div className="relative">
122
- <div className="absolute inset-0 flex items-center">
123
- <div className="w-full border-t border-border"></div>
124
- </div>
125
- <div className="relative flex justify-center text-sm">
126
- <span className="bg-muted px-2 text-muted-foreground">ou continue com</span>
127
- </div>
128
- </div>
129
-
130
- {/* Social/SSO login options */}
131
- <div className="space-y-3">
132
- {/* Google */}
133
- <Button
134
- type="button"
135
- variant="outline"
136
- className="w-full justify-center"
137
- onClick={() => handleSocialLogin('Google')}
138
- >
139
- <svg className="w-5 h-5 mr-2" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
140
- <path
141
- fill="#EA4335"
142
- d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
143
- ></path>
144
- <path
145
- fill="#4285F4"
146
- d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"
147
- ></path>
148
- <path
149
- fill="#FBBC05"
150
- d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"
151
- ></path>
152
- <path
153
- fill="#34A853"
154
- d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"
155
- ></path>
156
- <path fill="none" d="M0 0h48v48H0z"></path>
157
- </svg>
158
- <span>Entrar com Google</span>
159
- </Button>
160
-
161
- {/* MT Login */}
162
- <Button
163
- type="button"
164
- variant="outline"
165
- className="w-full justify-center"
166
- onClick={() => handleSocialLogin('MT Login')}
167
- >
168
- <Lock className="w-5 h-5 mr-2 text-[var(--chart-4)]" />
169
- <span>Entrar com MT Login</span>
170
- </Button>
171
-
172
- {/* gov.br */}
173
- <Button
174
- type="button"
175
- variant="outline"
176
- className="w-full justify-center font-normal"
177
- onClick={() => handleSocialLogin('gov.br')}
178
- >
179
- <span>
180
- Entrar com <strong className="font-semibold">gov.br</strong>
181
- </span>
182
- </Button>
183
- </div>
74
+ <div className="space-y-3">
75
+ <Button type="submit" className="w-full" disabled={isLoading}>
76
+ {isLoading ? t('forgotPassword.submitting') : t('forgotPassword.submit')}
77
+ </Button>
78
+
79
+ <Button
80
+ type="button"
81
+ onClick={() => navigate('/login')}
82
+ variant="outline"
83
+ className="w-full text-muted-foreground hover:text-foreground"
84
+ >
85
+ <ArrowLeft className="w-4 h-4 mr-2" />
86
+ {t('forgotPassword.backToLogin')}
87
+ </Button>
184
88
  </div>
185
- </div>
186
- </div>
89
+ </form>
90
+
91
+ <SocialLoginButtons onSocialLogin={handleSocialLogin} />
92
+ </AuthPageShell>
187
93
  );
188
94
  }