xertica-ui 1.2.7 → 1.2.9
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/App.tsx +33 -30
- package/README.md +37 -0
- package/components/Header.tsx +5 -5
- package/components/HomeContent.tsx +5 -7
- package/components/HomePage.tsx +13 -41
- package/components/TemplateContent.tsx +6 -6
- package/components/TemplatePage.tsx +13 -41
- package/components/XerticaProvider.tsx +43 -0
- package/components/index.ts +1 -0
- package/contexts/LayoutContext.tsx +73 -0
- package/contexts/ThemeContext.tsx +19 -12
- package/contexts/index.ts +1 -0
- package/dist/components/Header.d.ts +1 -3
- package/dist/components/HomeContent.d.ts +1 -5
- package/dist/components/HomePage.d.ts +6 -0
- package/dist/components/TemplateContent.d.ts +1 -5
- package/dist/components/TemplatePage.d.ts +6 -0
- package/dist/components/XerticaProvider.d.ts +8 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/contexts/LayoutContext.d.ts +15 -0
- package/dist/contexts/index.d.ts +1 -0
- package/dist/index.es.js +961 -850
- package/dist/index.umd.js +961 -850
- package/package.json +11 -6
package/App.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import { ThemeProvider } from './contexts/ThemeContext';
|
|
|
10
10
|
import { LanguageProvider } from './contexts/LanguageContext';
|
|
11
11
|
import { ApiKeyProvider } from './contexts/ApiKeyContext';
|
|
12
12
|
import { AssistenteProvider } from './contexts/AssistenteContext';
|
|
13
|
+
import { LayoutProvider } from './contexts/LayoutContext';
|
|
13
14
|
import { BrandColorsProvider } from './contexts/BrandColorsContext';
|
|
14
15
|
import { GoogleMapsLoaderProvider } from './components/ui/google-maps-loader';
|
|
15
16
|
import { Toaster } from './components/ui/sonner';
|
|
@@ -19,7 +20,7 @@ import { XerticaAssistant } from './components/ui/xertica-assistant';
|
|
|
19
20
|
if (typeof window !== 'undefined') {
|
|
20
21
|
// Remover classe dark imediatamente
|
|
21
22
|
document.documentElement.classList.remove('dark');
|
|
22
|
-
|
|
23
|
+
|
|
23
24
|
// Se não há tema salvo, definir light mode
|
|
24
25
|
const savedTheme = localStorage.getItem('xertica-theme');
|
|
25
26
|
if (!savedTheme) {
|
|
@@ -78,69 +79,69 @@ function AuthWrapper() {
|
|
|
78
79
|
return (
|
|
79
80
|
<div className="min-h-screen bg-muted overflow-x-hidden max-w-full">
|
|
80
81
|
<Routes>
|
|
81
|
-
<Route
|
|
82
|
-
path="/login"
|
|
82
|
+
<Route
|
|
83
|
+
path="/login"
|
|
83
84
|
element={
|
|
84
85
|
user ? (
|
|
85
86
|
<Navigate to="/home" replace />
|
|
86
87
|
) : (
|
|
87
88
|
<LoginPage onLogin={handleLogin} />
|
|
88
89
|
)
|
|
89
|
-
}
|
|
90
|
+
}
|
|
90
91
|
/>
|
|
91
|
-
<Route
|
|
92
|
-
path="/forgot-password"
|
|
92
|
+
<Route
|
|
93
|
+
path="/forgot-password"
|
|
93
94
|
element={
|
|
94
95
|
user ? (
|
|
95
96
|
<Navigate to="/home" replace />
|
|
96
97
|
) : (
|
|
97
98
|
<ForgotPasswordPage />
|
|
98
99
|
)
|
|
99
|
-
}
|
|
100
|
+
}
|
|
100
101
|
/>
|
|
101
|
-
<Route
|
|
102
|
-
path="/verify-email"
|
|
102
|
+
<Route
|
|
103
|
+
path="/verify-email"
|
|
103
104
|
element={
|
|
104
105
|
user ? (
|
|
105
106
|
<Navigate to="/home" replace />
|
|
106
107
|
) : (
|
|
107
108
|
<VerifyEmailPage />
|
|
108
109
|
)
|
|
109
|
-
}
|
|
110
|
+
}
|
|
110
111
|
/>
|
|
111
|
-
<Route
|
|
112
|
-
path="/reset-password"
|
|
112
|
+
<Route
|
|
113
|
+
path="/reset-password"
|
|
113
114
|
element={
|
|
114
115
|
user ? (
|
|
115
116
|
<Navigate to="/home" replace />
|
|
116
117
|
) : (
|
|
117
118
|
<ResetPasswordPage />
|
|
118
119
|
)
|
|
119
|
-
}
|
|
120
|
+
}
|
|
120
121
|
/>
|
|
121
|
-
<Route
|
|
122
|
-
path="/home"
|
|
122
|
+
<Route
|
|
123
|
+
path="/home"
|
|
123
124
|
element={
|
|
124
125
|
<ProtectedRoute user={user}>
|
|
125
126
|
<HomePage user={user} onLogout={handleLogout} />
|
|
126
127
|
</ProtectedRoute>
|
|
127
|
-
}
|
|
128
|
+
}
|
|
128
129
|
/>
|
|
129
|
-
<Route
|
|
130
|
-
path="/template"
|
|
130
|
+
<Route
|
|
131
|
+
path="/template"
|
|
131
132
|
element={
|
|
132
133
|
<ProtectedRoute user={user}>
|
|
133
134
|
<TemplatePage user={user} onLogout={handleLogout} />
|
|
134
135
|
</ProtectedRoute>
|
|
135
|
-
}
|
|
136
|
+
}
|
|
136
137
|
/>
|
|
137
|
-
<Route
|
|
138
|
-
path="/"
|
|
139
|
-
element={<Navigate to={user ? "/home" : "/login"} replace />}
|
|
138
|
+
<Route
|
|
139
|
+
path="/"
|
|
140
|
+
element={<Navigate to={user ? "/home" : "/login"} replace />}
|
|
140
141
|
/>
|
|
141
|
-
<Route
|
|
142
|
-
path="*"
|
|
143
|
-
element={<Navigate to={user ? "/home" : "/login"} replace />}
|
|
142
|
+
<Route
|
|
143
|
+
path="*"
|
|
144
|
+
element={<Navigate to={user ? "/home" : "/login"} replace />}
|
|
144
145
|
/>
|
|
145
146
|
</Routes>
|
|
146
147
|
|
|
@@ -154,7 +155,7 @@ export default function App() {
|
|
|
154
155
|
useLayoutEffect(() => {
|
|
155
156
|
const root = document.documentElement;
|
|
156
157
|
const savedTheme = localStorage.getItem('xertica-theme');
|
|
157
|
-
|
|
158
|
+
|
|
158
159
|
if (!savedTheme || savedTheme === 'light') {
|
|
159
160
|
root.classList.remove('dark');
|
|
160
161
|
localStorage.setItem('xertica-theme', 'light');
|
|
@@ -168,10 +169,12 @@ export default function App() {
|
|
|
168
169
|
<BrandColorsProvider>
|
|
169
170
|
<ThemeProvider>
|
|
170
171
|
<AssistenteProvider>
|
|
171
|
-
<
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
<LayoutProvider>
|
|
173
|
+
<Router>
|
|
174
|
+
<AuthWrapper />
|
|
175
|
+
<Toaster position="top-right" richColors />
|
|
176
|
+
</Router>
|
|
177
|
+
</LayoutProvider>
|
|
175
178
|
</AssistenteProvider>
|
|
176
179
|
</ThemeProvider>
|
|
177
180
|
</BrandColorsProvider>
|
package/README.md
CHANGED
|
@@ -39,6 +39,43 @@ O método recomendado é usar o CLI:
|
|
|
39
39
|
npx xertica-ui init meu-app
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
### Instalação como Biblioteca
|
|
43
|
+
|
|
44
|
+
Se você deseja usar os componentes em um projeto React existente:
|
|
45
|
+
|
|
46
|
+
1. Instale o pacote:
|
|
47
|
+
```bash
|
|
48
|
+
npm install xertica-ui
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. Importe o CSS (obrigatório) no seu arquivo `main.tsx` ou `App.tsx`:
|
|
52
|
+
```tsx
|
|
53
|
+
import 'xertica-ui/style.css';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
3. Envolva sua aplicação com o `XerticaProvider`:
|
|
57
|
+
```tsx
|
|
58
|
+
import { XerticaProvider } from 'xertica-ui';
|
|
59
|
+
|
|
60
|
+
function App() {
|
|
61
|
+
return (
|
|
62
|
+
<XerticaProvider>
|
|
63
|
+
<SeuApp />
|
|
64
|
+
</XerticaProvider>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
4. Comece a usar os componentes:
|
|
70
|
+
```tsx
|
|
71
|
+
import { Button } from 'xertica-ui';
|
|
72
|
+
|
|
73
|
+
export function MeuComponente() {
|
|
74
|
+
return <Button>Clique aqui</Button>;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Desenvolvimento do Projeto (Contribuição)
|
|
42
79
|
Para desenvolvimento do próprio pacote/biblioteca:
|
|
43
80
|
1. Clone o repositório:
|
|
44
81
|
```bash
|
package/components/Header.tsx
CHANGED
|
@@ -4,9 +4,9 @@ import { Button } from './ui/button';
|
|
|
4
4
|
import { ThemeToggle } from './ThemeToggle';
|
|
5
5
|
import { LanguageSelector } from './LanguageSelector';
|
|
6
6
|
|
|
7
|
+
import { useLayout } from '../contexts/LayoutContext';
|
|
8
|
+
|
|
7
9
|
interface HeaderProps {
|
|
8
|
-
sidebarExpanded: boolean;
|
|
9
|
-
onToggleSidebar: () => void;
|
|
10
10
|
title: string;
|
|
11
11
|
showLanguageSelector?: boolean;
|
|
12
12
|
showThemeToggle?: boolean;
|
|
@@ -14,13 +14,13 @@ interface HeaderProps {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function Header({
|
|
17
|
-
sidebarExpanded,
|
|
18
|
-
onToggleSidebar,
|
|
19
17
|
title,
|
|
20
18
|
showLanguageSelector = true,
|
|
21
19
|
showThemeToggle = true,
|
|
22
20
|
className
|
|
23
21
|
}: HeaderProps) {
|
|
22
|
+
const { sidebarExpanded, toggleSidebar } = useLayout();
|
|
23
|
+
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<header className={`bg-card shadow-sm border-b border-border px-[24px] py-[14px] flex-shrink-0 ${className || ''}`}>
|
|
@@ -30,7 +30,7 @@ export function Header({
|
|
|
30
30
|
<Button
|
|
31
31
|
variant="ghost"
|
|
32
32
|
size="sm"
|
|
33
|
-
onClick={
|
|
33
|
+
onClick={toggleSidebar}
|
|
34
34
|
className="md:hidden mr-2 p-2"
|
|
35
35
|
>
|
|
36
36
|
<Menu className="w-5 h-5" />
|
|
@@ -10,14 +10,14 @@ import { ThemeToggle } from './ThemeToggle';
|
|
|
10
10
|
import { LanguageSelector } from './LanguageSelector';
|
|
11
11
|
import { Badge } from './ui/badge';
|
|
12
12
|
|
|
13
|
+
import { useLayout } from '../contexts/LayoutContext';
|
|
14
|
+
|
|
13
15
|
interface HomeContentProps {
|
|
14
|
-
|
|
15
|
-
assistenteExpanded?: boolean;
|
|
16
|
-
onToggleSidebar?: () => void;
|
|
17
|
-
onToggleAssistente?: () => void;
|
|
16
|
+
// Props de layout removidas em favor do LayoutContext
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
export function HomeContent({
|
|
19
|
+
export function HomeContent({ }: HomeContentProps) {
|
|
20
|
+
const { sidebarExpanded, assistenteExpanded } = useLayout();
|
|
21
21
|
const location = useLocation();
|
|
22
22
|
const navigate = useNavigate();
|
|
23
23
|
|
|
@@ -42,8 +42,6 @@ export function HomeContent({ sidebarExpanded, assistenteExpanded = false, onTog
|
|
|
42
42
|
}`}
|
|
43
43
|
>
|
|
44
44
|
<Header
|
|
45
|
-
sidebarExpanded={sidebarExpanded}
|
|
46
|
-
onToggleSidebar={onToggleSidebar || (() => { })}
|
|
47
45
|
title={breadcrumbLabel}
|
|
48
46
|
/>
|
|
49
47
|
|
package/components/HomePage.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useLocation, useNavigate } from 'react-router';
|
|
3
3
|
import { Sidebar } from './Sidebar';
|
|
4
4
|
import { HomeContent } from './HomeContent';
|
|
@@ -10,62 +10,34 @@ interface HomePageProps {
|
|
|
10
10
|
onLogout: () => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
import { useLayout } from '../contexts/LayoutContext';
|
|
14
|
+
|
|
15
|
+
interface HomePageProps {
|
|
16
|
+
user: { email: string } | null;
|
|
17
|
+
onLogout: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
export function HomePage({ user, onLogout }: HomePageProps) {
|
|
14
|
-
const
|
|
15
|
-
const [assistenteExpanded, setAssistenteExpanded] = useState(false);
|
|
21
|
+
const { sidebarExpanded, assistenteExpanded, toggleSidebar, toggleAssistente, toggleAssistenteWithTab } = useLayout();
|
|
16
22
|
const location = useLocation();
|
|
17
23
|
const navigate = useNavigate();
|
|
18
24
|
|
|
19
|
-
// Função para alternar a sidebar - fecha o assistente se estiver aberto
|
|
20
|
-
const handleToggleSidebar = () => {
|
|
21
|
-
if (!sidebarExpanded && assistenteExpanded) {
|
|
22
|
-
// Se a sidebar vai abrir e o assistente está aberto, fechar o assistente
|
|
23
|
-
setAssistenteExpanded(false);
|
|
24
|
-
}
|
|
25
|
-
setSidebarExpanded(!sidebarExpanded);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Função para alternar o assistente - fecha a sidebar se estiver aberta
|
|
29
|
-
const handleToggleAssistente = () => {
|
|
30
|
-
if (!assistenteExpanded && sidebarExpanded) {
|
|
31
|
-
// Se o assistente vai abrir e a sidebar está aberta, fechar a sidebar
|
|
32
|
-
setSidebarExpanded(false);
|
|
33
|
-
}
|
|
34
|
-
setAssistenteExpanded(!assistenteExpanded);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Função para abrir assistente com tab específica - fecha a sidebar se estiver aberta
|
|
38
|
-
const handleToggleAssistenteWithTab = (tab: string) => {
|
|
39
|
-
if (!assistenteExpanded) {
|
|
40
|
-
if (sidebarExpanded) {
|
|
41
|
-
// Se o assistente vai abrir e a sidebar está aberta, fechar a sidebar
|
|
42
|
-
setSidebarExpanded(false);
|
|
43
|
-
}
|
|
44
|
-
setAssistenteExpanded(true);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
25
|
return (
|
|
49
26
|
<div className="h-screen flex bg-muted overflow-hidden relative">
|
|
50
27
|
<Sidebar
|
|
51
28
|
expanded={sidebarExpanded}
|
|
52
|
-
onToggle={
|
|
29
|
+
onToggle={toggleSidebar}
|
|
53
30
|
user={user}
|
|
54
31
|
onLogout={onLogout}
|
|
55
32
|
location={location}
|
|
56
33
|
navigate={navigate}
|
|
57
34
|
routes={routes}
|
|
58
35
|
/>
|
|
59
|
-
<HomeContent
|
|
60
|
-
sidebarExpanded={sidebarExpanded}
|
|
61
|
-
assistenteExpanded={assistenteExpanded}
|
|
62
|
-
onToggleSidebar={handleToggleSidebar}
|
|
63
|
-
onToggleAssistente={handleToggleAssistente}
|
|
64
|
-
/>
|
|
36
|
+
<HomeContent />
|
|
65
37
|
<AssistenteXertica
|
|
66
38
|
isExpanded={assistenteExpanded}
|
|
67
|
-
onToggle={
|
|
68
|
-
onToggleWithTab={
|
|
39
|
+
onToggle={toggleAssistente}
|
|
40
|
+
onToggleWithTab={toggleAssistenteWithTab}
|
|
69
41
|
/>
|
|
70
42
|
</div>
|
|
71
43
|
);
|
|
@@ -21,14 +21,14 @@ import { ScrollArea } from './ui/scroll-area';
|
|
|
21
21
|
import { ThemeToggle } from './ThemeToggle';
|
|
22
22
|
import { LanguageSelector } from './LanguageSelector';
|
|
23
23
|
|
|
24
|
+
import { useLayout } from '../contexts/LayoutContext';
|
|
25
|
+
|
|
24
26
|
interface TemplateContentProps {
|
|
25
|
-
|
|
26
|
-
assistenteExpanded?: boolean;
|
|
27
|
-
onToggleSidebar?: () => void;
|
|
28
|
-
onToggleAssistente?: () => void;
|
|
27
|
+
// Props de layout removidas
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
export function TemplateContent({
|
|
30
|
+
export function TemplateContent({ }: TemplateContentProps) {
|
|
31
|
+
const { sidebarExpanded, assistenteExpanded, toggleSidebar } = useLayout();
|
|
32
32
|
const [progress, setProgress] = useState(45);
|
|
33
33
|
const [sliderValue, setSliderValue] = useState([50]);
|
|
34
34
|
const [switchEnabled, setSwitchEnabled] = useState(false);
|
|
@@ -52,7 +52,7 @@ export function TemplateContent({ sidebarExpanded, assistenteExpanded = false, o
|
|
|
52
52
|
<Button
|
|
53
53
|
variant="ghost"
|
|
54
54
|
size="sm"
|
|
55
|
-
onClick={
|
|
55
|
+
onClick={toggleSidebar}
|
|
56
56
|
className="md:hidden mr-2 p-2"
|
|
57
57
|
>
|
|
58
58
|
<Menu className="w-5 h-5" />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useLocation, useNavigate } from 'react-router';
|
|
3
3
|
import { Sidebar } from './Sidebar';
|
|
4
4
|
import { TemplateContent } from './TemplateContent';
|
|
@@ -10,62 +10,34 @@ interface TemplatePageProps {
|
|
|
10
10
|
onLogout: () => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
import { useLayout } from '../contexts/LayoutContext';
|
|
14
|
+
|
|
15
|
+
interface TemplatePageProps {
|
|
16
|
+
user: { email: string } | null;
|
|
17
|
+
onLogout: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
export function TemplatePage({ user, onLogout }: TemplatePageProps) {
|
|
14
|
-
const
|
|
15
|
-
const [assistenteExpanded, setAssistenteExpanded] = useState(false);
|
|
21
|
+
const { sidebarExpanded, assistenteExpanded, toggleSidebar, toggleAssistente, toggleAssistenteWithTab } = useLayout();
|
|
16
22
|
const location = useLocation();
|
|
17
23
|
const navigate = useNavigate();
|
|
18
24
|
|
|
19
|
-
// Função para alternar a sidebar - fecha o assistente se estiver aberto
|
|
20
|
-
const handleToggleSidebar = () => {
|
|
21
|
-
if (!sidebarExpanded && assistenteExpanded) {
|
|
22
|
-
// Se a sidebar vai abrir e o assistente está aberto, fechar o assistente
|
|
23
|
-
setAssistenteExpanded(false);
|
|
24
|
-
}
|
|
25
|
-
setSidebarExpanded(!sidebarExpanded);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Função para alternar o assistente - fecha a sidebar se estiver aberta
|
|
29
|
-
const handleToggleAssistente = () => {
|
|
30
|
-
if (!assistenteExpanded && sidebarExpanded) {
|
|
31
|
-
// Se o assistente vai abrir e a sidebar está aberta, fechar a sidebar
|
|
32
|
-
setSidebarExpanded(false);
|
|
33
|
-
}
|
|
34
|
-
setAssistenteExpanded(!assistenteExpanded);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Função para abrir assistente com tab específica - fecha a sidebar se estiver aberta
|
|
38
|
-
const handleToggleAssistenteWithTab = (tab: string) => {
|
|
39
|
-
if (!assistenteExpanded) {
|
|
40
|
-
if (sidebarExpanded) {
|
|
41
|
-
// Se o assistente vai abrir e a sidebar está aberta, fechar a sidebar
|
|
42
|
-
setSidebarExpanded(false);
|
|
43
|
-
}
|
|
44
|
-
setAssistenteExpanded(true);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
25
|
return (
|
|
49
26
|
<div className="h-screen flex bg-muted overflow-hidden relative">
|
|
50
27
|
<Sidebar
|
|
51
28
|
expanded={sidebarExpanded}
|
|
52
|
-
onToggle={
|
|
29
|
+
onToggle={toggleSidebar}
|
|
53
30
|
user={user}
|
|
54
31
|
onLogout={onLogout}
|
|
55
32
|
location={location}
|
|
56
33
|
navigate={navigate}
|
|
57
34
|
routes={routes}
|
|
58
35
|
/>
|
|
59
|
-
<TemplateContent
|
|
60
|
-
sidebarExpanded={sidebarExpanded}
|
|
61
|
-
assistenteExpanded={assistenteExpanded}
|
|
62
|
-
onToggleSidebar={handleToggleSidebar}
|
|
63
|
-
onToggleAssistente={handleToggleAssistente}
|
|
64
|
-
/>
|
|
36
|
+
<TemplateContent />
|
|
65
37
|
<AssistenteXertica
|
|
66
38
|
isExpanded={assistenteExpanded}
|
|
67
|
-
onToggle={
|
|
68
|
-
onToggleWithTab={
|
|
39
|
+
onToggle={toggleAssistente}
|
|
40
|
+
onToggleWithTab={toggleAssistenteWithTab}
|
|
69
41
|
/>
|
|
70
42
|
</div>
|
|
71
43
|
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ThemeProvider } from '../contexts/ThemeContext';
|
|
3
|
+
import { LanguageProvider } from '../contexts/LanguageContext';
|
|
4
|
+
import { ApiKeyProvider } from '../contexts/ApiKeyContext';
|
|
5
|
+
import { AssistenteProvider } from '../contexts/AssistenteContext';
|
|
6
|
+
import { LayoutProvider } from '../contexts/LayoutContext';
|
|
7
|
+
import { BrandColorsProvider } from '../contexts/BrandColorsContext';
|
|
8
|
+
import { GoogleMapsLoaderProvider } from './ui/google-maps-loader';
|
|
9
|
+
import { Toaster } from './ui/sonner';
|
|
10
|
+
import { TooltipProvider } from './ui/tooltip';
|
|
11
|
+
|
|
12
|
+
interface XerticaProviderProps {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
apiKey?: string; // Optional Gemini API Key
|
|
15
|
+
googleMapsApiKey?: string; // Optional Maps API Key
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function XerticaProvider({ children, apiKey, googleMapsApiKey }: XerticaProviderProps) {
|
|
19
|
+
// Note: ApiKeyProvider and GoogleMapsLoaderProvider might need props for keys if not handling internals
|
|
20
|
+
// Currently ApiKeyProvider seems to manage key internally or via props? logic check needed.
|
|
21
|
+
// Assuming default behavior for now, but ideally we pass keys here.
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<ApiKeyProvider>
|
|
25
|
+
<GoogleMapsLoaderProvider>
|
|
26
|
+
<LanguageProvider>
|
|
27
|
+
<BrandColorsProvider>
|
|
28
|
+
<ThemeProvider>
|
|
29
|
+
<AssistenteProvider>
|
|
30
|
+
<LayoutProvider>
|
|
31
|
+
<TooltipProvider>
|
|
32
|
+
{children}
|
|
33
|
+
<Toaster position="top-right" richColors />
|
|
34
|
+
</TooltipProvider>
|
|
35
|
+
</LayoutProvider>
|
|
36
|
+
</AssistenteProvider>
|
|
37
|
+
</ThemeProvider>
|
|
38
|
+
</BrandColorsProvider>
|
|
39
|
+
</LanguageProvider>
|
|
40
|
+
</GoogleMapsLoaderProvider>
|
|
41
|
+
</ApiKeyProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
package/components/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import '../index.css';
|
|
|
4
4
|
// ============================================================================
|
|
5
5
|
|
|
6
6
|
export { XerticaAssistant } from './ui/xertica-assistant';
|
|
7
|
+
export { XerticaProvider } from './XerticaProvider';
|
|
7
8
|
export type {
|
|
8
9
|
XerticaAssistantProps,
|
|
9
10
|
Message,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
interface LayoutContextType {
|
|
4
|
+
sidebarExpanded: boolean;
|
|
5
|
+
assistenteExpanded: boolean;
|
|
6
|
+
toggleSidebar: () => void;
|
|
7
|
+
toggleAssistente: () => void;
|
|
8
|
+
toggleAssistenteWithTab: (tab: string) => void;
|
|
9
|
+
setSidebarExpanded: (expanded: boolean) => void;
|
|
10
|
+
setAssistenteExpanded: (expanded: boolean) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const LayoutContext = createContext<LayoutContextType | undefined>(undefined);
|
|
14
|
+
|
|
15
|
+
export function LayoutProvider({ children }: { children: ReactNode }) {
|
|
16
|
+
const [sidebarExpanded, setSidebarExpandedState] = useState(false);
|
|
17
|
+
const [assistenteExpanded, setAssistenteExpandedState] = useState(false);
|
|
18
|
+
|
|
19
|
+
// Função para alternar a sidebar - fecha o assistente se estiver aberto
|
|
20
|
+
const toggleSidebar = useCallback(() => {
|
|
21
|
+
setSidebarExpandedState(prev => {
|
|
22
|
+
const newState = !prev;
|
|
23
|
+
if (newState && assistenteExpanded) {
|
|
24
|
+
setAssistenteExpandedState(false);
|
|
25
|
+
}
|
|
26
|
+
return newState;
|
|
27
|
+
});
|
|
28
|
+
}, [assistenteExpanded]);
|
|
29
|
+
|
|
30
|
+
// Função para alternar o assistente - fecha a sidebar se estiver aberta
|
|
31
|
+
const toggleAssistente = useCallback(() => {
|
|
32
|
+
setAssistenteExpandedState(prev => {
|
|
33
|
+
const newState = !prev;
|
|
34
|
+
if (newState && sidebarExpanded) {
|
|
35
|
+
setSidebarExpandedState(false);
|
|
36
|
+
}
|
|
37
|
+
return newState;
|
|
38
|
+
});
|
|
39
|
+
}, [sidebarExpanded]);
|
|
40
|
+
|
|
41
|
+
// Função para abrir assistente com tab específica - fecha a sidebar se estiver aberta
|
|
42
|
+
const toggleAssistenteWithTab = useCallback((tab: string) => {
|
|
43
|
+
if (!assistenteExpanded) {
|
|
44
|
+
if (sidebarExpanded) {
|
|
45
|
+
setSidebarExpandedState(false);
|
|
46
|
+
}
|
|
47
|
+
setAssistenteExpandedState(true);
|
|
48
|
+
}
|
|
49
|
+
// Lógica adicional para tab pode ser implementada aqui se necessário
|
|
50
|
+
}, [assistenteExpanded, sidebarExpanded]);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<LayoutContext.Provider value={{
|
|
54
|
+
sidebarExpanded,
|
|
55
|
+
assistenteExpanded,
|
|
56
|
+
toggleSidebar,
|
|
57
|
+
toggleAssistente,
|
|
58
|
+
toggleAssistenteWithTab,
|
|
59
|
+
setSidebarExpanded: setSidebarExpandedState,
|
|
60
|
+
setAssistenteExpanded: setAssistenteExpandedState
|
|
61
|
+
}}>
|
|
62
|
+
{children}
|
|
63
|
+
</LayoutContext.Provider>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function useLayout() {
|
|
68
|
+
const context = useContext(LayoutContext);
|
|
69
|
+
if (context === undefined) {
|
|
70
|
+
throw new Error('useLayout must be used within a LayoutProvider');
|
|
71
|
+
}
|
|
72
|
+
return context;
|
|
73
|
+
}
|
|
@@ -14,16 +14,17 @@ const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
|
|
14
14
|
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
15
15
|
// Inicialização mais direta - verificar localStorage imediatamente
|
|
16
16
|
const getInitialTheme = (): Theme => {
|
|
17
|
-
// Primeiro, garantir que não há classe dark aplicada por padrão
|
|
18
17
|
if (typeof window !== 'undefined') {
|
|
19
|
-
document.documentElement.classList.remove('dark');
|
|
20
|
-
|
|
21
18
|
const savedTheme = localStorage.getItem('xertica-theme') as Theme;
|
|
22
19
|
if (savedTheme && (savedTheme === 'light' || savedTheme === 'dark')) {
|
|
23
20
|
return savedTheme;
|
|
24
21
|
}
|
|
22
|
+
// Se não houver tema salvo, verificar preferência do sistema
|
|
23
|
+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
24
|
+
return 'dark';
|
|
25
|
+
}
|
|
25
26
|
}
|
|
26
|
-
//
|
|
27
|
+
// Padrão light se nada for detectado
|
|
27
28
|
return 'light';
|
|
28
29
|
};
|
|
29
30
|
|
|
@@ -32,24 +33,30 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
|
32
33
|
// Aplicar tema ao documento sempre que o tema mudar
|
|
33
34
|
useEffect(() => {
|
|
34
35
|
const root = document.documentElement;
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
// Remove ambas as classes para garantir estado limpo
|
|
38
|
+
root.classList.remove('light', 'dark');
|
|
39
|
+
|
|
36
40
|
if (theme === 'dark') {
|
|
37
41
|
root.classList.add('dark');
|
|
38
42
|
} else {
|
|
39
|
-
root.classList.
|
|
43
|
+
root.classList.add('light'); // Opcional, mas ajuda em alguns frameworks CSS
|
|
40
44
|
}
|
|
41
|
-
|
|
45
|
+
|
|
42
46
|
// Salvar no localStorage
|
|
43
47
|
localStorage.setItem('xertica-theme', theme);
|
|
44
48
|
}, [theme]);
|
|
45
49
|
|
|
46
|
-
//
|
|
50
|
+
// Listener para mudanças na preferência do sistema
|
|
47
51
|
useEffect(() => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
if (!localStorage.getItem('xertica-theme')) {
|
|
53
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
54
|
+
const handleChange = (e: MediaQueryListEvent) => {
|
|
55
|
+
setTheme(e.matches ? 'dark' : 'light');
|
|
56
|
+
};
|
|
57
|
+
mediaQuery.addEventListener('change', handleChange);
|
|
58
|
+
return () => mediaQuery.removeEventListener('change', handleChange);
|
|
51
59
|
}
|
|
52
|
-
localStorage.setItem('xertica-theme', theme);
|
|
53
60
|
}, []);
|
|
54
61
|
|
|
55
62
|
// Alternar tema
|
package/contexts/index.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
interface HeaderProps {
|
|
2
|
-
sidebarExpanded: boolean;
|
|
3
|
-
onToggleSidebar: () => void;
|
|
4
2
|
title: string;
|
|
5
3
|
showLanguageSelector?: boolean;
|
|
6
4
|
showThemeToggle?: boolean;
|
|
7
5
|
className?: string;
|
|
8
6
|
}
|
|
9
|
-
export declare function Header({
|
|
7
|
+
export declare function Header({ title, showLanguageSelector, showThemeToggle, className }: HeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
8
|
export {};
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
interface HomeContentProps {
|
|
2
|
-
sidebarExpanded: boolean;
|
|
3
|
-
assistenteExpanded?: boolean;
|
|
4
|
-
onToggleSidebar?: () => void;
|
|
5
|
-
onToggleAssistente?: () => void;
|
|
6
2
|
}
|
|
7
|
-
export declare function HomeContent({
|
|
3
|
+
export declare function HomeContent({}: HomeContentProps): import("react/jsx-runtime").JSX.Element;
|
|
8
4
|
export {};
|
|
@@ -4,5 +4,11 @@ interface HomePageProps {
|
|
|
4
4
|
} | null;
|
|
5
5
|
onLogout: () => void;
|
|
6
6
|
}
|
|
7
|
+
interface HomePageProps {
|
|
8
|
+
user: {
|
|
9
|
+
email: string;
|
|
10
|
+
} | null;
|
|
11
|
+
onLogout: () => void;
|
|
12
|
+
}
|
|
7
13
|
export declare function HomePage({ user, onLogout }: HomePageProps): import("react/jsx-runtime").JSX.Element;
|
|
8
14
|
export {};
|