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
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,52 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [2.1.4] — 2026-05-19
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **`XerticaAssistant` — decomposição em sub-componentes** — o componente monolítico (1 468 linhas) foi dividido em 9 sub-componentes focados em `parts/`: `AssistantHeader`, `AssistantCollapsedView`, `AssistantTabBar`, `AssistantWelcomeScreen`, `AssistantMessageBubble`, `AssistantTypingIndicator`, `AssistantConversationList`, `AssistantFeedbackDialog` e `AssistantDocumentEditor`. A API pública (`XerticaAssistantProps`) permanece 100% compatível.
|
|
15
|
+
- **`useAudioPlayer` — headless hook** — toda a lógica do `AudioPlayer` foi extraída para `components/media/audio-player/use-audio-player.ts`. O componente `AudioPlayer` agora consome o hook internamente; API pública inalterada. O hook é exportado via `components/hooks/index.ts`.
|
|
16
|
+
- **`useLayoutShortcuts` — headless hook** — registro de atalhos de teclado (Ctrl+B, Ctrl+I) extraído do `LayoutContext` para `components/hooks/use-layout-shortcuts.ts`. Exportado via `components/hooks/index.ts`.
|
|
17
|
+
- **`CustomTooltipContent` — componente compartilhado** — implementação duplicada de tooltip customizado (existia em `sidebar.tsx` e `xertica-assistant.tsx`) consolidada em `components/shared/CustomTooltipContent.tsx`.
|
|
18
|
+
- **`useIsMobile` — fonte única de detecção mobile** — `use-sidebar.ts`, `use-assistant.ts`, `LayoutContext.tsx` e `AudioPlayer.tsx` agora importam de `components/shared/use-mobile.ts` em vez de duplicar a lógica de `matchMedia`.
|
|
19
|
+
- **`utils/color-utils.ts` — utilitários de cor** — funções `hexToRgb`, `hexToRgba` e `isLightColor` extraídas do `BrandColorsContext` para `utils/color-utils.ts` como funções puras reutilizáveis.
|
|
20
|
+
- **`ThemeToggle` — usa `useTheme()`** — substituída referência direta ao `localStorage` pelo hook `useTheme()` do `ThemeContext`.
|
|
21
|
+
- **`types.ts` — fonte única de tipos do assistente** — `Message`, `Conversation`, `Suggestion`, `MockResponse`, `SearchResult`, `SearchSource`, `SearchCommand` e enums relacionados movidos para `components/assistant/xertica-assistant/types.ts`. `xertica-assistant.tsx` e `AssistenteContext.tsx` re-exportam os tipos para backward compatibility.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [2.1.3] — 2026-05-16
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **Headless hooks — 4 new logic-only hooks** — all logic extracted from their UI components into standalone, tree-shakeable hooks:
|
|
30
|
+
- **`useFileUpload`** — drag state, file validation (size + count), error messaging, and hidden input ref. Props: `maxFiles`, `maxSize`, `onFilesChange`, `onError`, `disabled`. Returns: `files`, `dragActive`, `errorMessage`, `inputRef`, `handleFiles`, `handleDrag`, `handleDrop`, `handleChange`, `removeFile`, `openFileDialog`.
|
|
31
|
+
- **`usePagination`** — computes the full page item list (page numbers + ellipsis markers) and exposes navigation helpers. Supports controlled (`page` prop) and uncontrolled modes. Props: `totalItems`, `pageSize`, `initialPage`, `page`, `onPageChange`, `siblingCount`. Returns: `currentPage`, `totalPages`, `startIndex`, `endIndex`, `canGoPrev`, `canGoNext`, `isFirstPage`, `isLastPage`, `items: PaginationPageItem[]`, `goTo`, `next`, `prev`, `first`, `last`.
|
|
32
|
+
- **`useStepper`** — step navigation with optional async `onBeforeNext` guard for per-step validation. Supports controlled (`step` prop) and uncontrolled modes. Props: `totalSteps`, `initialStep`, `step`, `onStepChange`, `onBeforeNext`. Returns: `currentStep`, `totalSteps`, `isFirstStep`, `isLastStep`, `canGoPrev`, `canGoNext`, `next` (async), `prev`, `goTo`, `reset`.
|
|
33
|
+
- **`useTreeView`** — expand/collapse state, single-node selection, full WAI-ARIA keyboard navigation (Arrow keys, Home, End, Space), and DOM focus management via `nodeRefs`. Supports controlled `selectedNodeId`. Returns: `expanded`, `effectiveSelectedId`, `nodeRefs`, `getNodeRef`, `toggleExpand`, `handleSelect`, `handleKeyDown`, `getVisibleNodes`.
|
|
34
|
+
- **New chart types — 4 new Recharts wrappers** added to `components/ui/chart/chart.tsx`:
|
|
35
|
+
- **`RadarMetricChart`** — multi-axis radar chart with optional fill, dots, and multi-series overlay.
|
|
36
|
+
- **`PieMetricChart`** — pie chart with optional percentage labels and exploded slice support.
|
|
37
|
+
- **`RadialBarMetricChart`** — radial bar chart with stacked rings and configurable arc angle.
|
|
38
|
+
- **`GaugeChart`** — pure SVG semicircle gauge with needle, threshold color zones, and optional label. Supports `thresholds` array for dynamic color changes at value breakpoints.
|
|
39
|
+
- **Chart color tokens expanded** — added `--chart-6`, `--chart-7`, `--chart-8` tokens to `styles/xertica/tokens.css`, `templates/src/styles/xertica/tokens.css`, and `bin/generate-tokens.ts`. All 8 chart tokens now use a vibrant, accessible palette.
|
|
40
|
+
- **Headless hook stories** — added `HeadlessHook` story variant to `file-upload.stories.tsx`, `pagination.stories.tsx`, `stepper.stories.tsx`, and `tree-view.stories.tsx` demonstrating fully custom UIs built with each hook.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **`GaugeChart` — filled-blob visual bug for values > 50%** — the SVG arc `largeArc` flag was set to `1` when `percent > 0.5`, causing the arc command to draw the reflex arc (> 180°) which rendered as a solid filled blob. Since the gauge is a semicircle (max 180°), `largeArc` is always `0`. Removed the conditional entirely and hardcoded `0` for both arc commands.
|
|
45
|
+
- **`GaugeChart` — needle overlapping value text** — the value text at `y=cy+4` was directly behind the needle pivot circle. Fixed by expanding the SVG `viewBox` from `"0 0 200 110"` to `"0 0 200 130"` and moving the value text to `y=cy+18` (13 px below the needle base circle bottom) and the label text to `y=cy+36`.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- **`FileUpload` component** — refactored to consume `useFileUpload` internally; public API unchanged.
|
|
50
|
+
- **`TreeView` component** — refactored to consume `useTreeView` internally; public API unchanged.
|
|
51
|
+
- **`Stepper` component** — refactored to consume `useStepper` internally; public API unchanged.
|
|
52
|
+
- **Documentation** — updated `docs/components/chart.md`, `docs/components/file-upload.md`, `docs/components/pagination.md`, `docs/components/stepper.md`, and `docs/components/tree-view.md` with full hook API reference, props/return tables, controlled/uncontrolled examples, and AI Rules sections.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
10
56
|
## [2.1.2] — 2026-05-14
|
|
11
57
|
|
|
12
58
|
### Fixed
|
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
|
-
[](https://www.npmjs.com/package/xertica-ui)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
8
|
---
|
package/bin/cli.ts
CHANGED
package/bin/generate-tokens.ts
CHANGED
|
@@ -71,8 +71,8 @@ export const generateTokensCss = (theme: ColorTheme): string => {
|
|
|
71
71
|
--success-foreground: rgba(250, 250, 250, 1);
|
|
72
72
|
--info: rgba(37, 99, 235, 1);
|
|
73
73
|
--info-foreground: rgba(250, 250, 250, 1);
|
|
74
|
-
--warning: rgba(
|
|
75
|
-
--warning-foreground: rgba(
|
|
74
|
+
--warning: rgba(234, 179, 8, 1);
|
|
75
|
+
--warning-foreground: rgba(28, 25, 23, 1);
|
|
76
76
|
|
|
77
77
|
--border: rgba(228, 228, 231, 1);
|
|
78
78
|
--input: rgba(244, 244, 245, 0.5);
|
|
@@ -95,12 +95,15 @@ export const generateTokensCss = (theme: ColorTheme): string => {
|
|
|
95
95
|
--sidebar-border: rgba(255, 255, 255, 0.1);
|
|
96
96
|
--sidebar-ring: ${rgba(colors.primary, 0.5)};
|
|
97
97
|
|
|
98
|
-
/* Charts */
|
|
98
|
+
/* Charts — vibrant, accessible, harmonious palette */
|
|
99
99
|
--chart-1: ${rgba(colors.chart1)};
|
|
100
100
|
--chart-2: ${rgba(colors.chart2)};
|
|
101
101
|
--chart-3: ${rgba(colors.chart3)};
|
|
102
102
|
--chart-4: ${rgba(colors.chart4)};
|
|
103
103
|
--chart-5: ${rgba(colors.chart5)};
|
|
104
|
+
--chart-6: rgba(168, 85, 247, 1); /* purple — extended palette */
|
|
105
|
+
--chart-7: rgba(20, 184, 166, 1); /* teal — extended palette */
|
|
106
|
+
--chart-8: rgba(251, 113, 133, 1); /* rose — extended palette */
|
|
104
107
|
|
|
105
108
|
/* Gradients */
|
|
106
109
|
--gradient-diagonal: linear-gradient(135deg, ${colors.gradientStart} 0%, ${colors.gradientEnd} 100%);
|
|
@@ -153,9 +156,9 @@ export const generateTokensCss = (theme: ColorTheme): string => {
|
|
|
153
156
|
--toast-success-border: rgba(5, 150, 105, 1);
|
|
154
157
|
--toast-success-icon: rgba(5, 150, 105, 1);
|
|
155
158
|
/* Toast - Warning */
|
|
156
|
-
--toast-warning-bg: rgba(254,
|
|
157
|
-
--toast-warning-border: rgba(
|
|
158
|
-
--toast-warning-icon: rgba(
|
|
159
|
+
--toast-warning-bg: rgba(254, 249, 195, 1);
|
|
160
|
+
--toast-warning-border: rgba(161, 98, 7, 1);
|
|
161
|
+
--toast-warning-icon: rgba(161, 98, 7, 1);
|
|
159
162
|
/* Toast - Info */
|
|
160
163
|
--toast-info-bg: rgba(219, 234, 254, 1);
|
|
161
164
|
--toast-info-border: rgba(37, 99, 235, 1);
|
|
@@ -213,12 +216,15 @@ export const generateTokensCss = (theme: ColorTheme): string => {
|
|
|
213
216
|
|
|
214
217
|
--elevation-sm: 0px 0px 48px 0px rgba(0, 0, 0, 0.3);
|
|
215
218
|
|
|
216
|
-
/* Charts */
|
|
219
|
+
/* Charts — dark mode: slightly lighter/more saturated for contrast on dark bg */
|
|
217
220
|
--chart-1: ${rgba(colors.chart1)};
|
|
218
221
|
--chart-2: ${rgba(colors.chart2)};
|
|
219
222
|
--chart-3: ${rgba(colors.chart3)};
|
|
220
223
|
--chart-4: ${rgba(colors.chart4)};
|
|
221
224
|
--chart-5: ${rgba(colors.chart5)};
|
|
225
|
+
--chart-6: rgba(196, 132, 252, 1); /* purple lighter */
|
|
226
|
+
--chart-7: rgba(45, 212, 191, 1); /* teal lighter */
|
|
227
|
+
--chart-8: rgba(253, 164, 175, 1); /* rose lighter */
|
|
222
228
|
|
|
223
229
|
/* Sidebar */
|
|
224
230
|
--sidebar: ${rgba(colors.sidebarDark)};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MessageSquare, Heart, History } from 'lucide-react';
|
|
3
|
+
import { Button } from '../../../ui/button';
|
|
4
|
+
import { Tooltip, TooltipTrigger } from '../../../ui/tooltip';
|
|
5
|
+
import { CustomTooltipContent as AssistantTooltipContent } from '../../../shared/CustomTooltipContent';
|
|
6
|
+
import { XerticaOrbe } from '../../../brand/xertica-orbe';
|
|
7
|
+
import type { AssistantTab } from '../types';
|
|
8
|
+
|
|
9
|
+
interface AssistantCollapsedViewProps {
|
|
10
|
+
showHistory: boolean;
|
|
11
|
+
showFavorites: boolean;
|
|
12
|
+
onToggle: () => void;
|
|
13
|
+
onExpandWithTab: (tab: AssistantTab) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* AssistantCollapsedView — Icon-only strip shown when the assistant panel is collapsed.
|
|
18
|
+
* Renders the Xertica Orbe logo and quick-access icons for Chat, Favorites, and History.
|
|
19
|
+
*/
|
|
20
|
+
export function AssistantCollapsedView({
|
|
21
|
+
showHistory,
|
|
22
|
+
showFavorites,
|
|
23
|
+
onToggle,
|
|
24
|
+
onExpandWithTab,
|
|
25
|
+
}: AssistantCollapsedViewProps) {
|
|
26
|
+
return (
|
|
27
|
+
<div className="flex flex-col items-center p-4 space-y-4">
|
|
28
|
+
{/* Ícone do Assistente - Xertica Orbe */}
|
|
29
|
+
<Tooltip>
|
|
30
|
+
<TooltipTrigger asChild>
|
|
31
|
+
<button
|
|
32
|
+
onClick={onToggle}
|
|
33
|
+
className="w-10 h-10 rounded-full flex items-center justify-center hover:bg-accent/50 transition-colors duration-200 cursor-pointer mx-auto"
|
|
34
|
+
aria-label="Abrir assistente"
|
|
35
|
+
>
|
|
36
|
+
<XerticaOrbe size={32} />
|
|
37
|
+
</button>
|
|
38
|
+
</TooltipTrigger>
|
|
39
|
+
<AssistantTooltipContent side="left" sideOffset={8}>
|
|
40
|
+
<p>Assistente Xertica</p>
|
|
41
|
+
</AssistantTooltipContent>
|
|
42
|
+
</Tooltip>
|
|
43
|
+
|
|
44
|
+
<Tooltip>
|
|
45
|
+
<TooltipTrigger asChild>
|
|
46
|
+
<Button
|
|
47
|
+
variant="ghost"
|
|
48
|
+
size="sm"
|
|
49
|
+
onClick={() => onExpandWithTab('chat')}
|
|
50
|
+
className="w-8 h-8 p-0 text-muted-foreground"
|
|
51
|
+
>
|
|
52
|
+
<MessageSquare className="w-4 h-4" />
|
|
53
|
+
</Button>
|
|
54
|
+
</TooltipTrigger>
|
|
55
|
+
<AssistantTooltipContent side="left" sideOffset={8}>
|
|
56
|
+
<p>Chat</p>
|
|
57
|
+
</AssistantTooltipContent>
|
|
58
|
+
</Tooltip>
|
|
59
|
+
|
|
60
|
+
{showFavorites && (
|
|
61
|
+
<Tooltip>
|
|
62
|
+
<TooltipTrigger asChild>
|
|
63
|
+
<Button
|
|
64
|
+
variant="ghost"
|
|
65
|
+
size="sm"
|
|
66
|
+
onClick={() => onExpandWithTab('favoritos')}
|
|
67
|
+
className="w-8 h-8 p-0 text-muted-foreground"
|
|
68
|
+
>
|
|
69
|
+
<Heart className="w-4 h-4" />
|
|
70
|
+
</Button>
|
|
71
|
+
</TooltipTrigger>
|
|
72
|
+
<AssistantTooltipContent side="left" sideOffset={8}>
|
|
73
|
+
<p>Favoritos</p>
|
|
74
|
+
</AssistantTooltipContent>
|
|
75
|
+
</Tooltip>
|
|
76
|
+
)}
|
|
77
|
+
|
|
78
|
+
{showHistory && (
|
|
79
|
+
<Tooltip>
|
|
80
|
+
<TooltipTrigger asChild>
|
|
81
|
+
<Button
|
|
82
|
+
variant="ghost"
|
|
83
|
+
size="sm"
|
|
84
|
+
onClick={() => onExpandWithTab('historico')}
|
|
85
|
+
className="w-8 h-8 p-0 text-muted-foreground"
|
|
86
|
+
>
|
|
87
|
+
<History className="w-4 h-4" />
|
|
88
|
+
</Button>
|
|
89
|
+
</TooltipTrigger>
|
|
90
|
+
<AssistantTooltipContent side="left" sideOffset={8}>
|
|
91
|
+
<p>Histórico</p>
|
|
92
|
+
</AssistantTooltipContent>
|
|
93
|
+
</Tooltip>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Plus, Heart } from 'lucide-react';
|
|
3
|
+
import { Button } from '../../../ui/button';
|
|
4
|
+
import { ScrollArea } from '../../../ui/scroll-area';
|
|
5
|
+
import { cn } from '../../../shared/utils';
|
|
6
|
+
import type { Conversation, AssistantTab } from '../types';
|
|
7
|
+
|
|
8
|
+
interface AssistantConversationListProps {
|
|
9
|
+
conversations: Conversation[];
|
|
10
|
+
currentConversationId: string | null;
|
|
11
|
+
activeTab: AssistantTab;
|
|
12
|
+
isFullPage: boolean;
|
|
13
|
+
onNewConversation: () => void;
|
|
14
|
+
onSelectConversation: (id: string) => void;
|
|
15
|
+
onToggleFavorite: (id: string) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* AssistantConversationList — Scrollable list of saved conversations shown in
|
|
20
|
+
* the History and Favorites tabs.
|
|
21
|
+
*/
|
|
22
|
+
export function AssistantConversationList({
|
|
23
|
+
conversations,
|
|
24
|
+
currentConversationId,
|
|
25
|
+
activeTab,
|
|
26
|
+
isFullPage,
|
|
27
|
+
onNewConversation,
|
|
28
|
+
onSelectConversation,
|
|
29
|
+
onToggleFavorite,
|
|
30
|
+
}: AssistantConversationListProps) {
|
|
31
|
+
return (
|
|
32
|
+
<ScrollArea className="flex-1 min-h-0">
|
|
33
|
+
<div className={`p-4 ${isFullPage ? 'mx-auto w-full max-w-6xl' : ''}`}>
|
|
34
|
+
{/* New Conversation Button */}
|
|
35
|
+
<Button
|
|
36
|
+
variant="outline"
|
|
37
|
+
size="sm"
|
|
38
|
+
onClick={onNewConversation}
|
|
39
|
+
className="w-full mb-4 justify-start"
|
|
40
|
+
>
|
|
41
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
42
|
+
Nova Conversa
|
|
43
|
+
</Button>
|
|
44
|
+
|
|
45
|
+
{/* Conversations List */}
|
|
46
|
+
<div className="space-y-2">
|
|
47
|
+
{conversations.length === 0 ? (
|
|
48
|
+
<div className="text-center py-8">
|
|
49
|
+
<Heart className="w-12 h-12 mx-auto text-muted-foreground/50 mb-2" />
|
|
50
|
+
<p className="text-muted-foreground">
|
|
51
|
+
{activeTab === 'favoritos'
|
|
52
|
+
? 'Nenhuma conversa favorita ainda'
|
|
53
|
+
: 'Nenhuma conversa no histórico'}
|
|
54
|
+
</p>
|
|
55
|
+
</div>
|
|
56
|
+
) : (
|
|
57
|
+
conversations.map((conversa) => (
|
|
58
|
+
<div
|
|
59
|
+
key={conversa.id}
|
|
60
|
+
onClick={() => onSelectConversation(conversa.id)}
|
|
61
|
+
className={cn(
|
|
62
|
+
'p-3 rounded-[var(--radius)] cursor-pointer transition-colors duration-200 border',
|
|
63
|
+
conversa.id === currentConversationId
|
|
64
|
+
? 'border-primary bg-primary/10'
|
|
65
|
+
: 'border-border hover:bg-muted',
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
<div className="flex items-start justify-between mb-1">
|
|
69
|
+
<h4 className="text-sm font-medium text-foreground truncate flex-1">
|
|
70
|
+
{conversa.title}
|
|
71
|
+
</h4>
|
|
72
|
+
<Button
|
|
73
|
+
variant="ghost"
|
|
74
|
+
size="sm"
|
|
75
|
+
onClick={(e) => {
|
|
76
|
+
e.stopPropagation();
|
|
77
|
+
onToggleFavorite(conversa.id);
|
|
78
|
+
}}
|
|
79
|
+
className="h-6 w-6 p-0 flex-shrink-0 ml-1"
|
|
80
|
+
>
|
|
81
|
+
<Heart
|
|
82
|
+
className={cn(
|
|
83
|
+
'w-3 h-3',
|
|
84
|
+
conversa.isFavorite
|
|
85
|
+
? 'text-destructive fill-current'
|
|
86
|
+
: 'text-muted-foreground',
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
</Button>
|
|
90
|
+
</div>
|
|
91
|
+
{conversa.lastMessage && (
|
|
92
|
+
<p className="text-sm text-muted-foreground truncate mb-1">
|
|
93
|
+
{conversa.lastMessage}
|
|
94
|
+
</p>
|
|
95
|
+
)}
|
|
96
|
+
<p className="text-sm text-muted-foreground">{conversa.timestamp}</p>
|
|
97
|
+
</div>
|
|
98
|
+
))
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</ScrollArea>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { X, FileText, Check } from 'lucide-react';
|
|
3
|
+
import { Button } from '../../../ui/button';
|
|
4
|
+
import { RichTextEditor } from '../../../ui/rich-text-editor';
|
|
5
|
+
import { cn } from '../../../shared/utils';
|
|
6
|
+
|
|
7
|
+
interface EditingDocument {
|
|
8
|
+
content: string;
|
|
9
|
+
title: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface AssistantDocumentEditorProps {
|
|
13
|
+
document: EditingDocument;
|
|
14
|
+
isMobile: boolean;
|
|
15
|
+
containerWidth: string;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
onChange: (doc: EditingDocument) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* AssistantDocumentEditor — Overlay panel with a rich text editor for editing documents
|
|
22
|
+
* generated by the assistant. Slides in from the left of the assistant panel.
|
|
23
|
+
*/
|
|
24
|
+
export function AssistantDocumentEditor({
|
|
25
|
+
document,
|
|
26
|
+
isMobile,
|
|
27
|
+
containerWidth,
|
|
28
|
+
onClose,
|
|
29
|
+
onChange,
|
|
30
|
+
}: AssistantDocumentEditorProps) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={cn(
|
|
34
|
+
'flex flex-col border-border bg-background overflow-hidden transition-all duration-300',
|
|
35
|
+
isMobile
|
|
36
|
+
? 'fixed inset-0 z-[110] w-full h-[100dvh]'
|
|
37
|
+
: 'absolute top-0 bottom-0 right-full w-[800px] border-l border-r border-border shadow-[-25px_0_50px_-15px_rgba(0,0,0,0.15)] z-[90]',
|
|
38
|
+
)}
|
|
39
|
+
style={{ maxWidth: isMobile ? 'none' : `calc(100vw - ${containerWidth})` }}
|
|
40
|
+
>
|
|
41
|
+
<div className="h-full flex flex-col">
|
|
42
|
+
{/* Header Toolbar */}
|
|
43
|
+
<div className="px-4 h-[64px] border-b border-border bg-card flex items-center justify-between">
|
|
44
|
+
<div className="flex items-center gap-3">
|
|
45
|
+
<div className="p-2 bg-primary/10 rounded-md">
|
|
46
|
+
<FileText className="w-4 h-4 text-primary" />
|
|
47
|
+
</div>
|
|
48
|
+
<h3 className="font-semibold text-card-foreground text-sm">{document.title}</h3>
|
|
49
|
+
</div>
|
|
50
|
+
<Button
|
|
51
|
+
variant="ghost"
|
|
52
|
+
size="icon"
|
|
53
|
+
className="h-8 w-8 rounded-full"
|
|
54
|
+
onClick={onClose}
|
|
55
|
+
aria-label="Fechar editor de documento"
|
|
56
|
+
>
|
|
57
|
+
<X className="w-4 h-4" />
|
|
58
|
+
</Button>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
{/* Rich Text Editor */}
|
|
62
|
+
<div className="flex-1 bg-muted/20 p-0 sm:p-6 overflow-hidden">
|
|
63
|
+
<RichTextEditor
|
|
64
|
+
value={document.content || ''}
|
|
65
|
+
onChange={(newVal) =>
|
|
66
|
+
onChange({ ...document, content: newVal })
|
|
67
|
+
}
|
|
68
|
+
placeholder="Comece a digitar o conteúdo do seu documento aqui..."
|
|
69
|
+
className="max-w-4xl mx-auto h-full"
|
|
70
|
+
actionButton={
|
|
71
|
+
<Button size="sm" className="gap-2 h-8">
|
|
72
|
+
<Check className="w-3.5 h-3.5" />
|
|
73
|
+
Salvar
|
|
74
|
+
</Button>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from '../../../ui/button';
|
|
3
|
+
import { Textarea } from '../../../ui/textarea';
|
|
4
|
+
import {
|
|
5
|
+
Dialog,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogDescription,
|
|
8
|
+
DialogFooter,
|
|
9
|
+
DialogHeader,
|
|
10
|
+
DialogTitle,
|
|
11
|
+
} from '../../../ui/dialog';
|
|
12
|
+
|
|
13
|
+
export interface EvaluationState {
|
|
14
|
+
isOpen: boolean;
|
|
15
|
+
messageId: string | null;
|
|
16
|
+
type?: 'dislike' | null;
|
|
17
|
+
category?: string | null;
|
|
18
|
+
reason: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface AssistantFeedbackDialogProps {
|
|
22
|
+
state: EvaluationState;
|
|
23
|
+
onReasonChange: (reason: string) => void;
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
onSubmit: () => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* AssistantFeedbackDialog — Modal dialog for collecting negative feedback (dislike) on messages.
|
|
30
|
+
* Supports both categorized feedback (from feedbackOptions) and free-text input.
|
|
31
|
+
*/
|
|
32
|
+
export function AssistantFeedbackDialog({
|
|
33
|
+
state,
|
|
34
|
+
onReasonChange,
|
|
35
|
+
onClose,
|
|
36
|
+
onSubmit,
|
|
37
|
+
}: AssistantFeedbackDialogProps) {
|
|
38
|
+
return (
|
|
39
|
+
<Dialog
|
|
40
|
+
open={state.isOpen}
|
|
41
|
+
onOpenChange={(open) => !open && onClose()}
|
|
42
|
+
>
|
|
43
|
+
<DialogContent className="sm:max-w-[600px]">
|
|
44
|
+
<DialogHeader>
|
|
45
|
+
<DialogTitle className="pr-8">
|
|
46
|
+
{state.category
|
|
47
|
+
? `Enviar feedback: ${state.category}`
|
|
48
|
+
: 'Enviar feedback'}
|
|
49
|
+
</DialogTitle>
|
|
50
|
+
<DialogDescription>
|
|
51
|
+
{state.category
|
|
52
|
+
? 'Gostaria de adicionar algum comentário? (Opcional)'
|
|
53
|
+
: 'Conte-nos por que essa resposta não foi útil para que possamos melhorar.'}
|
|
54
|
+
</DialogDescription>
|
|
55
|
+
</DialogHeader>
|
|
56
|
+
|
|
57
|
+
<div className="grid gap-4 py-4 px-6">
|
|
58
|
+
<Textarea
|
|
59
|
+
className="min-h-[100px]"
|
|
60
|
+
placeholder={
|
|
61
|
+
state.category ? 'Comentário adicional...' : 'Descreva o motivo...'
|
|
62
|
+
}
|
|
63
|
+
aria-label={
|
|
64
|
+
state.category ? 'Comentário adicional' : 'Descreva o motivo'
|
|
65
|
+
}
|
|
66
|
+
value={state.reason}
|
|
67
|
+
onChange={(e) => onReasonChange(e.target.value)}
|
|
68
|
+
rows={4}
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<DialogFooter>
|
|
73
|
+
<Button variant="outline" onClick={onClose}>
|
|
74
|
+
Cancelar
|
|
75
|
+
</Button>
|
|
76
|
+
<Button
|
|
77
|
+
onClick={onSubmit}
|
|
78
|
+
disabled={!state.category && !state.reason.trim()}
|
|
79
|
+
>
|
|
80
|
+
{state.category ? 'Confirmar e Enviar' : 'Enviar Feedback'}
|
|
81
|
+
</Button>
|
|
82
|
+
</DialogFooter>
|
|
83
|
+
</DialogContent>
|
|
84
|
+
</Dialog>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChevronRight, PanelRight, Maximize2 } from 'lucide-react';
|
|
3
|
+
import { motion } from 'framer-motion';
|
|
4
|
+
import { Button } from '../../../ui/button';
|
|
5
|
+
import { XerticaOrbe } from '../../../brand/xertica-orbe';
|
|
6
|
+
import { cn } from '../../../shared/utils';
|
|
7
|
+
|
|
8
|
+
interface AssistantHeaderProps {
|
|
9
|
+
isExpanded: boolean;
|
|
10
|
+
onToggle: () => void;
|
|
11
|
+
onNavigateFullPage?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* AssistantHeader — Top bar shown in expanded/collapsed (non-fullPage) mode.
|
|
16
|
+
* Contains the Xertica Orbe logo, title, expand-to-full-page button, and toggle button.
|
|
17
|
+
*/
|
|
18
|
+
export function AssistantHeader({
|
|
19
|
+
isExpanded,
|
|
20
|
+
onToggle,
|
|
21
|
+
onNavigateFullPage,
|
|
22
|
+
}: AssistantHeaderProps) {
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className={cn(
|
|
26
|
+
'border-b border-border flex items-center h-[64px]',
|
|
27
|
+
isExpanded ? 'justify-between px-4' : 'justify-center px-0',
|
|
28
|
+
)}
|
|
29
|
+
>
|
|
30
|
+
{isExpanded && (
|
|
31
|
+
<motion.div
|
|
32
|
+
initial={{ opacity: 0, x: -10 }}
|
|
33
|
+
animate={{ opacity: 1, x: 0 }}
|
|
34
|
+
exit={{ opacity: 0, x: -10 }}
|
|
35
|
+
className="flex items-center gap-2 overflow-hidden"
|
|
36
|
+
>
|
|
37
|
+
<div className="flex-shrink-0">
|
|
38
|
+
<XerticaOrbe size={32} />
|
|
39
|
+
</div>
|
|
40
|
+
<span className="text-foreground font-medium truncate">Assistente Xertica</span>
|
|
41
|
+
</motion.div>
|
|
42
|
+
)}
|
|
43
|
+
|
|
44
|
+
<div className="flex items-center gap-1">
|
|
45
|
+
{isExpanded && onNavigateFullPage && (
|
|
46
|
+
<Button
|
|
47
|
+
variant="ghost"
|
|
48
|
+
size="sm"
|
|
49
|
+
onClick={onNavigateFullPage}
|
|
50
|
+
className="h-8 w-8 p-0 text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-full"
|
|
51
|
+
title="Expandir assistente"
|
|
52
|
+
aria-label="Expandir assistente"
|
|
53
|
+
>
|
|
54
|
+
<Maximize2 className="w-4 h-4" />
|
|
55
|
+
</Button>
|
|
56
|
+
)}
|
|
57
|
+
|
|
58
|
+
<Button
|
|
59
|
+
variant="ghost"
|
|
60
|
+
size="sm"
|
|
61
|
+
onClick={onToggle}
|
|
62
|
+
className={cn(
|
|
63
|
+
'h-8 w-8 p-0 text-muted-foreground hover:bg-accent hover:text-accent-foreground rounded-full',
|
|
64
|
+
!isExpanded && 'w-10 h-10',
|
|
65
|
+
)}
|
|
66
|
+
aria-label={isExpanded ? 'Recolher assistente' : 'Expandir assistente'}
|
|
67
|
+
>
|
|
68
|
+
{isExpanded ? (
|
|
69
|
+
<ChevronRight className="w-4 h-4" />
|
|
70
|
+
) : (
|
|
71
|
+
<PanelRight className="w-4 h-4" />
|
|
72
|
+
)}
|
|
73
|
+
</Button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|