diff options
| author | grm <grm@eyesin.space> | 2026-09-12 19:47:28 +0300 |
|---|---|---|
| committer | grm <grm@eyesin.space> | 2026-09-12 19:47:28 +0300 |
| commit | e974eb6f3feb06c8951f85c1d34161938905f807 (patch) | |
| tree | 3bba878b6764e9d18519efd393d4e780eaabd81a /internal/web/handlers_media.go | |
| parent | dd13e4b73a105ee416b6cfd8eb19b217622c0031 (diff) | |
| download | blogspace-e974eb6f3feb06c8951f85c1d34161938905f807.tar.gz blogspace-e974eb6f3feb06c8951f85c1d34161938905f807.tar.bz2 blogspace-e974eb6f3feb06c8951f85c1d34161938905f807.zip | |
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'internal/web/handlers_media.go')
| -rw-r--r-- | internal/web/handlers_media.go | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/internal/web/handlers_media.go b/internal/web/handlers_media.go index e651135..9d5a515 100644 --- a/internal/web/handlers_media.go +++ b/internal/web/handlers_media.go @@ -3,6 +3,7 @@ package web import ( "bytes" "errors" + "io/fs" "net/http" "github.com/google/uuid" @@ -36,3 +37,23 @@ func (s *Server) handleMedia(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Content-Type-Options", "nosniff") http.ServeContent(w, r, img.Filename, img.CreatedAt, bytes.NewReader(img.Data)) } + +// handleFavicon answers the browsers that ask for /favicon.ico regardless of +// the <link rel="icon"> tags: the blog's own icon if it set one, else the +// Blogspace default. Without this the request would render the 404 page. +func (s *Server) handleFavicon(w http.ResponseWriter, r *http.Request) { + if icon := ParseTheme(currentBlog(r).ThemeJSON).Favicon; icon != "" { + http.Redirect(w, r, "/media/"+icon, http.StatusFound) + return + } + data, err := fs.ReadFile(s.tpl.AssetsFS(), "favicon.png") + if err != nil { + s.serverError(w, err) + return + } + w.Header().Set("Content-Type", "image/png") + if !s.cfg.Dev { + w.Header().Set("Cache-Control", "public, max-age=3600") + } + w.Write(data) +} |
