fix: offline-content renamed to downloads

This commit is contained in:
gosangam
2026-07-14 16:51:17 +05:30
parent 12a5c15121
commit 1683abc2e9
6 changed files with 39 additions and 27 deletions
@@ -1,7 +1,7 @@
"use client";
/**
* /offline-content — the reader's device-local offline library.
* /downloads — the reader's device-local offline library.
*
* Lists everything saved via the header's "Save offline" button and lets them
* open (offline-capable) or remove each item. Items link with a plain <a> (a
@@ -10,7 +10,7 @@
* fail. This page also doubles as the SW's offline navigation fallback.
*/
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState, useSyncExternalStore } from "react";
import {
BookOpen,
FileText,
@@ -67,33 +67,45 @@ function formatDate(ms: number): string {
}
}
export default function OfflineContentPage() {
// External-store readers for the two client-only, non-React values. Using
// useSyncExternalStore (instead of setState-in-an-effect) is SSR-safe and
// avoids the "setState synchronously within an effect" cascade warning.
function subscribeOnline(cb: () => void) {
window.addEventListener("online", cb);
window.addEventListener("offline", cb);
return () => {
window.removeEventListener("online", cb);
window.removeEventListener("offline", cb);
};
}
const noopSubscribe = () => () => {};
export default function DownloadsPage() {
const [items, setItems] = useState<OfflineItem[] | null>(null);
const [usage, setUsage] = useState<number | null>(null);
const [online, setOnline] = useState(true);
const [supported, setSupported] = useState(true);
// Client-only reads via external stores (SSR snapshot → server-safe default).
const online = useSyncExternalStore(
subscribeOnline,
() => navigator.onLine,
() => true,
);
const supported = useSyncExternalStore(
noopSubscribe,
() => offlineSupported(),
() => false,
);
const refresh = useCallback(async () => {
setItems(await listOffline());
setUsage(await usageBytes());
}, []);
// Load the library once mounted. The setState calls happen after an await
// (asynchronously), not synchronously in the effect body.
useEffect(() => {
if (!offlineSupported()) {
setSupported(false);
setItems([]);
return;
}
setOnline(navigator.onLine);
if (!offlineSupported()) return;
void refresh();
const on = () => setOnline(true);
const off = () => setOnline(false);
window.addEventListener("online", on);
window.addEventListener("offline", off);
return () => {
window.removeEventListener("online", on);
window.removeEventListener("offline", off);
};
}, [refresh]);
async function remove(key: string) {
+1 -1
View File
@@ -71,7 +71,7 @@ export default function SettingsPage() {
description="Pages and lectures you've saved to read or listen to without a connection. Saved on this device — open the library to remove downloads and free up space."
>
<ul className="divide-y divide-border">
<LegalLink href="/offline-content" label="Manage offline library" />
<LegalLink href="/downloads" label="Manage offline downloads" />
</ul>
</Section>