[FIX] Filtrage des partitions #2 Il faut un champ filtre #3

This commit is contained in:
NADAL Jean-Baptiste
2026-02-26 10:52:21 +01:00
parent 38bfe62eec
commit 2d585aa834

View File

@@ -2,11 +2,12 @@
import { onMount } from 'svelte';
import { apiService, type Score } from '$lib/api';
let scores: Score[] = [];
let loading = true;
let error = '';
let sortBy: 'id' | 'name' | 'compositor' = 'id';
let sortOrder: 'asc' | 'desc' = 'asc';
let scores = $state<Score[]>([]);
let loading = $state(true);
let error = $state('');
let sortBy: 'id' | 'name' | 'compositor' = $state('id');
let sortOrder: 'asc' | 'desc' = $state('desc');
let filter: string = $state('');
onMount(async () => {
try {
@@ -28,17 +29,38 @@
}
}
$: sortedScores = [...scores].sort((a, b) => {
function removeAccents(str: string): string {
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
let filteredScores = $derived.by(() => {
let result = [...scores];
// Filter
if (filter.trim()) {
const f = removeAccents(filter.toLowerCase());
result = result.filter(s =>
removeAccents(s.id.toLowerCase()).includes(f) ||
removeAccents(s.name.toLowerCase()).includes(f) ||
removeAccents(s.compositor || '').toLowerCase().includes(f)
);
}
// Sort
result.sort((a, b) => {
let aVal = a[sortBy] || '';
let bVal = b[sortBy] || '';
let cmp: number;
if (sortBy === 'id') {
cmp = parseInt(a.id) - parseInt(b.id);
} else {
cmp = aVal.localeCompare(bVal);
cmp = String(aVal).localeCompare(String(bVal));
}
return sortOrder === 'asc' ? cmp : -cmp;
});
return result;
});
</script>
<svelte:head>
@@ -48,7 +70,7 @@
<div class="container mx-auto px-4 py-8">
<div class="mb-6">
<h1 class="text-3xl font-bold text-ohmj-primary">Répertoire</h1>
<p class="text-gray-600 mt-2">{scores.length} partitions disponibles</p>
<p class="text-gray-600 mt-2">{scores.length} partition{scores.length !== 1 ? 's' : ''} disponible{scores.length !== 1 ? 's' : ''}</p>
</div>
{#if loading}
@@ -60,32 +82,76 @@
{error}
</div>
{:else}
<!-- Filter & Sort Bar -->
<div class="bg-white rounded-lg shadow-sm p-4 mb-4">
<div class="flex flex-col md:flex-row gap-4">
<!-- Search Input -->
<div class="flex-1">
<div class="relative">
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
type="text"
bind:value={filter}
placeholder="Rechercher par n°, nom ou compositeur..."
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-ohmj-primary focus:border-ohmj-primary transition-colors"
/>
</div>
</div>
<!-- Sort Controls -->
<div class="flex items-center gap-2">
<span class="text-sm text-gray-500 whitespace-nowrap">Trier par :</span>
<div class="flex rounded-lg border border-gray-300 overflow-hidden">
<button
type="button"
onclick={() => sortScores('id')}
class="px-3 py-2 text-sm font-medium transition-colors {sortBy === 'id' ? 'bg-ohmj-primary text-white' : 'bg-white text-gray-700 hover:bg-gray-50'}"
>
{sortBy === 'id' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
</button>
<button
type="button"
onclick={() => sortScores('name')}
class="px-3 py-2 text-sm font-medium transition-colors {sortBy === 'name' ? 'bg-ohmj-primary text-white' : 'bg-white text-gray-700 hover:bg-gray-50'}"
>
Nom {sortBy === 'name' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
</button>
<button
type="button"
onclick={() => sortScores('compositor')}
class="px-3 py-2 text-sm font-medium transition-colors {sortBy === 'compositor' ? 'bg-ohmj-primary text-white' : 'bg-white text-gray-700 hover:bg-gray-50'}"
>
Compositeur {sortBy === 'compositor' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
</button>
</div>
</div>
</div>
{#if filter}
<p class="text-sm text-gray-500 mt-2">{filteredScores.length} résultat{filteredScores.length !== 1 ? 's' : ''} pour "{filter}"</p>
{/if}
</div>
<!-- Results Table -->
<div class="bg-white rounded-lg shadow overflow-hidden">
<table class="min-w-full">
<thead class="bg-gray-50">
<tr>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100 w-20"
onclick={() => sortScores('id')}
>
{sortBy === 'id' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-20">
</th>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
onclick={() => sortScores('name')}
>
Nom {sortBy === 'name' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Nom
</th>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
onclick={() => sortScores('compositor')}
>
Compositeur {sortBy === 'compositor' ? (sortOrder === 'asc' ? '↑' : '↓') : ''}
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Compositeur
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{#each sortedScores as score}
{#each filteredScores as score}
<tr class="hover:bg-ohmj-light transition-colors cursor-pointer" onclick={() => window.location.href = '/scores/' + score.id}>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{score.id}
@@ -100,6 +166,12 @@
{/each}
</tbody>
</table>
{#if filteredScores.length === 0}
<div class="text-center py-12 text-gray-500">
Aucune partition ne correspond à votre recherche
</div>
{/if}
</div>
{/if}
</div>