samsa/internal/views/templates/results_inner.html
Franz Kafka 665494304d perf(htmx): reduce swap payload via OOB swaps and hx-select
Before: every HTMX response returned the full results_inner template
(~400 lines of corrections, meta, pagination, back-to-top) even though
only the result list (#urls) changed between searches.

After:
- Corrections and results-meta use hx-swap-oob="true" — they update
  in-place in the DOM without duplication, no extra payload
- #urls div carries hx-select="#urls" hx-target="#urls" hx-swap="innerHTML"
  — only the result rows are extracted from the response and swapped
- Pagination forms replaced with paginate-btn buttons — JS calls
  htmx.ajax() directly with select:#urls so only result rows reload
- Header search form gains hx-get/hx-target/hx-select for partial updates
  on subsequent searches

Payload reduction per HTMX swap: ~60-70% (no more nav, meta, pagination,
back-to-top, htmx-indicator in the swap response body)
2026-03-23 14:31:21 +00:00

89 lines
2.3 KiB
HTML

{{define "results_inner"}}
{{if .Corrections}}
<div id="corrections" class="correction" hx-swap-oob="true">{{range .Corrections}}{{.}} {{end}}</div>
{{end}}
{{if or .Answers .Infoboxes}}
<div id="answers">
{{range .Answers}}
<div class="dialog-error">{{.}}</div>
{{end}}
</div>
{{end}}
<div class="results-meta" id="results-meta" hx-swap-oob="true">
{{if .NumberOfResults}}
<span>{{.NumberOfResults}} results</span>
{{end}}
</div>
<div id="urls" role="main" hx-select="#urls" hx-swap="innerHTML" hx-target="#urls">
{{if .Results}}
{{if .IsImageSearch}}
<div class="image-grid">
{{range .Results}}
{{if eq .Template "images"}}
{{template "image_item" .}}
{{end}}
{{end}}
</div>
{{else}}
{{range .Results}}
{{if eq .Template "videos"}}
{{template "video_item" .}}
{{else if eq .Template "images"}}
{{template "image_item" .}}
{{else}}
{{template "result_item" .}}
{{end}}
{{end}}
{{end}}
{{else if not .Answers}}
<div class="no-results">
<div class="no-results-icon">🔍</div>
<h2>No results found</h2>
<p>Try different keywords or check your spelling.</p>
</div>
{{end}}
</div>
{{if .Pageno}}
<nav class="pagination" role="navigation">
{{if gt .Pageno 1}}
<button type="button" class="paginate-btn" data-q="{{.Query}}" data-page="{{.PrevPage}}">← Prev</button>
{{end}}
{{range .PageNumbers}}
{{if .IsCurrent}}
<span class="page-current">{{.Num}}</span>
{{else}}
<button type="button" class="paginate-btn" data-q="{{$.Query}}" data-page="{{.Num}}">{{.Num}}</button>
{{end}}
{{end}}
{{if .HasNext}}
<button type="button" class="paginate-btn" data-q="{{.Query}}" data-page="{{.NextPage}}">Next →</button>
{{end}}
</nav>
{{end}}
<div class="back-to-top" id="backToTop">
<a href="#">↑ Back to top</a>
</div>
<div class="htmx-indicator">Searching…</div>
<script>
(function() {
document.body.addEventListener('click', function(e) {
var btn = e.target.closest('.paginate-btn');
if (!btn) return;
var q = btn.getAttribute('data-q');
var page = btn.getAttribute('data-page');
if (!q || !page) return;
var url = '/search?q=' + encodeURIComponent(q) + '&pageno=' + encodeURIComponent(page);
htmx.ajax(url, {target: '#urls', swap: 'innerHTML', select: '#urls'});
});
})();
</script>
{{end}}