From e974eb6f3feb06c8951f85c1d34161938905f807 Mon Sep 17 00:00:00 2001 From: grm Date: Sat, 12 Sep 2026 19:47:28 +0300 Subject: Add a favicon and rework the Design page Blogs had no icon at all, and browsers probing /favicon.ico ended up rendering the 404 page. Ship a default paper & ink icon (svg + png) and let each blog replace it from the Design page; /favicon.ico now serves the default or redirects to the blog's own image. ICO uploads accepted. The Design page gains colour schemes, reset to defaults, thumbnail image pickers, jump links and a sticky save bar, plus new options: heading font, link underline/hover, content box style and padding, header image height, post dates and format, footer RSS toggle, menu alignment/style/hover and sidebar width. The Menu card picks the position with illustrated tiles and shows only the options that apply to it, using CSS :checked rules rather than JavaScript. All new defaults reproduce the previous look, so existing blogs are unchanged until edited. Theme is jsonb, so no migration. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/web/routes.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'internal/web/routes.go') diff --git a/internal/web/routes.go b/internal/web/routes.go index bd39a18..84b19a6 100644 --- a/internal/web/routes.go +++ b/internal/web/routes.go @@ -48,6 +48,8 @@ func (s *Server) rootRoutes() http.Handler { m.HandleFunc("POST /b/{sub}/announcements/{id}/toggle", s.withBlog(s.handleSectionToggle)) m.HandleFunc("GET /b/{sub}/design", s.withBlog(s.handleDesignForm)) m.HandleFunc("POST /b/{sub}/design", s.withBlog(s.handleDesign)) + m.HandleFunc("POST /b/{sub}/design/preset", s.withBlog(s.handleDesignPreset)) + m.HandleFunc("POST /b/{sub}/design/reset", s.withBlog(s.handleDesignReset)) m.HandleFunc("GET /b/{sub}/images", s.withBlog(s.handleImages)) m.HandleFunc("POST /b/{sub}/images/upload", s.withBlog(s.handleImageUpload)) m.HandleFunc("POST /b/{sub}/images/{id}/delete", s.withBlog(s.handleImageDelete)) @@ -64,6 +66,7 @@ func (s *Server) rootRoutes() http.Handler { m.HandleFunc("GET /media/{id}", s.handleMedia) m.Handle("GET /static/{file}", s.staticHandler()) + m.HandleFunc("GET /favicon.ico", s.hostBlog(s.handleFavicon)) // The root domain also serves the superadmin's blog. Literal routes above win // over these wildcards; see reservedPageSlugs for the names that are shadowed. s.blogRoutes(m, s.hostBlog) @@ -84,6 +87,7 @@ func (s *Server) subdomainRoutes() http.Handler { m.HandleFunc("GET /webadmin", s.handleWebadminRedirect) m.HandleFunc("GET /media/{id}", s.handleMedia) m.Handle("GET /static/{file}", s.staticHandler()) + m.HandleFunc("GET /favicon.ico", s.hostBlog(s.handleFavicon)) s.blogRoutes(m, s.hostBlog) return m } -- cgit v1.2.3