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)
89 lines
2.3 KiB
HTML
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}}
|