From 839343a3108734a15e331b542a20ed9c77ef582b Mon Sep 17 00:00:00 2001 From: grm Date: Wed, 16 Sep 2026 00:00:57 +0300 Subject: Add a search box module and a search page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Readers had no way to find a post. The new "search" module goes in the header (a bar under the nav) or a side column (a box with a heading) and is a plain GET form to /search, so it works without JavaScript. The results page lists the published posts of every page whose title or Markdown body matches the query — case-insensitive, each word literal, spaces meaning "anything in between", in order — as title, date and a short snippet with the match marked, 20 per page. modules.kind is a CHECK constraint, so a migration widens it; "search" becomes a reserved page slug so the literal route keeps winning over /{page}. moduleHasSettings now takes the module: a header search box has no heading, hence nothing to edit. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/web/routes.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'internal/web/routes.go') diff --git a/internal/web/routes.go b/internal/web/routes.go index a8a60d2..563639c 100644 --- a/internal/web/routes.go +++ b/internal/web/routes.go @@ -95,7 +95,8 @@ func (s *Server) rootRoutes() http.Handler { func (s *Server) blogRoutes(m *http.ServeMux, wrap func(http.HandlerFunc) http.HandlerFunc) { m.HandleFunc("GET /{$}", wrap(s.handleBlogHome)) m.HandleFunc("GET /feed.xml", wrap(s.handleBlogFeed)) - m.HandleFunc("GET /tag/{tag}", wrap(s.handleBlogTag)) // literal segment: wins over /{page}/{post} + m.HandleFunc("GET /tag/{tag}", wrap(s.handleBlogTag)) // literal segments: win over /{page} and /{page}/{post} + m.HandleFunc("GET /search", wrap(s.handleBlogSearch)) m.HandleFunc("GET /{page}", wrap(s.handleBlogPage)) m.HandleFunc("GET /{page}/{post}", wrap(s.handleBlogPost)) } -- cgit v1.2.3