@d34dman/flowdrop 0.0.44 → 0.0.46
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 +2 -2
- package/dist/components/ConfigForm.svelte +4 -20
- package/dist/components/Navbar.svelte +6 -7
- package/dist/components/NodeSidebar.svelte +6 -2
- package/dist/components/SchemaForm.svelte +2 -10
- package/dist/components/WorkflowEditor.svelte +143 -13
- package/dist/components/form/FormAutocomplete.svelte +5 -9
- package/dist/components/form/FormCheckboxGroup.svelte +11 -1
- package/dist/components/form/FormCheckboxGroup.svelte.d.ts +2 -0
- package/dist/components/form/FormCodeEditor.svelte +16 -7
- package/dist/components/form/FormCodeEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormField.svelte +20 -1
- package/dist/components/form/FormMarkdownEditor.svelte +29 -19
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormNumberField.svelte +4 -0
- package/dist/components/form/FormNumberField.svelte.d.ts +2 -0
- package/dist/components/form/FormRangeField.svelte +4 -0
- package/dist/components/form/FormRangeField.svelte.d.ts +2 -0
- package/dist/components/form/FormSelect.svelte +4 -0
- package/dist/components/form/FormSelect.svelte.d.ts +2 -0
- package/dist/components/form/FormTemplateEditor.svelte +16 -7
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +2 -0
- package/dist/components/form/FormTextField.svelte +4 -0
- package/dist/components/form/FormTextField.svelte.d.ts +2 -0
- package/dist/components/form/FormTextarea.svelte +4 -0
- package/dist/components/form/FormTextarea.svelte.d.ts +2 -0
- package/dist/components/form/FormToggle.svelte +4 -0
- package/dist/components/form/FormToggle.svelte.d.ts +2 -0
- package/dist/components/form/types.d.ts +5 -0
- package/dist/components/form/types.js +1 -1
- package/dist/components/layouts/MainLayout.svelte +5 -2
- package/dist/components/nodes/GatewayNode.svelte +99 -86
- package/dist/components/nodes/IdeaNode.svelte +20 -35
- package/dist/components/nodes/NotesNode.svelte +6 -2
- package/dist/components/nodes/SimpleNode.svelte +32 -31
- package/dist/components/nodes/SquareNode.svelte +35 -45
- package/dist/components/nodes/TerminalNode.svelte +25 -61
- package/dist/components/nodes/ToolNode.svelte +36 -18
- package/dist/components/nodes/WorkflowNode.svelte +97 -73
- package/dist/components/playground/Playground.svelte +43 -38
- package/dist/editor/index.d.ts +3 -1
- package/dist/editor/index.js +5 -1
- package/dist/helpers/nodeLayoutHelper.d.ts +14 -0
- package/dist/helpers/nodeLayoutHelper.js +19 -0
- package/dist/helpers/workflowEditorHelper.js +1 -2
- package/dist/services/autoSaveService.js +5 -5
- package/dist/services/historyService.d.ts +207 -0
- package/dist/services/historyService.js +317 -0
- package/dist/services/settingsService.d.ts +2 -2
- package/dist/services/settingsService.js +15 -21
- package/dist/services/toastService.d.ts +1 -1
- package/dist/services/toastService.js +10 -10
- package/dist/stores/historyStore.d.ts +133 -0
- package/dist/stores/historyStore.js +188 -0
- package/dist/stores/settingsStore.d.ts +1 -1
- package/dist/stores/settingsStore.js +40 -42
- package/dist/stores/themeStore.d.ts +2 -2
- package/dist/stores/themeStore.js +30 -32
- package/dist/stores/workflowStore.d.ts +52 -2
- package/dist/stores/workflowStore.js +102 -2
- package/dist/styles/base.css +67 -7
- package/dist/styles/toast.css +3 -1
- package/dist/styles/tokens.css +38 -2
- package/dist/types/settings.d.ts +3 -3
- package/dist/types/settings.js +13 -19
- package/dist/utils/colors.js +18 -18
- package/package.json +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History Store for FlowDrop
|
|
3
|
+
*
|
|
4
|
+
* Provides reactive Svelte store bindings for the history service.
|
|
5
|
+
* Exposes undo/redo state and actions for the workflow editor.
|
|
6
|
+
*
|
|
7
|
+
* @module stores/historyStore
|
|
8
|
+
*/
|
|
9
|
+
import { type HistoryState, type PushOptions } from '../services/historyService.js';
|
|
10
|
+
import type { Workflow } from '../types/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* Internal writable store for history state
|
|
13
|
+
*/
|
|
14
|
+
declare const historyStateStore: import("svelte/store").Writable<HistoryState>;
|
|
15
|
+
/**
|
|
16
|
+
* Reactive history state store
|
|
17
|
+
*
|
|
18
|
+
* Use this for binding to UI elements like undo/redo buttons.
|
|
19
|
+
* Subscribe using Svelte's $ prefix or the subscribe method.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```svelte
|
|
23
|
+
* <script>
|
|
24
|
+
* import { historyStateStore } from "./historyStore.js";
|
|
25
|
+
* </script>
|
|
26
|
+
*
|
|
27
|
+
* <button disabled={!$historyStateStore.canUndo} onclick={historyActions.undo}>
|
|
28
|
+
* Undo
|
|
29
|
+
* </button>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export { historyStateStore };
|
|
33
|
+
/**
|
|
34
|
+
* Derived store for canUndo state
|
|
35
|
+
*
|
|
36
|
+
* Convenience store that directly exposes the canUndo boolean.
|
|
37
|
+
*/
|
|
38
|
+
export declare const canUndo: import("svelte/store").Readable<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Derived store for canRedo state
|
|
41
|
+
*
|
|
42
|
+
* Convenience store that directly exposes the canRedo boolean.
|
|
43
|
+
*/
|
|
44
|
+
export declare const canRedo: import("svelte/store").Readable<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Set the callback for restoring workflow state
|
|
47
|
+
*
|
|
48
|
+
* This callback is invoked when undo/redo operations return a workflow.
|
|
49
|
+
* Use this to update the workflow store or other state management.
|
|
50
|
+
*
|
|
51
|
+
* @param callback - Function to call with restored workflow
|
|
52
|
+
*/
|
|
53
|
+
export declare function setOnRestoreCallback(callback: ((workflow: Workflow) => void) | null): void;
|
|
54
|
+
/**
|
|
55
|
+
* History actions for undo/redo operations
|
|
56
|
+
*
|
|
57
|
+
* Use these functions to interact with the history service.
|
|
58
|
+
* They handle the coordination between history and workflow state.
|
|
59
|
+
*/
|
|
60
|
+
export declare const historyActions: {
|
|
61
|
+
/**
|
|
62
|
+
* Initialize history with the current workflow
|
|
63
|
+
*
|
|
64
|
+
* Call this when loading a new workflow to reset history.
|
|
65
|
+
*
|
|
66
|
+
* @param workflow - The initial workflow state
|
|
67
|
+
*/
|
|
68
|
+
initialize: (workflow: Workflow) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Push the current state to history before making changes
|
|
71
|
+
*
|
|
72
|
+
* Call this BEFORE modifying the workflow to capture the "before" state.
|
|
73
|
+
*
|
|
74
|
+
* @param workflow - The current workflow state (before changes)
|
|
75
|
+
* @param options - Options for this history entry
|
|
76
|
+
*/
|
|
77
|
+
pushState: (workflow: Workflow, options?: PushOptions) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Undo the last change
|
|
80
|
+
*
|
|
81
|
+
* Restores the previous workflow state and invokes the restore callback.
|
|
82
|
+
*
|
|
83
|
+
* @returns true if undo was successful, false if at beginning of history
|
|
84
|
+
*/
|
|
85
|
+
undo: () => boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Redo the last undone change
|
|
88
|
+
*
|
|
89
|
+
* Restores the next workflow state and invokes the restore callback.
|
|
90
|
+
*
|
|
91
|
+
* @returns true if redo was successful, false if at end of history
|
|
92
|
+
*/
|
|
93
|
+
redo: () => boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Start a transaction for grouping multiple changes
|
|
96
|
+
*
|
|
97
|
+
* All changes during a transaction are combined into a single undo entry.
|
|
98
|
+
*
|
|
99
|
+
* @param workflow - The current workflow state (before changes)
|
|
100
|
+
* @param description - Description for the combined change
|
|
101
|
+
*/
|
|
102
|
+
startTransaction: (workflow: Workflow, description?: string) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Commit the current transaction
|
|
105
|
+
*/
|
|
106
|
+
commitTransaction: () => void;
|
|
107
|
+
/**
|
|
108
|
+
* Cancel the current transaction without committing
|
|
109
|
+
*/
|
|
110
|
+
cancelTransaction: () => void;
|
|
111
|
+
/**
|
|
112
|
+
* Clear all history
|
|
113
|
+
*
|
|
114
|
+
* @param currentWorkflow - If provided, keeps this as the initial state
|
|
115
|
+
*/
|
|
116
|
+
clear: (currentWorkflow?: Workflow) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Check if undo is available
|
|
119
|
+
*/
|
|
120
|
+
canUndo: () => boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Check if redo is available
|
|
123
|
+
*/
|
|
124
|
+
canRedo: () => boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Get the current history state synchronously
|
|
127
|
+
*
|
|
128
|
+
* @returns The current history state
|
|
129
|
+
*/
|
|
130
|
+
getState: () => HistoryState;
|
|
131
|
+
};
|
|
132
|
+
export type { HistoryEntry, HistoryState, PushOptions } from '../services/historyService.js';
|
|
133
|
+
export { HistoryService, historyService } from '../services/historyService.js';
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History Store for FlowDrop
|
|
3
|
+
*
|
|
4
|
+
* Provides reactive Svelte store bindings for the history service.
|
|
5
|
+
* Exposes undo/redo state and actions for the workflow editor.
|
|
6
|
+
*
|
|
7
|
+
* @module stores/historyStore
|
|
8
|
+
*/
|
|
9
|
+
import { writable, derived, get } from 'svelte/store';
|
|
10
|
+
import { historyService } from '../services/historyService.js';
|
|
11
|
+
// =========================================================================
|
|
12
|
+
// Reactive State Store
|
|
13
|
+
// =========================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Internal writable store for history state
|
|
16
|
+
*/
|
|
17
|
+
const historyStateStore = writable({
|
|
18
|
+
canUndo: false,
|
|
19
|
+
canRedo: false,
|
|
20
|
+
currentIndex: 0,
|
|
21
|
+
historyLength: 0,
|
|
22
|
+
isInTransaction: false
|
|
23
|
+
});
|
|
24
|
+
// Subscribe to history service changes and update the store
|
|
25
|
+
historyService.subscribe((state) => {
|
|
26
|
+
historyStateStore.set(state);
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Reactive history state store
|
|
30
|
+
*
|
|
31
|
+
* Use this for binding to UI elements like undo/redo buttons.
|
|
32
|
+
* Subscribe using Svelte's $ prefix or the subscribe method.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```svelte
|
|
36
|
+
* <script>
|
|
37
|
+
* import { historyStateStore } from "./historyStore.js";
|
|
38
|
+
* </script>
|
|
39
|
+
*
|
|
40
|
+
* <button disabled={!$historyStateStore.canUndo} onclick={historyActions.undo}>
|
|
41
|
+
* Undo
|
|
42
|
+
* </button>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export { historyStateStore };
|
|
46
|
+
/**
|
|
47
|
+
* Derived store for canUndo state
|
|
48
|
+
*
|
|
49
|
+
* Convenience store that directly exposes the canUndo boolean.
|
|
50
|
+
*/
|
|
51
|
+
export const canUndo = derived(historyStateStore, ($state) => $state.canUndo);
|
|
52
|
+
/**
|
|
53
|
+
* Derived store for canRedo state
|
|
54
|
+
*
|
|
55
|
+
* Convenience store that directly exposes the canRedo boolean.
|
|
56
|
+
*/
|
|
57
|
+
export const canRedo = derived(historyStateStore, ($state) => $state.canRedo);
|
|
58
|
+
// =========================================================================
|
|
59
|
+
// History Actions
|
|
60
|
+
// =========================================================================
|
|
61
|
+
/**
|
|
62
|
+
* Callback for when workflow state is restored from history
|
|
63
|
+
*
|
|
64
|
+
* Set this to handle the restored workflow state (e.g., update the workflow store)
|
|
65
|
+
*/
|
|
66
|
+
let onRestoreCallback = null;
|
|
67
|
+
/**
|
|
68
|
+
* Set the callback for restoring workflow state
|
|
69
|
+
*
|
|
70
|
+
* This callback is invoked when undo/redo operations return a workflow.
|
|
71
|
+
* Use this to update the workflow store or other state management.
|
|
72
|
+
*
|
|
73
|
+
* @param callback - Function to call with restored workflow
|
|
74
|
+
*/
|
|
75
|
+
export function setOnRestoreCallback(callback) {
|
|
76
|
+
onRestoreCallback = callback;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* History actions for undo/redo operations
|
|
80
|
+
*
|
|
81
|
+
* Use these functions to interact with the history service.
|
|
82
|
+
* They handle the coordination between history and workflow state.
|
|
83
|
+
*/
|
|
84
|
+
export const historyActions = {
|
|
85
|
+
/**
|
|
86
|
+
* Initialize history with the current workflow
|
|
87
|
+
*
|
|
88
|
+
* Call this when loading a new workflow to reset history.
|
|
89
|
+
*
|
|
90
|
+
* @param workflow - The initial workflow state
|
|
91
|
+
*/
|
|
92
|
+
initialize: (workflow) => {
|
|
93
|
+
historyService.initialize(workflow);
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Push the current state to history before making changes
|
|
97
|
+
*
|
|
98
|
+
* Call this BEFORE modifying the workflow to capture the "before" state.
|
|
99
|
+
*
|
|
100
|
+
* @param workflow - The current workflow state (before changes)
|
|
101
|
+
* @param options - Options for this history entry
|
|
102
|
+
*/
|
|
103
|
+
pushState: (workflow, options) => {
|
|
104
|
+
historyService.push(workflow, options);
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* Undo the last change
|
|
108
|
+
*
|
|
109
|
+
* Restores the previous workflow state and invokes the restore callback.
|
|
110
|
+
*
|
|
111
|
+
* @returns true if undo was successful, false if at beginning of history
|
|
112
|
+
*/
|
|
113
|
+
undo: () => {
|
|
114
|
+
const previousState = historyService.undo();
|
|
115
|
+
if (previousState && onRestoreCallback) {
|
|
116
|
+
onRestoreCallback(previousState);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return previousState !== null;
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Redo the last undone change
|
|
123
|
+
*
|
|
124
|
+
* Restores the next workflow state and invokes the restore callback.
|
|
125
|
+
*
|
|
126
|
+
* @returns true if redo was successful, false if at end of history
|
|
127
|
+
*/
|
|
128
|
+
redo: () => {
|
|
129
|
+
const nextState = historyService.redo();
|
|
130
|
+
if (nextState && onRestoreCallback) {
|
|
131
|
+
onRestoreCallback(nextState);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Start a transaction for grouping multiple changes
|
|
138
|
+
*
|
|
139
|
+
* All changes during a transaction are combined into a single undo entry.
|
|
140
|
+
*
|
|
141
|
+
* @param workflow - The current workflow state (before changes)
|
|
142
|
+
* @param description - Description for the combined change
|
|
143
|
+
*/
|
|
144
|
+
startTransaction: (workflow, description) => {
|
|
145
|
+
historyService.startTransaction(workflow, description);
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Commit the current transaction
|
|
149
|
+
*/
|
|
150
|
+
commitTransaction: () => {
|
|
151
|
+
historyService.commitTransaction();
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* Cancel the current transaction without committing
|
|
155
|
+
*/
|
|
156
|
+
cancelTransaction: () => {
|
|
157
|
+
historyService.cancelTransaction();
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* Clear all history
|
|
161
|
+
*
|
|
162
|
+
* @param currentWorkflow - If provided, keeps this as the initial state
|
|
163
|
+
*/
|
|
164
|
+
clear: (currentWorkflow) => {
|
|
165
|
+
historyService.clear(currentWorkflow);
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Check if undo is available
|
|
169
|
+
*/
|
|
170
|
+
canUndo: () => {
|
|
171
|
+
return historyService.canUndo();
|
|
172
|
+
},
|
|
173
|
+
/**
|
|
174
|
+
* Check if redo is available
|
|
175
|
+
*/
|
|
176
|
+
canRedo: () => {
|
|
177
|
+
return historyService.canRedo();
|
|
178
|
+
},
|
|
179
|
+
/**
|
|
180
|
+
* Get the current history state synchronously
|
|
181
|
+
*
|
|
182
|
+
* @returns The current history state
|
|
183
|
+
*/
|
|
184
|
+
getState: () => {
|
|
185
|
+
return get(historyStateStore);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
export { HistoryService, historyService } from '../services/historyService.js';
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module stores/settingsStore
|
|
11
11
|
*/
|
|
12
|
-
import type { FlowDropSettings, ThemeSettings, EditorSettings, UISettings, BehaviorSettings, ApiSettings, PartialSettings, SyncStatus, ResolvedTheme, ThemePreference, SettingsChangeCallback, SettingsCategory } from
|
|
12
|
+
import type { FlowDropSettings, ThemeSettings, EditorSettings, UISettings, BehaviorSettings, ApiSettings, PartialSettings, SyncStatus, ResolvedTheme, ThemePreference, SettingsChangeCallback, SettingsCategory } from '../types/settings.js';
|
|
13
13
|
/**
|
|
14
14
|
* Main settings store (read-only access to current settings)
|
|
15
15
|
*/
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module stores/settingsStore
|
|
11
11
|
*/
|
|
12
|
-
import { writable, derived, get } from
|
|
13
|
-
import { DEFAULT_SETTINGS, SETTINGS_STORAGE_KEY } from
|
|
12
|
+
import { writable, derived, get } from 'svelte/store';
|
|
13
|
+
import { DEFAULT_SETTINGS, SETTINGS_STORAGE_KEY } from '../types/settings.js';
|
|
14
14
|
// =========================================================================
|
|
15
15
|
// Internal State
|
|
16
16
|
// =========================================================================
|
|
@@ -32,7 +32,7 @@ const changeListeners = new Set();
|
|
|
32
32
|
* @returns Saved settings or null if not found/invalid
|
|
33
33
|
*/
|
|
34
34
|
function loadFromStorage() {
|
|
35
|
-
if (typeof window ===
|
|
35
|
+
if (typeof window === 'undefined') {
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
try {
|
|
@@ -44,7 +44,7 @@ function loadFromStorage() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
47
|
-
console.warn(
|
|
47
|
+
console.warn('Failed to load settings from localStorage:', error);
|
|
48
48
|
}
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
@@ -54,14 +54,14 @@ function loadFromStorage() {
|
|
|
54
54
|
* @param settings - Settings to persist
|
|
55
55
|
*/
|
|
56
56
|
function saveToStorage(settings) {
|
|
57
|
-
if (typeof window ===
|
|
57
|
+
if (typeof window === 'undefined') {
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
try {
|
|
61
61
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
|
-
console.warn(
|
|
64
|
+
console.warn('Failed to save settings to localStorage:', error);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
// =========================================================================
|
|
@@ -117,7 +117,7 @@ const initialSettings = loadFromStorage() ?? DEFAULT_SETTINGS;
|
|
|
117
117
|
const storeState = writable({
|
|
118
118
|
settings: initialSettings,
|
|
119
119
|
initialized: true,
|
|
120
|
-
syncStatus:
|
|
120
|
+
syncStatus: 'idle',
|
|
121
121
|
lastSyncedAt: null,
|
|
122
122
|
syncError: null
|
|
123
123
|
});
|
|
@@ -163,26 +163,24 @@ export const apiSettings = derived(settingsStore, ($settings) => $settings.api);
|
|
|
163
163
|
* System theme preference store
|
|
164
164
|
* Updates when system preference changes
|
|
165
165
|
*/
|
|
166
|
-
const systemTheme = writable(typeof window !==
|
|
166
|
+
const systemTheme = writable(typeof window !== 'undefined' ? getSystemTheme() : 'light');
|
|
167
167
|
/**
|
|
168
168
|
* Get the system's color scheme preference
|
|
169
169
|
*/
|
|
170
170
|
function getSystemTheme() {
|
|
171
|
-
if (typeof window ===
|
|
172
|
-
return
|
|
171
|
+
if (typeof window === 'undefined') {
|
|
172
|
+
return 'light';
|
|
173
173
|
}
|
|
174
|
-
return window.matchMedia(
|
|
175
|
-
? "dark"
|
|
176
|
-
: "light";
|
|
174
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
177
175
|
}
|
|
178
176
|
// Listen for system theme changes
|
|
179
|
-
if (typeof window !==
|
|
180
|
-
const mediaQuery = window.matchMedia(
|
|
177
|
+
if (typeof window !== 'undefined') {
|
|
178
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
181
179
|
const handleSystemThemeChange = (event) => {
|
|
182
|
-
systemTheme.set(event.matches ?
|
|
180
|
+
systemTheme.set(event.matches ? 'dark' : 'light');
|
|
183
181
|
};
|
|
184
182
|
if (mediaQuery.addEventListener) {
|
|
185
|
-
mediaQuery.addEventListener(
|
|
183
|
+
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
186
184
|
}
|
|
187
185
|
else {
|
|
188
186
|
// Fallback for older browsers
|
|
@@ -198,7 +196,7 @@ export const theme = derived(themeSettings, ($theme) => $theme.preference);
|
|
|
198
196
|
* Always returns the actual theme being applied ('light' or 'dark')
|
|
199
197
|
*/
|
|
200
198
|
export const resolvedTheme = derived([themeSettings, systemTheme], ([$themeSettings, $systemTheme]) => {
|
|
201
|
-
if ($themeSettings.preference ===
|
|
199
|
+
if ($themeSettings.preference === 'auto') {
|
|
202
200
|
return $systemTheme;
|
|
203
201
|
}
|
|
204
202
|
return $themeSettings.preference;
|
|
@@ -221,7 +219,7 @@ function notifyChange(category, key, previousValue, newValue) {
|
|
|
221
219
|
listener(event);
|
|
222
220
|
}
|
|
223
221
|
catch (error) {
|
|
224
|
-
console.error(
|
|
222
|
+
console.error('Settings change listener error:', error);
|
|
225
223
|
}
|
|
226
224
|
});
|
|
227
225
|
}
|
|
@@ -245,7 +243,7 @@ export function updateSettings(partial) {
|
|
|
245
243
|
// Notify listeners for each changed category
|
|
246
244
|
for (const category of Object.keys(partial)) {
|
|
247
245
|
const partialCategory = partial[category];
|
|
248
|
-
if (partialCategory && typeof partialCategory ===
|
|
246
|
+
if (partialCategory && typeof partialCategory === 'object') {
|
|
249
247
|
for (const key of Object.keys(partialCategory)) {
|
|
250
248
|
const prevCat = getCategoryAsRecord(previousSettings, category);
|
|
251
249
|
const newCat = getCategoryAsRecord(newSettings, category);
|
|
@@ -308,11 +306,11 @@ export function setTheme(newTheme) {
|
|
|
308
306
|
export function toggleTheme() {
|
|
309
307
|
const currentTheme = get(theme);
|
|
310
308
|
const currentResolved = get(resolvedTheme);
|
|
311
|
-
if (currentTheme ===
|
|
312
|
-
setTheme(currentResolved ===
|
|
309
|
+
if (currentTheme === 'auto') {
|
|
310
|
+
setTheme(currentResolved === 'dark' ? 'light' : 'dark');
|
|
313
311
|
}
|
|
314
312
|
else {
|
|
315
|
-
setTheme(currentTheme ===
|
|
313
|
+
setTheme(currentTheme === 'dark' ? 'light' : 'dark');
|
|
316
314
|
}
|
|
317
315
|
}
|
|
318
316
|
/**
|
|
@@ -321,14 +319,14 @@ export function toggleTheme() {
|
|
|
321
319
|
export function cycleTheme() {
|
|
322
320
|
const currentTheme = get(theme);
|
|
323
321
|
switch (currentTheme) {
|
|
324
|
-
case
|
|
325
|
-
setTheme(
|
|
322
|
+
case 'light':
|
|
323
|
+
setTheme('dark');
|
|
326
324
|
break;
|
|
327
|
-
case
|
|
328
|
-
setTheme(
|
|
325
|
+
case 'dark':
|
|
326
|
+
setTheme('auto');
|
|
329
327
|
break;
|
|
330
|
-
case
|
|
331
|
-
setTheme(
|
|
328
|
+
case 'auto':
|
|
329
|
+
setTheme('light');
|
|
332
330
|
break;
|
|
333
331
|
}
|
|
334
332
|
}
|
|
@@ -338,10 +336,10 @@ export function cycleTheme() {
|
|
|
338
336
|
* @param resolved - The resolved theme to apply
|
|
339
337
|
*/
|
|
340
338
|
function applyTheme(resolved) {
|
|
341
|
-
if (typeof document ===
|
|
339
|
+
if (typeof document === 'undefined') {
|
|
342
340
|
return;
|
|
343
341
|
}
|
|
344
|
-
document.documentElement.setAttribute(
|
|
342
|
+
document.documentElement.setAttribute('data-theme', resolved);
|
|
345
343
|
}
|
|
346
344
|
/**
|
|
347
345
|
* Initialize the theme system
|
|
@@ -373,12 +371,12 @@ export function setSettingsService(service) {
|
|
|
373
371
|
*/
|
|
374
372
|
export async function syncSettingsToApi() {
|
|
375
373
|
if (!settingsService) {
|
|
376
|
-
console.warn(
|
|
374
|
+
console.warn('Settings service not configured for API sync');
|
|
377
375
|
return;
|
|
378
376
|
}
|
|
379
377
|
storeState.update((state) => ({
|
|
380
378
|
...state,
|
|
381
|
-
syncStatus:
|
|
379
|
+
syncStatus: 'syncing',
|
|
382
380
|
syncError: null
|
|
383
381
|
}));
|
|
384
382
|
try {
|
|
@@ -386,16 +384,16 @@ export async function syncSettingsToApi() {
|
|
|
386
384
|
await settingsService.savePreferences(currentSettings);
|
|
387
385
|
storeState.update((state) => ({
|
|
388
386
|
...state,
|
|
389
|
-
syncStatus:
|
|
387
|
+
syncStatus: 'synced',
|
|
390
388
|
lastSyncedAt: Date.now(),
|
|
391
389
|
syncError: null
|
|
392
390
|
}));
|
|
393
391
|
}
|
|
394
392
|
catch (error) {
|
|
395
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
393
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to sync settings';
|
|
396
394
|
storeState.update((state) => ({
|
|
397
395
|
...state,
|
|
398
|
-
syncStatus:
|
|
396
|
+
syncStatus: 'error',
|
|
399
397
|
syncError: errorMessage
|
|
400
398
|
}));
|
|
401
399
|
throw error;
|
|
@@ -408,12 +406,12 @@ export async function syncSettingsToApi() {
|
|
|
408
406
|
*/
|
|
409
407
|
export async function loadSettingsFromApi() {
|
|
410
408
|
if (!settingsService) {
|
|
411
|
-
console.warn(
|
|
409
|
+
console.warn('Settings service not configured for API sync');
|
|
412
410
|
return;
|
|
413
411
|
}
|
|
414
412
|
storeState.update((state) => ({
|
|
415
413
|
...state,
|
|
416
|
-
syncStatus:
|
|
414
|
+
syncStatus: 'syncing',
|
|
417
415
|
syncError: null
|
|
418
416
|
}));
|
|
419
417
|
try {
|
|
@@ -422,7 +420,7 @@ export async function loadSettingsFromApi() {
|
|
|
422
420
|
storeState.update((state) => ({
|
|
423
421
|
...state,
|
|
424
422
|
settings: mergedSettings,
|
|
425
|
-
syncStatus:
|
|
423
|
+
syncStatus: 'synced',
|
|
426
424
|
lastSyncedAt: Date.now(),
|
|
427
425
|
syncError: null
|
|
428
426
|
}));
|
|
@@ -430,10 +428,10 @@ export async function loadSettingsFromApi() {
|
|
|
430
428
|
saveToStorage(mergedSettings);
|
|
431
429
|
}
|
|
432
430
|
catch (error) {
|
|
433
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
431
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to load settings from API';
|
|
434
432
|
storeState.update((state) => ({
|
|
435
433
|
...state,
|
|
436
|
-
syncStatus:
|
|
434
|
+
syncStatus: 'error',
|
|
437
435
|
syncError: errorMessage
|
|
438
436
|
}));
|
|
439
437
|
throw error;
|
|
@@ -482,7 +480,7 @@ export async function initializeSettings(options) {
|
|
|
482
480
|
}
|
|
483
481
|
catch {
|
|
484
482
|
// Silently fail - local settings are still available
|
|
485
|
-
console.warn(
|
|
483
|
+
console.warn('Failed to sync settings from API on initialization');
|
|
486
484
|
}
|
|
487
485
|
}
|
|
488
486
|
}
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* @module stores/themeStore
|
|
22
22
|
*/
|
|
23
23
|
/** Theme preference options */
|
|
24
|
-
export type ThemePreference =
|
|
24
|
+
export type ThemePreference = 'light' | 'dark' | 'auto';
|
|
25
25
|
/** Resolved theme (actual applied theme, never 'auto') */
|
|
26
|
-
export type ResolvedTheme =
|
|
26
|
+
export type ResolvedTheme = 'light' | 'dark';
|
|
27
27
|
/**
|
|
28
28
|
* User's theme preference store
|
|
29
29
|
* Can be 'light', 'dark', or 'auto'
|