diff --git a/pkg/help/templates.go b/pkg/help/templates.go
index fd738af..c3cfc13 100644
--- a/pkg/help/templates.go
+++ b/pkg/help/templates.go
@@ -3,89 +3,15 @@ package help
import (
"cmp"
- "embed"
- "html/template"
- "io"
"slices"
- "strings"
)
-//go:embed templates/*.html
-var templateFS embed.FS
-
-// templateFuncs returns the function map for help templates.
-func templateFuncs() template.FuncMap {
- return template.FuncMap{
- "renderMarkdown": func(content string) template.HTML {
- html, err := RenderMarkdown(content)
- if err != nil {
- return template.HTML("
Error rendering content.
")
- }
- return template.HTML(html) //nolint:gosec // trusted content from catalog
- },
- "truncate": func(s string, n int) string {
- // Strip markdown headings for truncation preview
- lines := strings.SplitSeq(s, "\n")
- var clean []string
- for line := range lines {
- trimmed := strings.TrimSpace(line)
- if trimmed == "" || strings.HasPrefix(trimmed, "#") {
- continue
- }
- clean = append(clean, trimmed)
- }
- text := strings.Join(clean, " ")
- runes := []rune(text)
- if len(runes) <= n {
- return text
- }
- return string(runes[:n]) + "..."
- },
- "pluralise": func(count int, singular, plural string) string {
- if count == 1 {
- return singular
- }
- return plural
- },
- "multiply": func(a, b int) int {
- return a * b
- },
- "sub": func(a, b int) int {
- return a - b
- },
- }
-}
-
-// parseTemplates parses the base layout together with a page template.
-func parseTemplates(page string) (*template.Template, error) {
- return template.New("base.html").Funcs(templateFuncs()).ParseFS(
- templateFS, "templates/base.html", "templates/"+page,
- )
-}
-
// topicGroup groups topics under a tag for the index page.
type topicGroup struct {
Tag string
Topics []*Topic
}
-// indexData holds template data for the index page.
-type indexData struct {
- Topics []*Topic
- Groups []topicGroup
-}
-
-// topicData holds template data for a single topic page.
-type topicData struct {
- Topic *Topic
-}
-
-// searchData holds template data for the search results page.
-type searchData struct {
- Query string
- Results []*SearchResult
-}
-
// groupTopicsByTag groups topics by their first tag.
// Topics without tags are grouped under "other".
// Groups are sorted alphabetically by tag name.
@@ -118,12 +44,3 @@ func groupTopicsByTag(topics []*Topic) []topicGroup {
return result
}
-
-// renderPage renders a named page template into the writer.
-func renderPage(w io.Writer, page string, data any) error {
- tmpl, err := parseTemplates(page)
- if err != nil {
- return err
- }
- return tmpl.Execute(w, data)
-}
diff --git a/pkg/help/templates/404.html b/pkg/help/templates/404.html
deleted file mode 100644
index 7acef70..0000000
--- a/pkg/help/templates/404.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{{define "title"}}Not Found - Help{{end}}
-{{define "content"}}
-
-{{end}}
diff --git a/pkg/help/templates/base.html b/pkg/help/templates/base.html
deleted file mode 100644
index 62ce765..0000000
--- a/pkg/help/templates/base.html
+++ /dev/null
@@ -1,161 +0,0 @@
-
-
-
-
-
- {{block "title" .}}Help{{end}}
-
- {{block "head" .}}{{end}}
-
-
-
-
-
- {{block "content" .}}{{end}}
-
-
-
-
-
diff --git a/pkg/help/templates/index.html b/pkg/help/templates/index.html
deleted file mode 100644
index 7ad6e35..0000000
--- a/pkg/help/templates/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{{define "title"}}Help Topics{{end}}
-{{define "content"}}
-Help Topics {{len .Topics}} {{pluralise (len .Topics) "topic" "topics"}}
-
-{{if .Groups}}
-{{range .Groups}}
-{{.Tag}}
-{{range .Topics}}
-
-
- {{if .Tags}}
{{range .Tags}}{{.}}{{end}}
{{end}}
- {{if .Content}}
{{truncate .Content 120}}
{{end}}
-
-{{end}}
-{{end}}
-{{else}}
-No topics available.
-{{end}}
-{{end}}
diff --git a/pkg/help/templates/search.html b/pkg/help/templates/search.html
deleted file mode 100644
index 61a70fa..0000000
--- a/pkg/help/templates/search.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{{define "title"}}Search: {{.Query}} - Help{{end}}
-{{define "search_value"}}{{.Query}}{{end}}
-{{define "content"}}
-Search Results
-
- {{if .Results}}Found {{len .Results}} {{pluralise (len .Results) "result" "results"}} for “{{.Query}}”{{else}}No results for “{{.Query}}”{{end}}
-
-
-{{if .Results}}
-{{range .Results}}
-
-
- {{if .Snippet}}
{{.Snippet}}
{{end}}
- {{if .Topic.Tags}}
{{range .Topic.Tags}}{{.}}{{end}}
{{end}}
-
-{{end}}
-{{else}}
-
-
Try a different search term or browse all topics.
-
-{{end}}
-{{end}}
diff --git a/pkg/help/templates/topic.html b/pkg/help/templates/topic.html
deleted file mode 100644
index 79db4d5..0000000
--- a/pkg/help/templates/topic.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{{define "title"}}{{.Topic.Title}} - Help{{end}}
-{{define "content"}}
-
-
- {{if .Topic.Tags}}{{range .Topic.Tags}}{{.}}{{end}}
{{end}}
- {{renderMarkdown .Topic.Content}}
-
-
-
-
-{{end}}
diff --git a/pkg/help/templates_test.go b/pkg/help/templates_test.go
index c3a4f08..f588a58 100644
--- a/pkg/help/templates_test.go
+++ b/pkg/help/templates_test.go
@@ -2,104 +2,12 @@
package help
import (
- "bytes"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestParseTemplates_Good(t *testing.T) {
- pages := []string{"index.html", "topic.html", "search.html", "404.html"}
- for _, page := range pages {
- t.Run(page, func(t *testing.T) {
- tmpl, err := parseTemplates(page)
- require.NoError(t, err, "template %s should parse without error", page)
- assert.NotNil(t, tmpl)
- })
- }
-}
-
-func TestRenderPage_Good_Index(t *testing.T) {
- topics := []*Topic{
- {ID: "getting-started", Title: "Getting Started", Tags: []string{"intro"}, Content: "Welcome."},
- {ID: "config", Title: "Configuration", Tags: []string{"setup"}, Content: "Config options."},
- }
-
- data := indexData{
- Topics: topics,
- Groups: groupTopicsByTag(topics),
- }
-
- var buf bytes.Buffer
- err := renderPage(&buf, "index.html", data)
- require.NoError(t, err)
-
- html := buf.String()
- assert.Contains(t, html, "Getting Started")
- assert.Contains(t, html, "Configuration")
- assert.Contains(t, html, "2 topics")
- assert.Contains(t, html, "core help")
-}
-
-func TestRenderPage_Good_Topic(t *testing.T) {
- topic := &Topic{
- ID: "getting-started",
- Title: "Getting Started",
- Content: "# Getting Started\n\nWelcome to the **guide**.\n",
- Tags: []string{"intro"},
- Sections: []Section{
- {ID: "overview", Title: "Overview", Level: 2},
- },
- Related: []string{"config"},
- }
-
- data := topicData{Topic: topic}
-
- var buf bytes.Buffer
- err := renderPage(&buf, "topic.html", data)
- require.NoError(t, err)
-
- html := buf.String()
- assert.Contains(t, html, "Getting Started")
- assert.Contains(t, html, "guide")
- assert.Contains(t, html, "Overview")
- assert.Contains(t, html, "config")
-}
-
-func TestRenderPage_Good_Search(t *testing.T) {
- data := searchData{
- Query: "install",
- Results: []*SearchResult{
- {
- Topic: &Topic{ID: "install", Title: "Installation", Tags: []string{"setup"}},
- Score: 12.5,
- Snippet: "How to **install** the tool.",
- },
- },
- }
-
- var buf bytes.Buffer
- err := renderPage(&buf, "search.html", data)
- require.NoError(t, err)
-
- html := buf.String()
- assert.Contains(t, html, "install")
- assert.Contains(t, html, "Installation")
- assert.Contains(t, html, "1 result")
- assert.Contains(t, html, "12.5")
-}
-
-func TestRenderPage_Good_404(t *testing.T) {
- var buf bytes.Buffer
- err := renderPage(&buf, "404.html", nil)
- require.NoError(t, err)
-
- html := buf.String()
- assert.Contains(t, html, "not found")
- assert.Contains(t, html, "404")
-}
-
func TestGroupTopicsByTag_Good(t *testing.T) {
topics := []*Topic{
{ID: "a", Title: "Alpha", Tags: []string{"setup"}, Order: 2},
@@ -122,46 +30,3 @@ func TestGroupTopicsByTag_Good(t *testing.T) {
assert.Equal(t, "Beta", setupGroup.Topics[0].Title) // Order 1
assert.Equal(t, "Alpha", setupGroup.Topics[1].Title) // Order 2
}
-
-func TestTemplateFuncs_Good(t *testing.T) {
- fns := templateFuncs()
-
- t.Run("truncate short string", func(t *testing.T) {
- fn := fns["truncate"].(func(string, int) string)
- assert.Equal(t, "hello", fn("hello", 10))
- })
-
- t.Run("truncate long string", func(t *testing.T) {
- fn := fns["truncate"].(func(string, int) string)
- result := fn("hello world this is long", 11)
- assert.Equal(t, "hello world...", result)
- })
-
- t.Run("truncate strips headings", func(t *testing.T) {
- fn := fns["truncate"].(func(string, int) string)
- result := fn("# Title\n\nSome content here.", 100)
- assert.Equal(t, "Some content here.", result)
- assert.NotContains(t, result, "#")
- })
-
- t.Run("pluralise singular", func(t *testing.T) {
- fn := fns["pluralise"].(func(int, string, string) string)
- assert.Equal(t, "topic", fn(1, "topic", "topics"))
- })
-
- t.Run("pluralise plural", func(t *testing.T) {
- fn := fns["pluralise"].(func(int, string, string) string)
- assert.Equal(t, "topics", fn(0, "topic", "topics"))
- assert.Equal(t, "topics", fn(5, "topic", "topics"))
- })
-
- t.Run("multiply", func(t *testing.T) {
- fn := fns["multiply"].(func(int, int) int)
- assert.Equal(t, 24, fn(4, 6))
- })
-
- t.Run("sub", func(t *testing.T) {
- fn := fns["sub"].(func(int, int) int)
- assert.Equal(t, 2, fn(5, 3))
- })
-}