feat(m5a): channel manager, tabbed settings panel, per-user sync status

Backend: /api/channels (list + PATCH priority/hidden + attach/detach user tags),
user-tag CRUD on /api/tags, /api/sync/my-status (per-user channel sync counts).
Frontend: feed|channels page nav (URL-synced) from the account menu; a slide-in
tabbed Settings panel (Appearance, Notifications=6b sound+duration, Sync status +
actions + admin pause/resume, Account); a channel manager with priority, hide,
per-channel user tags, sync badges and 'view in feed'. Notifications now honor the
configurable sound + auto-dismiss settings.
This commit is contained in:
npeter83 2026-06-11 20:45:48 +02:00
parent b8a8605797
commit a8822d3935
11 changed files with 1063 additions and 45 deletions

View file

@ -74,9 +74,19 @@ export function hasFilterParams(params: URLSearchParams): boolean {
return KEYS.some((k) => params.has(k));
}
/** Reflect the current filters into the address bar without adding history entries. */
export function syncUrl(f: FeedFilters): void {
const qs = filtersToParams(f).toString();
export type Page = "feed" | "channels";
export function readPage(): Page {
return new URLSearchParams(window.location.search).get("page") === "channels"
? "channels"
: "feed";
}
/** Reflect the current filters + page into the address bar without adding history entries. */
export function syncUrl(f: FeedFilters, page: Page = "feed"): void {
const params = filtersToParams(f);
if (page !== "feed") params.set("page", page);
const qs = params.toString();
const url = qs ? `${window.location.pathname}?${qs}` : window.location.pathname;
window.history.replaceState(null, "", url);
}