@d34dman/flowdrop 0.0.61 → 0.0.62
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/README.md +6 -0
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -1
- package/dist/api/client.d.ts +4 -0
- package/dist/api/client.js +6 -1
- package/dist/api/enhanced-client.js +7 -6
- package/dist/components/App.svelte +143 -219
- package/dist/components/CanvasBanner.stories.svelte +25 -0
- package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
- package/dist/components/CanvasBanner.svelte +2 -2
- package/dist/components/ConfigForm.svelte +37 -36
- package/dist/components/ConfigPanel.stories.svelte +38 -0
- package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
- package/dist/components/ConfigPanel.svelte +2 -2
- package/dist/components/ConnectionLine.svelte +2 -2
- package/dist/components/FlowDropZone.svelte +18 -2
- package/dist/components/FlowDropZone.svelte.d.ts +2 -0
- package/dist/components/LoadingSpinner.stories.svelte +30 -0
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.stories.svelte +22 -0
- package/dist/components/Logo.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.svelte +33 -13
- package/dist/components/Logo.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +21 -0
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
- package/dist/components/MarkdownDisplay.svelte +4 -3
- package/dist/components/Navbar.stories.svelte +41 -0
- package/dist/components/Navbar.stories.svelte.d.ts +27 -0
- package/dist/components/Navbar.svelte +4 -4
- package/dist/components/NodeSidebar.svelte +12 -12
- package/dist/components/NodeStatusOverlay.stories.svelte +74 -0
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
- package/dist/components/PipelineStatus.svelte +11 -4
- package/dist/components/PortCoordinateTracker.svelte +1 -1
- package/dist/components/SchemaForm.stories.svelte +101 -0
- package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
- package/dist/components/SchemaForm.svelte +17 -12
- package/dist/components/SettingsModal.svelte +3 -3
- package/dist/components/SettingsPanel.svelte +23 -22
- package/dist/components/StatusIcon.stories.svelte +60 -0
- package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
- package/dist/components/StatusIcon.svelte +7 -0
- package/dist/components/StatusLabel.stories.svelte +17 -0
- package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.stories.svelte +25 -0
- package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.svelte +8 -8
- package/dist/components/UniversalNode.svelte +1 -1
- package/dist/components/WorkflowEditor.svelte +298 -294
- package/dist/components/form/FormAutocomplete.svelte +20 -19
- package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormField.svelte +3 -3
- package/dist/components/form/FormFieldLight.svelte +2 -2
- package/dist/components/form/FormFieldWrapper.stories.svelte +31 -0
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormFieldset.svelte +7 -7
- package/dist/components/form/FormNumberField.stories.svelte +33 -0
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormRangeField.stories.svelte +31 -0
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormSelect.stories.svelte +50 -0
- package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTemplateEditor.svelte +2 -1
- package/dist/components/form/FormTextField.stories.svelte +30 -0
- package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTextarea.stories.svelte +31 -0
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormToggle.stories.svelte +30 -0
- package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormUISchemaRenderer.svelte +1 -1
- package/dist/components/form/types.d.ts +15 -47
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +43 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +24 -24
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +49 -0
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +19 -19
- package/dist/components/interrupt/FormPrompt.svelte +15 -15
- package/dist/components/interrupt/InterruptBubble.svelte +202 -236
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +46 -0
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ReviewPrompt.svelte +842 -0
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +34 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +21 -21
- package/dist/components/nodes/GatewayNode.stories.svelte +76 -0
- package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/GatewayNode.svelte +19 -17
- package/dist/components/nodes/IdeaNode.stories.svelte +48 -0
- package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/IdeaNode.svelte +10 -26
- package/dist/components/nodes/NotesNode.stories.svelte +69 -0
- package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/NotesNode.svelte +8 -8
- package/dist/components/nodes/SimpleNode.stories.svelte +101 -0
- package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SimpleNode.svelte +16 -24
- package/dist/components/nodes/SquareNode.stories.svelte +56 -0
- package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SquareNode.svelte +13 -21
- package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
- package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/TerminalNode.svelte +6 -6
- package/dist/components/nodes/ToolNode.stories.svelte +71 -0
- package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/ToolNode.svelte +7 -15
- package/dist/components/nodes/WorkflowNode.stories.svelte +50 -0
- package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/WorkflowNode.svelte +13 -13
- package/dist/components/playground/ChatPanel.svelte +48 -48
- package/dist/components/playground/ExecutionLogs.svelte +23 -23
- package/dist/components/playground/InputCollector.svelte +24 -24
- package/dist/components/playground/MessageBubble.stories.svelte +49 -0
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
- package/dist/components/playground/MessageBubble.svelte +49 -46
- package/dist/components/playground/Playground.svelte +194 -129
- package/dist/components/playground/PlaygroundModal.svelte +5 -5
- package/dist/components/playground/SessionManager.svelte +26 -26
- package/dist/config/constants.d.ts +22 -0
- package/dist/config/constants.js +22 -0
- package/dist/config/endpoints.d.ts +19 -0
- package/dist/config/runtimeConfig.js +2 -1
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.js +9 -1
- package/dist/editor/index.d.ts +13 -9
- package/dist/editor/index.js +15 -11
- package/dist/form/code.d.ts +2 -1
- package/dist/form/code.js +1 -3
- package/dist/form/markdown.d.ts +2 -1
- package/dist/form/markdown.js +1 -3
- package/dist/helpers/workflowEditorHelper.js +13 -9
- package/dist/mocks/app-forms.js +1 -0
- package/dist/mocks/app-navigation.js +3 -1
- package/dist/mocks/app-stores.d.ts +4 -4
- package/dist/playground/index.d.ts +4 -3
- package/dist/playground/index.js +12 -10
- package/dist/playground/mount.js +6 -13
- package/dist/services/agentSpecExecutionService.js +2 -1
- package/dist/services/api.js +10 -18
- package/dist/services/apiVariableService.js +2 -1
- package/dist/services/autoSaveService.d.ts +3 -3
- package/dist/services/autoSaveService.js +21 -17
- package/dist/services/categoriesApi.js +13 -5
- package/dist/services/draftStorage.js +5 -4
- package/dist/services/dynamicSchemaService.js +4 -4
- package/dist/services/globalSave.d.ts +60 -11
- package/dist/services/globalSave.js +160 -83
- package/dist/services/historyService.d.ts +2 -1
- package/dist/services/historyService.js +7 -3
- package/dist/services/interruptService.js +9 -8
- package/dist/services/nodeExecutionService.js +14 -6
- package/dist/services/playgroundService.js +2 -1
- package/dist/services/portConfigApi.js +11 -7
- package/dist/services/toastService.d.ts +1 -1
- package/dist/services/toastService.js +6 -5
- package/dist/services/variableService.js +3 -2
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js +1 -1
- package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
- package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
- package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
- package/dist/stores/editorStateMachine.svelte.js +132 -0
- package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
- package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
- package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
- package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
- package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +41 -33
- package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +164 -84
- package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
- package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
- package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
- package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
- package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
- package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
- package/dist/stories/CanvasDecorator.svelte +50 -0
- package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
- package/dist/stories/NodeDecorator.svelte +74 -0
- package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
- package/dist/stories/utils.d.ts +93 -0
- package/dist/stories/utils.js +122 -0
- package/dist/styles/base.css +114 -61
- package/dist/styles/toast.css +2 -2
- package/dist/styles/tokens.css +250 -185
- package/dist/svelte-app.d.ts +0 -6
- package/dist/svelte-app.js +13 -31
- package/dist/types/index.d.ts +2 -0
- package/dist/types/interrupt.d.ts +89 -5
- package/dist/types/interrupt.js +13 -1
- package/dist/types/playground.d.ts +5 -0
- package/dist/types/settings.js +1 -1
- package/dist/utils/colors.js +4 -4
- package/dist/utils/connections.js +33 -8
- package/dist/utils/icons.js +1 -1
- package/dist/utils/logger.d.ts +47 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/nodeWrapper.js +1 -1
- package/dist/utils/sanitize.d.ts +19 -0
- package/dist/utils/sanitize.js +31 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.js +39 -0
- package/package.json +243 -232
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings Store for FlowDrop
|
|
2
|
+
* Settings Store for FlowDrop (Svelte 5 Runes)
|
|
3
3
|
*
|
|
4
4
|
* Provides unified state management for all user-configurable settings with:
|
|
5
5
|
* - Hybrid persistence (localStorage primary, optional API sync)
|
|
6
|
-
* - Category-specific
|
|
6
|
+
* - Category-specific getter functions for performance
|
|
7
7
|
* - Deep merge support for partial updates
|
|
8
8
|
* - Integrated theme system with system preference detection
|
|
9
9
|
*
|
|
@@ -12,47 +12,58 @@
|
|
|
12
12
|
import type { FlowDropSettings, ThemeSettings, EditorSettings, UISettings, BehaviorSettings, ApiSettings, PartialSettings, SyncStatus, ResolvedTheme, ThemePreference, SettingsChangeCallback, SettingsCategory } from '../types/settings.js';
|
|
13
13
|
export type { ThemePreference, ResolvedTheme } from '../types/settings.js';
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Get current settings (replaces settingsStore derived store)
|
|
16
16
|
*/
|
|
17
|
-
export declare
|
|
17
|
+
export declare function getSettings(): FlowDropSettings;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Get sync status (replaces syncStatusStore derived store)
|
|
20
20
|
*/
|
|
21
|
-
export declare
|
|
21
|
+
export declare function getSyncStatus(): {
|
|
22
22
|
status: SyncStatus;
|
|
23
|
-
lastSyncedAt: number;
|
|
24
|
-
error: string;
|
|
25
|
-
}
|
|
23
|
+
lastSyncedAt: number | null;
|
|
24
|
+
error: string | null;
|
|
25
|
+
};
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Get theme settings (replaces themeSettings derived store)
|
|
28
28
|
*/
|
|
29
|
-
export declare
|
|
29
|
+
export declare function getThemeSettings(): ThemeSettings;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Get editor settings (replaces editorSettings derived store)
|
|
32
32
|
*/
|
|
33
|
-
export declare
|
|
33
|
+
export declare function getEditorSettings(): EditorSettings;
|
|
34
34
|
/**
|
|
35
|
-
* UI settings store
|
|
35
|
+
* Get UI settings (replaces uiSettings derived store)
|
|
36
36
|
*/
|
|
37
|
-
export declare
|
|
37
|
+
export declare function getUiSettings(): UISettings;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Get behavior settings (replaces behaviorSettings derived store)
|
|
40
40
|
*/
|
|
41
|
-
export declare
|
|
41
|
+
export declare function getBehaviorSettings(): BehaviorSettings;
|
|
42
42
|
/**
|
|
43
|
-
* API settings store
|
|
43
|
+
* Get API settings (replaces apiSettings derived store)
|
|
44
44
|
*/
|
|
45
|
-
export declare
|
|
45
|
+
export declare function getApiSettings(): ApiSettings;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* Derived from themeSettings for convenient access
|
|
47
|
+
* Get theme preference (replaces theme derived store)
|
|
49
48
|
*/
|
|
50
|
-
export declare
|
|
49
|
+
export declare function getTheme(): ThemePreference;
|
|
51
50
|
/**
|
|
52
|
-
*
|
|
51
|
+
* Get resolved theme - the actual theme applied ('light' or 'dark')
|
|
53
52
|
* When preference is 'auto', resolves based on system preference
|
|
53
|
+
* (replaces resolvedTheme derived store)
|
|
54
|
+
*/
|
|
55
|
+
export declare function getResolvedTheme(): ResolvedTheme;
|
|
56
|
+
/**
|
|
57
|
+
* Get system theme state (for internal use)
|
|
58
|
+
*/
|
|
59
|
+
export declare function getSystemThemeState(): ResolvedTheme;
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the system theme change listener.
|
|
62
|
+
* Sets up a media query listener for the system color scheme preference.
|
|
63
|
+
*
|
|
64
|
+
* @returns Cleanup function that removes the listener
|
|
54
65
|
*/
|
|
55
|
-
export declare
|
|
66
|
+
export declare function initThemeListener(): () => void;
|
|
56
67
|
/**
|
|
57
68
|
* Update settings with partial values
|
|
58
69
|
*
|
|
@@ -65,10 +76,6 @@ export declare function updateSettings(partial: PartialSettings): void;
|
|
|
65
76
|
* @param categories - Optional categories to reset (all if not specified)
|
|
66
77
|
*/
|
|
67
78
|
export declare function resetSettings(categories?: SettingsCategory[]): void;
|
|
68
|
-
/**
|
|
69
|
-
* Get current settings synchronously
|
|
70
|
-
*/
|
|
71
|
-
export declare function getSettings(): FlowDropSettings;
|
|
72
79
|
/**
|
|
73
80
|
* Set the theme preference
|
|
74
81
|
*
|
|
@@ -84,6 +91,12 @@ export declare function toggleTheme(): void;
|
|
|
84
91
|
* Cycle through theme options: light -> dark -> auto -> light
|
|
85
92
|
*/
|
|
86
93
|
export declare function cycleTheme(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Clean up the theme subscription created by initializeTheme().
|
|
96
|
+
* Call this when tearing down the settings system (e.g., in tests or
|
|
97
|
+
* component cleanup) to prevent memory leaks.
|
|
98
|
+
*/
|
|
99
|
+
export declare function cleanupThemeSubscription(): void;
|
|
87
100
|
/**
|
|
88
101
|
* Initialize the theme system
|
|
89
102
|
* Should be called once on app startup
|
|
@@ -91,6 +104,10 @@ export declare function cycleTheme(): void;
|
|
|
91
104
|
* This function:
|
|
92
105
|
* 1. Applies the current resolved theme to the document
|
|
93
106
|
* 2. Sets up reactivity to apply theme changes
|
|
107
|
+
*
|
|
108
|
+
* Note: In Svelte 5, we use $effect for reactivity. Since $effect can only
|
|
109
|
+
* be used in component context or $effect.root, we use $effect.root here
|
|
110
|
+
* to create a standalone reactive scope.
|
|
94
111
|
*/
|
|
95
112
|
export declare function initializeTheme(): void;
|
|
96
113
|
/**
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings Store for FlowDrop
|
|
2
|
+
* Settings Store for FlowDrop (Svelte 5 Runes)
|
|
3
3
|
*
|
|
4
4
|
* Provides unified state management for all user-configurable settings with:
|
|
5
5
|
* - Hybrid persistence (localStorage primary, optional API sync)
|
|
6
|
-
* - Category-specific
|
|
6
|
+
* - Category-specific getter functions for performance
|
|
7
7
|
* - Deep merge support for partial updates
|
|
8
8
|
* - Integrated theme system with system preference detection
|
|
9
9
|
*
|
|
10
10
|
* @module stores/settingsStore
|
|
11
11
|
*/
|
|
12
|
-
import { writable, derived, get } from 'svelte/store';
|
|
13
12
|
import { DEFAULT_SETTINGS, SETTINGS_STORAGE_KEY } from '../types/settings.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
14
|
// =========================================================================
|
|
15
15
|
// Internal State
|
|
16
16
|
// =========================================================================
|
|
@@ -44,7 +44,7 @@ function loadFromStorage() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
47
|
-
|
|
47
|
+
logger.warn('Failed to load settings from localStorage:', error);
|
|
48
48
|
}
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
@@ -61,7 +61,7 @@ function saveToStorage(settings) {
|
|
|
61
61
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
|
-
|
|
64
|
+
logger.warn('Failed to save settings to localStorage:', error);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
// =========================================================================
|
|
@@ -105,16 +105,16 @@ function deepMergeSettings(target, source) {
|
|
|
105
105
|
return result;
|
|
106
106
|
}
|
|
107
107
|
// =========================================================================
|
|
108
|
-
// Main Settings Store
|
|
108
|
+
// Main Settings Store (Rune-based)
|
|
109
109
|
// =========================================================================
|
|
110
110
|
/**
|
|
111
111
|
* Initial state loaded from localStorage or defaults
|
|
112
112
|
*/
|
|
113
113
|
const initialSettings = loadFromStorage() ?? DEFAULT_SETTINGS;
|
|
114
114
|
/**
|
|
115
|
-
* Main settings store state
|
|
115
|
+
* Main settings store state using $state rune
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
let storeState = $state({
|
|
118
118
|
settings: initialSettings,
|
|
119
119
|
initialized: true,
|
|
120
120
|
syncStatus: 'idle',
|
|
@@ -122,48 +122,85 @@ const storeState = writable({
|
|
|
122
122
|
syncError: null
|
|
123
123
|
});
|
|
124
124
|
/**
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
export const settingsStore = derived(storeState, ($state) => $state.settings);
|
|
128
|
-
/**
|
|
129
|
-
* Sync status store for UI indicators
|
|
125
|
+
* System theme preference using $state rune
|
|
126
|
+
* Updates when system preference changes
|
|
130
127
|
*/
|
|
131
|
-
|
|
132
|
-
status: $state.syncStatus,
|
|
133
|
-
lastSyncedAt: $state.lastSyncedAt,
|
|
134
|
-
error: $state.syncError
|
|
135
|
-
}));
|
|
128
|
+
let systemThemeState = $state(typeof window !== 'undefined' ? getSystemTheme() : 'light');
|
|
136
129
|
// =========================================================================
|
|
137
|
-
//
|
|
130
|
+
// Getter Functions (replacing derived stores)
|
|
138
131
|
// =========================================================================
|
|
139
132
|
/**
|
|
140
|
-
*
|
|
133
|
+
* Get current settings (replaces settingsStore derived store)
|
|
134
|
+
*/
|
|
135
|
+
export function getSettings() {
|
|
136
|
+
return storeState.settings;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get sync status (replaces syncStatusStore derived store)
|
|
140
|
+
*/
|
|
141
|
+
export function getSyncStatus() {
|
|
142
|
+
return {
|
|
143
|
+
status: storeState.syncStatus,
|
|
144
|
+
lastSyncedAt: storeState.lastSyncedAt,
|
|
145
|
+
error: storeState.syncError
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get theme settings (replaces themeSettings derived store)
|
|
150
|
+
*/
|
|
151
|
+
export function getThemeSettings() {
|
|
152
|
+
return storeState.settings.theme;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get editor settings (replaces editorSettings derived store)
|
|
156
|
+
*/
|
|
157
|
+
export function getEditorSettings() {
|
|
158
|
+
return storeState.settings.editor;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get UI settings (replaces uiSettings derived store)
|
|
162
|
+
*/
|
|
163
|
+
export function getUiSettings() {
|
|
164
|
+
return storeState.settings.ui;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get behavior settings (replaces behaviorSettings derived store)
|
|
141
168
|
*/
|
|
142
|
-
export
|
|
169
|
+
export function getBehaviorSettings() {
|
|
170
|
+
return storeState.settings.behavior;
|
|
171
|
+
}
|
|
143
172
|
/**
|
|
144
|
-
*
|
|
173
|
+
* Get API settings (replaces apiSettings derived store)
|
|
145
174
|
*/
|
|
146
|
-
export
|
|
175
|
+
export function getApiSettings() {
|
|
176
|
+
return storeState.settings.api;
|
|
177
|
+
}
|
|
147
178
|
/**
|
|
148
|
-
*
|
|
179
|
+
* Get theme preference (replaces theme derived store)
|
|
149
180
|
*/
|
|
150
|
-
export
|
|
181
|
+
export function getTheme() {
|
|
182
|
+
return storeState.settings.theme.preference;
|
|
183
|
+
}
|
|
151
184
|
/**
|
|
152
|
-
*
|
|
185
|
+
* Get resolved theme - the actual theme applied ('light' or 'dark')
|
|
186
|
+
* When preference is 'auto', resolves based on system preference
|
|
187
|
+
* (replaces resolvedTheme derived store)
|
|
153
188
|
*/
|
|
154
|
-
export
|
|
189
|
+
export function getResolvedTheme() {
|
|
190
|
+
if (storeState.settings.theme.preference === 'auto') {
|
|
191
|
+
return systemThemeState;
|
|
192
|
+
}
|
|
193
|
+
return storeState.settings.theme.preference;
|
|
194
|
+
}
|
|
155
195
|
/**
|
|
156
|
-
*
|
|
196
|
+
* Get system theme state (for internal use)
|
|
157
197
|
*/
|
|
158
|
-
export
|
|
198
|
+
export function getSystemThemeState() {
|
|
199
|
+
return systemThemeState;
|
|
200
|
+
}
|
|
159
201
|
// =========================================================================
|
|
160
202
|
// Theme System
|
|
161
203
|
// =========================================================================
|
|
162
|
-
/**
|
|
163
|
-
* System theme preference store
|
|
164
|
-
* Updates when system preference changes
|
|
165
|
-
*/
|
|
166
|
-
const systemTheme = writable(typeof window !== 'undefined' ? getSystemTheme() : 'light');
|
|
167
204
|
/**
|
|
168
205
|
* Get the system's color scheme preference
|
|
169
206
|
*/
|
|
@@ -173,35 +210,25 @@ function getSystemTheme() {
|
|
|
173
210
|
}
|
|
174
211
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
175
212
|
}
|
|
176
|
-
|
|
177
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Initialize the system theme change listener.
|
|
215
|
+
* Sets up a media query listener for the system color scheme preference.
|
|
216
|
+
*
|
|
217
|
+
* @returns Cleanup function that removes the listener
|
|
218
|
+
*/
|
|
219
|
+
export function initThemeListener() {
|
|
220
|
+
if (typeof window === 'undefined') {
|
|
221
|
+
return () => { };
|
|
222
|
+
}
|
|
178
223
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
179
224
|
const handleSystemThemeChange = (event) => {
|
|
180
|
-
|
|
225
|
+
systemThemeState = event.matches ? 'dark' : 'light';
|
|
226
|
+
};
|
|
227
|
+
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
228
|
+
return () => {
|
|
229
|
+
mediaQuery.removeEventListener('change', handleSystemThemeChange);
|
|
181
230
|
};
|
|
182
|
-
if (mediaQuery.addEventListener) {
|
|
183
|
-
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// Fallback for older browsers
|
|
187
|
-
mediaQuery.addListener(handleSystemThemeChange);
|
|
188
|
-
}
|
|
189
231
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Theme preference store
|
|
192
|
-
* Derived from themeSettings for convenient access
|
|
193
|
-
*/
|
|
194
|
-
export const theme = derived(themeSettings, ($theme) => $theme.preference);
|
|
195
|
-
/**
|
|
196
|
-
* Resolved theme - the actual theme applied ('light' or 'dark')
|
|
197
|
-
* When preference is 'auto', resolves based on system preference
|
|
198
|
-
*/
|
|
199
|
-
export const resolvedTheme = derived([themeSettings, systemTheme], ([$themeSettings, $systemTheme]) => {
|
|
200
|
-
if ($themeSettings.preference === 'auto') {
|
|
201
|
-
return $systemTheme;
|
|
202
|
-
}
|
|
203
|
-
return $themeSettings.preference;
|
|
204
|
-
});
|
|
205
232
|
// =========================================================================
|
|
206
233
|
// Settings Update Functions
|
|
207
234
|
// =========================================================================
|
|
@@ -220,7 +247,7 @@ function notifyChange(category, key, previousValue, newValue) {
|
|
|
220
247
|
listener(event);
|
|
221
248
|
}
|
|
222
249
|
catch (error) {
|
|
223
|
-
|
|
250
|
+
logger.error('Settings change listener error:', error);
|
|
224
251
|
}
|
|
225
252
|
});
|
|
226
253
|
}
|
|
@@ -236,29 +263,27 @@ function getCategoryAsRecord(settings, category) {
|
|
|
236
263
|
* @param partial - Partial settings to merge
|
|
237
264
|
*/
|
|
238
265
|
export function updateSettings(partial) {
|
|
239
|
-
storeState.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
notifyChange(category, key, prevCat[key], newCat[key]);
|
|
253
|
-
}
|
|
266
|
+
const previousSettings = storeState.settings;
|
|
267
|
+
const newSettings = deepMergeSettings(storeState.settings, partial);
|
|
268
|
+
// Persist to localStorage immediately
|
|
269
|
+
saveToStorage(newSettings);
|
|
270
|
+
// Notify listeners for each changed category
|
|
271
|
+
for (const category of Object.keys(partial)) {
|
|
272
|
+
const partialCategory = partial[category];
|
|
273
|
+
if (partialCategory && typeof partialCategory === 'object') {
|
|
274
|
+
for (const key of Object.keys(partialCategory)) {
|
|
275
|
+
const prevCat = getCategoryAsRecord(previousSettings, category);
|
|
276
|
+
const newCat = getCategoryAsRecord(newSettings, category);
|
|
277
|
+
if (prevCat[key] !== newCat[key]) {
|
|
278
|
+
notifyChange(category, key, prevCat[key], newCat[key]);
|
|
254
279
|
}
|
|
255
280
|
}
|
|
256
281
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
282
|
+
}
|
|
283
|
+
storeState = {
|
|
284
|
+
...storeState,
|
|
285
|
+
settings: newSettings
|
|
286
|
+
};
|
|
262
287
|
}
|
|
263
288
|
/**
|
|
264
289
|
* Reset settings to defaults
|
|
@@ -274,21 +299,13 @@ export function resetSettings(categories) {
|
|
|
274
299
|
updateSettings(partial);
|
|
275
300
|
}
|
|
276
301
|
else {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
};
|
|
283
|
-
});
|
|
302
|
+
saveToStorage(DEFAULT_SETTINGS);
|
|
303
|
+
storeState = {
|
|
304
|
+
...storeState,
|
|
305
|
+
settings: DEFAULT_SETTINGS
|
|
306
|
+
};
|
|
284
307
|
}
|
|
285
308
|
}
|
|
286
|
-
/**
|
|
287
|
-
* Get current settings synchronously
|
|
288
|
-
*/
|
|
289
|
-
export function getSettings() {
|
|
290
|
-
return get(settingsStore);
|
|
291
|
-
}
|
|
292
309
|
// =========================================================================
|
|
293
310
|
// Theme Actions
|
|
294
311
|
// =========================================================================
|
|
@@ -305,8 +322,8 @@ export function setTheme(newTheme) {
|
|
|
305
322
|
* If currently 'auto', switches to the opposite of system preference
|
|
306
323
|
*/
|
|
307
324
|
export function toggleTheme() {
|
|
308
|
-
const currentTheme =
|
|
309
|
-
const currentResolved =
|
|
325
|
+
const currentTheme = getTheme();
|
|
326
|
+
const currentResolved = getResolvedTheme();
|
|
310
327
|
if (currentTheme === 'auto') {
|
|
311
328
|
setTheme(currentResolved === 'dark' ? 'light' : 'dark');
|
|
312
329
|
}
|
|
@@ -318,7 +335,7 @@ export function toggleTheme() {
|
|
|
318
335
|
* Cycle through theme options: light -> dark -> auto -> light
|
|
319
336
|
*/
|
|
320
337
|
export function cycleTheme() {
|
|
321
|
-
const currentTheme =
|
|
338
|
+
const currentTheme = getTheme();
|
|
322
339
|
switch (currentTheme) {
|
|
323
340
|
case 'light':
|
|
324
341
|
setTheme('dark');
|
|
@@ -342,6 +359,22 @@ function applyTheme(resolved) {
|
|
|
342
359
|
}
|
|
343
360
|
document.documentElement.setAttribute('data-theme', resolved);
|
|
344
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Stored cleanup function for the theme effect.
|
|
364
|
+
* Retained so it can be called by cleanupThemeSubscription().
|
|
365
|
+
*/
|
|
366
|
+
let themeEffectCleanup = null;
|
|
367
|
+
/**
|
|
368
|
+
* Clean up the theme subscription created by initializeTheme().
|
|
369
|
+
* Call this when tearing down the settings system (e.g., in tests or
|
|
370
|
+
* component cleanup) to prevent memory leaks.
|
|
371
|
+
*/
|
|
372
|
+
export function cleanupThemeSubscription() {
|
|
373
|
+
if (themeEffectCleanup) {
|
|
374
|
+
themeEffectCleanup();
|
|
375
|
+
themeEffectCleanup = null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
345
378
|
/**
|
|
346
379
|
* Initialize the theme system
|
|
347
380
|
* Should be called once on app startup
|
|
@@ -349,13 +382,21 @@ function applyTheme(resolved) {
|
|
|
349
382
|
* This function:
|
|
350
383
|
* 1. Applies the current resolved theme to the document
|
|
351
384
|
* 2. Sets up reactivity to apply theme changes
|
|
385
|
+
*
|
|
386
|
+
* Note: In Svelte 5, we use $effect for reactivity. Since $effect can only
|
|
387
|
+
* be used in component context or $effect.root, we use $effect.root here
|
|
388
|
+
* to create a standalone reactive scope.
|
|
352
389
|
*/
|
|
353
390
|
export function initializeTheme() {
|
|
354
|
-
const resolved =
|
|
391
|
+
const resolved = getResolvedTheme();
|
|
355
392
|
applyTheme(resolved);
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
393
|
+
// Create a standalone reactive root to watch for theme changes.
|
|
394
|
+
// $effect.root returns a cleanup function.
|
|
395
|
+
themeEffectCleanup = $effect.root(() => {
|
|
396
|
+
$effect(() => {
|
|
397
|
+
const currentResolved = getResolvedTheme();
|
|
398
|
+
applyTheme(currentResolved);
|
|
399
|
+
});
|
|
359
400
|
});
|
|
360
401
|
}
|
|
361
402
|
/**
|
|
@@ -388,31 +429,31 @@ export function setSettingsService(service) {
|
|
|
388
429
|
*/
|
|
389
430
|
export async function syncSettingsToApi() {
|
|
390
431
|
if (!settingsService) {
|
|
391
|
-
|
|
432
|
+
logger.warn('Settings service not configured for API sync');
|
|
392
433
|
return;
|
|
393
434
|
}
|
|
394
|
-
storeState
|
|
395
|
-
...
|
|
435
|
+
storeState = {
|
|
436
|
+
...storeState,
|
|
396
437
|
syncStatus: 'syncing',
|
|
397
438
|
syncError: null
|
|
398
|
-
}
|
|
439
|
+
};
|
|
399
440
|
try {
|
|
400
|
-
const currentSettings =
|
|
441
|
+
const currentSettings = getSettings();
|
|
401
442
|
await settingsService.savePreferences(currentSettings);
|
|
402
|
-
storeState
|
|
403
|
-
...
|
|
443
|
+
storeState = {
|
|
444
|
+
...storeState,
|
|
404
445
|
syncStatus: 'synced',
|
|
405
446
|
lastSyncedAt: Date.now(),
|
|
406
447
|
syncError: null
|
|
407
|
-
}
|
|
448
|
+
};
|
|
408
449
|
}
|
|
409
450
|
catch (error) {
|
|
410
451
|
const errorMessage = error instanceof Error ? error.message : 'Failed to sync settings';
|
|
411
|
-
storeState
|
|
412
|
-
...
|
|
452
|
+
storeState = {
|
|
453
|
+
...storeState,
|
|
413
454
|
syncStatus: 'error',
|
|
414
455
|
syncError: errorMessage
|
|
415
|
-
}
|
|
456
|
+
};
|
|
416
457
|
throw error;
|
|
417
458
|
}
|
|
418
459
|
}
|
|
@@ -423,34 +464,34 @@ export async function syncSettingsToApi() {
|
|
|
423
464
|
*/
|
|
424
465
|
export async function loadSettingsFromApi() {
|
|
425
466
|
if (!settingsService) {
|
|
426
|
-
|
|
467
|
+
logger.warn('Settings service not configured for API sync');
|
|
427
468
|
return;
|
|
428
469
|
}
|
|
429
|
-
storeState
|
|
430
|
-
...
|
|
470
|
+
storeState = {
|
|
471
|
+
...storeState,
|
|
431
472
|
syncStatus: 'syncing',
|
|
432
473
|
syncError: null
|
|
433
|
-
}
|
|
474
|
+
};
|
|
434
475
|
try {
|
|
435
|
-
const
|
|
436
|
-
const mergedSettings = deepMergeSettings(DEFAULT_SETTINGS,
|
|
437
|
-
storeState
|
|
438
|
-
...
|
|
476
|
+
const apiSettingsData = await settingsService.getPreferences();
|
|
477
|
+
const mergedSettings = deepMergeSettings(DEFAULT_SETTINGS, apiSettingsData);
|
|
478
|
+
storeState = {
|
|
479
|
+
...storeState,
|
|
439
480
|
settings: mergedSettings,
|
|
440
481
|
syncStatus: 'synced',
|
|
441
482
|
lastSyncedAt: Date.now(),
|
|
442
483
|
syncError: null
|
|
443
|
-
}
|
|
484
|
+
};
|
|
444
485
|
// Also persist to localStorage
|
|
445
486
|
saveToStorage(mergedSettings);
|
|
446
487
|
}
|
|
447
488
|
catch (error) {
|
|
448
489
|
const errorMessage = error instanceof Error ? error.message : 'Failed to load settings from API';
|
|
449
|
-
storeState
|
|
450
|
-
...
|
|
490
|
+
storeState = {
|
|
491
|
+
...storeState,
|
|
451
492
|
syncStatus: 'error',
|
|
452
493
|
syncError: errorMessage
|
|
453
|
-
}
|
|
494
|
+
};
|
|
454
495
|
throw error;
|
|
455
496
|
}
|
|
456
497
|
}
|
|
@@ -480,12 +521,12 @@ export function onSettingsChange(callback) {
|
|
|
480
521
|
export async function initializeSettings(options) {
|
|
481
522
|
// Apply custom defaults if provided
|
|
482
523
|
if (options?.defaults) {
|
|
483
|
-
const currentSettings =
|
|
524
|
+
const currentSettings = getSettings();
|
|
484
525
|
const withDefaults = deepMergeSettings(currentSettings, options.defaults);
|
|
485
|
-
storeState
|
|
486
|
-
...
|
|
526
|
+
storeState = {
|
|
527
|
+
...storeState,
|
|
487
528
|
settings: withDefaults
|
|
488
|
-
}
|
|
529
|
+
};
|
|
489
530
|
saveToStorage(withDefaults);
|
|
490
531
|
}
|
|
491
532
|
// Initialize theme system
|
|
@@ -497,7 +538,7 @@ export async function initializeSettings(options) {
|
|
|
497
538
|
}
|
|
498
539
|
catch {
|
|
499
540
|
// Silently fail - local settings are still available
|
|
500
|
-
|
|
541
|
+
logger.warn('Failed to sync settings from API on initialization');
|
|
501
542
|
}
|
|
502
543
|
}
|
|
503
544
|
}
|