Update web/templates/search.html

This commit is contained in:
Joshua Laymon 2025-09-09 01:44:39 +00:00
parent 228e52b9a4
commit fc82767666

View File

@ -11,7 +11,8 @@
<button class="btn btn-primary">Search</button>
</div>
<div class="filter-row">
<!-- Desktop filters -->
<div class="filter-row desktop-filters">
{% for f in field_options %}
<label class="check-pill">
<input type="checkbox" name="{{ f.name }}" {% if f.checked %}checked{% endif %}>
@ -19,6 +20,21 @@
</label>
{% endfor %}
</div>
<!-- Mobile dropdown filters -->
<div class="filter-row mobile-filters">
<button type="button" id="filterDropdownBtn" class="btn btn-secondary dropdown-toggle" aria-expanded="false">
Filters ▾
</button>
<div id="filterDropdownPanel" class="dropdown-panel">
{% for f in field_options %}
<label class="check-pill" style="display:block; margin:6px 0;">
<input type="checkbox" name="{{ f.name }}" {% if f.checked %}checked{% endif %}>
<span>{{ f.label }}</span>
</label>
{% endfor %}
</div>
</div>
</form>
{% if ran_search and result_count == 0 %}
@ -109,7 +125,7 @@
return url + sep + 't=' + Date.now();
}
// Search history (keeps selected-fields subtitle)
// Search history
function renderHistory(items){
const list = document.getElementById('searchHistoryList');
const empty = document.getElementById('searchHistoryEmpty');
@ -197,6 +213,17 @@
});
});
// Dropdown toggle for mobile filters
(function(){
const btn = document.getElementById('filterDropdownBtn');
const panel = document.getElementById('filterDropdownPanel');
if (!btn || !panel) return;
btn.addEventListener('click', ()=>{
const open = panel.classList.toggle('open');
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
});
})();
// ===============================
// No-results: show a random funny illustration
// ===============================
@ -221,99 +248,6 @@
el.textContent = pick;
})();
/* ===============================
Illustration of the Day (client-only, deterministic)
=============================== */
(function illustrationOfTheDay(){
const total = {{ total|default:0 }};
const iotdTextEl = document.getElementById('iotd-text');
const iotdOpenEl = document.getElementById('iotd-open');
if (!iotdTextEl || !iotdOpenEl) return;
if (!total || total < 1){
iotdTextEl.textContent = 'No illustrations available yet.';
iotdOpenEl.style.display = 'none';
return;
}
// Seed from local date (YYYYMMDD) so its the same for everyone that day
const today = new Date();
const ymd = today.getFullYear()*10000 + (today.getMonth()+1)*100 + today.getDate();
// 32-bit xorshift PRNG for a good daily seed
function xorshift32(seed){
let x = seed | 0;
x ^= x << 13; x ^= x >>> 17; x ^= x << 5;
return (x >>> 0);
}
const seed = xorshift32(ymd ^ 0x9E3779B9);
const maxGuess = Math.max(100, Math.floor(total * 4));
const maxAttempts = Math.min(600, maxGuess);
function idAt(i){
const v = (Math.imul(i + 1, 1103515245) + 12345 + seed) >>> 0;
return 1 + (v % maxGuess);
}
async function fetchEntryHtml(id){
const url = entryUrlFor(id);
try{
const r = await fetch(url, { credentials: 'same-origin' });
if (r.ok) return await r.text();
}catch(_){}
return null;
}
function ensurePunct(str){
const s = (str || '').trim();
if (!s) return '';
return /[.!?…]$/.test(s) ? s : (s + '.');
}
function extractSectionText(doc, label){
const labels = doc.querySelectorAll('.section-label, .meta-label, h3, h4, strong');
for (const el of labels){
const t = (el.textContent || '').trim().toLowerCase();
if (t === label){
const section = el.closest('.section') || el.parentElement;
if (section){
const body = section.querySelector('.lead-text') ||
section.querySelector('.section-body') ||
section.querySelector('p');
if (body) return (body.textContent || '').trim();
}
}
}
const alt = doc.querySelector('.lead-text, .section-body');
return alt ? (alt.textContent || '').trim() : '';
}
function renderIotd(id, html){
const dom = new DOMParser().parseFromString(html, 'text/html');
const illustration = extractSectionText(dom, 'illustration');
const application = extractSectionText(dom, 'application');
const merged = (ensurePunct(illustration) + (application ? ' ' + application : '')).trim();
iotdTextEl.textContent = merged || 'Open to view todays illustration.';
iotdOpenEl.href = entryUrlFor(id);
iotdOpenEl.style.display = 'inline-block';
}
(async function findAndRender(){
for (let i = 0; i < maxAttempts; i++){
const id = idAt(i);
const html = await fetchEntryHtml(id);
if (html){
renderIotd(id, html);
return;
}
}
iotdTextEl.textContent = 'Unable to load todays illustration.';
iotdOpenEl.style.display = 'none';
})();
})();
})();
</script>
@ -342,32 +276,25 @@
padding:10px 16px;
margin:0;
}
</style>
<!-- Save q + selected fields exactly as submitted -->
<script>
(function(){
const form = document.querySelector('form.search-form') || document.querySelector('form[method="get"]');
if (!form) return;
const qInput = form.querySelector('input[name="q"]');
form.addEventListener('submit', () => {
const fd = new FormData(form);
const fields = [];
for (const [k, v] of fd.entries()) {
if (k.startsWith('sel[') && k.endsWith(']') && (v === 'on' || v === 'true' || v === '1')) {
fields.push(k.slice(4, -1));
}
/* Mobile filter dropdown styling */
.mobile-filters { display:none; margin-top:10px; }
@media (max-width: 700px){
.desktop-filters { display:none; }
.mobile-filters { display:block; }
#filterDropdownPanel {
border:1px solid var(--border);
background:#fff;
border-radius:10px;
margin-top:6px;
padding:10px;
}
const q = (qInput && qInput.value || '').trim();
try {
localStorage.setItem('lastSearchQ', q);
localStorage.setItem('lastSearchFields', JSON.stringify(fields));
} catch (_) {}
});
})();
</script>
#filterDropdownBtn {
width:100%;
text-align:left;
}
}
</style>
{% include "partials/announcement_modal.html" %}
{% endblock %}