fix(reader): authenticate book file fetch and inject reading theme colors

Books were failing to load because foliate-js fetches the file URL
without auth headers, getting rejected by JWT middleware. Also,
reading themes were not being applied because getCSS() didn't
inject background/text colors into the book iframe.

- Fetch book file with Bearer token, pass as File (not URL) to
  view.open() so foliate-js can detect format via filename extension
- Add reading theme class to body so foliate-themes.css activates
  the correct --reader-bg/--reader-text CSS variables
- Update getCSS() to read theme colors from outer page and embed
  them in the iframe CSS string (background-color, color, link
  color, selection color)
- Fix Alpine.start() deadlock: move call outside the alpine:init
  listener so Alpine actually initializes
- Remove unused tocItem from relocate handler destructuring
- Replace apiGet/apiPut with direct fetch in settings-manager to
  fix /api prefix mismatch (reader routes are at /readers/*, not
  /api/readers/*)
This commit is contained in:
2026-04-19 18:09:05 -04:00
parent 88c8fbc89d
commit 47e0e96ab8
2 changed files with 55 additions and 10 deletions
+22 -4
View File
@@ -1,4 +1,3 @@
import { apiGet, apiPut } from "../api";
import { getToken } from "../storage";
const LOCALSTORAGE_KEY = "reader_settings_local";
export async function loadSettings(): Promise<ReaderSettings> {
@@ -8,7 +7,12 @@ export async function loadSettings(): Promise<ReaderSettings> {
return local ? JSON.parse(local) : getDefaultSettings();
}
try {
const response = await apiGet("/readers/settings");
const response = await fetch("/readers/settings", {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
const settings = await response.json();
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(settings));
return settings;
@@ -28,7 +32,14 @@ export async function saveSettings(
return;
}
try {
await apiPut("/readers/settings", settings);
await fetch("/readers/settings", {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(settings),
});
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(updated));
} catch (error) {
localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(updated));
@@ -41,7 +52,14 @@ export async function syncSettings(): Promise<void> {
const token = getToken();
if (token) {
try {
await apiPut("/readers/settings", settings);
await fetch("/readers/settings", {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(settings),
});
} catch (error) {
console.error("Failed to sync settings:", error);
}