From 878b5586037da30c2e135b07f6ebc5855e0f935d Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:31:41 +0200 Subject: [PATCH 01/31] add emty settingsConfig.js --- src/features/settings/types/settingsConfig.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/features/settings/types/settingsConfig.js diff --git a/src/features/settings/types/settingsConfig.js b/src/features/settings/types/settingsConfig.js new file mode 100644 index 0000000..e69de29 From c387c1486f14b6921953e4c987c53aaec22225ec Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:32:51 +0200 Subject: [PATCH 02/31] feat(settings): add JSDoc type definitions for settings config --- src/features/settings/types/settingsConfig.js | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/features/settings/types/settingsConfig.js b/src/features/settings/types/settingsConfig.js index e69de29..c7a4135 100644 --- a/src/features/settings/types/settingsConfig.js +++ b/src/features/settings/types/settingsConfig.js @@ -0,0 +1,71 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * @typedef {'bool' | 'number' | 'string' | 'selection' | 'section'} SettingType + */ + +/** + * @typedef {Object} SelectionOption + * @property {string} name + * @property {string} i18n + */ + +/** + * @typedef {Object} BaseSettingConfig + * @property {SettingType} type + * @property {string} name + * @property {string} i18n + * @property {string} [description] + */ + +/** + * @typedef {BaseSettingConfig & { default: boolean }} BoolSettingConfig + */ + +/** + * @typedef {BaseSettingConfig & { default: number }} NumberSettingConfig + */ + +/** + * @typedef {BaseSettingConfig & { default: string }} StringSettingConfig + */ + +/** + * @typedef {BaseSettingConfig & { + * default: string | string[], + * allowMultiple: boolean, + * options: SelectionOption[] + * }} SelectionSettingConfig + */ + +/** + * @typedef {Object} SectionSettingConfig + * @property {'section'} type + * @property {string} name + * @property {string} [i18n] + * @property {string} [description] + * @property {SettingConfigEntry[]} content + */ + +/** + * @typedef {BoolSettingConfig | NumberSettingConfig | StringSettingConfig | SelectionSettingConfig | SectionSettingConfig} SettingConfigEntry + */ + +/** + * @typedef {Object} SettingsConfig + * @property {SettingConfigEntry[]} contents + */ \ No newline at end of file From 0d7814d65525923e1e9bce9b4ec9c5bd8173dd33 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:33:58 +0200 Subject: [PATCH 03/31] add emty settingsValidator.js --- src/features/settings/utils/settingsValidator.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/features/settings/utils/settingsValidator.js diff --git a/src/features/settings/utils/settingsValidator.js b/src/features/settings/utils/settingsValidator.js new file mode 100644 index 0000000..e69de29 From f6d72dbea3ebb0874bcb44fd7cbac2ff955ad1e8 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:34:14 +0200 Subject: [PATCH 04/31] feat(settings): add settings config validator --- .../settings/utils/settingsValidator.js | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/features/settings/utils/settingsValidator.js b/src/features/settings/utils/settingsValidator.js index e69de29..c699985 100644 --- a/src/features/settings/utils/settingsValidator.js +++ b/src/features/settings/utils/settingsValidator.js @@ -0,0 +1,101 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const VALID_TYPES = ['bool', 'number', 'string', 'selection', 'section']; + +function assertString(value, path) { + if (typeof value !== 'string' || value.trim() === '') { + throw new Error(`[settings] "${path}" must be a non-empty string`); + } +} + +function assertType(value, path) { + if (!VALID_TYPES.includes(value)) { + throw new Error( + `[settings] "${path}" has invalid type "${value}". Must be one of: ${VALID_TYPES.join(', ')}` + ); + } +} + +function validateSelectionOptions(options, path) { + if (!Array.isArray(options) || options.length === 0) { + throw new Error(`[settings] "${path}.options" must be a non-empty array`); + } + options.forEach((opt, i) => { + assertString(opt.name, `${path}.options[${i}].name`); + assertString(opt.i18n, `${path}.options[${i}].i18n`); + }); +} + +function validateEntry(entry, path) { + assertType(entry.type, `${path}.type`); + + if (entry.type === 'section') { + assertString(entry.name, `${path}.name`); + if (!Array.isArray(entry.content)) { + throw new Error(`[settings] "${path}.content" must be an array`); + } + entry.content.forEach((child, i) => + validateEntry(child, `${path}.content[${i}]`) + ); + return; + } + + assertString(entry.name, `${path}.name`); + assertString(entry.i18n, `${path}.i18n`); + + if (entry.default === undefined) { + throw new Error(`[settings] "${path}.default" is required`); + } + + if (entry.type === 'bool' && typeof entry.default !== 'boolean') { + throw new Error(`[settings] "${path}.default" must be a boolean`); + } + if (entry.type === 'number' && typeof entry.default !== 'number') { + throw new Error(`[settings] "${path}.default" must be a number`); + } + if (entry.type === 'string' && typeof entry.default !== 'string') { + throw new Error(`[settings] "${path}.default" must be a string`); + } + if (entry.type === 'selection') { + validateSelectionOptions(entry.options, path); + if (typeof entry.allowMultiple !== 'boolean') { + throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); + } + } +} + +/** + * Validates a raw settings config object. + * @param {unknown} raw + * @returns {{ valid: true, config: import('../types/settingsConfig').SettingsConfig } | { valid: false, error: string }} + */ +export function validateSettingsConfig(raw) { + try { + if (!raw || typeof raw !== 'object') { + throw new Error('[settings] Config must be an object'); + } + if (!Array.isArray(raw.contents)) { + throw new Error('[settings] "contents" must be an array'); + } + raw.contents.forEach((entry, i) => + validateEntry(entry, `contents[${i}]`) + ); + return { valid: true, config: raw }; + } catch (e) { + return { valid: false, error: e.message }; + } +} \ No newline at end of file From d09514f71f4bc95559a23d91fe75a00cbb1c89c8 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:34:40 +0200 Subject: [PATCH 05/31] add emtpy settingsParser.js --- src/features/settings/utils/settingsParser.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/features/settings/utils/settingsParser.js diff --git a/src/features/settings/utils/settingsParser.js b/src/features/settings/utils/settingsParser.js new file mode 100644 index 0000000..e69de29 From e376e9b36291c49de974495c426e860606a2d434 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:34:56 +0200 Subject: [PATCH 06/31] feat(settings): add settings config loader/parser --- src/features/settings/utils/settingsParser.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/features/settings/utils/settingsParser.js b/src/features/settings/utils/settingsParser.js index e69de29..0e05b9f 100644 --- a/src/features/settings/utils/settingsParser.js +++ b/src/features/settings/utils/settingsParser.js @@ -0,0 +1,43 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { validateSettingsConfig } from './settingsValidator.js'; + +/** + * Loads and parses the settings configuration from a JSON file. + * @param {string} [url='/settings.json'] + * @returns {Promise} + */ +export async function loadSettingsConfig(url = '/settings.json') { + let raw; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + raw = await response.json(); + } catch (e) { + throw new Error(`[settings] Failed to load config from "${url}": ${e.message}`); + } + + const result = validateSettingsConfig(raw); + if (!result.valid) { + throw new Error(result.error); + } + + return result.config; +} \ No newline at end of file From 1378813783a48f656069e9e1f408bf6f3fd74fe7 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:35:26 +0200 Subject: [PATCH 07/31] add emtpy useSettingsConfig.js --- src/features/settings/composables/useSettingsConfig.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/features/settings/composables/useSettingsConfig.js diff --git a/src/features/settings/composables/useSettingsConfig.js b/src/features/settings/composables/useSettingsConfig.js new file mode 100644 index 0000000..e69de29 From a165c13d7cce4ecb89482582e42eb76484db4193 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:35:35 +0200 Subject: [PATCH 08/31] feat(settings): add useSettingsConfig composable --- .../settings/composables/useSettingsConfig.js | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/features/settings/composables/useSettingsConfig.js b/src/features/settings/composables/useSettingsConfig.js index e69de29..0823203 100644 --- a/src/features/settings/composables/useSettingsConfig.js +++ b/src/features/settings/composables/useSettingsConfig.js @@ -0,0 +1,48 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { ref, readonly } from 'vue'; +import { loadSettingsConfig } from '../utils/settingsParser.js'; + +const config = ref(null); +const error = ref(null); +const loading = ref(false); + +/** + * Provides reactive access to the parsed settings configuration. + * The config is loaded once and shared across all consumers. + */ +export function useSettingsConfig() { + async function load(url = '/settings.json') { + loading.value = true; + error.value = null; + try { + config.value = await loadSettingsConfig(url); + } catch (e) { + error.value = e.message; + config.value = null; + } finally { + loading.value = false; + } + } + + return { + config: readonly(config), + error: readonly(error), + loading: readonly(loading), + load, + }; +} \ No newline at end of file From 37ca0baa6d69e5fb68cdd0685ffa03b18bddbf2b Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:36:26 +0200 Subject: [PATCH 09/31] add emty public/settings.json --- public/settings.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/settings.js diff --git a/public/settings.js b/public/settings.js new file mode 100644 index 0000000..e69de29 From aeb348fcfd8ff47b739b0100c007fb985a65dc21 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 11:37:34 +0200 Subject: [PATCH 10/31] feat(settings): add example settings.json to public/ --- public/settings.json | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 public/settings.json diff --git a/public/settings.json b/public/settings.json new file mode 100644 index 0000000..8a87a57 --- /dev/null +++ b/public/settings.json @@ -0,0 +1,55 @@ +{ + "contents": [ + { + "name": "general", + "type": "section", + "i18n": "preferences.settings.sections.general.name", + "description": "preferences.settings.sections.general.description", + "content": [ + { + "type": "bool", + "name": "darkMode", + "i18n": "preferences.darkMode", + "default": true + }, + { + "type": "selection", + "name": "language", + "i18n": "preferences.settings.language", + "description": "preferences.settings.language.description", + "default": "en", + "allowMultiple": false, + "options": [ + { + "name": "en", + "i18n": "preferences.locale.languages.en" + }, + { + "name": "de", + "i18n": "preferences.locale.languages.de" + } + ] + }, + { + "type": "section", + "name": "exampleSection", + "description": "preferences.settings.sections.exampleSection.description", + "content": [ + { + "type": "number", + "name": "aNumber", + "i18n": "preferences.settings.sections.exampleSection.content.aNumber", + "default": 42 + } + ] + } + ] + }, + { + "name": "exampleStandaloneConfiguration", + "type": "bool", + "i18n": "preferences.settings.exampleStandalone.name", + "default": false + } + ] +} \ No newline at end of file From 5d2064134b90ccd07bc131767142a0a29cdcb48b Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Tue, 26 May 2026 12:21:54 +0200 Subject: [PATCH 11/31] feat(settings): Make setting default value optional --- .../settings/utils/settingsValidator.js | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/features/settings/utils/settingsValidator.js b/src/features/settings/utils/settingsValidator.js index c699985..005024a 100644 --- a/src/features/settings/utils/settingsValidator.js +++ b/src/features/settings/utils/settingsValidator.js @@ -57,23 +57,21 @@ function validateEntry(entry, path) { assertString(entry.name, `${path}.name`); assertString(entry.i18n, `${path}.i18n`); - if (entry.default === undefined) { - throw new Error(`[settings] "${path}.default" is required`); - } - - if (entry.type === 'bool' && typeof entry.default !== 'boolean') { - throw new Error(`[settings] "${path}.default" must be a boolean`); - } - if (entry.type === 'number' && typeof entry.default !== 'number') { - throw new Error(`[settings] "${path}.default" must be a number`); - } - if (entry.type === 'string' && typeof entry.default !== 'string') { - throw new Error(`[settings] "${path}.default" must be a string`); - } - if (entry.type === 'selection') { - validateSelectionOptions(entry.options, path); - if (typeof entry.allowMultiple !== 'boolean') { - throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); + if (entry.default !== undefined) { + if (entry.type === 'bool' && typeof entry.default !== 'boolean') { + throw new Error(`[settings] "${path}.default" must be a boolean`); + } + if (entry.type === 'number' && typeof entry.default !== 'number') { + throw new Error(`[settings] "${path}.default" must be a number`); + } + if (entry.type === 'string' && typeof entry.default !== 'string') { + throw new Error(`[settings] "${path}.default" must be a string`); + } + if (entry.type === 'selection') { + validateSelectionOptions(entry.options, path); + if (typeof entry.allowMultiple !== 'boolean') { + throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); + } } } } From 462ae005069f0cb182f1e2f56e7b4c35c04461e8 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 14:49:10 +0200 Subject: [PATCH 12/31] feat(settings): move settings.json to src and remove example content --- public/settings.json | 55 ----------------------------- src/features/settings/settings.json | 3 ++ 2 files changed, 3 insertions(+), 55 deletions(-) delete mode 100644 public/settings.json create mode 100644 src/features/settings/settings.json diff --git a/public/settings.json b/public/settings.json deleted file mode 100644 index 8a87a57..0000000 --- a/public/settings.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "contents": [ - { - "name": "general", - "type": "section", - "i18n": "preferences.settings.sections.general.name", - "description": "preferences.settings.sections.general.description", - "content": [ - { - "type": "bool", - "name": "darkMode", - "i18n": "preferences.darkMode", - "default": true - }, - { - "type": "selection", - "name": "language", - "i18n": "preferences.settings.language", - "description": "preferences.settings.language.description", - "default": "en", - "allowMultiple": false, - "options": [ - { - "name": "en", - "i18n": "preferences.locale.languages.en" - }, - { - "name": "de", - "i18n": "preferences.locale.languages.de" - } - ] - }, - { - "type": "section", - "name": "exampleSection", - "description": "preferences.settings.sections.exampleSection.description", - "content": [ - { - "type": "number", - "name": "aNumber", - "i18n": "preferences.settings.sections.exampleSection.content.aNumber", - "default": 42 - } - ] - } - ] - }, - { - "name": "exampleStandaloneConfiguration", - "type": "bool", - "i18n": "preferences.settings.exampleStandalone.name", - "default": false - } - ] -} \ No newline at end of file diff --git a/src/features/settings/settings.json b/src/features/settings/settings.json new file mode 100644 index 0000000..1e36b85 --- /dev/null +++ b/src/features/settings/settings.json @@ -0,0 +1,3 @@ +{ + "contents": [] +} \ No newline at end of file From 035aa1aa77a3b3f1320a608658fef3a7500538fc Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 14:49:41 +0200 Subject: [PATCH 13/31] feat(settings): replace fetch with dynamic import for settings.json --- src/features/settings/utils/settingsParser.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/features/settings/utils/settingsParser.js b/src/features/settings/utils/settingsParser.js index 0e05b9f..2b7e658 100644 --- a/src/features/settings/utils/settingsParser.js +++ b/src/features/settings/utils/settingsParser.js @@ -17,21 +17,16 @@ limitations under the License. import { validateSettingsConfig } from './settingsValidator.js'; /** - * Loads and parses the settings configuration from a JSON file. - * @param {string} [url='/settings.json'] + * Loads and parses the settings configuration via dynamic import. * @returns {Promise} */ -export async function loadSettingsConfig(url = '/settings.json') { +export async function loadSettingsConfig() { let raw; try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - raw = await response.json(); + raw = (await import('../settings.json')).default; } catch (e) { - throw new Error(`[settings] Failed to load config from "${url}": ${e.message}`); + throw new Error(`[settings] Failed to load settings.json: ${e.message}`); } const result = validateSettingsConfig(raw); From 4ef6008976e4ef17589985b07d752595fb5d9718 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 14:50:23 +0200 Subject: [PATCH 14/31] feat(settings): default allowMultiple to false if not specified --- .../settings/utils/settingsValidator.js | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/features/settings/utils/settingsValidator.js b/src/features/settings/utils/settingsValidator.js index 005024a..c699985 100644 --- a/src/features/settings/utils/settingsValidator.js +++ b/src/features/settings/utils/settingsValidator.js @@ -57,21 +57,23 @@ function validateEntry(entry, path) { assertString(entry.name, `${path}.name`); assertString(entry.i18n, `${path}.i18n`); - if (entry.default !== undefined) { - if (entry.type === 'bool' && typeof entry.default !== 'boolean') { - throw new Error(`[settings] "${path}.default" must be a boolean`); - } - if (entry.type === 'number' && typeof entry.default !== 'number') { - throw new Error(`[settings] "${path}.default" must be a number`); - } - if (entry.type === 'string' && typeof entry.default !== 'string') { - throw new Error(`[settings] "${path}.default" must be a string`); - } - if (entry.type === 'selection') { - validateSelectionOptions(entry.options, path); - if (typeof entry.allowMultiple !== 'boolean') { - throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); - } + if (entry.default === undefined) { + throw new Error(`[settings] "${path}.default" is required`); + } + + if (entry.type === 'bool' && typeof entry.default !== 'boolean') { + throw new Error(`[settings] "${path}.default" must be a boolean`); + } + if (entry.type === 'number' && typeof entry.default !== 'number') { + throw new Error(`[settings] "${path}.default" must be a number`); + } + if (entry.type === 'string' && typeof entry.default !== 'string') { + throw new Error(`[settings] "${path}.default" must be a string`); + } + if (entry.type === 'selection') { + validateSelectionOptions(entry.options, path); + if (typeof entry.allowMultiple !== 'boolean') { + throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); } } } From 547bc241daa743162fb9ac84bc54cd9db369bca0 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 14:51:33 +0200 Subject: [PATCH 15/31] feat(settings): use type field as discriminant in JSDoc type definitions --- src/features/settings/types/settingsConfig.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/features/settings/types/settingsConfig.js b/src/features/settings/types/settingsConfig.js index c7a4135..db6db07 100644 --- a/src/features/settings/types/settingsConfig.js +++ b/src/features/settings/types/settingsConfig.js @@ -68,4 +68,13 @@ limitations under the License. /** * @typedef {Object} SettingsConfig * @property {SettingConfigEntry[]} contents + */ +/** + * @typedef {{ type: 'bool', name: string, i18n: string, description?: string, default: boolean }} BoolSettingConfig + * @typedef {{ type: 'number', name: string, i18n: string, description?: string, default: number }} NumberSettingConfig + * @typedef {{ type: 'string', name: string, i18n: string, description?: string, default: string }} StringSettingConfig + * @typedef {{ type: 'selection', name: string, i18n: string, description?: string, default: string | string[], allowMultiple?: boolean, options: SelectionOption[] }} SelectionSettingConfig + * @typedef {{ type: 'section', name: string, i18n?: string, description?: string, content: SettingConfigEntry[] }} SectionSettingConfig + * @typedef {BoolSettingConfig | NumberSettingConfig | StringSettingConfig | SelectionSettingConfig | SectionSettingConfig} SettingConfigEntry + * @typedef {{ contents: SettingConfigEntry[] }} SettingsConfig */ \ No newline at end of file From da76d14d15a681b3543d7bcc30fed9a59732d1e1 Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Tue, 26 May 2026 14:53:45 +0200 Subject: [PATCH 16/31] WIP --- public/settings.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 public/settings.js diff --git a/public/settings.js b/public/settings.js deleted file mode 100644 index e69de29..0000000 From 34a7cb3f2c0cbed745de8abedeb9d5a52819dbc7 Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Tue, 26 May 2026 19:51:45 +0200 Subject: [PATCH 17/31] feat(settings): Make setting default value optional --- .../settings/utils/settingsValidator.js | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/features/settings/utils/settingsValidator.js b/src/features/settings/utils/settingsValidator.js index c699985..ec30713 100644 --- a/src/features/settings/utils/settingsValidator.js +++ b/src/features/settings/utils/settingsValidator.js @@ -57,24 +57,22 @@ function validateEntry(entry, path) { assertString(entry.name, `${path}.name`); assertString(entry.i18n, `${path}.i18n`); - if (entry.default === undefined) { - throw new Error(`[settings] "${path}.default" is required`); - } - - if (entry.type === 'bool' && typeof entry.default !== 'boolean') { - throw new Error(`[settings] "${path}.default" must be a boolean`); - } - if (entry.type === 'number' && typeof entry.default !== 'number') { - throw new Error(`[settings] "${path}.default" must be a number`); - } - if (entry.type === 'string' && typeof entry.default !== 'string') { - throw new Error(`[settings] "${path}.default" must be a string`); - } - if (entry.type === 'selection') { - validateSelectionOptions(entry.options, path); - if (typeof entry.allowMultiple !== 'boolean') { - throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); - } + if (entry.default !== undefined) { + if (entry.type === 'bool' && typeof entry.default !== 'boolean') { + throw new Error(`[settings] "${path}.default" must be a boolean`); + } + if (entry.type === 'number' && typeof entry.default !== 'number') { + throw new Error(`[settings] "${path}.default" must be a number`); + } + if (entry.type === 'string' && typeof entry.default !== 'string') { + throw new Error(`[settings] "${path}.default" must be a string`); + } + if (entry.type === 'selection') { + validateSelectionOptions(entry.options, path); + if (typeof entry.allowMultiple !== 'boolean') { + throw new Error(`[settings] "${path}.allowMultiple" must be a boolean`); + } + } } } From b47ab0355ee853c54e5b69893cf4ebec22df0cea Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Tue, 26 May 2026 19:55:45 +0200 Subject: [PATCH 18/31] feat(settings): Remove parameter 'url' from the loading function of the settings composable --- src/features/settings/composables/useSettingsConfig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/settings/composables/useSettingsConfig.js b/src/features/settings/composables/useSettingsConfig.js index 0823203..06d4bd8 100644 --- a/src/features/settings/composables/useSettingsConfig.js +++ b/src/features/settings/composables/useSettingsConfig.js @@ -26,11 +26,11 @@ const loading = ref(false); * The config is loaded once and shared across all consumers. */ export function useSettingsConfig() { - async function load(url = '/settings.json') { + async function load() { loading.value = true; error.value = null; try { - config.value = await loadSettingsConfig(url); + config.value = await loadSettingsConfig(); } catch (e) { error.value = e.message; config.value = null; From 11800f6ef4bf800d9e7411acd6a397fcc44a8157 Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Tue, 26 May 2026 19:57:36 +0200 Subject: [PATCH 19/31] feat(settings): Remove old JSDoc typedefs --- src/features/settings/types/settingsConfig.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/features/settings/types/settingsConfig.js b/src/features/settings/types/settingsConfig.js index db6db07..d2ee124 100644 --- a/src/features/settings/types/settingsConfig.js +++ b/src/features/settings/types/settingsConfig.js @@ -32,18 +32,6 @@ limitations under the License. * @property {string} [description] */ -/** - * @typedef {BaseSettingConfig & { default: boolean }} BoolSettingConfig - */ - -/** - * @typedef {BaseSettingConfig & { default: number }} NumberSettingConfig - */ - -/** - * @typedef {BaseSettingConfig & { default: string }} StringSettingConfig - */ - /** * @typedef {BaseSettingConfig & { * default: string | string[], From 733bc2b16a31f9b0da4046a4ee53300eada53b3c Mon Sep 17 00:00:00 2001 From: "johannes.vos" Date: Thu, 28 May 2026 21:47:46 +0200 Subject: [PATCH 20/31] add class to link --- src/features/footer/components/Footer.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/footer/components/Footer.vue b/src/features/footer/components/Footer.vue index 89c8deb..b01452b 100644 --- a/src/features/footer/components/Footer.vue +++ b/src/features/footer/components/Footer.vue @@ -33,7 +33,7 @@ const copyrightPeriod =