| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Design tab
Fonts become a file kind of their own (sniffed from the bytes like images,
served inline from /media), and the theme gets custom_font and
custom_heading_font: a chosen file is declared as @font-face and put first
in the stack, the built-in Font / Heading font choice behind it as the
fallback, so there is no "custom" enum value and no invalid state. The
pickers are plain selects with an upload input, no script. Fonts uploaded
before this are reclassified by the migration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The look and the layout of a blog were split over two tabs that cross-linked
each other, and the Layout tab saved every toggle, move and add straight
away through a dozen tiny forms. Now one Design tab holds it all, organised
by part of the blog (colours & fonts, header, menu, content, side columns,
footer, logo & icon) behind a sticky side index, and one Save stores the
theme, every module and the menu atomically (BlogStore.SaveDesign). Module
settings are edited inline; Discard changes throws the edits away; a
validation error shows the form again exactly as it was sent.
The image pickers no longer render the whole library four times over: a
select of the newest images, and a script-driven panel that fetches the
library page by page (GET /files as JSON) with lazy thumbnails.
New options: posts per page, site title size, footer alignment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Markdown is the default and unchanged; the editor's new Format switch
stores the text as raw HTML instead, put on the blog exactly as written.
Like the custom HTML module it is unsanitised on purpose: the escape
hatch for embeds, scripts and inline styles that Markdown cannot express.
The source column keeps holding the text in both modes and a `format`
column says how to read it, so the public templates and the feed still
print the stored `*_html`. The dashboard preview of HTML goes into a
sandboxed iframe rather than the page, because a superadmin edits other
people's blogs and their markup must never run on the dashboard origin.
Search snippets of HTML posts are cut from a tag-stripped copy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|
|
|
Bloggers want to attach PDFs, archives, audio and other files to posts,
not only images. The Images tab becomes Files: any type is accepted,
listed by kind with search, paging, rename and multi-file upload, and the
editor's paste/drop/"Insert file" takes anything (images are shown,
everything else becomes a link). The default limit goes from 5 to 10 MB
and the superadmin can override it per blog from /admin/.
Files stay in Postgres so one pg_dump is still the whole blog. The bytea
column is STORAGE EXTERNAL and /media streams it in substring() slices,
so serving never holds a whole file in memory whatever limit a blog gets.
Serving any type on the root domain, which carries the session cookie,
needs a policy: uploads are typed by sniffing (the extension may only
refine a generic sniff to an allowlisted type) and only images, PDF,
plain text, audio and video render inline; HTML, SVG, XML, scripts,
archives and binaries always go out as application/octet-stream with
Content-Disposition: attachment.
The body cap moves out of requireAuth into guardPOST, which runs after
withBlog has resolved the blog and so knows its limit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
|