Set up web/ directory with complete frontend scaffolding: - Vue 3 + TypeScript + Vite with Tailwind CSS v4 - Vue Router with auth guard (redirects to /login when unauthenticated) - Pinia stores: auth, cookies, devices, settings - Axios HTTP client with token interceptor - Views: Login, Dashboard, Cookies, Devices, Settings - Vite dev server proxy to relay API on port 8100 - Headless UI and Heroicons dependencies Co-Authored-By: Paperclip <noreply@paperclip.ing>
93 lines
3.2 KiB
Vue
93 lines
3.2 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted } from "vue";
|
|
import { useSettingsStore } from "@/stores/settings";
|
|
|
|
const store = useSettingsStore();
|
|
|
|
onMounted(() => store.fetchSettings());
|
|
|
|
async function save() {
|
|
await store.updateSettings(store.settings);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-8">
|
|
<h2 class="text-2xl font-semibold text-gray-900">Settings</h2>
|
|
<p class="mt-1 text-sm text-gray-500">Configure sync and security settings</p>
|
|
|
|
<div class="mt-6 max-w-lg space-y-6">
|
|
<!-- Sync Settings -->
|
|
<section class="rounded-xl bg-white p-6 ring-1 ring-gray-200">
|
|
<h3 class="font-medium text-gray-900">Sync</h3>
|
|
<div class="mt-4 space-y-4">
|
|
<div class="flex items-center justify-between">
|
|
<label class="text-sm text-gray-700">Auto-sync</label>
|
|
<button
|
|
class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors"
|
|
:class="store.settings.autoSync ? 'bg-blue-600' : 'bg-gray-200'"
|
|
@click="store.settings.autoSync = !store.settings.autoSync"
|
|
>
|
|
<span
|
|
class="inline-block h-4 w-4 rounded-full bg-white transition-transform"
|
|
:class="store.settings.autoSync ? 'translate-x-6' : 'translate-x-1'"
|
|
/>
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-700">Sync interval (seconds)</label>
|
|
<input
|
|
:value="store.settings.syncIntervalMs / 1000"
|
|
type="number"
|
|
min="5"
|
|
max="300"
|
|
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"
|
|
@input="store.settings.syncIntervalMs = Number(($event.target as HTMLInputElement).value) * 1000"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Security Settings -->
|
|
<section class="rounded-xl bg-white p-6 ring-1 ring-gray-200">
|
|
<h3 class="font-medium text-gray-900">Security</h3>
|
|
<div class="mt-4 space-y-4">
|
|
<div>
|
|
<label class="block text-sm text-gray-700">Max devices</label>
|
|
<input
|
|
v-model.number="store.settings.maxDevices"
|
|
type="number"
|
|
min="1"
|
|
max="50"
|
|
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Appearance -->
|
|
<section class="rounded-xl bg-white p-6 ring-1 ring-gray-200">
|
|
<h3 class="font-medium text-gray-900">Appearance</h3>
|
|
<div class="mt-4">
|
|
<label class="block text-sm text-gray-700">Theme</label>
|
|
<select
|
|
v-model="store.settings.theme"
|
|
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"
|
|
>
|
|
<option value="system">System</option>
|
|
<option value="light">Light</option>
|
|
<option value="dark">Dark</option>
|
|
</select>
|
|
</div>
|
|
</section>
|
|
|
|
<button
|
|
class="w-full rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
|
|
@click="save"
|
|
>
|
|
Save Settings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|