feat(vue-fiches): composant VueFiches (Carte · Mixte · Fiches, poignée, barre d'outils) et filtres par dimension (B11-M3, M4)
Filtres à un seul endroit par état, chips à 0 grisées, repli au-delà de 14, feuille « Filtrer » sous 768 px, pastilles actives en état Carte. FicheMiniCard : racine <article> + bouton étiré pour rendre les chips cliquables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SCt6e8wWiYqRXLJAuKqP5i
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
38df1d5eb5
commit
5a4c7af79c
@@ -1,12 +1,22 @@
|
||||
<!--
|
||||
FicheMiniCard — B3-M2, B11-M2
|
||||
La carte entière ouvre la fiche (bouton étiré par ::after) ; avec
|
||||
`etiquettesCliquables`, les chips deviennent des boutons qui émettent
|
||||
`etiquette` (la vue fiches ajoute le filtre). Un bouton ne pouvant pas en
|
||||
contenir d'autres, la racine est un <article>, plus un <button> : apparence
|
||||
inchangée, page /dev/fiche-mini-card comprise.
|
||||
-->
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="fiche-mini-card"
|
||||
:aria-label="fiche.nom"
|
||||
@click="emit('open')"
|
||||
>
|
||||
<span class="fiche-mini-card__nom">{{ fiche.nom }}</span>
|
||||
<span v-if="fiche.resume" class="fiche-mini-card__resume">{{ fiche.resume }}</span>
|
||||
<article class="fiche-mini-card" :class="{ 'fiche-mini-card--actif': actif }">
|
||||
<button
|
||||
type="button"
|
||||
class="fiche-mini-card__ouvrir"
|
||||
:aria-label="fiche.nom"
|
||||
@click="emit('open')"
|
||||
>
|
||||
<span class="fiche-mini-card__nom">{{ fiche.nom }}</span>
|
||||
<span v-if="fiche.resume" class="fiche-mini-card__resume">{{ fiche.resume }}</span>
|
||||
</button>
|
||||
|
||||
<ChipGroup
|
||||
v-if="fiche.chips.length || fiche.echelle"
|
||||
@@ -14,11 +24,24 @@
|
||||
class="fiche-mini-card__chips"
|
||||
>
|
||||
<Chip v-if="fiche.echelle" as="span" variant="echelle" :label="fiche.echelle" />
|
||||
<Chip v-for="chip in fiche.chips" :key="chip" as="span" variant="fonction" :label="chip" />
|
||||
<template v-if="etiquettesCliquables">
|
||||
<Chip
|
||||
v-for="chip in fiche.chips"
|
||||
:key="chip"
|
||||
variant="fonction"
|
||||
:label="chip"
|
||||
:active="etiquettesActives?.includes(chip)"
|
||||
:aria-label="`Filtrer par ${chip}`"
|
||||
@toggle="emit('etiquette', chip)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Chip v-for="chip in fiche.chips" :key="chip" as="span" variant="fonction" :label="chip" />
|
||||
</template>
|
||||
</ChipGroup>
|
||||
|
||||
<span v-if="!fiche.geoloc" class="fiche-mini-card__no-geo">Sans localisation</span>
|
||||
</button>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -26,30 +49,37 @@ import type { MiniFiche } from '~/composables/useFicheAdapter'
|
||||
|
||||
defineProps<{
|
||||
fiche: MiniFiche
|
||||
etiquettesCliquables?: boolean
|
||||
/** Libellés de chips déjà filtrés (affichés pressés). */
|
||||
etiquettesActives?: string[]
|
||||
/** Fiche survolée sur la carte ou sélectionnée. */
|
||||
actif?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
open: []
|
||||
etiquette: [label: string]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fiche-mini-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: var(--space-sm);
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
transition: background-color var(--dur-fast) var(--ease-out),
|
||||
box-shadow var(--dur-fast) var(--ease-out);
|
||||
box-shadow var(--dur-fast) var(--ease-out),
|
||||
border-color var(--dur-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
@@ -63,11 +93,42 @@ const emit = defineEmits<{
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.fiche-mini-card:focus-visible {
|
||||
/* Survol d'une épingle ou fiche sélectionnée : liseré safran */
|
||||
.fiche-mini-card--actif {
|
||||
border-color: var(--accent);
|
||||
box-shadow: inset 3px 0 0 var(--accent);
|
||||
}
|
||||
|
||||
.fiche-mini-card:has(.fiche-mini-card__ouvrir:focus-visible) {
|
||||
outline: 2px solid var(--focus-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Bouton étiré : toute la carte ouvre la fiche, les chips cliquables passent dessus */
|
||||
.fiche-mini-card__ouvrir {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.fiche-mini-card__ouvrir::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
}
|
||||
.fiche-mini-card__ouvrir:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.fiche-mini-card__nom {
|
||||
width: 100%;
|
||||
font-size: var(--fs-sm);
|
||||
@@ -92,7 +153,13 @@ const emit = defineEmits<{
|
||||
}
|
||||
|
||||
.fiche-mini-card__chips {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: var(--space-xs);
|
||||
pointer-events: none;
|
||||
}
|
||||
.fiche-mini-card__chips :deep(button) {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.fiche-mini-card__no-geo {
|
||||
|
||||
Reference in New Issue
Block a user