Fully implement settings
This commit is contained in:
@@ -70,6 +70,7 @@
|
||||
scope="row"
|
||||
>
|
||||
</th>
|
||||
<!-- svelte-ignore a11y-autofocus -->
|
||||
<td
|
||||
bind:innerText={name}
|
||||
class:border-[3px]={!name}
|
||||
|
@@ -58,7 +58,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative flex flex-col flex-grow h-[95vh]" data-vaul-drawer-wrapper id="page">
|
||||
<div class="relative flex flex-col flex-grow h-[93vh] select-none" data-vaul-drawer-wrapper id="page">
|
||||
<div class="relative overflow-auto h-full shadow-md sm:rounded-lg">
|
||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
||||
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||
|
@@ -1,5 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { link, location } from "svelte-spa-router";
|
||||
import { faGear } from "@fortawesome/free-solid-svg-icons";
|
||||
import Fa from "svelte-fa";
|
||||
import Settings from "./Settings/Settings.svelte";
|
||||
Fa;
|
||||
|
||||
type Link = {
|
||||
label: string;
|
||||
@@ -38,6 +42,8 @@
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
let showModal = true;
|
||||
</script>
|
||||
|
||||
<header
|
||||
@@ -75,4 +81,12 @@
|
||||
{/each}
|
||||
</nav>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="absolute right-0 pt-4 pb-4 pr-8 pl-8 cursor-pointer" on:click={() => (showModal = true)}>
|
||||
<button>
|
||||
<Fa icon={faGear} scale={2} />
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<Settings bind:showModal />
|
||||
|
50
frontend/src/lib/components/Modal.svelte
Normal file
50
frontend/src/lib/components/Modal.svelte
Normal file
@@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
export let showModal: boolean;
|
||||
|
||||
let dialog: HTMLDialogElement;
|
||||
|
||||
$: if (dialog && showModal) dialog.showModal();
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<dialog
|
||||
bind:this={dialog}
|
||||
class="min-w-[40vw] rounded-lg border-0 p-0 bg-gray-800 text-white"
|
||||
on:close={() => (showModal = false)}
|
||||
on:click|self={() => dialog.close()}
|
||||
>
|
||||
<div class="p-6" on:click|stopPropagation>
|
||||
<slot name="header" />
|
||||
<hr class="my-2 border-gray-600" />
|
||||
<slot />
|
||||
<hr class="my-2 border-gray-600" />
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<style>
|
||||
dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
dialog[open] {
|
||||
animation: zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
@keyframes zoom {
|
||||
from {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
dialog[open]::backdrop {
|
||||
animation: fade 0.2s ease-out;
|
||||
}
|
||||
@keyframes fade {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
43
frontend/src/lib/components/Settings/Setting.svelte
Normal file
43
frontend/src/lib/components/Settings/Setting.svelte
Normal file
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { settingsStore } from "$lib/store/SettingsStore";
|
||||
import { SetSetting } from "$wails/main/App";
|
||||
import { toast } from "svelte-sonner";
|
||||
|
||||
export let key: string;
|
||||
export let setting: number;
|
||||
|
||||
let editSetting = String(setting);
|
||||
async function updateSetting() {
|
||||
const numSetting = parseInt(editSetting);
|
||||
if (isNaN(numSetting)) {
|
||||
console.log("Invalid setting, must be number");
|
||||
editSetting = String(setting);
|
||||
return;
|
||||
}
|
||||
const res = await SetSetting(key, numSetting);
|
||||
if (!res.success) {
|
||||
toast.error(`Failed to set setting with error ${res.error}`);
|
||||
editSetting = String(setting);
|
||||
return
|
||||
}
|
||||
setting = numSetting;
|
||||
settingsStore.update((store) => {
|
||||
// @ts-ignore
|
||||
store[key] = numSetting;
|
||||
return store;
|
||||
});
|
||||
toast.success(`Successfully set setting ${key} to ${numSetting}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center">
|
||||
<span class="w-[30vw] capitalize">{key}</span>
|
||||
<span
|
||||
contenteditable="true"
|
||||
on:focusout={updateSetting}
|
||||
class="w-[10vw] ml-2 p-1 border rounded bg-slate-900"
|
||||
bind:innerText={editSetting}
|
||||
></span>
|
||||
</div>
|
||||
</template>
|
17
frontend/src/lib/components/Settings/Settings.svelte
Normal file
17
frontend/src/lib/components/Settings/Settings.svelte
Normal file
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { settingsStore } from "$lib/store/SettingsStore";
|
||||
import Modal from "../Modal.svelte";
|
||||
import Setting from "./Setting.svelte";
|
||||
|
||||
export let showModal: boolean = false;
|
||||
</script>
|
||||
|
||||
<Modal bind:showModal>
|
||||
<h2 slot="header" class="select-none text-2xl font-bold">Settings</h2>
|
||||
|
||||
<div class="flex flex-2 flex-col gap-4 text-left text-xl">
|
||||
{#each Object.keys($settingsStore) as key}
|
||||
<Setting key={key} setting={$settingsStore[key]} />
|
||||
{/each}
|
||||
</div>
|
||||
</Modal>
|
@@ -2,6 +2,7 @@ import { type Writable, writable } from "svelte/store";
|
||||
import { main } from "$wails/models";
|
||||
import { GetFood } from "$wails/main/App";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { settingsStore } from "./SettingsStore";
|
||||
|
||||
async function createStore(): Promise<Writable<main.Food[]>> {
|
||||
let foods: main.Food[] = [];
|
||||
@@ -29,4 +30,10 @@ async function createStore(): Promise<Writable<main.Food[]>> {
|
||||
};
|
||||
}
|
||||
|
||||
export const foodStore = await createStore();
|
||||
const foodStore = await createStore();
|
||||
settingsStore.subscribe((settings) => {
|
||||
// @ts-ignore
|
||||
foodStore.refresh();
|
||||
});
|
||||
|
||||
export {foodStore}
|
||||
|
Reference in New Issue
Block a user