@moontra/moonui-pro 2.20.0 → 2.20.2
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/dist/index.d.ts +691 -261
- package/dist/index.mjs +7419 -4935
- package/package.json +4 -3
- package/scripts/postbuild.js +27 -0
- package/src/components/advanced-chart/index.tsx +5 -1
- package/src/components/advanced-forms/index.tsx +175 -16
- package/src/components/calendar/event-dialog.tsx +18 -13
- package/src/components/calendar/index.tsx +197 -50
- package/src/components/dashboard/dashboard-grid.tsx +21 -3
- package/src/components/dashboard/types.ts +3 -0
- package/src/components/dashboard/widgets/activity-feed.tsx +6 -1
- package/src/components/dashboard/widgets/comparison-widget.tsx +177 -0
- package/src/components/dashboard/widgets/index.ts +5 -0
- package/src/components/dashboard/widgets/metric-card.tsx +21 -1
- package/src/components/dashboard/widgets/progress-widget.tsx +113 -0
- package/src/components/error-boundary/index.tsx +160 -37
- package/src/components/form-wizard/form-wizard-context.tsx +54 -26
- package/src/components/form-wizard/form-wizard-progress.tsx +33 -2
- package/src/components/form-wizard/types.ts +2 -1
- package/src/components/github-stars/hooks.ts +1 -0
- package/src/components/github-stars/variants.tsx +3 -1
- package/src/components/health-check/index.tsx +14 -14
- package/src/components/hover-card-3d/index.tsx +2 -3
- package/src/components/index.ts +5 -3
- package/src/components/kanban/kanban.tsx +23 -18
- package/src/components/license-error/index.tsx +2 -0
- package/src/components/magnetic-button/index.tsx +56 -7
- package/src/components/memory-efficient-data/index.tsx +117 -115
- package/src/components/navbar/index.tsx +781 -0
- package/src/components/performance-debugger/index.tsx +62 -38
- package/src/components/performance-monitor/index.tsx +47 -33
- package/src/components/phone-number-input/index.tsx +32 -27
- package/src/components/phone-number-input/phone-number-input-simple.tsx +167 -0
- package/src/components/rich-text-editor/index.tsx +26 -28
- package/src/components/rich-text-editor/slash-commands-extension.ts +15 -5
- package/src/components/sidebar/index.tsx +32 -13
- package/src/components/timeline/index.tsx +84 -49
- package/src/components/ui/accordion.tsx +550 -42
- package/src/components/ui/avatar.tsx +2 -0
- package/src/components/ui/badge.tsx +2 -0
- package/src/components/ui/breadcrumb.tsx +2 -0
- package/src/components/ui/button.tsx +39 -33
- package/src/components/ui/card.tsx +2 -0
- package/src/components/ui/collapsible.tsx +546 -50
- package/src/components/ui/command.tsx +790 -67
- package/src/components/ui/dialog.tsx +510 -92
- package/src/components/ui/dropdown-menu.tsx +540 -52
- package/src/components/ui/index.ts +37 -5
- package/src/components/ui/input.tsx +2 -0
- package/src/components/ui/magnetic-button.tsx +1 -1
- package/src/components/ui/media-gallery.tsx +1 -2
- package/src/components/ui/navigation-menu.tsx +130 -0
- package/src/components/ui/pagination.tsx +2 -0
- package/src/components/ui/select.tsx +6 -2
- package/src/components/ui/spotlight-card.tsx +1 -1
- package/src/components/ui/table.tsx +2 -0
- package/src/components/ui/tabs-pro.tsx +542 -0
- package/src/components/ui/tabs.tsx +23 -167
- package/src/components/ui/toggle.tsx +13 -13
- package/src/index.ts +11 -3
- package/src/styles/index.css +596 -0
- package/src/use-performance-optimizer.ts +1 -1
- package/src/utils/chart-helpers.ts +1 -1
- package/src/__tests__/use-intersection-observer.test.tsx +0 -216
- package/src/__tests__/use-local-storage.test.tsx +0 -174
- package/src/__tests__/use-pro-access.test.tsx +0 -183
- package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
- package/src/components/data-table/data-table.test.tsx +0 -187
- package/src/components/enhanced/badge.tsx +0 -191
- package/src/components/enhanced/button.tsx +0 -362
- package/src/components/enhanced/card.tsx +0 -266
- package/src/components/enhanced/dialog.tsx +0 -246
- package/src/components/enhanced/index.ts +0 -4
- package/src/components/file-upload/file-upload.test.tsx +0 -243
- package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
- package/src/types/moonui.d.ts +0 -22
|
@@ -21,7 +21,7 @@ import TaskItem from '@tiptap/extension-task-item';
|
|
|
21
21
|
import Typography from '@tiptap/extension-typography';
|
|
22
22
|
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
|
|
23
23
|
import { common, createLowlight } from 'lowlight';
|
|
24
|
-
import { SlashCommandsExtension } from './slash-commands-extension';
|
|
24
|
+
import { SlashCommandsExtension, type SlashCommand } from './slash-commands-extension';
|
|
25
25
|
import { motion } from 'framer-motion';
|
|
26
26
|
|
|
27
27
|
// Import pro access hooks
|
|
@@ -138,14 +138,7 @@ const SUPPORTED_LANGUAGES = [
|
|
|
138
138
|
{ code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
|
|
139
139
|
];
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
id?: string
|
|
143
|
-
title?: string
|
|
144
|
-
description: string
|
|
145
|
-
command: string
|
|
146
|
-
icon?: string
|
|
147
|
-
action: (text: string) => Promise<{ text: string; error?: string }> | void
|
|
148
|
-
}
|
|
141
|
+
// Use SlashCommand from slash-commands-extension.ts
|
|
149
142
|
|
|
150
143
|
// Get AI provider instance
|
|
151
144
|
const getAIProvider = (settings: AISettingsType): AIProviderInterface | null => {
|
|
@@ -177,7 +170,7 @@ const getAIProvider = (settings: AISettingsType): AIProviderInterface | null =>
|
|
|
177
170
|
import './slash-commands.css';
|
|
178
171
|
import './table-styles.css';
|
|
179
172
|
|
|
180
|
-
export interface
|
|
173
|
+
export interface EditorAIConfig {
|
|
181
174
|
provider?: 'openai' | 'claude' | 'gemini' | 'cohere';
|
|
182
175
|
apiKey?: string;
|
|
183
176
|
model?: string;
|
|
@@ -208,7 +201,7 @@ interface RichTextEditorProps {
|
|
|
208
201
|
color?: boolean;
|
|
209
202
|
ai?: boolean;
|
|
210
203
|
};
|
|
211
|
-
aiConfig?:
|
|
204
|
+
aiConfig?: EditorAIConfig;
|
|
212
205
|
persistAISettings?: boolean;
|
|
213
206
|
}
|
|
214
207
|
|
|
@@ -392,10 +385,8 @@ export function RichTextEditor({
|
|
|
392
385
|
if (persistAISettings && typeof window !== 'undefined') {
|
|
393
386
|
try {
|
|
394
387
|
const stored = localStorage.getItem('moonui-ai-settings');
|
|
395
|
-
console.log('[RichTextEditor] Loading AI settings from localStorage:', stored);
|
|
396
388
|
if (stored) {
|
|
397
389
|
const parsed = JSON.parse(stored);
|
|
398
|
-
console.log('[RichTextEditor] Parsed AI settings:', parsed);
|
|
399
390
|
// Props'tan gelen değerler her zaman öncelikli
|
|
400
391
|
const settings = {
|
|
401
392
|
provider: (aiConfig.provider !== undefined ? aiConfig.provider : parsed.provider || 'openai') as 'openai' | 'claude' | 'gemini' | 'cohere',
|
|
@@ -404,7 +395,6 @@ export function RichTextEditor({
|
|
|
404
395
|
temperature: aiConfig.temperature !== undefined ? aiConfig.temperature : parsed.temperature ?? 0.7,
|
|
405
396
|
maxTokens: aiConfig.maxTokens !== undefined ? aiConfig.maxTokens : parsed.maxTokens ?? 1000,
|
|
406
397
|
};
|
|
407
|
-
console.log('[RichTextEditor] Final settings with props override:', settings);
|
|
408
398
|
return settings;
|
|
409
399
|
}
|
|
410
400
|
} catch (e) {
|
|
@@ -420,7 +410,6 @@ export function RichTextEditor({
|
|
|
420
410
|
temperature: aiConfig.temperature ?? 0.7,
|
|
421
411
|
maxTokens: aiConfig.maxTokens ?? 1000,
|
|
422
412
|
};
|
|
423
|
-
console.log('[RichTextEditor] Using default settings:', defaultSettings);
|
|
424
413
|
return defaultSettings;
|
|
425
414
|
});
|
|
426
415
|
const [isAiSettingsOpen, setIsAiSettingsOpen] = useState(false);
|
|
@@ -714,16 +703,16 @@ export function RichTextEditor({
|
|
|
714
703
|
const selectedText = editor.state.doc.textBetween(from, to, ' ');
|
|
715
704
|
|
|
716
705
|
setIsProcessing(true);
|
|
717
|
-
setCurrentAction(command.id);
|
|
706
|
+
setCurrentAction(command.id || '');
|
|
718
707
|
|
|
719
708
|
try {
|
|
720
|
-
const response = await command.action(selectedText || editor.getText());
|
|
709
|
+
const response = command.action ? await command.action(selectedText || editor.getText()) : { text: '', error: 'No action defined' };
|
|
721
710
|
if (response.text) {
|
|
722
711
|
// Check if this command should use modal preview
|
|
723
|
-
if (shouldUseModal(command.id)) {
|
|
712
|
+
if (shouldUseModal(command.id || '')) {
|
|
724
713
|
// Open preview modal
|
|
725
714
|
setPreviewContent(response.text);
|
|
726
|
-
setPreviewAction(command.id);
|
|
715
|
+
setPreviewAction(command.id || '');
|
|
727
716
|
setPreviewOriginalText(selectedText || editor.getText());
|
|
728
717
|
setIsAiPreviewOpen(true);
|
|
729
718
|
} else {
|
|
@@ -1762,7 +1751,7 @@ export function RichTextEditor({
|
|
|
1762
1751
|
<Settings className="w-4 h-4" />
|
|
1763
1752
|
</ToolbarButton>
|
|
1764
1753
|
</DialogTrigger>
|
|
1765
|
-
<DialogContent className="sm:max-w-[425px]">
|
|
1754
|
+
<DialogContent className="sm:max-w-[425px] overflow-visible" style={{ zIndex: 9998 }}>
|
|
1766
1755
|
<DialogHeader>
|
|
1767
1756
|
<DialogTitle>AI Settings</DialogTitle>
|
|
1768
1757
|
<DialogDescription>
|
|
@@ -1775,11 +1764,12 @@ export function RichTextEditor({
|
|
|
1775
1764
|
<Select
|
|
1776
1765
|
value={aiSettings.provider}
|
|
1777
1766
|
onValueChange={(value: 'openai' | 'claude' | 'gemini' | 'cohere') => {
|
|
1767
|
+
console.log('Provider changed to:', value);
|
|
1778
1768
|
// Update model when provider changes
|
|
1779
1769
|
const defaultModels = {
|
|
1780
1770
|
openai: 'gpt-3.5-turbo',
|
|
1781
1771
|
claude: 'claude-3-sonnet-20240229',
|
|
1782
|
-
gemini: 'gemini-2.0-flash',
|
|
1772
|
+
gemini: 'gemini-2.0-flash-exp',
|
|
1783
1773
|
cohere: 'command'
|
|
1784
1774
|
};
|
|
1785
1775
|
const newSettings = {
|
|
@@ -1797,7 +1787,7 @@ export function RichTextEditor({
|
|
|
1797
1787
|
<SelectTrigger>
|
|
1798
1788
|
<SelectValue />
|
|
1799
1789
|
</SelectTrigger>
|
|
1800
|
-
<SelectContent>
|
|
1790
|
+
<SelectContent className="z-[9999]" sideOffset={5}>
|
|
1801
1791
|
<SelectItem value="openai">OpenAI</SelectItem>
|
|
1802
1792
|
<SelectItem value="claude">Claude (Anthropic)</SelectItem>
|
|
1803
1793
|
<SelectItem value="gemini">Gemini (Google)</SelectItem>
|
|
@@ -1838,25 +1828,33 @@ export function RichTextEditor({
|
|
|
1838
1828
|
<SelectTrigger>
|
|
1839
1829
|
<SelectValue />
|
|
1840
1830
|
</SelectTrigger>
|
|
1841
|
-
<SelectContent>
|
|
1831
|
+
<SelectContent className="z-[9999]" sideOffset={5}>
|
|
1842
1832
|
{aiSettings.provider === 'openai' && (
|
|
1843
1833
|
<>
|
|
1834
|
+
<SelectItem value="gpt-4-turbo-preview">GPT-4 Turbo</SelectItem>
|
|
1844
1835
|
<SelectItem value="gpt-4">GPT-4</SelectItem>
|
|
1845
1836
|
<SelectItem value="gpt-3.5-turbo">GPT-3.5 Turbo</SelectItem>
|
|
1837
|
+
<SelectItem value="gpt-3.5-turbo-16k">GPT-3.5 Turbo 16K</SelectItem>
|
|
1846
1838
|
</>
|
|
1847
1839
|
)}
|
|
1848
1840
|
{aiSettings.provider === 'claude' && (
|
|
1849
1841
|
<>
|
|
1850
|
-
<SelectItem value="claude-3-opus">Claude 3 Opus</SelectItem>
|
|
1851
|
-
<SelectItem value="claude-3-sonnet">Claude 3 Sonnet</SelectItem>
|
|
1852
|
-
<SelectItem value="claude-3-haiku">Claude 3 Haiku</SelectItem>
|
|
1842
|
+
<SelectItem value="claude-3-opus-20240229">Claude 3 Opus</SelectItem>
|
|
1843
|
+
<SelectItem value="claude-3-sonnet-20240229">Claude 3 Sonnet</SelectItem>
|
|
1844
|
+
<SelectItem value="claude-3-haiku-20240307">Claude 3 Haiku</SelectItem>
|
|
1845
|
+
<SelectItem value="claude-2.1">Claude 2.1</SelectItem>
|
|
1846
|
+
<SelectItem value="claude-2.0">Claude 2.0</SelectItem>
|
|
1853
1847
|
</>
|
|
1854
1848
|
)}
|
|
1855
1849
|
{aiSettings.provider === 'gemini' && (
|
|
1856
1850
|
<>
|
|
1857
|
-
<SelectItem value="gemini-2.0-flash">Gemini 2.0 Flash</SelectItem>
|
|
1858
|
-
<SelectItem value="gemini-
|
|
1851
|
+
<SelectItem value="gemini-2.0-flash-exp">Gemini 2.0 Flash (Experimental)</SelectItem>
|
|
1852
|
+
<SelectItem value="gemini-2.0-flash-thinking-exp">Gemini 2.0 Flash Thinking (Experimental)</SelectItem>
|
|
1859
1853
|
<SelectItem value="gemini-1.5-pro">Gemini 1.5 Pro</SelectItem>
|
|
1854
|
+
<SelectItem value="gemini-1.5-flash">Gemini 1.5 Flash</SelectItem>
|
|
1855
|
+
<SelectItem value="gemini-1.5-flash-8b">Gemini 1.5 Flash 8B</SelectItem>
|
|
1856
|
+
<SelectItem value="gemini-pro">Gemini Pro</SelectItem>
|
|
1857
|
+
<SelectItem value="gemini-pro-vision">Gemini Pro Vision</SelectItem>
|
|
1860
1858
|
</>
|
|
1861
1859
|
)}
|
|
1862
1860
|
{aiSettings.provider === 'cohere' && (
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { Extension } from '@tiptap/core';
|
|
2
2
|
import { Plugin, PluginKey } from '@tiptap/pm/state';
|
|
3
3
|
import { Decoration, DecorationSet } from '@tiptap/pm/view';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
// SlashCommand type definition
|
|
6
|
+
export interface SlashCommand {
|
|
7
|
+
id?: string;
|
|
8
|
+
command: string;
|
|
9
|
+
description: string;
|
|
10
|
+
icon?: string;
|
|
11
|
+
action?: (text: string) => Promise<{ text?: string; error?: string }>;
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
declare module '@tiptap/core' {
|
|
7
15
|
interface Commands<ReturnType> {
|
|
@@ -29,6 +37,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
29
37
|
},
|
|
30
38
|
|
|
31
39
|
addCommands() {
|
|
40
|
+
const extension = this;
|
|
32
41
|
return {
|
|
33
42
|
selectSlashCommand: (index: number) => ({ editor }) => {
|
|
34
43
|
const state = slashCommandsPluginKey.getState(editor.state);
|
|
@@ -43,7 +52,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
43
52
|
.run();
|
|
44
53
|
|
|
45
54
|
// Execute the command
|
|
46
|
-
|
|
55
|
+
extension.options.onSelectCommand(command);
|
|
47
56
|
|
|
48
57
|
return true;
|
|
49
58
|
}
|
|
@@ -98,6 +107,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
98
107
|
},
|
|
99
108
|
|
|
100
109
|
addProseMirrorPlugins() {
|
|
110
|
+
const extension = this;
|
|
101
111
|
return [
|
|
102
112
|
new Plugin({
|
|
103
113
|
key: slashCommandsPluginKey,
|
|
@@ -136,7 +146,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
136
146
|
|
|
137
147
|
if (match) {
|
|
138
148
|
const query = match[1].toLowerCase();
|
|
139
|
-
const filteredCommands =
|
|
149
|
+
const filteredCommands = extension.options.commands.filter((cmd: SlashCommand) =>
|
|
140
150
|
cmd.command.toLowerCase().includes(query) ||
|
|
141
151
|
cmd.description.toLowerCase().includes(query)
|
|
142
152
|
);
|
|
@@ -159,7 +169,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
159
169
|
props: {
|
|
160
170
|
decorations(state) {
|
|
161
171
|
const pluginState = this.getState(state);
|
|
162
|
-
if (!pluginState.active) {
|
|
172
|
+
if (!pluginState || !pluginState.active) {
|
|
163
173
|
return DecorationSet.empty;
|
|
164
174
|
}
|
|
165
175
|
|
|
@@ -169,7 +179,7 @@ export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
|
|
|
169
179
|
const container = document.createElement('div');
|
|
170
180
|
container.className = 'slash-commands-menu';
|
|
171
181
|
|
|
172
|
-
pluginState.filteredCommands.forEach((cmd, index) => {
|
|
182
|
+
pluginState.filteredCommands.forEach((cmd: SlashCommand, index: number) => {
|
|
173
183
|
const item = document.createElement('div');
|
|
174
184
|
item.className = `slash-command-item ${index === pluginState.selectedIndex ? 'selected' : ''}`;
|
|
175
185
|
|
|
@@ -71,11 +71,15 @@ const SearchInput = React.memo(({
|
|
|
71
71
|
clearTimeout(timeoutRef.current)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// Debounce the parent update
|
|
74
|
+
// Debounce the parent update with shorter delay
|
|
75
75
|
timeoutRef.current = setTimeout(() => {
|
|
76
76
|
onSearchChange(newValue)
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
// Keep focus on input after state update
|
|
78
|
+
if (searchInputRef.current) {
|
|
79
|
+
searchInputRef.current.focus()
|
|
80
|
+
}
|
|
81
|
+
}, 150)
|
|
82
|
+
}, [onSearchChange, searchInputRef])
|
|
79
83
|
|
|
80
84
|
// Cleanup timeout on unmount
|
|
81
85
|
useEffect(() => {
|
|
@@ -112,6 +116,8 @@ const SearchInput = React.memo(({
|
|
|
112
116
|
)
|
|
113
117
|
})
|
|
114
118
|
|
|
119
|
+
SearchInput.displayName = 'SearchInput'
|
|
120
|
+
|
|
115
121
|
export interface SidebarItem {
|
|
116
122
|
id: string
|
|
117
123
|
title: string
|
|
@@ -351,6 +357,7 @@ export function Sidebar({
|
|
|
351
357
|
|
|
352
358
|
// Handle search change
|
|
353
359
|
const handleSearch = useCallback((value: string) => {
|
|
360
|
+
setCurrentSearchQuery(value)
|
|
354
361
|
onSearchChange?.(value)
|
|
355
362
|
}, [onSearchChange])
|
|
356
363
|
|
|
@@ -780,16 +787,6 @@ export function Sidebar({
|
|
|
780
787
|
const SidebarContent = React.memo(() => {
|
|
781
788
|
return (
|
|
782
789
|
<>
|
|
783
|
-
<SidebarHeader />
|
|
784
|
-
{showSearch && (!collapsed || isMobile) && (
|
|
785
|
-
<SearchInput
|
|
786
|
-
searchInputRef={searchInputRef}
|
|
787
|
-
searchPlaceholder={searchPlaceholder}
|
|
788
|
-
initialValue={searchQuery}
|
|
789
|
-
onSearchChange={handleSearch}
|
|
790
|
-
keyboardShortcuts={keyboardShortcuts}
|
|
791
|
-
/>
|
|
792
|
-
)}
|
|
793
790
|
<SidebarMenuContent />
|
|
794
791
|
<SidebarFooter />
|
|
795
792
|
</>
|
|
@@ -839,6 +836,17 @@ export function Sidebar({
|
|
|
839
836
|
}}
|
|
840
837
|
/>
|
|
841
838
|
)}
|
|
839
|
+
<SidebarHeader />
|
|
840
|
+
{showSearch && (!collapsed || isMobile) && (
|
|
841
|
+
<SearchInput
|
|
842
|
+
key="sidebar-search-mobile"
|
|
843
|
+
searchInputRef={searchInputRef}
|
|
844
|
+
searchPlaceholder={searchPlaceholder}
|
|
845
|
+
initialValue={currentSearchQuery}
|
|
846
|
+
onSearchChange={handleSearch}
|
|
847
|
+
keyboardShortcuts={keyboardShortcuts}
|
|
848
|
+
/>
|
|
849
|
+
)}
|
|
842
850
|
<SidebarContent />
|
|
843
851
|
</div>
|
|
844
852
|
</SheetContent>
|
|
@@ -857,6 +865,17 @@ export function Sidebar({
|
|
|
857
865
|
}}
|
|
858
866
|
/>
|
|
859
867
|
)}
|
|
868
|
+
<SidebarHeader />
|
|
869
|
+
{showSearch && (!collapsed || isMobile) && (
|
|
870
|
+
<SearchInput
|
|
871
|
+
key="sidebar-search-desktop"
|
|
872
|
+
searchInputRef={searchInputRef}
|
|
873
|
+
searchPlaceholder={searchPlaceholder}
|
|
874
|
+
initialValue={currentSearchQuery}
|
|
875
|
+
onSearchChange={handleSearch}
|
|
876
|
+
keyboardShortcuts={keyboardShortcuts}
|
|
877
|
+
/>
|
|
878
|
+
)}
|
|
860
879
|
<SidebarContent />
|
|
861
880
|
</aside>
|
|
862
881
|
)
|
|
@@ -203,23 +203,23 @@ const timelineVariants = cva("w-full", {
|
|
|
203
203
|
|
|
204
204
|
// Default color schemes
|
|
205
205
|
const DEFAULT_COLORS: Record<TimelineEventType, string> = {
|
|
206
|
-
success: 'bg-green-500 border-green-
|
|
207
|
-
warning: 'bg-yellow-500 border-yellow-
|
|
208
|
-
error: 'bg-red-500 border-red-
|
|
209
|
-
info: 'bg-blue-500 border-blue-
|
|
210
|
-
pending: 'bg-
|
|
211
|
-
milestone: 'bg-purple-500 border-purple-
|
|
212
|
-
custom: 'bg-slate-500 border-slate-
|
|
206
|
+
success: 'bg-green-500 border-green-600',
|
|
207
|
+
warning: 'bg-yellow-500 border-yellow-600',
|
|
208
|
+
error: 'bg-red-500 border-red-600',
|
|
209
|
+
info: 'bg-blue-500 border-blue-600',
|
|
210
|
+
pending: 'bg-gray-400 border-gray-500',
|
|
211
|
+
milestone: 'bg-purple-500 border-purple-600',
|
|
212
|
+
custom: 'bg-slate-500 border-slate-600'
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
const DEFAULT_ICONS: Record<TimelineEventType, React.ReactNode> = {
|
|
216
|
-
success: <CheckCircle2 className="h-
|
|
217
|
-
warning: <AlertCircle className="h-
|
|
218
|
-
error: <XCircle className="h-
|
|
219
|
-
info: <Circle className="h-
|
|
220
|
-
pending: <Clock className="h-
|
|
221
|
-
milestone: <Flag className="h-
|
|
222
|
-
custom: <Sparkles className="h-
|
|
216
|
+
success: <CheckCircle2 className="h-5 w-5 text-white" />,
|
|
217
|
+
warning: <AlertCircle className="h-5 w-5 text-white" />,
|
|
218
|
+
error: <XCircle className="h-5 w-5 text-white" />,
|
|
219
|
+
info: <Circle className="h-5 w-5 text-white" />,
|
|
220
|
+
pending: <Clock className="h-5 w-5 text-white" />,
|
|
221
|
+
milestone: <Flag className="h-5 w-5 text-white" />,
|
|
222
|
+
custom: <Sparkles className="h-5 w-5 text-white" />
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
const TEXT_COLORS: Record<TimelineEventType, string> = {
|
|
@@ -540,25 +540,36 @@ export function Timeline({
|
|
|
540
540
|
|
|
541
541
|
if (isLast) return null
|
|
542
542
|
|
|
543
|
-
const baseClasses = cn(
|
|
544
|
-
"absolute",
|
|
545
|
-
layout === 'horizontal' ? "h-0.5 top-4" : "w-0.5 left-1/2 -ml-px transform -translate-x-1/2",
|
|
546
|
-
gradientConnectors && "bg-gradient-to-b from-border to-transparent"
|
|
547
|
-
)
|
|
548
|
-
|
|
549
543
|
if (layout === 'horizontal') {
|
|
550
|
-
return
|
|
544
|
+
return (
|
|
545
|
+
<div
|
|
546
|
+
className={cn(
|
|
547
|
+
"absolute h-1 bg-border",
|
|
548
|
+
gradientConnectors ? "bg-gradient-to-r from-primary/60 via-primary/30 to-transparent" : "bg-border"
|
|
549
|
+
)}
|
|
550
|
+
style={{
|
|
551
|
+
width: '100%',
|
|
552
|
+
left: '100%',
|
|
553
|
+
top: '50%',
|
|
554
|
+
transform: 'translateY(-50%)'
|
|
555
|
+
}}
|
|
556
|
+
/>
|
|
557
|
+
)
|
|
551
558
|
}
|
|
552
559
|
|
|
560
|
+
const baseClasses = cn(
|
|
561
|
+
"absolute w-1 left-1/2 -ml-0.5 transform -translate-x-1/2",
|
|
562
|
+
gradientConnectors ? "bg-gradient-to-b from-primary/60 via-primary/30 to-transparent" : "bg-border"
|
|
563
|
+
)
|
|
564
|
+
|
|
553
565
|
return (
|
|
554
566
|
<div className={cn(
|
|
555
567
|
baseClasses,
|
|
556
|
-
"
|
|
557
|
-
layout === 'alternating' && "hidden"
|
|
568
|
+
layout === 'alternating' && "left-1/2 -ml-0.5"
|
|
558
569
|
)}
|
|
559
570
|
style={{
|
|
560
|
-
height: 'calc(100% +
|
|
561
|
-
top: '
|
|
571
|
+
height: 'calc(100% + 3rem)',
|
|
572
|
+
top: '2.5rem'
|
|
562
573
|
}} />
|
|
563
574
|
)
|
|
564
575
|
}, [connectorRenderer, layout, gradientConnectors])
|
|
@@ -587,17 +598,14 @@ export function Timeline({
|
|
|
587
598
|
}}
|
|
588
599
|
tabIndex={keyboardNavigation ? 0 : -1}
|
|
589
600
|
className={cn(
|
|
590
|
-
"relative flex gap-
|
|
591
|
-
compactMode ? "pb-
|
|
601
|
+
"relative flex gap-6",
|
|
602
|
+
compactMode ? "pb-4" : "pb-10",
|
|
592
603
|
layout === 'alternating' && index % 2 === 0 && "flex-row-reverse",
|
|
593
|
-
layout === 'horizontal' && "flex-col items-center",
|
|
594
|
-
"
|
|
595
|
-
|
|
596
|
-
isSelected && "bg-muted/70",
|
|
597
|
-
isFocused && "ring-2 ring-ring",
|
|
604
|
+
layout === 'horizontal' && "flex-col items-center pb-0 mr-8",
|
|
605
|
+
"transition-all duration-200",
|
|
606
|
+
isFocused && "scale-[1.02]",
|
|
598
607
|
printMode && "print:break-inside-avoid"
|
|
599
608
|
)}
|
|
600
|
-
onClick={() => handleEventClick(event)}
|
|
601
609
|
onFocus={() => setFocusedEventId(event.id)}
|
|
602
610
|
role="button"
|
|
603
611
|
aria-label={`Event: ${event.title}`}
|
|
@@ -610,26 +618,50 @@ export function Timeline({
|
|
|
610
618
|
)}>
|
|
611
619
|
<motion.div
|
|
612
620
|
className={cn(
|
|
613
|
-
"flex items-center justify-center rounded-full border-
|
|
614
|
-
isMilestoneEvent ? "w-
|
|
621
|
+
"flex items-center justify-center rounded-full border-4 bg-background z-10 shadow-lg relative",
|
|
622
|
+
isMilestoneEvent ? "w-12 h-12" : "w-10 h-10",
|
|
615
623
|
eventColor,
|
|
616
|
-
isSelected && "ring-
|
|
624
|
+
isSelected && "ring-4 ring-ring ring-offset-2"
|
|
617
625
|
)}
|
|
618
|
-
whileHover={{ scale: 1.
|
|
626
|
+
whileHover={{ scale: 1.15 }}
|
|
619
627
|
whileTap={{ scale: 0.95 }}
|
|
620
628
|
>
|
|
621
629
|
{renderEventIcon(event)}
|
|
630
|
+
|
|
631
|
+
{/* Connector - Horizontal için node'un içinden çıkan çizgi */}
|
|
632
|
+
{!isLast && layout === 'horizontal' && (
|
|
633
|
+
<div
|
|
634
|
+
className={cn(
|
|
635
|
+
"absolute h-1",
|
|
636
|
+
gradientConnectors ? "bg-gradient-to-r from-border via-border/60 to-border/30" : "bg-border"
|
|
637
|
+
)}
|
|
638
|
+
style={{
|
|
639
|
+
width: '18.5rem', // Card genişliği (16rem) + margin (2rem) + node yarısı (0.5rem)
|
|
640
|
+
left: isMilestoneEvent ? '3rem' : '2.5rem', // Node genişliğinin yarısı
|
|
641
|
+
top: '50%',
|
|
642
|
+
transform: 'translateY(-50%)',
|
|
643
|
+
zIndex: -1
|
|
644
|
+
}}
|
|
645
|
+
/>
|
|
646
|
+
)}
|
|
622
647
|
</motion.div>
|
|
623
648
|
|
|
624
|
-
{/* Connector */}
|
|
625
|
-
{!isLast && renderConnector(event, events[index + 1], isLast)}
|
|
649
|
+
{/* Connector - Vertical layouts için */}
|
|
650
|
+
{!isLast && layout !== 'horizontal' && renderConnector(event, events[index + 1], isLast)}
|
|
626
651
|
</div>
|
|
627
652
|
|
|
628
653
|
{/* Event Content */}
|
|
629
|
-
<
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
654
|
+
<Card
|
|
655
|
+
className={cn(
|
|
656
|
+
layout === 'horizontal' ? "w-64" : "flex-1 min-w-0",
|
|
657
|
+
"shadow-md hover:shadow-lg transition-shadow duration-200 cursor-pointer",
|
|
658
|
+
layout === 'alternating' && index % 2 === 0 && "text-right",
|
|
659
|
+
isSelected && "ring-2 ring-primary",
|
|
660
|
+
"bg-card/50 backdrop-blur-sm"
|
|
661
|
+
)}
|
|
662
|
+
onClick={() => handleEventClick(event)}
|
|
663
|
+
>
|
|
664
|
+
<CardContent className="p-4">
|
|
633
665
|
{/* Header */}
|
|
634
666
|
<div className="flex items-start justify-between gap-2 mb-2">
|
|
635
667
|
<div className="flex-1">
|
|
@@ -880,7 +912,8 @@ export function Timeline({
|
|
|
880
912
|
)}
|
|
881
913
|
</Button>
|
|
882
914
|
)}
|
|
883
|
-
|
|
915
|
+
</CardContent>
|
|
916
|
+
</Card>
|
|
884
917
|
</div>
|
|
885
918
|
)
|
|
886
919
|
|
|
@@ -1011,9 +1044,13 @@ export function Timeline({
|
|
|
1011
1044
|
) : (
|
|
1012
1045
|
<div className={cn(
|
|
1013
1046
|
"space-y-0",
|
|
1014
|
-
layout === 'horizontal' && "flex overflow-x-auto gap-
|
|
1047
|
+
layout === 'horizontal' && "flex flex-row overflow-x-auto gap-0 pb-4 items-start",
|
|
1015
1048
|
layout === 'alternating' && "relative"
|
|
1016
1049
|
)}>
|
|
1050
|
+
{/* Center line for alternating layout */}
|
|
1051
|
+
{layout === 'alternating' && (
|
|
1052
|
+
<div className="absolute left-1/2 -ml-0.5 top-0 bottom-0 w-1 bg-border" />
|
|
1053
|
+
)}
|
|
1017
1054
|
{filteredAndSortedEvents.map((event, index) =>
|
|
1018
1055
|
renderEvent(event, index, index === filteredAndSortedEvents.length - 1)
|
|
1019
1056
|
)}
|
|
@@ -1047,16 +1084,13 @@ export function Timeline({
|
|
|
1047
1084
|
aria-label={ariaLabel}
|
|
1048
1085
|
{...props}
|
|
1049
1086
|
>
|
|
1087
|
+
{(showSearch || showFilter || showExport) && (
|
|
1050
1088
|
<CardHeader className={cn(
|
|
1051
1089
|
compactMode && "pb-3",
|
|
1052
1090
|
printMode && "print:pb-2"
|
|
1053
1091
|
)}>
|
|
1054
1092
|
<div className="flex items-center justify-between">
|
|
1055
1093
|
<div>
|
|
1056
|
-
<CardTitle className="flex items-center gap-2">
|
|
1057
|
-
<Clock className="h-5 w-5" />
|
|
1058
|
-
Timeline
|
|
1059
|
-
</CardTitle>
|
|
1060
1094
|
<CardDescription>
|
|
1061
1095
|
{filteredAndSortedEvents.length} event{filteredAndSortedEvents.length !== 1 ? 's' : ''}
|
|
1062
1096
|
{searchQuery && ` matching "${searchQuery}"`}
|
|
@@ -1123,6 +1157,7 @@ export function Timeline({
|
|
|
1123
1157
|
</div>
|
|
1124
1158
|
)}
|
|
1125
1159
|
</CardHeader>
|
|
1160
|
+
)}
|
|
1126
1161
|
|
|
1127
1162
|
<CardContent className={cn(
|
|
1128
1163
|
compactMode ? "pt-2" : "pt-6",
|