Consolidate MangaCircus app, scraper, and Compose baseline
This commit is contained in:
1 parent
cfb2d79103
commit
eef4ffa07c
103 files changed
+9316
-172
No files matched your search
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
// Two navigation levels; scraper tabs stay within their section, not another menu.
|
||||
const SETTINGS_SECTIONS = [
|
||||
{ id: 'user/reading', group: 'User', title: 'Reading', hint: 'Reader modes, page spacing and zoom.' },
|
||||
{ id: 'user/reading-time', group: 'User', title: 'Reading time & privacy', hint: 'Your clock, Reading Story and personal data.' },
|
||||
{ id: 'user/notifications', group: 'User', title: 'Notifications', hint: 'Chapter alerts and your optional webhook.' },
|
||||
{ id: 'user/account', group: 'User', title: 'Account', hint: 'Your account and password.' },
|
||||
{ id: 'admin/scraper', group: 'Admin', title: 'Scraper', hint: 'Live activity, downloads, update checks and sources.' },
|
||||
{ id: 'admin/library', group: 'Admin', title: 'Server & library', hint: 'Library location, scan status and maintenance.' },
|
||||
{ id: 'admin/users', group: 'Admin', title: 'Users & access', hint: 'Manage accounts, passwords and administrators.' },
|
||||
{ id: 'admin/collections', group: 'Admin', title: 'Collections & metadata', hint: 'Group manga and review their relationships.', href: 'collections.html' },
|
||||
{ id: 'admin/health', group: 'Admin', title: 'Service health', hint: 'Service status, incidents and recovery.', href: 'health.html' },
|
||||
];
|
||||
const SCRAPER_TABS = ['activity', 'queue', 'updates', 'sources'];
|
||||
|
||||
function settingsRoute(hash, admin) {
|
||||
const parts = String(hash || '').replace(/^#/, '').split('/');
|
||||
const candidate = parts.slice(0, 2).join('/'), tab = parts[2];
|
||||
const section = SETTINGS_SECTIONS.find(item => item.id === candidate && (admin || item.group === 'User'));
|
||||
return { id: section?.id || 'user/reading', tab: SCRAPER_TABS.includes(tab) ? tab : tab === 'hosters' ? 'sources' : 'activity' };
|
||||
}
|
||||
|
||||
function settingsShell(me, active = 'user/reading') {
|
||||
const main = $('main'); main.textContent = '';
|
||||
const nav = h('nav', { class: 'settings-menu', 'aria-label': 'Settings sections' });
|
||||
const links = new Map();
|
||||
for (const group of me.admin ? ['User', 'Admin'] : ['User']) {
|
||||
nav.append(h('div', { class: 'settings-menu-group' }, h('h2', {}, group),
|
||||
SETTINGS_SECTIONS.filter(section => section.group === group).map(section => {
|
||||
const link = h('a', { href: section.href || 'settings.html#' + section.id }, section.title);
|
||||
links.set(section.id, link);
|
||||
return link;
|
||||
})));
|
||||
}
|
||||
const crumb = h('p', { class: 'settings-breadcrumb muted small' });
|
||||
const title = h('h1', { tabindex: '-1' });
|
||||
const titleRow = h('div', { class: 'settings-title-row' }, title);
|
||||
const hint = h('p', { class: 'muted settings-hint' });
|
||||
const content = h('div', { class: 'settings-content' });
|
||||
main.append(h('div', { class: 'settings-layout' }, nav,
|
||||
h('div', { class: 'settings-workspace' }, crumb, titleRow, hint, content)));
|
||||
function select(id, focus = false) {
|
||||
const section = SETTINGS_SECTIONS.find(item => item.id === id);
|
||||
if (!section || (section.group === 'Admin' && !me.admin)) return;
|
||||
for (const [key, link] of links) {
|
||||
if (key === id) link.setAttribute('aria-current', 'page');
|
||||
else link.removeAttribute('aria-current');
|
||||
}
|
||||
crumb.textContent = 'Settings / ' + section.group;
|
||||
title.textContent = section.title;
|
||||
hint.textContent = section.hint;
|
||||
document.title = section.title + ' · Settings · MangaCircus';
|
||||
if (focus) title.focus({ preventScroll: true });
|
||||
}
|
||||
select(active);
|
||||
return { content, titleRow, select };
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined') module.exports = { SETTINGS_SECTIONS, SCRAPER_TABS, settingsRoute };
|
||||
Reference in new issue
Block a user