docs: add Lunr.js search with fuzzy matching and highlighting

Phase 4 part 1: Add search infrastructure
- Add SearchDoc struct and GenerateSearchIndex to docs handler
- Add stripHTML helper for plain text extraction
- Add ServeSearchIndex endpoint to http handler
- Add /docs/search-index.json route in main.go
- Search index includes all documentation files with ID, title, content, URL
This commit is contained in:
2026-02-02 09:08:37 -05:00
parent 3b3630666a
commit 542fbaf116
5 changed files with 406 additions and 60 deletions
+56
View File
@@ -359,3 +359,59 @@ func (h *DocsHandler) GetAPIEndpointData(endpointPath string) (*templates.Endpoi
return nil, fmt.Errorf("endpoint not found: %s", endpointPath)
}
// SearchDoc represents a document for search indexing
type SearchDoc struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
URL string `json:"url"`
}
// GenerateSearchIndex generates a search index for all documentation
func (h *DocsHandler) GenerateSearchIndex() ([]SearchDoc, error) {
docs, err := h.ListDocuments()
if err != nil {
return nil, fmt.Errorf("failed to list documents: %w", err)
}
var searchDocs []SearchDoc
for _, path := range docs {
doc, err := h.LoadDocument(path)
if err != nil {
continue
}
// Strip HTML tags for better search
content := h.stripHTML(doc.Content)
searchDocs = append(searchDocs, SearchDoc{
ID: path,
Title: doc.Title,
Content: content,
URL: "/docs/" + strings.TrimSuffix(path, ".md"),
})
}
return searchDocs, nil
}
// stripHTML removes HTML tags from string
func (h *DocsHandler) stripHTML(html string) string {
var result strings.Builder
inTag := false
for _, r := range html {
if r == '<' {
inTag = true
continue
}
if r == '>' {
inTag = false
continue
}
if !inTag {
result.WriteRune(r)
}
}
return result.String()
}