Compare commits

..

1 Commits

Author SHA1 Message Date
Admin
bfd0ad8fb7 fix: chapter content vanishes — replace stale untrack snapshots with $derived
Some checks failed
Release / Test backend (push) Successful in 44s
Release / Check ui (push) Successful in 46s
Release / Docker / caddy (push) Successful in 48s
Release / Docker / backend (push) Successful in 2m53s
Release / Docker / runner (push) Successful in 2m58s
Release / Docker / ui (push) Successful in 4m58s
Release / Gitea Release (push) Has been cancelled
html and fetchingContent were captured with untrack() at mount time.
When SvelteKit re-ran the page load (triggered by the layout's settings PUT),
data.html updated but html stayed stale. The {#key} block in the layout then
destroyed and recreated the component, and on remount data.html was momentarily
empty so html became '' and the live-scrape fallback ran unnecessarily.

Fix:
- html is now $derived(scrapedHtml || data.html || '') — always tracks load
- scrapedHtml is a separate $state only set by the live-scrape fallback
- fetchingContent starts false; the fallback sets it true only when actually fetching
- translationStatus/translatingLang: dropped untrack() so they also react to re-runs
- Removed unused untrack import
2026-04-04 20:26:43 +05:00

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount, untrack, getContext } from 'svelte';
import { onMount, getContext } from 'svelte';
import { browser } from '$app/environment';
import { goto } from '$app/navigation';
import { page } from '$app/state';
@@ -11,8 +11,9 @@
let { data }: { data: PageData } = $props();
let html = $state(untrack(() => data.html));
let fetchingContent = $state(untrack(() => !data.isPreview && !data.html));
let scrapedHtml = $state(''); // only set by the live-preview fallback
let html = $derived(scrapedHtml || data.html || '');
let fetchingContent = $state(false);
let fetchError = $state('');
let audioProRequired = $state(false);
@@ -202,8 +203,8 @@
{ code: 'pt', label: 'PT' },
{ code: 'fr', label: 'FR' }
];
let translationStatus = $state(untrack(() => data.translationStatus ?? 'idle'));
let translatingLang = $state(untrack(() => data.lang ?? ''));
let translationStatus = $state(data.translationStatus ?? 'idle');
let translatingLang = $state(data.lang ?? '');
let pollingTimer: ReturnType<typeof setTimeout> | null = null;
function currentLang() {
@@ -293,6 +294,7 @@
// If the normal path returned no content, fall back to live preview scrape
if (!data.isPreview && !data.html) {
fetchingContent = true;
(async () => {
try {
const res = await fetch(
@@ -302,7 +304,7 @@
const d = (await res.json()) as { text?: string };
if (d.text) {
const { marked } = await import('marked');
html = await marked(d.text, { async: true });
scrapedHtml = await marked(d.text, { async: true });
} else {
fetchError = m.reader_audio_error();
}