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/templates/blog/search.html | 23 +++++++++++++++++++++++ internal/web/templates/dashboard/layout.html | 2 +- internal/web/templates/dashboard/module_form.html | 6 ++++-- internal/web/templates/layouts/blog.html | 6 ++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 internal/web/templates/blog/search.html (limited to 'internal/web/templates') diff --git a/internal/web/templates/blog/search.html b/internal/web/templates/blog/search.html new file mode 100644 index 0000000..b146f5e --- /dev/null +++ b/internal/web/templates/blog/search.html @@ -0,0 +1,23 @@ +{{define "title"}}{{if .Data.q}}{{tf "Results for “%s”" .Data.q}}{{else}}{{t "Search"}}{{end}} · {{.Blog.Title}}{{end}} +{{define "content"}} +

{{if .Data.q}}{{tf "Results for “%s”" .Data.q}}{{else}}{{t "Search"}}{{end}}

+
{{template "searchform" .}}
+{{if not .Data.q}}

{{t "Type a word or two to find posts."}}

+{{else if not .Data.hits}}

{{tf "Nothing matched “%s”." .Data.q}}

+{{else}} +

{{if eq .Data.total 1}}{{t "One post matches."}}{{else}}{{tf "%d posts match." .Data.total}}{{end}}

+ +{{if gt .Data.lastPage 1}} +
+ {{if gt .Data.pageNum 1}}← {{t "Newer"}}{{end}} + {{tf "Page %d of %d" .Data.pageNum .Data.lastPage}} + {{if lt .Data.pageNum .Data.lastPage}}{{t "Older"}} →{{end}} +
+{{end}} +{{end}} +{{end}} diff --git a/internal/web/templates/dashboard/layout.html b/internal/web/templates/dashboard/layout.html index 48b6778..5c9332a 100644 --- a/internal/web/templates/dashboard/layout.html +++ b/internal/web/templates/dashboard/layout.html @@ -102,7 +102,7 @@ {{t (index $r.Data.names .Kind)}}{{with modsummary .}} — {{.}}{{end}} {{if and (eq .Kind "logo") (not $r.Data.theme.Logo)}}{{t "no logo chosen"}} {{t "pick one on the"}} {{t "Design"}} {{t "tab."}}{{end}} - {{if modsettings .Kind}}{{t "edit"}} {{end}}{{t "remove"}} + {{if modsettings .}}{{t "edit"}} {{end}}{{t "remove"}} {{end}} {{else}}

{{if ne $area "header"}}{{t "Nothing here yet — this area is not shown until you add a module."}}{{else}}{{t "Nothing here yet."}}{{end}}

{{end}}
diff --git a/internal/web/templates/dashboard/module_form.html b/internal/web/templates/dashboard/module_form.html index 8b28f2e..a0fe95b 100644 --- a/internal/web/templates/dashboard/module_form.html +++ b/internal/web/templates/dashboard/module_form.html @@ -5,8 +5,8 @@

{{.Data.name}} {{tf "in the %s" (lower .Data.area)}}

- {{if or (eq $m.Kind "recent") (eq $m.Kind "archive") (eq $m.Kind "sitemap") (eq $m.Kind "tags") (eq $m.Kind "tagcloud") (and (eq $m.Kind "html") (or (eq $m.Area "left") (eq $m.Area "right") (eq $m.Area "footer")))}} - + {{if or (eq $m.Kind "recent") (eq $m.Kind "archive") (eq $m.Kind "sitemap") (eq $m.Kind "tags") (eq $m.Kind "tagcloud") (eq $m.Kind "search") (and (eq $m.Kind "html") (or (eq $m.Area "left") (eq $m.Area "right") (eq $m.Area "footer")))}} + {{end}} {{if eq $m.Kind "recent"}}
@@ -20,6 +20,8 @@

{{t "Your tags with the number of posts in each, most used first. Only published posts count."}}

{{else if eq $m.Kind "tagcloud"}}

{{t "Every tag in alphabetical order, bigger the more posts use it."}}

+ {{else if eq $m.Kind "search"}} +

{{t "A box that searches the published posts of every page by title and text; the results open on your blog’s search page. Case does not matter, and several words find posts that contain them in that order, with anything in between."}}

{{else if eq $m.Kind "html"}} diff --git a/internal/web/templates/layouts/blog.html b/internal/web/templates/layouts/blog.html index cf00272..3e854f6 100644 --- a/internal/web/templates/layouts/blog.html +++ b/internal/web/templates/layouts/blog.html @@ -76,6 +76,8 @@ {{- else if eq $m.Kind "tagcloud"}}
{{template "modtitle" $m}}

{{range $r.Data.tagcloud}}{{.Name}} {{else}}{{t "No tags yet."}}{{end}}

+{{- else if eq $m.Kind "search"}}{{if eq $m.Area "header"}} +{{else}}{{end}} {{- else if eq $m.Kind "html"}}{{if not $m.Body}}{{else if or (eq $m.Area "above") (eq $m.Area "below")}}
{{html $m.Body}}
{{else}}
{{template "modtitle" $m}}{{html $m.Body}}
{{end}} {{- else if eq $m.Kind "rss"}}

{{t "RSS feed"}}

@@ -85,6 +87,10 @@ {{- end}}{{end}} +{{/* The search box: a plain GET form, so it works without JavaScript. .Data.q + only exists on the search page, hence the with. */}} +{{define "searchform"}}
{{end}} + {{define "modtitle"}}{{if .Title}}

{{.Title}}

{{end}}{{end}} {{define "menulinks"}}{{range .Data.menu}}{{.Text}} -- cgit v1.2.3