fix: svelte settings Sync

This commit is contained in:
sethburkart123
2024-09-04 09:42:07 +10:00
parent e4ba89073c
commit c008b32efa
15 changed files with 220 additions and 233 deletions
+2 -2
View File
@@ -54,7 +54,7 @@
"@codemirror/lang-less": "^6.0.2", "@codemirror/lang-less": "^6.0.2",
"@heroicons/react": "^2.1.3", "@heroicons/react": "^2.1.3",
"@million/lint": "latest", "@million/lint": "latest",
"@sveltejs/vite-plugin-svelte": "^3.1.2", "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@tsconfig/svelte": "^5.0.4", "@tsconfig/svelte": "^5.0.4",
"@types/color": "^3.0.6", "@types/color": "^3.0.6",
@@ -88,7 +88,7 @@
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"sortablejs": "^1.15.2", "sortablejs": "^1.15.2",
"svelte": "^4.2.19", "svelte": "^5.0.0-next.243",
"svelte-hash-router": "^1.0.1", "svelte-hash-router": "^1.0.1",
"svelte-motion": "^0.12.2", "svelte-motion": "^0.12.2",
"swiper": "latest", "swiper": "latest",
+1
View File
@@ -48,6 +48,7 @@ var IsSEQTAPage = false
const hasSEQTAText = document.childNodes[1].textContent?.includes('Copyright (c) SEQTA Software') const hasSEQTAText = document.childNodes[1].textContent?.includes('Copyright (c) SEQTA Software')
init() init()
async function init() { async function init() {
CheckForMenuList() CheckForMenuList()
const hasSEQTATitle = document.title.includes('SEQTA Learn') const hasSEQTATitle = document.title.includes('SEQTA Learn')
+1 -1
View File
@@ -1,5 +1,5 @@
import browser from 'webextension-polyfill' import browser from 'webextension-polyfill'
import { SettingsState } from "@/types/storage"; import type { SettingsState } from "@/types/storage";
export const openDB = () => { export const openDB = () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -2,15 +2,18 @@ import browser from 'webextension-polyfill';
import type { SettingsState } from '@/types/storage'; import type { SettingsState } from '@/types/storage';
type ChangeListener = (newValue: any, oldValue: any) => void; type ChangeListener = (newValue: any, oldValue: any) => void;
type GlobalChangeListener = (newValue: any, oldValue: any, key: string) => void;
class StorageManager { class StorageManager {
private static instance: StorageManager; private static instance: StorageManager;
private data: SettingsState; private data: SettingsState;
private listeners: { [key: string]: ChangeListener[] }; private listeners: { [key: string]: ChangeListener[] };
private globalListeners: GlobalChangeListener[];
private constructor() { private constructor() {
this.data = {} as SettingsState; this.data = {} as SettingsState;
this.listeners = {}; this.listeners = {};
this.globalListeners = [];
this.loadFromStorage(); this.loadFromStorage();
const handler: ProxyHandler<StorageManager> = { const handler: ProxyHandler<StorageManager> = {
@@ -58,6 +61,11 @@ class StorageManager {
return instance; return instance;
} }
public setKey<K extends keyof SettingsState>(key: K, value: SettingsState[K]): void {
this.data[key] = value;
this.saveToStorage();
}
private async loadFromStorage(): Promise<void> { private async loadFromStorage(): Promise<void> {
const result = await browser.storage.local.get(); const result = await browser.storage.local.get();
this.data = { ...this.data, ...result }; this.data = { ...this.data, ...result };
@@ -85,6 +93,9 @@ class StorageManager {
listener(newValue, oldValue); listener(newValue, oldValue);
} }
} }
for (const listener of this.globalListeners) {
listener(newValue, oldValue, key);
}
} }
} }
}); });
@@ -101,6 +112,22 @@ class StorageManager {
} }
this.listeners[prop].push(listener); this.listeners[prop].push(listener);
} }
/**
* Register a listener for any setting.
* @param listener The listener to call when any setting changes -> takes two arguments, (newValue, oldValue)
*/
public registerGlobal(listener: GlobalChangeListener): void {
this.globalListeners.push(listener);
}
/**
* Get all settings.
* @returns All settings.
*/
public getAll(): SettingsState {
return this.data;
}
} }
export const settingsState = StorageManager.getInstance(); export const settingsState = StorageManager.getInstance();
+35 -36
View File
@@ -1,64 +1,63 @@
<script> <script lang="ts">
import { settingsState } from '../state/SettingsState.ts';
import { animate, spring } from 'motion'; import { animate, spring } from 'motion';
import './Switch.css' import { onMount } from "svelte";
import { onMount } from "svelte"
import { delay } from "../../seqta/utils/delay"
export let setting; let { state, onChange } = $props<{ state: boolean, onChange: (newState: boolean) => void }>();
export let onChange = () => {}
let handle: HTMLElement | null = null;
const toggleSwitch = () => { const toggleSwitch = () => {
const newIsOn = !$settingsState[setting] onChange(!state);
onChange(newIsOn) };
}
$effect(() => {
console.log('state', state);
});
const springParams = { const springParams = {
type: 'spring',
stiffness: 700, stiffness: 700,
damping: 30, damping: 30,
} };
let handle; const animateSwitch = (enabled: boolean) => {
const animation = (enabled) => {
if (handle) { if (handle) {
animate( animate(
handle, handle,
{ x: enabled ? 20 : 0 },
{ {
x: enabled ? 24 : 0, easing: spring(springParams),
},
{
easing: spring({ stiffness: 500, damping: 30 })
}
)
} }
);
} }
};
$: ((enabled) => { // Trigger animation whenever state changes
if (handle) { $effect(() => animateSwitch(state));
animate(
handle,
{ x: enabled ? 24 : 0 },
{ easing: spring({ stiffness: 500, damping: 30 }) }
)
}
})($settingsState[setting])
onMount(() => {
// Initialize the position of the switch
animateSwitch(state);
});
</script> </script>
<div <div
id={setting}
class="flex w-14 p-1 cursor-pointer transition rounded-full dark:bg-[#38373D] bg-[#DDDDDD] switch" class="flex w-14 p-1 cursor-pointer transition rounded-full dark:bg-[#38373D] bg-[#DDDDDD] switch"
data-ison={$settingsState[setting]} data-ison={state}
on:click={toggleSwitch} onclick={toggleSwitch}
on:keydown={(e) => e.key === "Enter" && toggleSwitch()} onkeydown={(e) => e.key === "Enter" && toggleSwitch()}
role="switch" role="switch"
aria-checked={$settingsState[setting]} aria-checked={state}
tabindex="0" tabindex="0"
> >
<div <div
bind:this={handle} bind:this={handle}
class="w-6 h-6 bg-white dark:bg-[#FEFEFE] rounded-full drop-shadow-md" class="w-6 h-6 bg-white dark:bg-[#FEFEFE] rounded-full drop-shadow-md"
/> ></div>
</div> </div>
<style>
.dark .switch[data-ison="true"],
.switch[data-ison="true"] {
background-color: #30D259;
}
</style>
@@ -1,33 +1,41 @@
<script> <script lang="ts">
// @ts-expect-error umm idk
import { MotionDiv } from 'svelte-motion'; import { MotionDiv } from 'svelte-motion';
import { onMount, onDestroy } from 'svelte';
import { writable, derived } from 'svelte/store';
import './TabbedContainer.css'; import './TabbedContainer.css';
import type { Component } from 'svelte'
import { onMount } from 'svelte';
export let tabs = []; let { tabs } = $props<{ tabs: { title: string, Content: Component }[] }>();
let activeTab = $state(0);
let activeTab = writable(0); let hoveredTab = $state<number | null>(null);
const hoveredTab = writable(null); let containerRef: HTMLElement | null = null;
const position = writable(0); let tabWidth = $state(0);
let tabWidth = 0;
let containerRef;
const springTransition = { type: 'spring', stiffness: 250, damping: 25 }; const springTransition = { type: 'spring', stiffness: 250, damping: 25 };
// Calculate tabWidth dynamically based on tabs length const updateTabWidth = () => {
onMount(() => { tabWidth = tabs.length > 0 ? 100 / tabs.length : 0;
if (!containerRef) return;
containerRef.style.setProperty('--tab-width', `${tabWidth}%`);
};
const calcXPos = (index: number | null) => {
if (containerRef) { if (containerRef) {
return tabWidth * (index !== null ? index : activeTab) * containerRef.getBoundingClientRect().width / 100;
tabWidth = 100 / tabs.length;
document.documentElement.style.setProperty('--tab-width', `${tabWidth}%`);
calcXPos = (index) => tabWidth * (index !== null ? index : $activeTab) * (containerRef !== null ? containerRef.getBoundingClientRect().width : 0) / 100;
} }
return 0;
};
// Listen for messages $effect(() => {
const handleMessage = (event) => { calcXPos(hoveredTab);
});
onMount(() => {
updateTabWidth();
const handleMessage = (event: MessageEvent) => {
if (event.data === "popupClosed") { if (event.data === "popupClosed") {
activeTab.set(0); activeTab = 0;
} }
}; };
window.addEventListener("message", handleMessage); window.addEventListener("message", handleMessage);
@@ -37,23 +45,28 @@
}; };
}); });
let calcXPos = (index) => tabWidth * (index !== null ? index : $activeTab); /* $effect(() => {
if (tabs.length > 0) {
updateTabWidth();
}
}); */
</script> </script>
<div bind:this={containerRef} class="top-0 z-10 text-[0.875rem] pb-0.5 mx-4"> <div bind:this={containerRef} class="top-0 z-10 text-[0.875rem] pb-0.5 mx-4 tab-width-container">
<div class="hidden tab-width"></div> <div class="hidden tab-width"></div>
<div class="relative flex"> <div class="relative flex">
<MotionDiv <MotionDiv
class="absolute top-0 left-0 z-0 h-full bg-[#DDDDDD] dark:bg-[#38373D] tab-width rounded-full opacity-40" class="absolute top-0 left-0 z-0 h-full bg-[#DDDDDD] dark:bg-[#38373D] rounded-full opacity-40"
animate={{ x: calcXPos($hoveredTab) }} animate={{ x: calcXPos(hoveredTab) }}
style="width: var(--tab-width)"
transition={springTransition} transition={springTransition}
/> />
{#each tabs as { title }, index} {#each tabs as { title }, index}
<button <button
class="relative z-10 flex-1 px-4 py-2" class="relative z-10 flex-1 px-4 py-2"
on:click={() => activeTab.set(index)} onclick={() => activeTab = index}
on:mouseenter={() => hoveredTab.set(index)} onmouseenter={() => hoveredTab = index}
on:mouseleave={() => hoveredTab.set(null)} onmouseleave={() => hoveredTab = null}
> >
{title} {title}
</button> </button>
@@ -62,14 +75,14 @@
</div> </div>
<div class="h-full px-4 overflow-y-scroll overflow-x-clip"> <div class="h-full px-4 overflow-y-scroll overflow-x-clip">
<MotionDiv <MotionDiv
animate={{ x: `${-$activeTab * 100}%` }} animate={{ x: `${-activeTab * 100}%` }}
transition={springTransition} transition={springTransition}
> >
<div class="flex"> <div class="flex">
{#each tabs as { content }, index} {#each tabs as { Content }, index}
<div class="absolute w-full transition-opacity duration-300 pb-4 {$activeTab === index ? 'opacity-100' : 'opacity-0'}" <div class="absolute w-full transition-opacity duration-300 pb-4 {activeTab === index ? 'opacity-100' : 'opacity-0'}"
style="left: {index * 100}%;"> style="left: {index * 100}%;">
<svelte:component this={content} /> <Content />
</div> </div>
{/each} {/each}
</div> </div>
@@ -77,7 +90,7 @@
</div> </div>
<style> <style>
:root { .tab-width {
--tab-width: 0px; width: var(--tab-width);
} }
</style> </style>
+5 -4
View File
@@ -1,18 +1,19 @@
// @ts-expect-error - Svelte Hash Router is not typed (yet) // @ts-expect-error - Svelte Hash Router is not typed (yet)
import { routes } from 'svelte-hash-router' import { routes } from 'svelte-hash-router'
import App from './+layout.svelte'; //import App from './+layout.svelte';
import Settings from './pages/settings.svelte'; import Settings from './pages/settings.svelte';
import styles from './index.css?inline'; import styles from './index.css?inline';
import { mount } from 'svelte';
export default function initSvelteInterface(shadow: ShadowRoot) { export default function initSvelteInterface(shadow: ShadowRoot) {
console.log(shadow) console.log(shadow)
routes.set({ /* routes.set({
'settings': Settings, 'settings': Settings,
'*': Settings '*': Settings
}) }) */
const app = new App({ const app = mount(Settings, {
target: shadow, target: shadow,
}); });
+5 -8
View File
@@ -11,13 +11,6 @@
}; };
let standalone = false; let standalone = false;
// Define the tabs array
const tabs = [
{ title: 'Settings', content: Settings },
{ title: 'Shortcuts', content: Shortcuts },
{ title: 'Themes', content: Theme },
];
</script> </script>
<div class="relative flex flex-col w-[384px] shadow-2xl gap-2 bg-white {standalone ? '' : 'rounded-xl'} h-[100vh] overflow-clip dark:bg-zinc-800 dark:text-white"> <div class="relative flex flex-col w-[384px] shadow-2xl gap-2 bg-white {standalone ? '' : 'rounded-xl'} h-[100vh] overflow-clip dark:bg-zinc-800 dark:text-white">
@@ -27,5 +20,9 @@
<button on:click={openChangelog} class="absolute w-8 h-8 text-lg rounded-xl font-IconFamily top-1 right-1 bg-zinc-100 dark:bg-zinc-700"></button> <button on:click={openChangelog} class="absolute w-8 h-8 text-lg rounded-xl font-IconFamily top-1 right-1 bg-zinc-100 dark:bg-zinc-700"></button>
</div> </div>
<!-- <Picker /> --> <!-- <Picker /> -->
<TabbedContainer {tabs} /> <TabbedContainer tabs={[
{ title: 'Settings', Content: Settings },
{ title: 'Shortcuts', Content: Shortcuts },
{ title: 'Themes', Content: Theme },
]} />
</div> </div>
@@ -1,66 +1,62 @@
<script lang="ts"> <script lang="ts">
import Switch from "../../components/Switch.svelte" import Switch from "../../components/Switch.svelte"
import Button from "../../components/Button.svelte" import Button from "../../components/Button.svelte"
import PickerSwatch from "../../components/PickerSwatch.svelte" //import PickerSwatch from "../../components/PickerSwatch.svelte"
import Slider from "../../components/Slider.svelte" import Slider from "../../components/Slider.svelte"
import browser from "webextension-polyfill" import browser from "webextension-polyfill"
import type { SettingsList } from "../../types/SettingsProps" import type { SettingsList } from "../../types/SettingsProps"
import { setSettingsValue } from "../../state/SettingsState" import { createSettingsState } from "../../state/SettingsStore.svelte.ts"
const settingsStore = createSettingsState();
let test = $state(false);
const settings: SettingsList[] = [ const settings: SettingsList[] = [
{ {
title: "Transparency Effects", title: "Transparency Effects",
description: "Enables transparency effects on certain elements such as blur. (May impact battery life)", description: "Enables transparency effects on certain elements such as blur. (May impact battery life)",
id: 1, id: 1,
component: Switch, Component: Switch,
props: { props: {
state: 'transparencyEffects', /* state: $settingsStore.transparencyEffects,
onChange: (isOn: boolean) => setSettingsValue('transparencyEffects', isOn) onChange: (isOn: boolean) => settingsStore.setKey('transparencyEffects', isOn) */
state: test,
onChange: (isOn: boolean) => test = isOn
} }
}, },
{ {
title: "Animated Background", title: "Animated Background",
description: "Adds an animated background to BetterSEQTA. (May impact battery life)", description: "Adds an animated background to BetterSEQTA. (May impact battery life)",
id: 2, id: 2,
component: Switch, Component: Switch as any,
props: { props: {
state: 'animatedBackground', state: $settingsStore.animatedbk,
onChange: (isOn: boolean) => setSettingsValue('animatedBackground', isOn) onChange: (isOn: boolean) => settingsStore.setKey('animatedbk', isOn)
} }
}, },
{ {
title: "Animated Background Speed", title: "Animated Background Speed",
description: "Controls the speed of the animated background.", description: "Controls the speed of the animated background.",
id: 3, id: 3,
component: Slider, Component: Slider,
props: { props: {
state: 'animatedBackgroundSpeed', state: $settingsStore.bksliderinput,
onChange: (value: number) => setSettingsValue('animatedBackgroundSpeed', `${value}`) onChange: (value: number) => settingsStore.setKey('bksliderinput', `${value}`)
} }
}, },
{ /* {
title: "Custom Theme Colour", title: "Custom Theme Colour",
description: "Customise the overall theme colour of SEQTA Learn.", description: "Customise the overall theme colour of SEQTA Learn.",
id: 4, id: 4,
component: PickerSwatch Component: PickerSwatch
}, }, */
{
title: "Telemetry",
description: "Enables/disables error collecting.",
id: 5,
component: Switch,
props: {
state: 'telemetry',
onChange: (isOn: boolean) => setSettingsValue('telemetry', isOn)
}
},
{ {
title: "Edit Sidebar Layout", title: "Edit Sidebar Layout",
description: "Customise the sidebar layout.", description: "Customise the sidebar layout.",
id: 6, id: 6,
component: Button, Component: Button,
props: { props: {
onClick: () => browser.runtime.sendMessage({ type: 'currentTab', info: 'EditSidebar' }), onClick: () => browser.runtime.sendMessage({ type: 'currentTab', info: 'EditSidebar' }),
text: "Edit" text: "Edit"
@@ -70,49 +66,48 @@
title: "Notification Collector", title: "Notification Collector",
description: "Uncaps the 9+ limit for notifications, showing the real number.", description: "Uncaps the 9+ limit for notifications, showing the real number.",
id: 7, id: 7,
component: Switch, Component: Switch,
props: { props: {
state: 'notificationCollector', state: $settingsStore.notificationcollector,
onChange: (isOn: boolean) => setSettingsValue('notificationCollector', isOn) onChange: (isOn: boolean) => settingsStore.setKey('notificationcollector', isOn)
} }
}, },
{ {
title: "Lesson Alerts", title: "Lesson Alerts",
description: "Sends a native browser notification ~5 minutes prior to lessons.", description: "Sends a native browser notification ~5 minutes prior to lessons.",
id: 8, id: 8,
component: Switch, Component: Switch,
props: { props: {
state: 'lessonAlerts', state: $settingsStore.lessonalert,
onChange: (isOn: boolean) => setSettingsValue('lessonAlerts', isOn) onChange: (isOn: boolean) => settingsStore.setKey('lessonalert', isOn)
} }
}, },
{ {
title: "BetterSEQTA+", title: "BetterSEQTA+",
description: "Enables BetterSEQTA+ features", description: "Enables BetterSEQTA+ features",
id: 9, id: 9,
component: Switch, Component: Switch,
props: { props: {
state: 'betterSEQTAPlus', state: $settingsStore.onoff,
onChange: (isOn: boolean) => setSettingsValue('betterSEQTAPlus', isOn) onChange: (isOn: boolean) => settingsStore.setKey('onoff', isOn)
} }
} }
]; ];
</script> </script>
<div class="flex flex-col -mt-4 overflow-y-scroll divide-y divide-zinc-100 dark:divide-zinc-700"> <div class="flex flex-col -mt-4 overflow-y-scroll divide-y divide-zinc-100 dark:divide-zinc-700">
{#each settings as { title, description, component: Component, props, id } (id)} <Switch state={$settingsStore.DarkMode} onChange={(isOn: boolean) => settingsStore.setKey('DarkMode', isOn)} />
{#if settings}
{#each settings as { title, description, Component, props, id } (id)}
<div class="flex items-center justify-between px-4 py-3"> <div class="flex items-center justify-between px-4 py-3">
<div class="pr-4"> <div class="pr-4">
<h2 class="text-sm font-bold">{title}</h2> <h2 class="text-sm font-bold">{title}</h2>
<p class="text-xs">{description}</p> <p class="text-xs">{description}</p>
</div> </div>
<div> <div>
{#if props?.state !== undefined} <Component {...props} />
<svelte:component this={Component} {...props} bind:setting={props.state} />
{:else}
<svelte:component this={Component} {...props} />
{/if}
</div> </div>
</div> </div>
{/each} {/each}
{/if}
</div> </div>
@@ -1,91 +0,0 @@
import browser from "webextension-polyfill";
import type { MainConfig, SettingsState } from "../types/AppProps";
import { writable } from "svelte/store";
const initialState: SettingsState = {
notificationCollector: false,
lessonAlerts: false,
telemetry: false,
animatedBackground: false,
animatedBackgroundSpeed: '0',
customThemeColor: '',
betterSEQTAPlus: false,
shortcuts: [],
customshortcuts: [],
transparencyEffects: false,
theme: ''
};
const keyToStateMap: { [key: string]: string } = {
notificationcollector: 'notificationCollector',
lessonalert: 'lessonAlerts',
telemetry: 'telemetry',
animatedbk: 'animatedBackground',
bksliderinput: 'animatedBackgroundSpeed',
selectedColor: 'customThemeColor',
onoff: 'betterSEQTAPlus',
shortcuts: 'shortcuts',
customshortcuts: 'customshortcuts',
transparencyEffects: 'transparencyEffects'
};
const stateToKeyMap = Object.fromEntries(
Object.entries(keyToStateMap).map(([key, value]) => [value, key])
);
const storageChangeListener = async (changes: browser.Storage.StorageChange) => {
for (const [key, { newValue }] of Object.entries(changes)) {
const stateKey = keyToStateMap[key] || key;
if (stateKey === 'DarkMode') {
if (newValue) {
document.body.classList.add('dark');
} else {
document.body.classList.remove('dark');
}
}
settingsState.update((prevState) => ({ ...prevState, [stateKey]: newValue }));
}
}
const initialStorageLoad = async (storage: MainConfig) => {
for (const [key, value] of Object.entries(storage)) {
const stateKey = keyToStateMap[key] || key;
if (stateKey === 'DarkMode') {
if (value) {
document.body.classList.add('dark');
} else {
document.body.classList.remove('dark');
}
}
settingsState.update((prevState) => ({ ...prevState, [stateKey]: value }));
}
}
const settingsSubscription = (/* set: (value: SettingsState) => void */) => {
settingsState.subscribe((newState) => {
const stateToSave = Object.fromEntries(
Object.entries(newState).map(([key, value]) => [stateToKeyMap[key] || key, value])
);
browser.storage.local.set(stateToSave);
/* set(newState); */
});
}
export const initializeListeners = async () => {
const result = await browser.storage.local.get() as MainConfig;
await initialStorageLoad(result);
settingsSubscription();
browser.storage.onChanged.addListener(storageChangeListener);
}
export const settingsState = writable(initialState);
export const setSettingsValue = <K extends keyof SettingsState>(key: K, value: SettingsState[K]) => {
settingsState.update((prevState) => ({ ...prevState, [key]: value }));
}
@@ -0,0 +1,45 @@
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
import type { SettingsState } from '@/types/storage';
export function createSettingsState() {
let settings = $state<SettingsState>(settingsState);
const subscribers = new Set<(value: SettingsState) => void>();
// Register a global listener to notify subscribers on any change
settingsState.registerGlobal((newValue, oldValue, key) => {
console.log('Global listener triggered:', { newValue, oldValue, key });
if (newValue !== undefined) {
settings = { ...settings, [key]: newValue };
notifySubscribers(settings);
}
});
function notifySubscribers(newValue: SettingsState) {
console.log('Notifying subscribers with:', newValue);
subscribers.forEach(subscriber => subscriber(newValue));
}
return {
get settings() { return settings; },
set(newSettings: SettingsState) {
settings = newSettings;
notifySubscribers(settings);
},
setKey<K extends keyof SettingsState>(key: K, value: SettingsState[K]) {
settings[key] = value;
settingsState.setKey(key, value);
notifySubscribers(settings);
},
subscribe(callback: (value: SettingsState) => void) {
subscribers.add(callback);
// Immediately call the callback with the current value
callback(settings);
// Return an unsubscribe function
return () => {
subscribers.delete(callback);
};
}
};
}
+2 -2
View File
@@ -1,11 +1,11 @@
import type { SettingsState } from './AppProps'; import type { SettingsState } from './AppProps';
import { ComponentType } from 'svelte'; import type { Component } from 'svelte';
export interface SettingsList { export interface SettingsList {
title: string; title: string;
id: number; id: number;
description: string; description: string;
component: ComponentType; Component: Component;
props?: any; props?: any;
} }
export interface SettingsProps { export interface SettingsProps {
+2 -2
View File
@@ -9,7 +9,7 @@
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": false, "allowImportingTsExtensions": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": false, "noEmit": false,
@@ -25,5 +25,5 @@
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }
}, },
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte", "src/svelte-interface/+layout.sveltes"]
} }
+2 -2
View File
@@ -29,7 +29,7 @@ export default defineConfig({
base64Loader, base64Loader,
//react(), //react(),
svelte({ svelte({
emitCss: false, emitCss: false
}), }),
//million.vite({ auto: true }), //million.vite({ auto: true }),
//MillionLint.vite(), /* enable for testing and debugging performance */ //MillionLint.vite(), /* enable for testing and debugging performance */
@@ -54,7 +54,7 @@ export default defineConfig({
}, },
build: { build: {
outDir: resolve(__dirname, 'dist', mode), outDir: resolve(__dirname, 'dist', mode),
emptyOutDir: true, emptyOutDir: false,
minify: false, minify: false,
rollupOptions: { rollupOptions: {
input: { input: {