feat: replace server-rendered index with JS-rendered shell page

- Rewrites indexPage to render a shell page with embedded JSON + JS
- Adds searchJs with vanilla JS for client-side list rendering, filtering, sorting
- Hash-based sort modes (#alpha, #tags, #course)
- Search filters by title and filename (case-insensitive)
- Fix: recipe links use /recipes/ prefix and encodeURIComponent for # encoding
- Fix: avoid double-render on initial page load
This commit is contained in:
2026-05-19 21:40:02 -04:00
parent 954bad87bd
commit d5e9c7e0d3
+3 -4
View File
@@ -255,7 +255,7 @@ searchJs = T.unlines
, " if (items.length === 0) return '<p>No recipes found.</p>';"
, " let html = '<ul class=\'roux-recipes\'>';"
, " items.forEach(r => {"
, " html += '<li><a href=\"' + encodeURI(r.filename) + '\">' + escapeHtml(r.title) + '</a></li>';"
, " html += '<li><a href=\"/recipes/' + encodeURIComponent(r.filename) + '\">' + escapeHtml(r.title) + '</a></li>';"
, " });"
, " html += '</ul>';"
, " return html;"
@@ -317,10 +317,9 @@ searchJs = T.unlines
, "}"
, "window.addEventListener('hashchange', updateActiveNav);"
, ""
, "// Initial render"
, "// Initial render -- setting hash triggers hashchange"
, "if (!location.hash) location.hash = 'alpha';"
, "updateActiveNav();"
, "render();"
, "else { updateActiveNav(); render(); }"
, ""
, "})();"
]