diff options
| author | grm <grm@eyesin.space> | 2026-09-18 19:34:35 +0300 |
|---|---|---|
| committer | grm <grm@eyesin.space> | 2026-09-18 19:34:35 +0300 |
| commit | 96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f (patch) | |
| tree | e7851ddadf2ed776ab24a1bad4d446b7c48567db /AGENTS.md | |
| parent | 63f9fdff6e5bdf6333a4b7813ebeb5b797838b6d (diff) | |
| download | blogspace-96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f.tar.gz blogspace-96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f.tar.bz2 blogspace-96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f.zip | |
Show a live preview of the header on the Design tab's Menu card
The menu options had grown to a dozen switches with nothing to look at
but the blog after a save. A new POST /b/{sub}/design/preview reads the
form as a save would and renders the header alone — the real blog.css
and theme CSS, the modules in their order, the menu as edited — into a
sandboxed frame that refreshes shortly after every change, with a Wide
screen / Phone toggle. Nothing is stored.
The frame keeps the dashboard's origin (allow-same-origin, no scripts)
so the blog's logo and fonts, linked through /b/<sub>/media since the
root host's /media is the root blog's, get the session cookie; that is
safe because no header module is owner HTML. The frame runs no scripts,
so the page's own script folds the menu in it the way the blog does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'AGENTS.md')
| -rw-r--r-- | AGENTS.md | 21 |
1 files changed, 20 insertions, 1 deletions
@@ -194,7 +194,26 @@ internal/web/ server.go (host router, middleware, render helpers) return every row along with the error; a bad link stays as a row to fix). `POST /b/{sub}/design/reset` stores `DefaultTheme()` and calls `ResetModules`. `GET /b/{sub}/layout` (the old tab) redirects to - `/design#columns`. + `/design#columns`. **Header preview** (`POST /b/{sub}/design/preview`, + `handleDesignPreview`, `blog/preview.html`): the Menu card's frame. The + handler reads the form exactly as a save would (theme, modules, menu — + errors ignored, what was sent is shown), drops the banner, and executes the + `preview` template alone (a whole small page: blog.css, the theme CSS, the + `siteheader` template) — never the layout. Because the dashboard is on the + root host, where `/media` is the root blog's files, the page's images and + fonts are linked through `view.Media` (`/media` from `renderStatus`, + `/b/<sub>/media` here; the theme CSS through `Theme.CSSAt`). The script + POSTs the form (file inputs dropped) 300 ms after any change — `touch()` + schedules it, so module order counts too — into + `<iframe sandbox="allow-same-origin" srcdoc>`: same origin, unlike the + editor's HTML preview, because the session cookie is `SameSite=Lax` and an + opaque origin would not send it for those images; safe only while no header + module kind is owner HTML (all four are template-escaped) and there is no + `allow-scripts`. The frame runs no scripts, so the dashboard's script folds + the menu inside it the way the blog's own script does (`fitFrame`), sizes + the frame to the header, and re-runs on the frame's `change` (the fold + button) and on the Wide/Phone toggle (the frame at 380px, so blog.css's + phone rules apply). - **Theme** (`web/theme.go`): struct stored as jsonb on `settings.theme`. `ParseTheme` merges over `DefaultTheme()` and `normalize()` clamps every value to an allowlist (hex colours, enum strings, uuid image ids, column |
