Files
nav-carte/components/FichesPanel.vue
T

136 lines
3.1 KiB
Vue

<!--
FichesPanel — B3-M3
Panneau « toutes les fiches » : reçoit une liste déjà filtrée (recherche +
filtres en cours côté page), l'affiche en grille de FicheMiniCard, et
expose ses propres chips de filtrage branchées sur le MÊME état que la
page appelante (pas un second état — voir vérification du brief).
Ne crée pas de second champ de recherche : `query` sert uniquement à
nuancer le message d'état vide.
-->
<template>
<div class="fiches-panel">
<div class="fiches-panel__head">
<p class="fiches-panel__intention">{{ intention }}</p>
<ChipGroup v-if="hashtags.length" aria-label="Filtrer les fiches" class="fiches-panel__chips">
<Chip
v-for="tag in hashtags"
:key="tag"
:label="tag"
variant="fonction"
:active="selected.includes(tag)"
@toggle="toggle(tag)"
/>
</ChipGroup>
<div class="fiches-panel__count">
{{ fiches.length }} fiche{{ fiches.length > 1 ? 's' : '' }}
</div>
</div>
<div class="fiches-panel__body">
<p v-if="fiches.length === 0" class="fiches-panel__empty">
Aucun résultat<template v-if="query"> pour « {{ query }} »</template>.
</p>
<div v-else class="fiches-panel__grid">
<FicheMiniCard
v-for="fiche in fiches"
:key="`${fiche.kind}-${fiche.id}`"
:fiche="fiche"
@open="emit('open', fiche)"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { MiniFiche } from '~/composables/useFicheAdapter'
const props = defineProps<{
fiches: MiniFiche[]
hashtags: string[]
selected: string[]
query: string
intention: string
}>()
const emit = defineEmits<{
'update:selected': [value: string[]]
open: [fiche: MiniFiche]
}>()
function toggle(tag: string) {
if (props.selected.includes(tag)) {
emit('update:selected', props.selected.filter((t) => t !== tag))
} else {
emit('update:selected', [...props.selected, tag])
}
}
</script>
<style scoped>
.fiches-panel {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
.fiches-panel__head {
flex-shrink: 0;
padding: var(--space-sm) var(--space-md);
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.fiches-panel__intention {
margin: 0 0 var(--space-xs);
font-size: var(--fs-sm);
line-height: var(--lh-base);
color: var(--text-muted);
}
.fiches-panel__count {
margin-top: var(--space-xs);
font-size: var(--fs-xs);
font-weight: var(--fw-semibold);
text-transform: uppercase;
letter-spacing: 0.02em;
color: var(--text-subtle);
}
.fiches-panel__body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: var(--space-md);
}
.fiches-panel__empty {
margin: var(--space-xl) 0;
text-align: center;
font-size: var(--fs-sm);
color: var(--text-muted);
}
.fiches-panel__grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-sm);
}
@media (min-width: 768px) {
.fiches-panel__grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1280px) {
.fiches-panel__grid {
grid-template-columns: repeat(3, 1fr);
}
}
</style>