feat: add reader settings state and stylesheet generator
Settings are validated on read, not only on write: several go straight onto foliate's renderer as custom-element attributes, where a bad value wedges the layout silently rather than throwing. Unknown keys are stripped and missing ones filled from the defaults, so settings added later do not invalidate what a reader already has stored. The stylesheet is built as foliate's [before, after] pair. The paginator prepends the first to the section's <head> and appends the second, so the book's own CSS overrides the first and loses to the second. Typography goes in the first — a book that styles its own headings still gets to, and font size lands on <html> without !important so rem/em headings scale rather than being flattened. Colour goes in the second, because most EPUBs set a body background and would otherwise leave the page white against a dark UI. Font choices are reused from the app theme's FONT_STACKS rather than duplicated, so the reader cannot drift from the rest of the UI. Rename the ambient declaration to foliate-js.d.ts: as foliate.d.ts beside foliate.ts, TypeScript takes it for that file's emitted declaration, drops it from the program, and every $foliate import fails with TS2307.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
|
||||
import type { ReaderSettings } from '$lib/schema/reader';
|
||||
import {
|
||||
DEFAULT_READER_SETTINGS,
|
||||
loadReaderSettings,
|
||||
saveReaderSettings,
|
||||
toRendererAttributes
|
||||
} from '$lib/reader/settings';
|
||||
|
||||
export class ReaderSettingsState {
|
||||
settings = $state<ReaderSettings>(DEFAULT_READER_SETTINGS);
|
||||
|
||||
/** The half foliate takes as renderer attributes. */
|
||||
readonly attributes = $derived(toRendererAttributes(this.settings));
|
||||
|
||||
constructor() {
|
||||
// Defaults during SSR, real values once the browser has localStorage. The
|
||||
// reader only applies these after mount, so there is nothing to flash.
|
||||
if (browser) this.settings = loadReaderSettings();
|
||||
}
|
||||
|
||||
set<K extends keyof ReaderSettings>(key: K, value: ReaderSettings[K]) {
|
||||
this.settings = { ...this.settings, [key]: value };
|
||||
saveReaderSettings(this.settings);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.settings = DEFAULT_READER_SETTINGS;
|
||||
saveReaderSettings(this.settings);
|
||||
}
|
||||
}
|
||||
|
||||
const READER_SETTINGS_KEY = Symbol('READER_SETTINGS');
|
||||
|
||||
export function setReaderSettingsState() {
|
||||
return setContext(READER_SETTINGS_KEY, new ReaderSettingsState());
|
||||
}
|
||||
|
||||
export function getReaderSettingsState() {
|
||||
return getContext<ReturnType<typeof setReaderSettingsState>>(READER_SETTINGS_KEY);
|
||||
}
|
||||
Reference in New Issue
Block a user