From dd13e4b73a105ee416b6cfd8eb19b217622c0031 Mon Sep 17 00:00:00 2001 From: grm Date: Sat, 12 Sep 2026 12:33:57 +0300 Subject: 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 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/web/handlers_blog.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'internal/web/handlers_blog.go') diff --git a/internal/web/handlers_blog.go b/internal/web/handlers_blog.go index b768c4d..9b2fe5e 100644 --- a/internal/web/handlers_blog.go +++ b/internal/web/handlers_blog.go @@ -12,13 +12,17 @@ import ( const postsPerPage = 10 -// blogView gathers what every public page needs: theme css, nav, the blog. +// blogView gathers what every public page needs: theme css, nav, announcements, the blog. func (s *Server) blogView(r *http.Request) (map[string]any, error) { blog := currentBlog(r) pages, err := s.st.ListPages(r.Context(), blog.ID) if err != nil { return nil, err } + sections, err := s.st.EnabledSections(r.Context(), blog.ID) + if err != nil { + return nil, err + } theme := ParseTheme(blog.ThemeJSON) var nav []store.Page for _, p := range pages { @@ -26,7 +30,24 @@ func (s *Server) blogView(r *http.Request) (map[string]any, error) { nav = append(nav, p) } } - return map[string]any{"theme": theme, "css": theme.CSS(), "nav": nav}, nil + above, below, sidebar := splitSections(sections, theme.NavPosition == "left-sidebar") + return map[string]any{"theme": theme, "css": theme.CSS(), "nav": nav, "above": above, "below": below, "sidebar": sidebar}, nil +} + +// splitSections groups announcements by placement. The sidebar only exists in +// the left-sidebar layout; elsewhere sidebar announcements go above the content. +func splitSections(secs []store.Section, hasSidebar bool) (above, below, sidebar []store.Section) { + for _, sec := range secs { + switch { + case sec.Placement == "below": + below = append(below, sec) + case sec.Placement == "sidebar" && hasSidebar: + sidebar = append(sidebar, sec) + default: + above = append(above, sec) + } + } + return } func (s *Server) handleBlogHome(w http.ResponseWriter, r *http.Request) { -- cgit v1.2.3