web: implement settings core
this was a torture
This commit is contained in:
parent
21e03a407c
commit
009a2cc863
6 changed files with 139 additions and 2 deletions
12
web/package-lock.json
generated
12
web/package-lock.json
generated
|
@ -11,7 +11,8 @@
|
|||
"dependencies": {
|
||||
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
||||
"@fontsource/ibm-plex-mono": "^5.0.13",
|
||||
"@tabler/icons-svelte": "^3.6.0"
|
||||
"@tabler/icons-svelte": "^3.6.0",
|
||||
"ts-deepmerge": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.5.0",
|
||||
|
@ -3048,6 +3049,15 @@
|
|||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-deepmerge": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.0.tgz",
|
||||
"integrity": "sha512-WZ/iAJrKDhdINv1WG6KZIGHrZDar6VfhftG1QJFpVbOYZMYJLJOvZOo1amictRXVdBXZIgBHKswMTXzElngprA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=14.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"dependencies": {
|
||||
"@fontsource-variable/noto-sans-mono": "^5.0.20",
|
||||
"@fontsource/ibm-plex-mono": "^5.0.13",
|
||||
"@tabler/icons-svelte": "^3.6.0"
|
||||
"@tabler/icons-svelte": "^3.6.0",
|
||||
"ts-deepmerge": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
|
42
web/src/lib/settings.ts
Normal file
42
web/src/lib/settings.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { readable, type Updater } from 'svelte/store';
|
||||
import { merge } from 'ts-deepmerge';
|
||||
|
||||
import type { RecursivePartial } from './types/generic';
|
||||
import type { CobaltSettings } from './types/settings';
|
||||
|
||||
import defaultSettings from "$lib/settings/defaults";
|
||||
|
||||
const writeToStorage = (settings: CobaltSettings) => {
|
||||
localStorage.setItem(
|
||||
"settings",
|
||||
JSON.stringify(settings)
|
||||
);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
const loadFromStorage = () => {
|
||||
const settings = localStorage.getItem('settings');
|
||||
if (!settings) {
|
||||
return writeToStorage(defaultSettings);
|
||||
}
|
||||
|
||||
return JSON.parse(settings) as CobaltSettings;
|
||||
}
|
||||
|
||||
let update: (_: Updater<CobaltSettings>) => void;
|
||||
|
||||
export default readable<CobaltSettings>(
|
||||
loadFromStorage(),
|
||||
(_, _update) => { update = _update }
|
||||
);
|
||||
|
||||
// update settings from outside
|
||||
export function updateSetting(settings: RecursivePartial<CobaltSettings>) {
|
||||
update((current) => {
|
||||
// deep merge partial type into full CobaltSettings type
|
||||
current = merge(current, settings) as CobaltSettings;
|
||||
|
||||
return writeToStorage(current);
|
||||
});
|
||||
}
|
35
web/src/lib/settings/defaults.ts
Normal file
35
web/src/lib/settings/defaults.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import type { CobaltSettings } from "$lib/types/settings";
|
||||
|
||||
const defaultSettings: CobaltSettings = {
|
||||
schemaVersion: 1,
|
||||
accessibility: {
|
||||
reduceAnimations: false,
|
||||
reduceTransparency: false
|
||||
},
|
||||
appearance: {
|
||||
theme: "auto"
|
||||
},
|
||||
general: {
|
||||
customProcessingEndpoint: "",
|
||||
seenOnboarding: false,
|
||||
seenSafetyWarning: false
|
||||
},
|
||||
save: {
|
||||
audioFormat: "mp3",
|
||||
disableMetadata: false,
|
||||
downloadMode: "auto",
|
||||
downloadPopup: true,
|
||||
filenameStyle: "classic",
|
||||
tiktokH265: false,
|
||||
tiktokFullAudio: false,
|
||||
twitterGif: false,
|
||||
videoQuality: "720",
|
||||
youtubeVideoCodec: "h264",
|
||||
youtubeDubBrowserLang: false
|
||||
},
|
||||
privacy: {
|
||||
trafficAnalytics: true
|
||||
}
|
||||
}
|
||||
|
||||
export default defaultSettings;
|
8
web/src/lib/types/generic.ts
Normal file
8
web/src/lib/types/generic.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
// more readable version of recursive partial taken from stackoverflow:
|
||||
// https://stackoverflow.com/a/51365037
|
||||
export type RecursivePartial<Type> = {
|
||||
[Key in keyof Type]?:
|
||||
Type[Key] extends (infer ElementType)[] ? RecursivePartial<ElementType>[] :
|
||||
Type[Key] extends object | undefined ? RecursivePartial<Type[Key]> :
|
||||
Type[Key];
|
||||
};
|
41
web/src/lib/types/settings.ts
Normal file
41
web/src/lib/types/settings.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
type CobaltSettingsAccessibility = {
|
||||
reduceAnimations: boolean,
|
||||
reduceTransparency: boolean,
|
||||
};
|
||||
|
||||
type CobaltSettingsAppearance = {
|
||||
theme: "auto" | "light" | "dark",
|
||||
};
|
||||
|
||||
type CobaltSettingsGeneral = {
|
||||
customProcessingEndpoint: string,
|
||||
seenOnboarding: boolean,
|
||||
seenSafetyWarning: boolean,
|
||||
};
|
||||
|
||||
type CobaltSettingsSave = {
|
||||
audioFormat: "best" | "mp3" | "ogg" | "wav" | "opus",
|
||||
disableMetadata: boolean,
|
||||
downloadMode: "auto" | "audio" | "mute",
|
||||
downloadPopup: boolean,
|
||||
filenameStyle: "classic" | "basic" | "pretty" | "nerdy",
|
||||
tiktokH265: boolean,
|
||||
tiktokFullAudio: boolean,
|
||||
twitterGif: boolean,
|
||||
videoQuality: "max" | "2160" | "1440" | "1080" | "720" | "360" | "240" | "144",
|
||||
youtubeVideoCodec: "h264" | "av1" | "vp9",
|
||||
youtubeDubBrowserLang: boolean,
|
||||
};
|
||||
|
||||
type CobaltSettingsPrivacy = {
|
||||
trafficAnalytics: boolean,
|
||||
};
|
||||
|
||||
export type CobaltSettings = {
|
||||
schemaVersion: number,
|
||||
accessibility: CobaltSettingsAccessibility,
|
||||
appearance: CobaltSettingsAppearance,
|
||||
general: CobaltSettingsGeneral,
|
||||
save: CobaltSettingsSave,
|
||||
privacy: CobaltSettingsPrivacy,
|
||||
};
|
Loading…
Reference in a new issue