fix(vue-fiches): passe /autofeedback — Échap dans un champ garde le brouillon, titre d'onglet = fiche ouverte, contrastes et mini-carte décorative de FicheDetail
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AGNSEFZdoKvbdsGyfSnu5S
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a6dcf48c71
commit
a9befb25ab
+14
-13
@@ -35,14 +35,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Méta : échelle + ville -->
|
<!-- Méta : échelle + ville -->
|
||||||
<div class="flex flex-wrap items-center gap-2 text-sm mb-3" style="color: var(--nav-text-muted);">
|
<div class="flex flex-wrap items-center gap-2 text-sm mb-3" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">
|
||||||
<span
|
<span
|
||||||
v-if="org.echelle"
|
v-if="org.echelle"
|
||||||
class="px-2 py-0.5 rounded-full text-xs font-medium"
|
class="px-2 py-0.5 rounded-full text-xs font-medium"
|
||||||
style="background: var(--nav-primary); color: var(--nav-text-on-primary);"
|
style="background: var(--nav-primary-solid); color: var(--nav-text-on-primary);"
|
||||||
>{{ org.echelle }}</span>
|
>{{ org.echelle }}</span>
|
||||||
<span v-if="org.territoire && org.territoire !== 'Métropole'" class="text-xs" style="color: var(--nav-text-muted);">{{ org.territoire }}</span>
|
<span v-if="org.territoire && org.territoire !== 'Métropole'" class="text-xs" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">{{ org.territoire }}</span>
|
||||||
<span v-if="org.localisation_ville" style="color: var(--nav-text-muted);">{{ org.localisation_ville }}</span>
|
<span v-if="org.localisation_ville" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">{{ org.localisation_ville }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tags fonction -->
|
<!-- Tags fonction -->
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<!-- Description soumise par le contributeur -->
|
<!-- Description soumise par le contributeur -->
|
||||||
<div v-if="descriptionUser" class="mb-4">
|
<div v-if="descriptionUser" class="mb-4">
|
||||||
<p class="text-sm leading-relaxed" style="color: var(--nav-text-muted);">Description communauté</p>
|
<p class="text-sm leading-relaxed" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">Description communauté</p>
|
||||||
<p class="mt-1 leading-relaxed" style="color: var(--nav-text);">{{ descriptionUser }}</p>
|
<p class="mt-1 leading-relaxed" style="color: var(--nav-text);">{{ descriptionUser }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
<!-- Description enrichie IA -->
|
<!-- Description enrichie IA -->
|
||||||
<div v-if="descriptionEnrichie" class="mb-4">
|
<div v-if="descriptionEnrichie" class="mb-4">
|
||||||
<p class="text-sm leading-relaxed flex items-center gap-1.5" style="color: var(--nav-text-muted);">
|
<p class="text-sm leading-relaxed flex items-center gap-1.5" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">
|
||||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
||||||
<path d="M2 17l10 5 10-5"/>
|
<path d="M2 17l10 5 10-5"/>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
<!-- Points clés -->
|
<!-- Points clés -->
|
||||||
<div v-if="pointsCles.length" class="mt-4">
|
<div v-if="pointsCles.length" class="mt-4">
|
||||||
<p class="text-sm font-medium mb-2" style="color: var(--nav-text-muted);">Points clés</p>
|
<p class="text-sm font-medium mb-2" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">Points clés</p>
|
||||||
<ul class="space-y-1">
|
<ul class="space-y-1">
|
||||||
<li
|
<li
|
||||||
v-for="(point, i) in pointsCles"
|
v-for="(point, i) in pointsCles"
|
||||||
@@ -123,11 +123,11 @@
|
|||||||
style="height: 180px; border: 1px solid var(--nav-bg-alt);"
|
style="height: 180px; border: 1px solid var(--nav-bg-alt);"
|
||||||
>
|
>
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<div ref="mapContainer" class="w-full h-full"></div>
|
<div ref="mapContainer" class="w-full h-full" role="img" :aria-label="`Carte : ${org.nom}${org.localisation_ville ? `, ${org.localisation_ville}` : ''}`"></div>
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<div
|
<div
|
||||||
class="w-full h-full flex items-center justify-center text-xs"
|
class="w-full h-full flex items-center justify-center text-xs"
|
||||||
style="background: var(--nav-bg-alt); color: var(--nav-text-muted);"
|
style="background: var(--nav-bg-alt); color: color-mix(in srgb, var(--nav-text) 78%, transparent);"
|
||||||
>Carte…</div>
|
>Carte…</div>
|
||||||
</template>
|
</template>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
<Transition name="report-form">
|
<Transition name="report-form">
|
||||||
<div v-if="reportOpen" class="report-panel">
|
<div v-if="reportOpen" class="report-panel">
|
||||||
<p class="text-xs mb-3" style="color: var(--nav-text-muted);">
|
<p class="text-xs mb-3" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent);">
|
||||||
Tes suggestions seront transmises à l'équipe AEP par email.
|
Tes suggestions seront transmises à l'équipe AEP par email.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p v-if="reportError" class="text-xs" style="color: #e53e3e;">{{ reportError }}</p>
|
<p v-if="reportError" class="text-xs" style="color: #e53e3e;">{{ reportError }}</p>
|
||||||
<p v-if="reportSuccess" class="text-xs" style="color: #38a169;">{{ reportSuccess }}</p>
|
<p v-if="reportSuccess" class="text-xs" style="color: #38a169;">{{ reportSuccess }}</p>
|
||||||
<p class="text-xs" style="color: var(--nav-text-muted); opacity: 0.6;">
|
<p class="text-xs" style="color: color-mix(in srgb, var(--nav-text) 78%, transparent); opacity: 0.6;">
|
||||||
{{ reportMessage.length }}/500
|
{{ reportMessage.length }}/500
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -331,7 +331,8 @@ async function initMap(el: HTMLElement) {
|
|||||||
iconAnchor: [7, 7],
|
iconAnchor: [7, 7],
|
||||||
})
|
})
|
||||||
|
|
||||||
L.marker([lat, lng], { icon }).addTo(map)
|
// Épingle décorative : ni clic ni clavier (la mini-carte est une image, nommée par son conteneur)
|
||||||
|
L.marker([lat, lng], { icon, interactive: false, keyboard: false }).addTo(map)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -342,7 +343,7 @@ async function initMap(el: HTMLElement) {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
color: var(--nav-text-muted);
|
color: color-mix(in srgb, var(--nav-text) 78%, transparent);
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -459,11 +459,18 @@ watch(() => props.vf.ficheId, (id, avant) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function clavierDetail(e: KeyboardEvent) {
|
function clavierDetail(e: KeyboardEvent) {
|
||||||
if (e.key === 'Escape') { e.preventDefault(); props.vf.fermerFiche(); return }
|
const t = e.target as HTMLElement
|
||||||
|
const champ = !!t.closest('input, textarea, select, [contenteditable="true"]')
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault()
|
||||||
|
// Échap dans un champ (commentaire, signalement) le quitte d'abord : un brouillon ne se perd pas d'une touche
|
||||||
|
if (champ) { detail.value?.focus({ preventScroll: true }); return }
|
||||||
|
props.vf.fermerFiche()
|
||||||
|
return
|
||||||
|
}
|
||||||
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return
|
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return
|
||||||
const t = e.target as HTMLElement
|
if (champ) return
|
||||||
if (t.closest('input, textarea, select, [contenteditable="true"]')) return
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (e.key === 'ArrowLeft') props.vf.fichePrecedente()
|
if (e.key === 'ArrowLeft') props.vf.fichePrecedente()
|
||||||
else props.vf.ficheSuivante()
|
else props.vf.ficheSuivante()
|
||||||
|
|||||||
+2
-1
@@ -250,7 +250,8 @@ onMounted(() => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
})
|
})
|
||||||
|
|
||||||
useHead({ title: "AEP - Réseaux de bifurcation architecturale" })
|
// Une fiche ouverte donne son nom à l'onglet (les données arrivent après le rendu serveur ici)
|
||||||
|
useHead({ title: computed(() => (vf.ficheOuverte ? `${vf.ficheOuverte.nom} — AEP` : 'AEP - Réseaux de bifurcation architecturale')) })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
+2
-1
@@ -249,7 +249,8 @@ onMounted(() => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
})
|
})
|
||||||
|
|
||||||
useHead({ title: 'AEP — Cartographie de l\'écologie politique architecturale' })
|
// Un lien partagé avec fiche= porte le nom de la fiche (onglet, aperçu de lien), dès le rendu serveur
|
||||||
|
useHead({ title: computed(() => (vf.ficheOuverte ? `${vf.ficheOuverte.nom} — AEP` : 'AEP — Cartographie de l\'écologie politique architecturale')) })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user