search: pagination and scroll, add range counter, mobile version

This commit is contained in:
Pontoporeia
2026-07-03 16:53:16 +02:00
parent e607833b2e
commit 880d169e72
8 changed files with 378 additions and 116 deletions
+30 -6
View File
@@ -24,7 +24,7 @@ class SearchController
{
private const RATE_LIMIT_MAX = 300;
private const RATE_LIMIT_WINDOW = 60; // seconds
private const ITEMS_PER_PAGE = 30;
private const ITEMS_PER_PAGE = 15;
private Database $db;
private RateLimit $rateLimit;
@@ -79,6 +79,7 @@ class SearchController
$searchParams = $this->collectSearchParams();
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
$offset = ($page - 1) * self::ITEMS_PER_PAGE;
$isHtmx = !empty($_SERVER['HTTP_HX_REQUEST']);
$validationError = null;
$results = [];
@@ -99,11 +100,13 @@ class SearchController
);
$totalItems = $this->db->countSearchResults($searchParams);
$totalPages = (int) ceil($totalItems / self::ITEMS_PER_PAGE);
$years = $this->db->getAvailableYears();
$orientations = $this->db->getAllOrientations();
$apPrograms = $this->db->getAllAPPrograms();
$finalityTypes = $this->db->getAllFinalityTypes();
$formatTypes = $this->db->getAllFormatTypes();
if (!$isHtmx) {
$years = $this->db->getAvailableYears();
$orientations = $this->db->getAllOrientations();
$apPrograms = $this->db->getAllAPPrograms();
$finalityTypes = $this->db->getAllFinalityTypes();
$formatTypes = $this->db->getAllFormatTypes();
}
if (!empty($results)) {
$coverMap = $this->db->getCoverPathsForTheses(array_column($results, 'id'));
}
@@ -119,6 +122,14 @@ class SearchController
$query = $_GET['query'] ?? '';
// HTMX partial: render just the results fragment and exit
if ($isHtmx) {
$this->renderSearchResultsFragment(compact(
'results', 'totalItems', 'totalPages', 'page',
'baseParams', 'coverMap', 'validationError',
));
}
return [
'searchParams' => $searchParams,
'page' => $page,
@@ -154,6 +165,7 @@ class SearchController
],
'currentNav' => 'repertoire',
'extraCss' => ['/assets/dist/repertoire.min.css'],
'extraJs' => ['/assets/js/vendor/htmx.min.js'],
'bodyClass' => 'search-body',
];
}
@@ -212,6 +224,18 @@ class SearchController
// ── Private helpers ───────────────────────────────────────────────────────
/**
* Render the search results fragment and exit (for HTMX pagination).
* Never returns.
*/
private function renderSearchResultsFragment(array $vars): never
{
header('Content-Type: text/html; charset=UTF-8');
extract($vars);
include APP_ROOT . '/templates/partials/search-results.php';
exit();
}
/**
* Render the repertoire index partial and exit (for HTMX swaps).
* Never returns.