From a1dfc548198a1326e71f1dd70303a5d3441f7a39 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 21 Jun 2024 13:02:08 +0200 Subject: refactor: switch to templ for HTML templates --- internal/server/error.go | 10 +++-- internal/server/mux.go | 93 +++++++++++++++++++------------------------- internal/server/templates.go | 25 +----------- 3 files changed, 46 insertions(+), 82 deletions(-) (limited to 'internal/server') diff --git a/internal/server/error.go b/internal/server/error.go index e700d3b..4a8acbc 100644 --- a/internal/server/error.go +++ b/internal/server/error.go @@ -3,6 +3,8 @@ package server import ( "log/slog" "net/http" + + "searchix/internal/components" "searchix/internal/config" ) @@ -14,9 +16,9 @@ func createErrorHandler( if message == "" { message = http.StatusText(code) } - indexData := TemplateData{ + indexData := components.TemplateData{ ExtraHeadHTML: config.Web.ExtraHeadHTML, - Sources: config.Importer.Sources, + Sources: sources, Code: code, Message: message, } @@ -24,9 +26,9 @@ func createErrorHandler( w.Header().Del("Vary") w.WriteHeader(code) if r.Header.Get("Fetch") == "true" { - err = templates["error"].ExecuteTemplate(w, "main", indexData) + err = components.Error(indexData).Render(r.Context(), w) } else { - err = templates["error"].Execute(w, indexData) + err = components.ErrorPage(indexData).Render(r.Context(), w) } if err != nil { slog.Error( diff --git a/internal/server/mux.go b/internal/server/mux.go index 79e24cd..89ce952 100644 --- a/internal/server/mux.go +++ b/internal/server/mux.go @@ -3,7 +3,6 @@ package server import ( "context" "fmt" - "html/template" "io" "log" "log/slog" @@ -16,11 +15,10 @@ import ( "time" "searchix/frontend" + "searchix/internal/components" "searchix/internal/config" search "searchix/internal/index" - "searchix/internal/nix" - "github.com/blevesearch/bleve/v2" sentryhttp "github.com/getsentry/sentry-go/http" "github.com/osdevisnot/sorvor/pkg/livereload" "github.com/pkg/errors" @@ -33,36 +31,10 @@ type HTTPError struct { Code int } -const jsSnippet = template.HTML(livereload.JsSnippet) // #nosec G203 - -type TemplateData struct { - Sources map[string]*config.Source - Source config.Source - Query string - Results bool - SourceResult *bleve.SearchResult - ExtraHeadHTML template.HTML - Code int - Message string - Assets *frontend.AssetCollection -} - -type ResultData struct { - TemplateData - Query string - ResultsPerPage int - Results *search.Result - Prev string - Next string -} - -type DocumentData struct { - TemplateData - Document *nix.Importable - Children *search.Result -} - -var templates TemplateCollection +var ( + templates TemplateCollection + sources []*config.Source +) func applyDevModeOverrides(cfg *config.Config) { if len(cfg.Web.ContentSecurityPolicy.ScriptSrc) == 0 { @@ -70,10 +42,18 @@ func applyDevModeOverrides(cfg *config.Config) { } cfg.Web.ContentSecurityPolicy.ScriptSrc = append( cfg.Web.ContentSecurityPolicy.ScriptSrc, + "http://localhost:7331", "'unsafe-inline'", ) } +func sortSources(ss map[string]*config.Source) { + sources = make([]*config.Source, len(ss)) + for _, v := range ss { + sources[v.Order] = v + } +} + func NewMux( cfg *config.Config, index *search.ReadIndex, @@ -93,19 +73,20 @@ func NewMux( if err != nil { log.Panicf("could not load templates: %v", err) } + sortSources(cfg.Importer.Sources) errorHandler := createErrorHandler(cfg) top := http.NewServeMux() mux := http.NewServeMux() mux.HandleFunc("/{$}", func(w http.ResponseWriter, r *http.Request) { - indexData := TemplateData{ + indexData := components.TemplateData{ ExtraHeadHTML: cfg.Web.ExtraHeadHTML, - Sources: cfg.Importer.Sources, + Sources: sources, Assets: frontend.Assets, } w.Header().Add("Cache-Control", "max-age=86400") - err := templates["index"].Execute(w, indexData) + err := components.Homepage(indexData).Render(r.Context(), w) if err != nil { errorHandler(w, r, err.Error(), http.StatusInternalServerError) } @@ -146,12 +127,13 @@ func NewMux( errorHandler(w, r, err.Error(), http.StatusInternalServerError) } - tdata := ResultData{ - TemplateData: TemplateData{ + tdata := components.ResultData{ + TemplateData: components.TemplateData{ ExtraHeadHTML: cfg.Web.ExtraHeadHTML, Source: *source, - Sources: cfg.Importer.Sources, + Sources: sources, Assets: frontend.Assets, + Query: qs, }, ResultsPerPage: search.ResultsPerPage, Query: qs, @@ -193,9 +175,9 @@ func NewMux( w.Header().Add("Vary", "Fetch") if r.Header.Get("Fetch") == "true" { w.Header().Add("Content-Type", "text/html; charset=utf-8") - err = templates[importerType.String()].ExecuteTemplate(w, "results", tdata) + err = components.Results(tdata).Render(r.Context(), w) } else { - err = templates[importerType.String()].Execute(w, tdata) + err = components.ResultsPage(tdata).Render(r.Context(), w) } if err != nil { slog.Error("template error", "template", importerType, "error", err) @@ -210,13 +192,16 @@ func NewMux( } w.Header().Add("Cache-Control", "max-age=14400") - err = templates["search"].Execute(w, TemplateData{ - ExtraHeadHTML: cfg.Web.ExtraHeadHTML, - Sources: cfg.Importer.Sources, - Source: *source, - SourceResult: sourceResult, - Assets: frontend.Assets, - }) + err = components.SearchPage( + components.TemplateData{ + ExtraHeadHTML: cfg.Web.ExtraHeadHTML, + Sources: sources, + Source: *source, + SourceResult: sourceResult, + Assets: frontend.Assets, + }, + components.ResultData{}, + ).Render(r.Context(), w) if err != nil { errorHandler(w, r, err.Error(), http.StatusInternalServerError) @@ -260,20 +245,20 @@ func NewMux( return } - tdata := DocumentData{ - TemplateData: TemplateData{ + tdata := components.DocumentData{ + TemplateData: components.TemplateData{ ExtraHeadHTML: cfg.Web.ExtraHeadHTML, Source: *source, - Sources: cfg.Importer.Sources, + Sources: sources, Assets: frontend.Assets, }, Document: doc, } if r.Header.Get("Fetch") == "true" { w.Header().Add("Content-Type", "text/html; charset=utf-8") - err = templates[importerSingular].ExecuteTemplate(w, "main", tdata) + err = components.Detail(*doc).Render(r.Context(), w) } else { - err = templates[importerSingular].Execute(w, tdata) + err = components.DetailPage(tdata.TemplateData, *doc).Render(r.Context(), w) } if err != nil { slog.Error("template error", "template", importerSingular, "error", err) @@ -337,7 +322,7 @@ func NewMux( if liveReload { applyDevModeOverrides(cfg) - cfg.Web.ExtraHeadHTML = jsSnippet + cfg.Web.ExtraHeadHTML = livereload.JsSnippet liveReload := livereload.New() liveReload.Start() top.Handle("/livereload", liveReload) diff --git a/internal/server/templates.go b/internal/server/templates.go index 38ff5d4..fa95425 100644 --- a/internal/server/templates.go +++ b/internal/server/templates.go @@ -95,21 +95,13 @@ func loadTemplates() (TemplateCollection, error) { templateDir := "templates" templates := make(TemplateCollection, 0) - layoutFile := path.Join(templateDir, "index.gotmpl") - - index, err := loadTemplate(layoutFile) - if err != nil { - return nil, err - } - templates["index"] = index - glob := path.Join(templateDir, "*.gotmpl") templatePaths, err := fs.Glob(frontend.Files, glob) if err != nil { return nil, errors.WithMessage(err, "could not glob main templates") } for _, fullname := range templatePaths { - tpl, err := loadTemplate(layoutFile, fullname) + tpl, err := loadTemplate(fullname) if err != nil { return nil, err } @@ -117,20 +109,5 @@ func loadTemplates() (TemplateCollection, error) { templates[name] = tpl } - glob = path.Join(templateDir, "blocks", "*.gotmpl") - templatePaths, err = fs.Glob(frontend.Files, glob) - if err != nil { - return nil, errors.WithMessage(err, "could not glob block templates") - } - for _, fullname := range templatePaths { - tpl, err := loadTemplate(layoutFile, glob, fullname) - if err != nil { - return nil, err - } - - name, _ := strings.CutSuffix(path.Base(fullname), ".gotmpl") - templates[name] = tpl - } - return templates, nil } -- cgit 1.4.1