diff --git a/ui/src/lib/components/AudioPlayer.svelte b/ui/src/lib/components/AudioPlayer.svelte
index cc75479..8732444 100644
--- a/ui/src/lib/components/AudioPlayer.svelte
+++ b/ui/src/lib/components/AudioPlayer.svelte
@@ -875,6 +875,7 @@
diff --git a/ui/src/lib/components/ui/dialog/Dialog.svelte b/ui/src/lib/components/ui/dialog/Dialog.svelte
index c438585..b846c3d 100644
--- a/ui/src/lib/components/ui/dialog/Dialog.svelte
+++ b/ui/src/lib/components/ui/dialog/Dialog.svelte
@@ -18,6 +18,13 @@
}
}
+ function handleBackdropKeyDown(e: KeyboardEvent) {
+ if ((e.key === 'Enter' || e.key === ' ') && e.target === e.currentTarget) {
+ open = false;
+ onclose?.();
+ }
+ }
+
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape') {
open = false;
@@ -34,7 +41,9 @@
class="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm p-4"
role="dialog"
aria-modal="true"
+ tabindex="-1"
onclick={handleBackdropClick}
+ onkeydown={handleBackdropKeyDown}
>
{@render children?.()}
diff --git a/ui/src/lib/paraglide/messages.js b/ui/src/lib/paraglide/messages.js
index 608d20d..83a0d9d 100644
--- a/ui/src/lib/paraglide/messages.js
+++ b/ui/src/lib/paraglide/messages.js
@@ -1,4 +1,2 @@
/* eslint-disable */
-export * from './messages/_index.js'
-// enabling auto-import by exposing all messages as m
-export * as m from './messages/_index.js'
\ No newline at end of file
+export * from './messages/_index.js'
\ No newline at end of file
diff --git a/ui/src/routes/+layout.svelte b/ui/src/routes/+layout.svelte
index 73af50e..2c7fc83 100644
--- a/ui/src/routes/+layout.svelte
+++ b/ui/src/routes/+layout.svelte
@@ -54,8 +54,11 @@
let audioEl = $state
(null);
// ── Theme ──────────────────────────────────────────────────────────────
+ // svelte-ignore state_referenced_locally
let currentTheme = $state(data.settings?.theme ?? 'amber');
+ // svelte-ignore state_referenced_locally
let currentFontFamily = $state(data.settings?.fontFamily ?? 'system');
+ // svelte-ignore state_referenced_locally
let currentFontSize = $state(data.settings?.fontSize ?? 1.0);
// Expose theme + font state to child pages (e.g. profile picker)
diff --git a/ui/src/routes/admin/catalogue-tools/+page.svelte b/ui/src/routes/admin/catalogue-tools/+page.svelte
index bc1c311..e3b5284 100644
--- a/ui/src/routes/admin/catalogue-tools/+page.svelte
+++ b/ui/src/routes/admin/catalogue-tools/+page.svelte
@@ -4,6 +4,7 @@
let { data }: { data: PageData } = $props();
+ // svelte-ignore state_referenced_locally
const imgModels = data.imgModels ?? [];
// ── Config persistence ────────────────────────────────────────────────────────
diff --git a/ui/src/routes/admin/image-gen/+page.svelte b/ui/src/routes/admin/image-gen/+page.svelte
index a57b0e3..95c0ede 100644
--- a/ui/src/routes/admin/image-gen/+page.svelte
+++ b/ui/src/routes/admin/image-gen/+page.svelte
@@ -61,6 +61,7 @@
});
// ── Book autocomplete ────────────────────────────────────────────────────────
+ // svelte-ignore state_referenced_locally
const books: BookSummary[] = data.books ?? [];
let slugInput = $state('');
let slugFocused = $state(false);
@@ -144,6 +145,7 @@
let saveSuccess = $state(false);
// ── Model helpers ────────────────────────────────────────────────────────────
+ // svelte-ignore state_referenced_locally
const models: ImageModelInfo[] = data.models ?? [];
let coverModels = $derived(models.filter((m) => m.recommended_for.includes('cover')));
@@ -633,19 +635,19 @@
Reference image (optional, img2img)
{#if selectedBook?.cover && selectedModelInfo?.supports_ref}
-
+
{/if}
{#if referenceFile && referencePreviewUrl}
@@ -719,20 +721,20 @@
@@ -740,10 +742,10 @@
{#if referenceFile}
-
+
{strength.toFixed(2)}
-
0 = copy reference · 1 = ignore reference
@@ -797,7 +799,8 @@
diff --git a/ui/src/routes/books/[slug]/+page.svelte b/ui/src/routes/books/[slug]/+page.svelte
index c55bb40..54c18e5 100644
--- a/ui/src/routes/books/[slug]/+page.svelte
+++ b/ui/src/routes/books/[slug]/+page.svelte
@@ -20,7 +20,9 @@
let saving = $state(false);
// ── Ratings ───────────────────────────────────────────────────────────────
+ // svelte-ignore state_referenced_locally
let userRating = $state(data.userRating ?? 0);
+ // svelte-ignore state_referenced_locally
let ratingAvg = $state(data.ratingAvg ?? { avg: 0, count: 0 });
async function rate(r: number) {
diff --git a/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte b/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte
index 876337f..0dbbd02 100644
--- a/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte
+++ b/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte
@@ -204,7 +204,9 @@
{ code: 'pt', label: 'PT' },
{ code: 'fr', label: 'FR' }
];
+ // svelte-ignore state_referenced_locally
let translationStatus = $state(data.translationStatus ?? 'idle');
+ // svelte-ignore state_referenced_locally
let translatingLang = $state(data.lang ?? '');
let pollingTimer: ReturnType | null = null;
@@ -505,6 +507,7 @@
-
(settingsPanelOpen = false)}>
+
(settingsPanelOpen = false)}>
diff --git a/ui/src/routes/discover/+page.svelte b/ui/src/routes/discover/+page.svelte
index c160639..2f98c0d 100644
--- a/ui/src/routes/discover/+page.svelte
+++ b/ui/src/routes/discover/+page.svelte
@@ -34,10 +34,13 @@
}
let prefs = $state
(loadPrefs());
+ // svelte-ignore state_referenced_locally
let showOnboarding = $state(!prefs.onboarded);
// Onboarding temp state
+ // svelte-ignore state_referenced_locally
let tempGenres = $state([...prefs.genres]);
+ // svelte-ignore state_referenced_locally
let tempStatus = $state(prefs.status);
function finishOnboarding(skip = false) {
@@ -85,6 +88,7 @@
let voted = $state<{ slug: string; action: string } | null>(null); // last voted, for undo
let activeTab = $state<'discover' | 'history'>('discover');
+ // svelte-ignore state_referenced_locally
let votedBooks = $state(data.votedBooks ?? []);
// Keep in sync if server data refreshes
@@ -356,6 +360,7 @@
class="relative w-full max-w-md bg-(--color-surface-2) rounded-2xl border border-(--color-border) shadow-2xl overflow-hidden"
role="dialog"
aria-modal="true"
+ tabindex="-1"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
>
@@ -529,8 +534,10 @@
{#if currentBook}
+
(autoNext = !autoNext)}
class="shrink-0 relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-(--color-brand) focus:ring-offset-2 focus:ring-offset-(--color-surface) {autoNext ? 'bg-(--color-brand)' : 'bg-(--color-surface-3) border border-(--color-border)'}"
>