diff --git a/app/src/Controllers/SearchController.php b/app/src/Controllers/SearchController.php index 1b8c046..8acf385 100644 --- a/app/src/Controllers/SearchController.php +++ b/app/src/Controllers/SearchController.php @@ -194,7 +194,6 @@ class SearchController "currentNav" => "repertoire", "extraCss" => ["/assets/css/repertoire.css"], "bodyClass" => "search-body", - "db" => $this->db, ]; } @@ -224,6 +223,7 @@ class SearchController exit(); } + header('Cache-Control: public, max-age=300'); include APP_ROOT . '/templates/partials/student-preview.php'; exit(); } @@ -234,7 +234,6 @@ class SearchController ): never { header("Content-Type: text/html; charset=UTF-8"); $isHtmx = true; - $db = $this->db; include APP_ROOT . "/templates/partials/repertoire-index.php"; exit(); } diff --git a/app/templates/partials/repertoire-index.php b/app/templates/partials/repertoire-index.php index bc99c9d..74e8bb4 100644 --- a/app/templates/partials/repertoire-index.php +++ b/app/templates/partials/repertoire-index.php @@ -31,10 +31,7 @@ ksort($studentWorks); // Legacy alias for single-id use $studentMap = array_map(fn($ids) => $ids[0], $studentWorks); -// Batch-fetch all preview data for visible students (one query) -$previewsByAuthor = !empty($studentWorks) - ? $db->getThesesForAuthors(array_keys($studentWorks)) - : []; + /** * Build the toggle URL for a filter button. @@ -182,15 +179,18 @@ $hx = 'hx-target="#repertoire-index" hx-swap="outerHTML" hx-push-url="true" hx-i $ids): ?>
  • + hx-get="" + hx-target="#student-popover" + hx-trigger="mouseenter once" + hx-swap="innerHTML">
  • @@ -224,38 +224,3 @@ $hx = 'hx-target="#repertoire-index" hx-swap="outerHTML" hx-push-url="true" hx-i - - $ids): - $templateId = 'sp-' . md5($name); - $theses = $previewsByAuthor[$name] ?? []; - if (empty($theses)) continue; -?> - - diff --git a/app/templates/public/repertoire.php b/app/templates/public/repertoire.php index 4d404a8..c3019a3 100644 --- a/app/templates/public/repertoire.php +++ b/app/templates/public/repertoire.php @@ -12,50 +12,49 @@ var popover = document.getElementById('student-popover'); var currentAnchor = null; - function positionPopover(anchor) { - var rect = anchor.getBoundingClientRect(); - var scrollY = window.scrollY || 0; - var scrollX = window.scrollX || 0; - var left = rect.right + scrollX + 12; - var top = rect.top + scrollY; - if (left + 300 > window.innerWidth + scrollX) { - left = rect.left + scrollX - 312; - } + function position(anchor) { + var r = anchor.getBoundingClientRect(); + var left = r.right + window.scrollX + 12; + var top = r.top + window.scrollY; + if (left + 300 > window.innerWidth + window.scrollX) left = r.left + window.scrollX - 312; popover.style.left = left + 'px'; popover.style.top = top + 'px'; } - function showPreview(anchor) { - var tplId = anchor.dataset.preview; - if (!tplId) return; - var tpl = document.getElementById(tplId); - if (!tpl) return; - popover.innerHTML = ''; - popover.appendChild(tpl.content.cloneNode(true)); - positionPopover(anchor); + // After htmx swaps content in, show and position the popover + document.body.addEventListener('htmx:afterSwap', function (e) { + if (e.detail.target !== popover) return; popover.hidden = false; - } - - function hidePreview() { - popover.hidden = true; - currentAnchor = null; - } + if (currentAnchor) position(currentAnchor); + }); + // On subsequent hovers (already cached by browser / htmx once), + // just reposition and show — htmx won't re-fire due to `once`, + // so we handle show/position on mouseenter ourselves. document.body.addEventListener('mouseenter', function (e) { - var a = e.target.closest('[data-preview]'); + var a = e.target.closest('[data-student-name]'); if (!a) return; currentAnchor = a; - showPreview(a); + // If popover already has this student's content, just show it + if (popover.dataset.loadedFor === a.dataset.studentName) { + position(a); + popover.hidden = false; + } }, true); + // Mark which student is loaded after swap + document.body.addEventListener('htmx:afterSwap', function (e) { + if (e.detail.target !== popover || !currentAnchor) return; + popover.dataset.loadedFor = currentAnchor.dataset.studentName; + }); + + // Hide on mouse leave (both anchor and popover) document.body.addEventListener('mouseleave', function (e) { - var a = e.target.closest('[data-preview]'); - var p = e.target.closest('#student-popover'); - if (!a && !p) return; + if (!e.target.closest('[data-student-name]') && !e.target.closest('#student-popover')) return; setTimeout(function () { - if (!document.querySelector('[data-preview]:hover') && + if (!document.querySelector('[data-student-name]:hover') && !document.querySelector('#student-popover:hover')) { - hidePreview(); + popover.hidden = true; } }, 120); }, true);