Files
xamxam/app/templates/partials/repertoire-index.php
T
Pontoporeia f86deaf02f repertoire: remove matched-first sorting and faded/disabled system for filter entries
Remove the system that sorted valid (matched) filter entries to the top and
faded/disabled unmatched ones when any filter was active. Entries now stay in
their natural alphabetical/numeric order regardless of selection state.

- Drop usort calls that reordered entries by matched status
- Simplify repFilterEntry: remove anyActive and colHasMatch params
- Remove colHasMatches computation
- Remove rep-entry--faded CSS rule
- All filter buttons remain clickable at all times
2026-07-10 12:35:45 +02:00

169 lines
6.8 KiB
PHP

<?php
/**
* Partial: répertoire index columns.
* Rendered both on full page load and as HTMX partial swap.
*
* Expected variables:
* $repData array output of Database::getRepertoireFilterData()
* $activeFilters array{years:int[], ap:string[], or:string[], fi:string[], kw:string[]}
*/
$activeSets = [
'years' => array_map('strval', $activeFilters['years'] ?? []),
'ap' => $activeFilters['ap'] ?? [],
'or' => $activeFilters['or'] ?? [],
'fi' => $activeFilters['fi'] ?? [],
'kw' => $activeFilters['kw'] ?? [],
];
// ── Students ────────────────────────────────────────────────────────────────
$studentWorks = [];
foreach ($repData['students'] as $s) {
if (empty($s['authors'])) continue;
foreach (explode(',', $s['authors']) as $name) {
$name = trim($name);
if ($name === '') continue;
$studentWorks[$name][] = (int)$s['id'];
}
}
ksort($studentWorks);
// ── Shared helpers ──────────────────────────────────────────────────────────
// AP abbreviation mapping (cf. maquette: diminutifs entre crochets)
const AP_ABBREVIATIONS = [
'Atelier Pratiques Situées' => '[APS]',
'Design et Politique du Multiple' => '[DPM]',
'Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes' => '[L.I.E.N.S.]',
];
function formatApDisplay(string $name): string {
$abbr = AP_ABBREVIATIONS[$name] ?? '';
return $abbr !== '' ? "$name $abbr" : $name;
}
function repToggleUrl(array $sets, string $dim, string $value): string {
if (in_array($value, $sets[$dim], true)) {
$sets[$dim] = array_values(array_filter($sets[$dim], fn($v) => $v !== $value));
} else {
$sets[$dim][] = $value;
}
$params = [];
foreach ($sets['years'] as $v) $params[] = 'fy[]=' . urlencode((string)$v);
foreach ($sets['ap'] as $v) $params[] = 'ap[]=' . urlencode($v);
foreach ($sets['or'] as $v) $params[] = 'or[]=' . urlencode($v);
foreach ($sets['fi'] as $v) $params[] = 'fi[]=' . urlencode($v);
foreach ($sets['kw'] as $v) $params[] = 'kw[]=' . urlencode($v);
$qs = implode('&', $params);
return '/repertoire' . ($qs ? '?' . $qs : '');
}
function repFilterEntry(
array $item,
string $dim,
array $activeSets,
string $hx,
): void {
$val = (string)$item['value'];
$isActive = in_array($val, $activeSets[$dim], true);
$cls = 'rep-entry'
. ($isActive ? ' rep-entry--selected' : '');
$url = repToggleUrl($activeSets, $dim, $val);
?>
<li>
<button type="button" class="<?= $cls ?>"
aria-pressed="<?= $isActive ? 'true' : 'false' ?>"
hx-get="<?= htmlspecialchars($url) ?>" <?= $hx ?>>
<?= htmlspecialchars($dim === 'ap' ? formatApDisplay($val) : $val) ?>
</button>
</li>
<?php
}
// ── Column definitions ──────────────────────────────────────────────────────
$hx = 'hx-target="#repertoire-index" hx-swap="outerHTML" hx-push-url="true" hx-indicator="#rep-indicator"';
$filterColumns = [
['dataKey' => 'years', 'dim' => 'years', 'heading' => 'Années'],
['dataKey' => 'ap_programs', 'dim' => 'ap', 'heading' => 'Ateliers Pluridisciplinaires'],
['dataKey' => 'orientations', 'dim' => 'or', 'heading' => 'Orientations'],
['dataKey' => 'finality_types', 'dim' => 'fi', 'heading' => 'Finalité du&nbsp;Master'],
['dataKey' => 'keywords', 'dim' => 'kw', 'heading' => 'Mots-clés'],
];
?>
<div id="repertoire-index" class="repertoire-index">
<?php
// Render filter columns in the correct left-to-right order.
// Students column (non-filter) is inserted between keywords and AP/or/fi/years.
$renderOrder = ['years', 'ap', 'or', 'fi', 'students', 'kw'];
foreach ($renderOrder as $colKey):
if ($colKey === 'students'): ?>
<!-- ÉTUDIANTES -->
<section class="repertoire-col rep-accordion" data-col="students">
<h2>
<span class="rep-accordion__heading-text">Étudiant·es</span>
<button type="button" class="rep-accordion__toggle" aria-expanded="false">
Étudiant·es
<span class="rep-accordion__chevron" aria-hidden="true"></span>
</button>
</h2>
<div class="rep-accordion__panel">
<ul>
<?php if (empty($studentWorks)): ?>
<li class="rep-empty">—</li>
<?php else: ?>
<?php foreach ($studentWorks as $name => $ids): ?>
<?php
$firstId = $ids[0];
$targetUrl = count($ids) === 1 ? '/tfe?id=' . $firstId : '#';
$previewUrl = '/repertoire/student-preview?name=' . urlencode($name);
?>
<li class="student-entry">
<a href="<?= htmlspecialchars($targetUrl) ?>"
class="rep-entry rep-entry--link"
data-student-name="<?= htmlspecialchars($name) ?>"
hx-get="<?= htmlspecialchars($previewUrl) ?>"
hx-target="#student-popover"
hx-trigger="mouseenter"
hx-swap="innerHTML">
<?= htmlspecialchars($name) ?>
</a>
</li>
<?php endforeach; ?>
<?php endif; ?>
</ul>
</div>
</section>
<?php else:
$col = array_values(array_filter($filterColumns, fn($c) => $c['dim'] === $colKey))[0];
// Count active filters in this column for the badge
$activeCount = count($activeSets[$col['dim']]);
?>
<section class="repertoire-col rep-accordion" data-col="<?= $col['dim'] ?>">
<h2>
<span class="rep-accordion__heading-text"><?= $col['heading'] ?></span>
<button type="button" class="rep-accordion__toggle" aria-expanded="false">
<?= $col['heading'] ?>
<?php if ($activeCount > 0): ?>
<span class="rep-accordion__badge"><?= $activeCount ?></span>
<?php endif; ?>
<span class="rep-accordion__chevron" aria-hidden="true"></span>
</button>
</h2>
<div class="rep-accordion__panel">
<ul>
<?php foreach ($repData[$col['dataKey']] as $item):
repFilterEntry($item, $col['dim'], $activeSets, $hx);
endforeach; ?>
</ul>
</div>
</section>
<?php endif;
endforeach; ?>
</div>