aboutsummaryrefslogtreecommitdiffstats
path: root/AGENTS.md
diff options
context:
space:
mode:
authorgrm <grm@eyesin.space>2026-09-12 12:33:57 +0300
committergrm <grm@eyesin.space>2026-09-12 12:33:57 +0300
commitdd13e4b73a105ee416b6cfd8eb19b217622c0031 (patch)
tree93ce503a09b99115efeeee6cd1a85781c1674b02 /AGENTS.md
parent2b450b66fee4906e746f6e04a6d07a72ff2faf64 (diff)
downloadblogspace-dd13e4b73a105ee416b6cfd8eb19b217622c0031.tar.gz
blogspace-dd13e4b73a105ee416b6cfd8eb19b217622c0031.tar.bz2
blogspace-dd13e4b73a105ee416b6cfd8eb19b217622c0031.zip
Add announcements: blog-wide notices on every page and post
A blog can have any number of announcements ("sections" in the schema): a book club's next meeting, this month's pick, a holiday closure. Each has a placement (above or below the posts, or under the menu when the menu is a left sidebar), a look (highlighted, warning, plain), an order, and an on/off switch so recurring notices can be kept around while hidden. 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.md27
1 files changed, 22 insertions, 5 deletions
diff --git a/AGENTS.md b/AGENTS.md
index cfe3d06..2352b85 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -23,7 +23,9 @@ table and deployment notes.
(e.g. the `<noscript>` button in `posts.html`).
- Server-rendered `html/template`; no SPA, no frontend toolchain.
- Postgres holds **everything**, including images (`images.data bytea`).
-- Posts are Markdown (goldmark → bluemonday). No WYSIWYG.
+- Posts are Markdown (goldmark → bluemonday). No WYSIWYG. The editor's
+ "Insert image" is the one scripted convenience (`partials/editor.html`);
+ it must keep its no-JS fallback (file appended on save).
- Changes are live immediately — there is no draft/preview system. The UX
is "save, then refresh your blog tab"; keep the "View blog ↗" links.
- Theme customisation is a structured form only; **no custom CSS input**.
@@ -36,14 +38,14 @@ table and deployment notes.
cmd/blogspace/ main.go (serve|seed|migrate, superadmin + root blog bootstrap), seed.go
internal/config/ env → Config; RootSubdomain = "www"
internal/db/ pgxpool + goose; migrations/*.sql embedded
-internal/store/ models + hand-written SQL (users, blogs, pages, posts, images)
+internal/store/ models + hand-written SQL (users, blogs, pages, posts, images, sections)
internal/auth/ bcrypt, JWT issue/parse, cookie, HMAC CSRF
internal/markdown/ Render(md) → sanitized HTML
internal/slug/ Make/Valid/WithSuffix (Greek transliteration included)
internal/web/ server.go (host router, middleware, render helpers)
- routes.go (all routes), handlers_*.go, theme.go
+ routes.go (all routes), handlers_*.go (sections = announcements), theme.go
templates/ (embedded; layouts/, partials/, auth/, dashboard/, admin/, blog/)
- static/ (dashboard.css, blog.css)
+ static/ (dashboard.css "paper & ink" look — plain CSS, no variables/flex; blog.css)
```
## Key mechanics
@@ -87,7 +89,22 @@ internal/web/ server.go (host router, middleware, render helpers)
`dashboard/design.html`.
- **Images**: `/media/{uuid}` served on every host with immutable cache
headers. Uploads are content-sniffed (png/jpeg/gif/webp). Deleting an
- image clears theme references to it.
+ image clears theme references to it. `POST /b/{sub}/images/upload`
+ answers JSON (`{id, filename, markdown}` / `{error}`) when the request
+ has `Accept: application/json`; that is what the editor script calls.
+- **Editor** (`partials/editor.html`, args via `dict`: name, value, rows,
+ tall, upload, csrf): textarea + "Insert image" + cheat-sheet. Forms using
+ it must be `multipart/form-data` and their save handler must call
+ `s.readUpload(r, "inline_image")` + `appendImageMD` (the no-JS path).
+- **Announcements** (`sections` table, `store/sections.go`,
+ `handlers_sections.go`, `/b/{sub}/announcements…`): per-blog notices with
+ `placement` (above|below|sidebar), `style` (plain|note|warning), `enabled`
+ and `sort_order`. `blogView` loads the enabled ones and `splitSections`
+ routes `sidebar` to the left-sidebar layout only (otherwise above).
+ Rendered by the `notices` template in `layouts/blog.html`; CSS classes
+ `notice notice-<style>` use translucent colours so they fit any theme.
+- **Dashboard nav**: `dashnav.html` marks the current tab with `hasPrefix
+ .Path`; a new management section needs a tab there.
- **Slugs**: auto-generated from the title; on collision generated slugs
get `-2`, `-3`…, user-typed slugs return a 409 with a message.
- **Errors**: `store.ErrNotFound` / `store.ErrConflict` are the sentinels