From c6d1299a101731f824f8dc9a98c3787df02ba95c Mon Sep 17 00:00:00 2001 From: Joery <44531907+Joery-M@users.noreply.github.com> Date: Fri, 21 Jun 2024 17:04:20 +0200 Subject: [PATCH 01/18] Start on settings manager --- packages/safelight/src/App.vue | 5 + .../src/components/Menu/Settings/Settings.vue | 23 +++ .../Menu/Settings/SettingsNamespaceItem.vue | 30 ++++ packages/safelight/src/main.ts | 2 + .../safelight/src/views/Editor/Editor.vue | 33 +++- .../shared/src/Settings/SettingsManager.ts | 165 ++++++++++++++++++ 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 packages/safelight/src/components/Menu/Settings/Settings.vue create mode 100644 packages/safelight/src/components/Menu/Settings/SettingsNamespaceItem.vue create mode 100644 packages/shared/src/Settings/SettingsManager.ts diff --git a/packages/safelight/src/App.vue b/packages/safelight/src/App.vue index d1ca8fa6..1a2524d1 100644 --- a/packages/safelight/src/App.vue +++ b/packages/safelight/src/App.vue @@ -1,10 +1,13 @@ diff --git a/packages/safelight/src/components/Menu/Settings/Settings.vue b/packages/safelight/src/components/Menu/Settings/Settings.vue new file mode 100644 index 00000000..c7164230 --- /dev/null +++ b/packages/safelight/src/components/Menu/Settings/Settings.vue @@ -0,0 +1,23 @@ + + + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsNamespaceItem.vue b/packages/safelight/src/components/Menu/Settings/SettingsNamespaceItem.vue new file mode 100644 index 00000000..0e305b25 --- /dev/null +++ b/packages/safelight/src/components/Menu/Settings/SettingsNamespaceItem.vue @@ -0,0 +1,30 @@ + + + diff --git a/packages/safelight/src/main.ts b/packages/safelight/src/main.ts index 551cb9d7..f5e87a67 100644 --- a/packages/safelight/src/main.ts +++ b/packages/safelight/src/main.ts @@ -5,6 +5,7 @@ import App from './App.vue'; import PrimeVue, { type PrimeVueConfiguration } from 'primevue/config'; import ConfirmationService from 'primevue/confirmationservice'; +import DialogService from 'primevue/dialogservice'; import 'primevue/resources/primevue.min.css'; import 'primevue/resources/themes/aura-dark-amber/theme.css'; import Tooltip from 'primevue/tooltip'; @@ -27,6 +28,7 @@ app.use(PrimeVue, { ripple: false } as PrimeVueConfiguration); app.use(ConfirmationService); +app.use(DialogService); // Phosphor icons app.provide('size', 18); diff --git a/packages/safelight/src/views/Editor/Editor.vue b/packages/safelight/src/views/Editor/Editor.vue index 898f830d..8a5b1743 100644 --- a/packages/safelight/src/views/Editor/Editor.vue +++ b/packages/safelight/src/views/Editor/Editor.vue @@ -8,7 +8,10 @@ }" > diff --git a/packages/shared/package.json b/packages/shared/package.json index 25e72928..c01b4bbf 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -16,14 +16,15 @@ "@vueuse/rxjs": "^10.10.0", "@vueuse/shared": "^10.10.0", "dexie": "^4.0.7", + "dot-path-value": "^0.0.10", "hash-wasm": "^4.11.0", "luxon": "^3.4.4", "mediainfo.js": "^0.3.1", "mime-matcher": "^1.0.5", + "primevue": "^3.52.0", "rxjs": "^7.8.1", "uuid": "^9.0.1", - "vue": "^3.4.29", - "primevue": "^3.52.0" + "vue": "^3.4.29" }, "devDependencies": { "@tsconfig/node20": "^20.1.4", diff --git a/packages/shared/src/Settings/SettingsManager.ts b/packages/shared/src/Settings/SettingsManager.ts index 4eac3add..8270d33c 100644 --- a/packages/shared/src/Settings/SettingsManager.ts +++ b/packages/shared/src/Settings/SettingsManager.ts @@ -1,4 +1,13 @@ -import { reactive } from 'vue'; +import { getByPath, setByPath } from 'dot-path-value'; +import { + computed, + defineAsyncComponent, + markRaw, + reactive, + type Component, + type ComputedRef, + type Raw +} from 'vue'; export class SettingsManager { private static defaultNamespaces: SettingsNamespaceDefinition[] = [ @@ -8,229 +17,27 @@ export class SettingsManager { childNamespaces: [] }, { - name: 'editor1', + name: 'editor', title: 'Editor', childNamespaces: [ { name: 'playback', title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'editor2', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'editor3', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'editor4', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'editor5', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', settings: [] - } - ] - }, - { - name: 'editor6', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', - settings: [ - { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' - } - ] }, { name: 'timeline', title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'editor7', - title: 'Editor', - childNamespaces: [ - { - name: 'playback', - title: 'Playback', settings: [ { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' + type: 'boolean', + name: 'useTrackpad', + title: 'Trackpad mode', + description: 'Will inverse the axes on which the timeline will scroll.', + default: false } ] }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, { name: 'media', title: 'Media', @@ -239,45 +46,24 @@ export class SettingsManager { ] }, { - name: 'editor8', - title: 'Editor', + name: 'keyboard', + title: 'Keyboard', childNamespaces: [ { - name: 'playback', - title: 'Playback', + name: 'hotkeys', + title: 'Hotkeys', settings: [ { - title: 'Bool 1', - description: 'AAAAAAAAfasf', - name: 'A', - type: 'boolean' - }, - { - title: 'Bool 2', - name: 'A', - type: 'boolean' + type: 'custom', + name: 'keybinds', + title: 'Hotkeys', + component: markRaw( + defineAsyncComponent( + () => import('../../../safelight/src/views/dev/Packages.vue') + ) + ) } ] - }, - { - name: 'timeline', - title: 'Timeline', - settings: [] - }, - { - name: 'media', - title: 'Media', - settings: [] - } - ] - }, - { - name: 'keyboard', - title: 'Keyboard', - childNamespaces: [ - { - name: 'hotkeys', - title: 'Hotkeys' } ] } @@ -285,9 +71,69 @@ export class SettingsManager { public static settingsDefinition = reactive(new Map()); + public static defaultSettings = reactive<{ [key: string]: any }>({}); + + public static currentSettings = reactive<{ [key: string]: any }>({}); + private static defaultsCreated = false; - public static createDefaultNamespaces(namespace = this.defaultNamespaces, path: string[] = []) { + public static setup() { + this.createDefaultNamespaces(this.defaultNamespaces, []); + this.createDefaultSettings(Array.from(this.settingsDefinition.values())); + } + + public static createNamespace(path: string[], namespace: SettingsNamespaceDefinition) { + const newNamespace = new SettingsNamespace(path, namespace); + if (path.length <= 1) { + this.settingsDefinition.set(path.join('.'), newNamespace); + } + + return newNamespace; + } + + public static getNamespace(path: string[]): SettingsNamespace | undefined; + public static getNamespace(path: string): SettingsNamespace | undefined; + public static getNamespace(path: string[] | string): SettingsNamespace | undefined { + const pathArray = Array.isArray(path) ? path : path.split('.'); + + // Loop through path array to find nested namespace + return pathArray.reduce((ns, path, curIndex) => { + if (!ns) return; + + const childNs = ns?.childNamespaces.find( + (ns) => ns.path == pathArray.slice(0, curIndex + 1).join('.') + ); + + return childNs ?? ns; + }, this.settingsDefinition.get(pathArray[0])); + } + + public static getSetting(path: string): ComputedRef; + public static getSetting(path: string[]): ComputedRef; + public static getSetting(path: string | string[]) { + const combinedPath = Array.isArray(path) ? path.join('.') : path; + + return computed(() => { + const currentValue = getByPath(this.currentSettings, combinedPath); + if (currentValue === undefined) { + console.log(currentValue); + return getByPath(this.defaultSettings, combinedPath); + } + return currentValue; + }); + } + + public static setSetting(path: string, value: any): void; + public static setSetting(path: string[], value: any): void; + public static setSetting(path: string | string[], value: any) { + const combinedPath = Array.isArray(path) ? path.join('.') : path; + setByPath(this.currentSettings, combinedPath, value); + } + + private static createDefaultNamespaces( + namespace: SettingsNamespaceDefinition[], + path: string[] + ) { if (this.defaultsCreated && path.length == 0) { this.defaultsCreated = true; return []; @@ -312,29 +158,52 @@ export class SettingsManager { return newNamespaces; } - public static createNamespace(path: string[], namespace: SettingsNamespaceDefinition) { - const newNamespace = new SettingsNamespace(path.join('.'), namespace); - this.settingsDefinition.set(path.join('.'), newNamespace); + /** + * Loop over each namespace and child namespaces to set the default settings + */ + private static createDefaultSettings(namespace?: SettingsNamespace[]) { + if (!namespace) return; - return newNamespace; + namespace.forEach((ns) => { + ns.setDefaultValues(); + this.createDefaultSettings(ns.childNamespaces); + }); } } export class SettingsNamespace { - public childNamespaces!: SettingsNamespace[]; + public path: string; public title: string; public description?: string; public name: string; + public childNamespaces!: SettingsNamespace[]; public settings: SettingsPropertyDefinition[]; + constructor( - public path: string, - private definition: SettingsNamespaceDefinition + public pathArray: string[], + definition: SettingsNamespaceDefinition ) { + this.path = pathArray.join('.'); this.title = definition.title; this.name = definition.name; this.description = definition.description; this.settings = definition.settings ?? []; } + + /** + * Set the default values of each setting in the namespace. + */ + public setDefaultValues() { + this.settings.forEach((setting) => { + if (setting.type !== 'group' && setting.default !== undefined) { + setByPath( + SettingsManager.defaultSettings, + [...this.pathArray, setting.name].join('.'), + setting.default + ); + } + }); + } } export interface SettingsNamespaceDefinition { @@ -346,13 +215,14 @@ export interface SettingsNamespaceDefinition { } export type SettingsPropertyDefinition = - | SettingsGroup | SettingsArrayProperty - | SettingsNumberProperty - | SettingsStringProperty + | SettingsBoolProperty + | SettingsCustomProperty | SettingsDictionaryProperty | SettingsEnumProperty - | SettingsBoolProperty; + | SettingsGroup + | SettingsNumberProperty + | SettingsStringProperty; interface DefaultSettingsProperty { type: string; @@ -404,6 +274,12 @@ export interface SettingsEnumProperty extends DefaultSettingsProperty { default?: any; } +export interface SettingsCustomProperty extends DefaultSettingsProperty { + type: 'custom'; + component: Raw; + default?: any; +} + export interface SettingsGroup { type: 'group'; title: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3549bbf7..c81ad910 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -307,6 +307,9 @@ importers: dexie: specifier: ^4.0.7 version: 4.0.7 + dot-path-value: + specifier: ^0.0.10 + version: 0.0.10 hash-wasm: specifier: ^4.11.0 version: 4.11.0 @@ -1985,7 +1988,7 @@ packages: pathe: 1.1.2 picocolors: 1.0.1 sirv: 2.0.4 - vitest: 1.6.0(@types/node@20.14.2)(@vitest/browser@1.6.0)(@vitest/ui@1.6.0) + vitest: 1.6.0(@vitest/browser@1.6.0)(@vitest/ui@1.6.0) dev: true /@vitest/utils@1.6.0: @@ -2857,6 +2860,10 @@ packages: esutils: 2.0.3 dev: true + /dot-path-value@0.0.10: + resolution: {integrity: sha512-MrVpDoFwk1xjeM0sGRuei7N3LQOylJ9iamgfxAQwPY0hPnDHL981hM/KpoQwFHMckgjZvJA0MyH7VN//ernFFA==} + dev: false + /dynamic-dedupe@0.3.0: resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} dependencies: From 991be9d7b7c6d9e1fa3e26302971b89180370692 Mon Sep 17 00:00:00 2001 From: Joery <44531907+Joery-M@users.noreply.github.com> Date: Sun, 23 Jun 2024 16:06:19 +0200 Subject: [PATCH 05/18] feat: Implemented basic UI for boolen setting --- .../Menu/Settings/NamespaceSettings.vue | 19 +++++++-- .../src/components/Menu/Settings/Settings.vue | 35 +++++++++++++---- .../SettingsProperties/ArraySetting.vue | 12 +++++- .../SettingsProperties/BooleanSetting.vue | 33 ++++++++++++++-- .../SettingsProperties/DictionarySetting.vue | 12 +++++- .../SettingsProperties/EnumSetting.vue | 12 +++++- .../SettingsProperties/NumberSetting.vue | 12 +++++- .../SettingsProperties/SettingsGroup.vue | 39 +++++++++++-------- .../SettingsProperties/StringSetting.vue | 12 +++++- .../safelight/src/views/Editor/Editor.vue | 4 +- 10 files changed, 146 insertions(+), 44 deletions(-) diff --git a/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue b/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue index a44607bf..60c336b0 100644 --- a/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue +++ b/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue @@ -1,5 +1,5 @@ @@ -23,5 +26,13 @@ const props = withDefaults(defineProps<{ path: string }>(), { path: () => 'general' }); -const currentSettings = computed(() => SettingsManager.settingsDefinition.get(props.path)); +const scrollContainer = ref(); + +const currentSettings = computed(() => SettingsManager.getNamespace(props.path)); + +watch(currentSettings, () => { + if (scrollContainer.value) { + scrollContainer.value.scrollTo(0, 0); + } +}); diff --git a/packages/safelight/src/components/Menu/Settings/Settings.vue b/packages/safelight/src/components/Menu/Settings/Settings.vue index 7ed2c8c5..f6859a8e 100644 --- a/packages/safelight/src/components/Menu/Settings/Settings.vue +++ b/packages/safelight/src/components/Menu/Settings/Settings.vue @@ -17,8 +17,8 @@ border-right-width: 1px; border-right-color: var(--color-border); " - > - + /> + @@ -32,24 +32,43 @@ const expandedKeys = ref({}); function onNodeSelect(data: TreeNode) { if (data.key) { - selectedPath.value = data.key; - if ((data.children ?? []).length > 0) { - expandedKeys.value = { ...expandedKeys.value, [data.key]: true }; + if ((SettingsManager.getNamespace(data.key)?.settings?.length ?? 0) > 0) { + selectedPath.value = data.key; + } + if (data.children && data.children.length > 0) { + expandedKeys.value = { [data.key]: true }; } } } const tree = computed(() => { - return (Array.from(SettingsManager.settingsDefinition.values()) as SettingsNamespace[]) - .filter((ns) => ns.path.split('.').length <= 1) - .map((ns) => mapSettingsNs(ns)); + return (Array.from(SettingsManager.settingsDefinition.values()) as SettingsNamespace[]).map( + (ns) => mapSettingsNs(ns) + ); }); function mapSettingsNs(ns: SettingsNamespace): TreeNode { return { key: ns.path, label: ns.title, + selectable: ns.settings?.length > 0 || ns.childNamespaces?.length > 0, children: ns.childNamespaces?.map(mapSettingsNs) } as TreeNode; } + + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/ArraySetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/ArraySetting.vue index 9fa3844c..0ff26570 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/ArraySetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/ArraySetting.vue @@ -1,3 +1,11 @@ - + - + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/BooleanSetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/BooleanSetting.vue index fa4d6aca..41e43c02 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/BooleanSetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/BooleanSetting.vue @@ -1,11 +1,36 @@ diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/DictionarySetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/DictionarySetting.vue index 9fa3844c..2fd3edd1 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/DictionarySetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/DictionarySetting.vue @@ -1,3 +1,11 @@ - + - + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/EnumSetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/EnumSetting.vue index 9fa3844c..960770d4 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/EnumSetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/EnumSetting.vue @@ -1,3 +1,11 @@ - + - + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/NumberSetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/NumberSetting.vue index 9fa3844c..8b805fc2 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/NumberSetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/NumberSetting.vue @@ -1,3 +1,11 @@ - + - + diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue index 8cdd424a..abc34a2d 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue @@ -1,35 +1,42 @@ diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/StringSetting.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/StringSetting.vue index 9fa3844c..6194b27f 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/StringSetting.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/StringSetting.vue @@ -1,3 +1,11 @@ - + - + diff --git a/packages/safelight/src/views/Editor/Editor.vue b/packages/safelight/src/views/Editor/Editor.vue index 9e11e978..1c5aa7f5 100644 --- a/packages/safelight/src/views/Editor/Editor.vue +++ b/packages/safelight/src/views/Editor/Editor.vue @@ -69,7 +69,7 @@ const menuItems: MenuItem[] = [ header: 'Settings', style: { width: '75vw', - height: '70vh' + height: '80vh' }, pt: { content: { style: { height: '100%' } } }, breakpoints: { @@ -77,7 +77,7 @@ const menuItems: MenuItem[] = [ '640px': '90vw' }, modal: true, - maximizable: true + draggable: false } }); } From 857d907d6309dfb48b4304960663e1ad0ecedee2 Mon Sep 17 00:00:00 2001 From: Joery <44531907+Joery-M@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:15:48 +0200 Subject: [PATCH 06/18] refactor: Updated for removing of autoimport Also fixed a build warning --- .../src/components/Menu/Settings/NamespaceSettings.vue | 3 ++- packages/safelight/src/components/Menu/Settings/Settings.vue | 2 ++ .../Menu/Settings/SettingsProperties/SettingsGroup.vue | 1 + packages/safelight/src/views/Editor/Editor.vue | 2 +- packages/safelight/src/views/dev/UI.vue | 1 + packages/safelight/src/views/dev/dev.vue | 1 + packages/timeline/src/Timeline.vue | 2 +- 7 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue b/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue index 60c336b0..ef4387dc 100644 --- a/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue +++ b/packages/safelight/src/components/Menu/Settings/NamespaceSettings.vue @@ -19,8 +19,9 @@ diff --git a/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue b/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue index 1f0e6c00..6d156520 100644 --- a/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue +++ b/packages/safelight/src/components/Menu/Settings/SettingsProperties/SettingsGroup.vue @@ -1,5 +1,8 @@