Publish menus from the browser instead of scp

The admin signs in with the shared password, creates a Menu Set, drops photos
into it (shrunk in the browser first), reorders Pages by dragging or with
up/down buttons, previews the Draft exactly as customers would see it, and
publishes it over the previous set. Restore and delete close the loop. Mutations
need a session, a same-origin request and a CSRF token derived from the session;
a Draft's media is served only to a session holder.
This commit is contained in:
tanshu committed 2026-09-22 21:22:26 +05:30
1 parent 9cb4021229
commit 58ecfa0dc3
14 files changed
+1824 -15

No files matched your search

+19 -5
View File
@@ -153,7 +153,8 @@ export function renderLanding(input: LandingInput): Html {
bodyClass: 'landing-page',
description: config.brand.tagline,
noindex: false,
script: false,
styles: [],
scripts: [],
body: html`<main class="landing">
<header class="masthead">
<h1 class="wordmark">${config.brand.name}</h1>
@@ -174,6 +175,8 @@ export interface SectionInput {
published: ReadonlySet<string>;
current: boolean;
archives: readonly StoredSet[];
/** Draft preview for the admin: adds a banner and skips the archive fold. */
preview: boolean;
}
export function renderSectionPage(input: SectionInput): Html {
@@ -186,14 +189,23 @@ export function renderSectionPage(input: SectionInput): Html {
${renderRail(config, section.slug, input.published)}
<div class="pour" aria-hidden="true"><span class="pour__fill" data-pour></span></div>
</header>
${input.preview
? html`<p class="notice notice--admin">
Preview of a Draft — customers cannot see this yet.
<a href="/admin/sets/${set.id}">Back to the editor</a>
</p>`
: ''}
<h2 class="section-heading">
<span class="section-heading__label">${set.manifest.label}</span>
<span class="section-heading__date">${setDateLabel(set.manifest)}</span>
</h2>
${input.current ? '' : html`<p class="notice">This is an older menu. <a href="${currentHref}">See the current menu</a>.</p>`}
${input.current || input.preview
? ''
: html`<p class="notice">This is an older menu. <a href="${currentHref}">See the current menu</a>.</p>`}
${renderPages(section, set.manifest.pages)}
<footer class="foot">
${renderPageIndex(total)} ${renderOlderMenus(section, input.archives, currentHref)}
${renderPageIndex(total)}
${input.preview ? '' : renderOlderMenus(section, input.archives, currentHref)}
</footer>
<button class="counter" type="button" data-counter hidden>
<span data-counter-current>1</span><span class="counter__total">/ ${total}</span>
@@ -205,7 +217,8 @@ export function renderSectionPage(input: SectionInput): Html {
bodyClass: 'section-page',
description: config.brand.tagline,
noindex: !input.current,
script: true,
styles: [],
scripts: ['/assets/app.js'],
body,
});
}
@@ -228,7 +241,8 @@ export function renderNotFound(config: SiteConfig, live: readonly SectionConfig[
bodyClass: 'landing-page',
description: null,
noindex: true,
script: false,
styles: [],
scripts: [],
body: html`<main class="landing">
<header class="masthead">
<h1 class="wordmark">${config.brand.name}</h1>