feat(media): Phase 8.G noeuds-ecoles + popup RAG info + lien Bonpote + migration Nebius
- CartePensees: noeuds ecole visibles (cercles proportionnels count auteurs, cliquables, emit select-ecole) - CartePensees: collision D3 ajustee pour repulsion auteurs autour des noeuds ecole - FicheEcole: nouveau composant modal (liste auteurs ingeres/non-ingeres, interroger RAG) - media: header lien Bonpote V2 cliquable + bouton i info RAG - media: popup FRACAS (description RAG, 662 dimensions, 3 couches, localStorage 1ere visite) - media: FicheEcole branchee (select-ecole, select-auteur-from-ecole, interroger-ecole) - ChatbotPensees: suppression mention corpusCount hardcoded (double source de verite) - chatbot, chatbot-v2, chatbot-reseaux, chatbot-taff: migration Mistral -> Nebius DeepSeek-V3.2 - nuxt.config: ajout nebiusApiKey runtime config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
101
components/FicheEcole.vue
Normal file
101
components/FicheEcole.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<Transition name="backdrop">
|
||||
<div v-if="open && ecole" class="fixed inset-0 z-[1500]" style="background: rgba(26,34,56,0.55);" @click="emit('close')" aria-hidden="true" />
|
||||
</Transition>
|
||||
<Transition name="modal">
|
||||
<div v-if="open && ecole" class="fixed z-[1501] left-1/2 flex flex-col"
|
||||
style="top:50%;transform:translate(-50%,-50%);width:min(540px,94vw);max-height:85vh;background:var(--nav-bg);border-radius:14px;box-shadow:0 16px 64px rgba(26,34,56,0.28);overflow:hidden;"
|
||||
role="dialog" aria-modal="true">
|
||||
<!-- Header -->
|
||||
<div class="flex items-start justify-between px-5 py-4 shrink-0"
|
||||
:style="`border-bottom: 3px solid ${ecole.color}; background: var(--nav-surface);`">
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="px-2 py-0.5 rounded-full text-xs font-semibold" :style="`background:${ecole.color}22;color:${ecole.color};`">Ecole de pensee</span>
|
||||
<h2 class="mt-2 font-bold text-lg leading-tight" style="color:var(--nav-text);">{{ ecole.label }}</h2>
|
||||
<p class="text-sm mt-1 leading-relaxed" style="color:var(--nav-text-muted);">{{ ecole.description }}</p>
|
||||
</div>
|
||||
<button @click="emit('close')" class="ml-3 shrink-0 flex items-center justify-center w-8 h-8 rounded-full hover:opacity-70"
|
||||
style="background:var(--nav-bg-alt);color:var(--nav-text-muted);" aria-label="Fermer">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Body -->
|
||||
<div class="flex-1 overflow-y-auto px-5 py-4 flex flex-col gap-4">
|
||||
<div v-if="auteursIngeres.length">
|
||||
<p class="text-xs font-bold uppercase tracking-widest mb-2" style="color:var(--nav-text-muted);">Dans le RAG ({{ auteursIngeres.length }})</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button v-for="a in auteursIngeres" :key="a.id"
|
||||
class="px-2.5 py-1 rounded-full text-xs font-medium hover:opacity-80 transition-opacity"
|
||||
:style="`background:${ecole.color}22;color:${ecole.color};border:1px solid ${ecole.color}44;cursor:pointer;`"
|
||||
@click="onSelectAuteur(a.id)">
|
||||
{{ a.nom }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="auteursNonIngeres.length">
|
||||
<p class="text-xs font-bold uppercase tracking-widest mb-2" style="color:var(--nav-text-muted);">Presents dans Bonpote, pas encore dans le RAG ({{ auteursNonIngeres.length }})</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span v-for="a in auteursNonIngeres" :key="a.id"
|
||||
class="px-2.5 py-1 rounded-full text-xs"
|
||||
style="background:var(--nav-bg-alt);color:var(--nav-text-muted);">
|
||||
{{ a.nom }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<div class="shrink-0 px-5 py-3 border-t" style="border-color:var(--nav-bg-alt);">
|
||||
<button @click="emit('interroger-ecole', ecoleId!)" class="w-full py-2.5 rounded-lg text-sm font-semibold hover:opacity-80"
|
||||
:style="`background:${ecole.color};color:white;`">
|
||||
Interroger le RAG sur {{ ecole.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface AuteurData { id: string; nom: string; ecoles: string[]; ecole_principale: string; ingere: boolean }
|
||||
interface EcoleData { id: string; label: string; description: string; color: string }
|
||||
interface PenseesData { ecoles: EcoleData[]; auteurs: AuteurData[] }
|
||||
|
||||
const props = defineProps<{ open: boolean; ecoleId: string | null; data: PenseesData | null }>()
|
||||
const emit = defineEmits<{ close: []; 'select-auteur': [auteurId: string]; 'interroger-ecole': [ecoleId: string] }>()
|
||||
|
||||
const ecole = computed<EcoleData | null>(() => {
|
||||
if (!props.ecoleId || !props.data) return null
|
||||
return props.data.ecoles.find(e => e.id === props.ecoleId) ?? null
|
||||
})
|
||||
|
||||
const auteursIngeres = computed(() => {
|
||||
if (!props.ecoleId || !props.data) return []
|
||||
return props.data.auteurs.filter(a => a.ecole_principale === props.ecoleId && (a as any).ingere)
|
||||
})
|
||||
|
||||
const auteursNonIngeres = computed(() => {
|
||||
if (!props.ecoleId || !props.data) return []
|
||||
return props.data.auteurs.filter(a => a.ecole_principale === props.ecoleId && !(a as any).ingere)
|
||||
})
|
||||
|
||||
function onSelectAuteur(id: string) {
|
||||
emit('close')
|
||||
emit('select-auteur', id)
|
||||
}
|
||||
|
||||
function onKey(e: KeyboardEvent) { if (e.key === 'Escape' && props.open) emit('close') }
|
||||
onMounted(() => window.addEventListener('keydown', onKey))
|
||||
onUnmounted(() => window.removeEventListener('keydown', onKey))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.backdrop-enter-active,.backdrop-leave-active { transition: opacity 0.2s; }
|
||||
.backdrop-enter-from,.backdrop-leave-to { opacity: 0; }
|
||||
.modal-enter-active { transition: opacity 0.2s, transform 0.22s cubic-bezier(0.34,1.56,0.64,1); }
|
||||
.modal-leave-active { transition: opacity 0.18s, transform 0.18s ease-in; }
|
||||
.modal-enter-from { opacity: 0; transform: translate(-50%,-48%) scale(0.94); }
|
||||
.modal-leave-to { opacity: 0; transform: translate(-50%,-48%) scale(0.96); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user