feat(web): add theme system with Obsidian, Paper, and Midnight themes
Three holistic design directions with CSS custom properties, a theme store persisted to localStorage, and a live switcher in both the header (cycle button) and settings page (card selector). Also fixes checkbox checkmark alignment and adds back navigation from settings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,25 @@
|
||||
<script>
|
||||
import '../app.css';
|
||||
import { themeStore } from '$lib/stores/theme.js';
|
||||
|
||||
// Subscribe to trigger initialization on mount (sets data-theme attribute)
|
||||
$: void $themeStore;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<!-- Prevent FOUC: apply theme before first paint -->
|
||||
{@html `<script>
|
||||
(function() {
|
||||
var t = localStorage.getItem('opal-theme');
|
||||
if (t && ['obsidian','paper','midnight'].includes(t)) {
|
||||
document.documentElement.dataset.theme = t;
|
||||
} else {
|
||||
document.documentElement.dataset.theme = 'obsidian';
|
||||
}
|
||||
})();
|
||||
</` + 'script>'}
|
||||
</svelte:head>
|
||||
|
||||
<div class="app">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import { authStore } from '$lib/stores/auth.js';
|
||||
import ThemeSwitcher from '$lib/components/ThemeSwitcher.svelte';
|
||||
import { syncStore } from '$lib/stores/sync.js';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Input from '$lib/components/ui/Input.svelte';
|
||||
@@ -75,8 +76,20 @@
|
||||
|
||||
<div class="page">
|
||||
<div class="container">
|
||||
<h1>Settings</h1>
|
||||
<div class="page-header">
|
||||
<a href="/" class="back-link" aria-label="Back to tasks">
|
||||
<svg class="back-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</a>
|
||||
<h1>Settings</h1>
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<h2>Theme</h2>
|
||||
<ThemeSwitcher mode="full" />
|
||||
</section>
|
||||
|
||||
{#if $authStore.isAuthenticated}
|
||||
<section class="section">
|
||||
<h2>Account</h2>
|
||||
@@ -153,6 +166,39 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
padding-top: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--text-secondary);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
background-color: var(--bg-tertiary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
background-color: var(--bg-primary);
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
Reference in New Issue
Block a user