aboutsummaryrefslogtreecommitdiffstats
path: root/AGENTS.md
diff options
context:
space:
mode:
Diffstat (limited to 'AGENTS.md')
-rw-r--r--AGENTS.md26
1 files changed, 20 insertions, 6 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 84b6a7b..d4a9284 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -185,13 +185,23 @@ internal/web/ server.go (host router, middleware, render helpers)
header text colour; hidden on phones so a long title can wrap. `NavStyle`
`plain` is regular weight + underline for the menu links (blog.css makes
them bold).
+ **Custom fonts** (`CustomFont`, `CustomHeadingFont`: font file ids or ""):
+ a chosen file is declared as `@font-face` (`"BlogFont"` / `"BlogHeadingFont"`,
+ `src:url(/media/<id>)`, same-origin so no CORS) and put first in the stack,
+ the built-in `Font`/`HeadingFont` choice behind it as the fallback — so
+ there is no "custom" enum value and no invalid state. `HeadingFontFamily`
+ builds on the text's stack when `HeadingFont` is `same`, and the `h1…h6`
+ rule is emitted whenever `HeadingFontSet` (a heading choice or a heading
+ file). Picked with the `fontpick` partial: a plain `<select>` of the newest
+ `recentImages` library fonts (`kind = font`) plus the chosen older one, and
+ an upload input — no library panel, no script.
Optional colours (`LinkHover`, `NavHover`) are `""` = inherit and come
from a colour input paired with a `<name>_custom` checkbox, shown/hidden
with CSS only (`.hoverpick > input:not(:checked) ~ …`). Image fields use the
`imagepick` partial: a `<select>` of the `recentImages` newest library
images (`kind = image`) plus the chosen one (`imageNames` looks up an older
- one's filename), so the page never grows with the library; `none` clears, a
- uuid selects, no value keeps (`pickImage`); an upload in `<name>_file` wins.
+ one's filename, fonts included), so the page never grows with the library; `none` clears, a
+ uuid selects, no value keeps (`pickFile`); an upload in `<name>_file` wins.
The `imagelib` partial (one per form; the design page and the post form
both include it) is the panel behind "Choose from library…", with its own
script: it marks every `.imagepick` with `.js` (hiding the select, showing
@@ -245,15 +255,18 @@ internal/web/ server.go (host router, middleware, render helpers)
- **Files** (`files` table, `store/files.go`, `handlers_files.go`,
`filetype.go`, `/b/{sub}/files…`): the upload library, any type. A row is
`id, filename, content_type, kind, size, data`; `kind` (image, document,
- audio, video, archive, other) is decided at upload by `fileType`, which
+ audio, video, font, archive, other) is decided at upload by `fileType`, which
trusts `http.DetectContentType` first and lets the extension refine only a
generic sniff (text/plain, octet-stream) to a type on the allowlists in
`filetype.go`; anything unknown is stored as `application/octet-stream`.
+ Fonts (`fontTypes`: WOFF2, WOFF, TTF, OTF) are known by their bytes alone,
+ like images; TTC and EOT stay `other`.
`/media/{uuid}` is served on every host with immutable cache headers, from
the host's blog database only (the root domain serves the root blog's
files); dashboard previews for another blog on the root host use
`GET /b/{sub}/media/{id}` (`withBlog`). **The root domain carries the
- session cookie, so `servedAs` renders inline only images, PDF, plain text,
+ session cookie, so `servedAs` renders inline only images, fonts (a browser
+ parses one only inside `@font-face`), PDF, plain text,
audio and video; everything else (HTML, SVG, XML, JS, archives, binaries)
goes out as `application/octet-stream` + `Content-Disposition: attachment`.**
`?download` forces attachment. SVG is therefore never an image (download
@@ -293,7 +306,8 @@ internal/web/ server.go (host router, middleware, render helpers)
`outro_file`) + `appendFile(body, f, format)`
(the no-JS path: `fileMarkdown` or `fileHTML`, i.e. `<img>`/`<a>`), and
store `renderBody(format, src)` (`markdown.Render`, or the source untouched
- for HTML) in the `*_html` column — the public templates only ever print
+ for HTML) in the `*_html` column (`readUpload`'s last argument is the kind
+ the field must be — `"image"`, `"font"` — or `""` for anything) — the public templates only ever print
that column.
**HTML mode** (`.editor.html`, toggled by the radios): the Markdown toolbar
groups (`.ed-md`), link box, shortcuts, list continuation and cheat-sheet
@@ -444,7 +458,7 @@ superadmin password to `admin`. Production refuses both.
`-- +goose Up/Down` sections; they run automatically at startup. Never
edit an applied migration. Blog chain so far: `00001_init`, `00002_language`,
`00003_files`, `00004_tags`, `00005_search`, `00006_format`, `00007_post_image`,
- `00008_page_outro`, `00009_gizmo_style`; control: `00001_init`, `00002_upload_limit`. Both chains were re-baselined at 00001 after
+ `00008_page_outro`, `00009_gizmo_style`, `00010_font_kind`; control: `00001_init`, `00002_upload_limit`. Both chains were re-baselined at 00001 after
the move to per-blog databases; deployments from before it have
`goose_db_version` rows 2–7 in the control DB that must be deleted once
(README "Upgrading from a single database") or the next control migration