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,229 @@
|
|
|
1
|
+
import { useState, useRef, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Types
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export interface TreeNode {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
children?: TreeNode[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface UseTreeViewProps {
|
|
15
|
+
/** The tree data to manage. */
|
|
16
|
+
data: TreeNode[];
|
|
17
|
+
/** Node IDs that are expanded by default (uncontrolled). */
|
|
18
|
+
defaultExpanded?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Controlled selected node ID.
|
|
21
|
+
* When provided, selection state is managed externally.
|
|
22
|
+
*/
|
|
23
|
+
selectedNodeId?: string;
|
|
24
|
+
/** Called when a node is clicked or activated via keyboard. */
|
|
25
|
+
onNodeClick?: (node: TreeNode) => void;
|
|
26
|
+
/** Called when a node becomes the selected item. */
|
|
27
|
+
onNodeSelect?: (node: TreeNode) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface UseTreeViewReturn {
|
|
31
|
+
// ── State ─────────────────────────────────────────────────────────────────
|
|
32
|
+
/** Set of currently expanded node IDs. */
|
|
33
|
+
expanded: Set<string>;
|
|
34
|
+
/** The currently selected node ID (controlled or internal). */
|
|
35
|
+
effectiveSelectedId: string | undefined;
|
|
36
|
+
|
|
37
|
+
// ── Refs ──────────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Map of node ID → button element.
|
|
40
|
+
* Attach via the `setRef` helper returned by `getNodeRef`.
|
|
41
|
+
*/
|
|
42
|
+
nodeRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
|
|
43
|
+
|
|
44
|
+
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
45
|
+
/** Returns a ref-setter callback for a given node ID. */
|
|
46
|
+
getNodeRef: (nodeId: string) => (el: HTMLButtonElement | null) => void;
|
|
47
|
+
|
|
48
|
+
// ── Handlers ──────────────────────────────────────────────────────────────
|
|
49
|
+
/** Toggle the expanded state of a node. */
|
|
50
|
+
toggleExpand: (nodeId: string) => void;
|
|
51
|
+
/** Select a node (updates internal state if uncontrolled, fires callbacks). */
|
|
52
|
+
handleSelect: (node: TreeNode) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Full WAI-ARIA keyboard handler.
|
|
55
|
+
* Attach to `onKeyDown` of each tree-item button.
|
|
56
|
+
*/
|
|
57
|
+
handleKeyDown: (e: React.KeyboardEvent, node: TreeNode) => void;
|
|
58
|
+
|
|
59
|
+
// ── Computed ──────────────────────────────────────────────────────────────
|
|
60
|
+
/** Returns the ordered list of all currently visible nodes (respects expand state). */
|
|
61
|
+
getVisibleNodes: () => TreeNode[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
// Hook
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Headless hook for hierarchical tree-view logic.
|
|
70
|
+
*
|
|
71
|
+
* @description
|
|
72
|
+
* Manages expand/collapse state, selection (controlled or uncontrolled),
|
|
73
|
+
* WAI-ARIA keyboard navigation (Arrow keys, Home, End, Enter/Space),
|
|
74
|
+
* and focus management via node refs. Pair with any custom tree UI.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```tsx
|
|
78
|
+
* const { expanded, effectiveSelectedId, toggleExpand, handleSelect, handleKeyDown, getNodeRef } =
|
|
79
|
+
* useTreeView({ data, onNodeSelect });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function useTreeView({
|
|
83
|
+
data,
|
|
84
|
+
defaultExpanded = [],
|
|
85
|
+
selectedNodeId,
|
|
86
|
+
onNodeClick,
|
|
87
|
+
onNodeSelect,
|
|
88
|
+
}: UseTreeViewProps): UseTreeViewReturn {
|
|
89
|
+
const [expanded, setExpanded] = useState<Set<string>>(new Set(defaultExpanded));
|
|
90
|
+
const [internalSelectedId, setInternalSelectedId] = useState<string | undefined>(undefined);
|
|
91
|
+
const nodeRefs = useRef<Map<string, HTMLButtonElement>>(new Map());
|
|
92
|
+
|
|
93
|
+
const isControlled = selectedNodeId !== undefined;
|
|
94
|
+
const effectiveSelectedId = isControlled ? selectedNodeId : internalSelectedId;
|
|
95
|
+
|
|
96
|
+
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
const getNodeRef = useCallback(
|
|
99
|
+
(nodeId: string) => (el: HTMLButtonElement | null) => {
|
|
100
|
+
if (el) nodeRefs.current.set(nodeId, el);
|
|
101
|
+
else nodeRefs.current.delete(nodeId);
|
|
102
|
+
},
|
|
103
|
+
[]
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const getVisibleNodes = useCallback((): TreeNode[] => {
|
|
107
|
+
const result: TreeNode[] = [];
|
|
108
|
+
const traverse = (nodes: TreeNode[]) => {
|
|
109
|
+
for (const node of nodes) {
|
|
110
|
+
result.push(node);
|
|
111
|
+
if (node.children?.length && expanded.has(node.id)) traverse(node.children);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
traverse(data);
|
|
115
|
+
return result;
|
|
116
|
+
}, [data, expanded]);
|
|
117
|
+
|
|
118
|
+
const findParent = useCallback(
|
|
119
|
+
(nodes: TreeNode[], targetId: string): TreeNode | null => {
|
|
120
|
+
for (const n of nodes) {
|
|
121
|
+
if (n.children?.some(c => c.id === targetId)) return n;
|
|
122
|
+
if (n.children) {
|
|
123
|
+
const found = findParent(n.children, targetId);
|
|
124
|
+
if (found) return found;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
},
|
|
129
|
+
// findParent is a pure recursive function over `data` — no reactive deps needed
|
|
130
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
131
|
+
[]
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// ── Handlers ──────────────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
const toggleExpand = useCallback((nodeId: string) => {
|
|
137
|
+
setExpanded(prev => {
|
|
138
|
+
const next = new Set(prev);
|
|
139
|
+
next.has(nodeId) ? next.delete(nodeId) : next.add(nodeId);
|
|
140
|
+
return next;
|
|
141
|
+
});
|
|
142
|
+
}, []);
|
|
143
|
+
|
|
144
|
+
const handleSelect = useCallback(
|
|
145
|
+
(node: TreeNode) => {
|
|
146
|
+
if (!isControlled) setInternalSelectedId(node.id);
|
|
147
|
+
onNodeSelect?.(node);
|
|
148
|
+
onNodeClick?.(node);
|
|
149
|
+
},
|
|
150
|
+
[isControlled, onNodeClick, onNodeSelect]
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const handleKeyDown = useCallback(
|
|
154
|
+
(e: React.KeyboardEvent, node: TreeNode) => {
|
|
155
|
+
const visibleNodes = getVisibleNodes();
|
|
156
|
+
const idx = visibleNodes.findIndex(n => n.id === node.id);
|
|
157
|
+
const hasChildren = !!(node.children?.length);
|
|
158
|
+
const isExpanded = expanded.has(node.id);
|
|
159
|
+
|
|
160
|
+
const focusNode = (id: string) => {
|
|
161
|
+
nodeRefs.current.get(id)?.focus();
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
switch (e.key) {
|
|
165
|
+
case 'ArrowDown': {
|
|
166
|
+
e.preventDefault();
|
|
167
|
+
const next = visibleNodes[idx + 1];
|
|
168
|
+
if (next) focusNode(next.id);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 'ArrowUp': {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
const prev = visibleNodes[idx - 1];
|
|
174
|
+
if (prev) focusNode(prev.id);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'ArrowRight': {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
if (hasChildren && !isExpanded) {
|
|
180
|
+
toggleExpand(node.id);
|
|
181
|
+
} else if (hasChildren && isExpanded && node.children?.length) {
|
|
182
|
+
focusNode(node.children[0].id);
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case 'ArrowLeft': {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
if (hasChildren && isExpanded) {
|
|
189
|
+
toggleExpand(node.id);
|
|
190
|
+
} else {
|
|
191
|
+
const parent = findParent(data, node.id);
|
|
192
|
+
if (parent) focusNode(parent.id);
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'Home': {
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
if (visibleNodes.length > 0) focusNode(visibleNodes[0].id);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case 'End': {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
const last = visibleNodes[visibleNodes.length - 1];
|
|
204
|
+
if (last) focusNode(last.id);
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case 'Enter':
|
|
208
|
+
case ' ': {
|
|
209
|
+
e.preventDefault();
|
|
210
|
+
if (hasChildren) toggleExpand(node.id);
|
|
211
|
+
handleSelect(node);
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
[data, expanded, findParent, getVisibleNodes, handleSelect, toggleExpand]
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
expanded,
|
|
221
|
+
effectiveSelectedId,
|
|
222
|
+
nodeRefs,
|
|
223
|
+
getNodeRef,
|
|
224
|
+
toggleExpand,
|
|
225
|
+
handleSelect,
|
|
226
|
+
handleKeyDown,
|
|
227
|
+
getVisibleNodes,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -1,44 +1,29 @@
|
|
|
1
1
|
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
Message,
|
|
4
|
+
SearchResult,
|
|
5
|
+
SearchSource,
|
|
6
|
+
SearchCommand,
|
|
7
|
+
MockResponse,
|
|
8
|
+
} from '../components/assistant/xertica-assistant/types';
|
|
2
9
|
|
|
10
|
+
// Re-export shared types for backward compatibility
|
|
11
|
+
export type { Message, SearchResult, SearchSource, SearchCommand, MockResponse };
|
|
3
12
|
|
|
4
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated Use `Suggestion` from `xertica-assistant/types` instead.
|
|
15
|
+
* Kept for backward compatibility with existing consumers.
|
|
16
|
+
*/
|
|
5
17
|
export interface Sugestao {
|
|
6
18
|
id: string;
|
|
7
19
|
texto: string;
|
|
8
20
|
icon?: ReactNode;
|
|
9
21
|
}
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
timestamp: Date;
|
|
16
|
-
isFavorite?: boolean;
|
|
17
|
-
chartData?: any[];
|
|
18
|
-
chartConfig?: any;
|
|
19
|
-
attachmentType?: 'image' | 'video' | 'audio' | 'file' | 'document' | 'podcast' | 'search';
|
|
20
|
-
attachmentName?: string;
|
|
21
|
-
documentContent?: string;
|
|
22
|
-
documentTitle?: string;
|
|
23
|
-
tableData?: {
|
|
24
|
-
caption?: string;
|
|
25
|
-
headers: string[];
|
|
26
|
-
rows: (string | ReactNode)[][];
|
|
27
|
-
};
|
|
28
|
-
audioUrl?: string;
|
|
29
|
-
searchResults?: SearchResult[];
|
|
30
|
-
searchSources?: SearchSource[];
|
|
31
|
-
searchCommands?: SearchCommand[];
|
|
32
|
-
evaluation?: 'like' | 'dislike';
|
|
33
|
-
evaluationReason?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface MockResponse {
|
|
37
|
-
trigger: string | RegExp;
|
|
38
|
-
response: string | Partial<Message>;
|
|
39
|
-
delay?: number;
|
|
40
|
-
}
|
|
41
|
-
|
|
23
|
+
/**
|
|
24
|
+
* A saved conversation in the AssistenteContext (Portuguese naming convention).
|
|
25
|
+
* Note: `Conversation` in `xertica-assistant/types` uses English naming.
|
|
26
|
+
*/
|
|
42
27
|
export interface Conversa {
|
|
43
28
|
id: string;
|
|
44
29
|
titulo: string;
|
|
@@ -48,28 +33,6 @@ export interface Conversa {
|
|
|
48
33
|
favorita?: boolean;
|
|
49
34
|
}
|
|
50
35
|
|
|
51
|
-
export interface SearchResult {
|
|
52
|
-
id: string;
|
|
53
|
-
title: string;
|
|
54
|
-
description: string;
|
|
55
|
-
type: 'document' | 'file' | 'project' | 'conversation' | 'contact';
|
|
56
|
-
path: string;
|
|
57
|
-
relevance: number;
|
|
58
|
-
lastModified?: string;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface SearchSource {
|
|
62
|
-
name: string;
|
|
63
|
-
count: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface SearchCommand {
|
|
67
|
-
id: string;
|
|
68
|
-
icon: string;
|
|
69
|
-
label: string;
|
|
70
|
-
description: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
36
|
interface AssistenteContextType {
|
|
74
37
|
historico: Message[];
|
|
75
38
|
conversaAtual: string;
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
PALETTE,
|
|
7
7
|
colorThemes,
|
|
8
8
|
} from './theme-data';
|
|
9
|
+
import { hexToRgb } from '../utils/color-utils';
|
|
9
10
|
|
|
10
11
|
interface BrandColorsContextType {
|
|
11
12
|
colors: BrandColors;
|
|
@@ -26,11 +27,11 @@ interface BrandColorsProviderProps {
|
|
|
26
27
|
useCustomTokens?: boolean;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
export const BrandColorsProvider: React.FC<BrandColorsProviderProps> = ({
|
|
30
|
-
children,
|
|
31
|
-
defaultTheme,
|
|
32
|
-
primaryColor,
|
|
33
|
-
useCustomTokens = false
|
|
30
|
+
export const BrandColorsProvider: React.FC<BrandColorsProviderProps> = ({
|
|
31
|
+
children,
|
|
32
|
+
defaultTheme,
|
|
33
|
+
primaryColor,
|
|
34
|
+
useCustomTokens = false
|
|
34
35
|
}) => {
|
|
35
36
|
const [currentTheme, setCurrentTheme] = useState<string>(() => {
|
|
36
37
|
// Se primaryColor for passado, ignoramos o nome do tema
|
|
@@ -75,18 +76,6 @@ export const BrandColorsProvider: React.FC<BrandColorsProviderProps> = ({
|
|
|
75
76
|
}
|
|
76
77
|
}, [currentTheme, primaryColor]);
|
|
77
78
|
|
|
78
|
-
// Função auxiliar para converter hex para rgb
|
|
79
|
-
const hexToRgb = (hex: string): { r: number; g: number; b: number } | null => {
|
|
80
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
81
|
-
return result
|
|
82
|
-
? {
|
|
83
|
-
r: parseInt(result[1], 16),
|
|
84
|
-
g: parseInt(result[2], 16),
|
|
85
|
-
b: parseInt(result[3], 16),
|
|
86
|
-
}
|
|
87
|
-
: null;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
79
|
// Função para aplicar as cores baseadas no modo atual e tema
|
|
91
80
|
const applyColors = React.useCallback(() => {
|
|
92
81
|
if (useCustomTokens) return; // Skip if user wants to use local tokens.css
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { createContext, useContext, useState, ReactNode, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useIsMobile } from '../components/shared/use-mobile';
|
|
2
3
|
|
|
3
4
|
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
4
5
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
5
|
-
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
6
6
|
|
|
7
7
|
interface LayoutContextType {
|
|
8
8
|
sidebarExpanded: boolean;
|
|
@@ -51,45 +51,19 @@ export function LayoutProvider({ children }: { children: ReactNode }) {
|
|
|
51
51
|
const saved = getCookie(SIDEBAR_COOKIE_NAME);
|
|
52
52
|
return saved === 'true';
|
|
53
53
|
});
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
const [assistenteExpanded, setAssistenteExpandedState] = useState(false);
|
|
56
56
|
const [sidebarWidth, setSidebarWidth] = useState(256);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
// Detect mobile
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (typeof window === 'undefined') return;
|
|
62
|
-
const checkMobile = () => {
|
|
63
|
-
setIsMobile(window.innerWidth < 768);
|
|
64
|
-
};
|
|
65
|
-
checkMobile();
|
|
66
|
-
window.addEventListener('resize', checkMobile);
|
|
67
|
-
return () => window.removeEventListener('resize', checkMobile);
|
|
68
|
-
}, []);
|
|
57
|
+
const isMobile = useIsMobile();
|
|
69
58
|
|
|
70
59
|
// Persist sidebar state
|
|
71
60
|
useEffect(() => {
|
|
72
61
|
setCookie(SIDEBAR_COOKIE_NAME, sidebarExpanded.toString());
|
|
73
62
|
}, [sidebarExpanded]);
|
|
74
63
|
|
|
75
|
-
// Keyboard shortcuts
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (typeof window === 'undefined') return;
|
|
78
|
-
const handleKeyDown = (event: KeyboardEvent) => {
|
|
79
|
-
if (
|
|
80
|
-
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
|
|
81
|
-
(event.metaKey || event.ctrlKey)
|
|
82
|
-
) {
|
|
83
|
-
event.preventDefault();
|
|
84
|
-
toggleSidebar();
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
89
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
90
|
-
}, [sidebarExpanded, assistenteExpanded]); // Dependencies to ensure toggleSidebar uses latest state
|
|
91
|
-
|
|
92
64
|
// Função para alternar a sidebar - fecha o assistente se estiver aberto
|
|
65
|
+
// Nota: atalhos de teclado (Ctrl+B) são registrados via useLayoutShortcuts()
|
|
66
|
+
// no componente raiz da aplicação — ver components/hooks/use-layout-shortcuts.ts
|
|
93
67
|
const toggleSidebar = useCallback(() => {
|
|
94
68
|
setSidebarExpandedState(prev => {
|
|
95
69
|
const newState = !prev;
|