feat(aep): Soutenir dans le menu déroulant, bandeau bas retiré, cartes Mistral et « souverain » retirés
Décisions Jules du 27/09 : ① À propos sans les cartes Mistral Nemo / Small (modèles qui ne sont plus en service), Le Chat sans « souverain » (outils.vue et fmhy-curated.json) ; ② le bandeau bas (transparence IA + don) est retiré, le menu déroulant devient visible à toutes les largeurs et porte un bouton Soutenir → liberapay.com/trans-former.fr/donate (onglets masqués dedans ≥1024px). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -163,8 +163,8 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
||||||
<!-- Hamburger mobile (lg:hidden) — toujours en dernier à droite -->
|
<!-- Menu déroulant — toutes largeurs (les onglets n'y apparaissent qu'en dessous de 1024px) ; porte « Soutenir » -->
|
||||||
<div class="lg:hidden relative">
|
<div class="relative">
|
||||||
<button
|
<button
|
||||||
@click="hamburgerOpen = !hamburgerOpen"
|
@click="hamburgerOpen = !hamburgerOpen"
|
||||||
class="p-2 rounded-lg transition-all hover:opacity-80"
|
class="p-2 rounded-lg transition-all hover:opacity-80"
|
||||||
@@ -185,16 +185,16 @@
|
|||||||
style="background: var(--nav-surface); border: 1px solid var(--nav-bg-alt); z-index: 9999;"
|
style="background: var(--nav-surface); border: 1px solid var(--nav-bg-alt); z-index: 9999;"
|
||||||
@click="hamburgerOpen = false"
|
@click="hamburgerOpen = false"
|
||||||
>
|
>
|
||||||
<NuxtLink to="/outils" class="block px-4 py-2.5 text-sm font-medium transition-opacity hover:opacity-70" :style="route.path === '/outils' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Outils</NuxtLink>
|
<NuxtLink to="/outils" class="lg:hidden block px-4 py-2.5 text-sm font-medium transition-opacity hover:opacity-70" :style="route.path === '/outils' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Outils</NuxtLink>
|
||||||
<NuxtLink to="/" class="block px-4 py-2.5 text-sm font-medium transition-opacity hover:opacity-70" :style="route.path === '/' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Écosystème Entraide</NuxtLink>
|
<NuxtLink to="/" class="lg:hidden block px-4 py-2.5 text-sm font-medium transition-opacity hover:opacity-70" :style="route.path === '/' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Écosystème Entraide</NuxtLink>
|
||||||
<NuxtLink to="/agences" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/agences' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Réseaux AEP</NuxtLink>
|
<NuxtLink to="/agences" class="lg:hidden block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/agences' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Réseaux AEP</NuxtLink>
|
||||||
<NuxtLink to="/trouver-du-taf" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/trouver-du-taf' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Jobs</NuxtLink>
|
<NuxtLink to="/trouver-du-taf" class="lg:hidden block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/trouver-du-taf' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Jobs</NuxtLink>
|
||||||
<NuxtLink to="/media" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path.startsWith('/media') ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">recherche-média</NuxtLink>
|
<NuxtLink to="/media" class="lg:hidden block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path.startsWith('/media') ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">recherche-média</NuxtLink>
|
||||||
<NuxtLink to="/codev" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path.startsWith('/codev') ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Codev</NuxtLink>
|
<NuxtLink to="/codev" class="lg:hidden block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path.startsWith('/codev') ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text);'">Codev</NuxtLink>
|
||||||
<div style="height: 1px; background: var(--nav-bg-alt); margin: 4px 0;"></div>
|
<div class="lg:hidden" style="height: 1px; background: var(--nav-bg-alt); margin: 4px 0;"></div>
|
||||||
<NuxtLink to="/manifeste" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/manifeste' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text-muted);'">Manifeste</NuxtLink>
|
<NuxtLink to="/manifeste" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" :style="route.path === '/manifeste' ? 'color: var(--nav-primary-solid); font-weight: 700;' : 'color: var(--nav-text-muted);'">Manifeste</NuxtLink>
|
||||||
<NuxtLink to="/a-propos" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" style="color: var(--nav-text-muted);">À propos</NuxtLink>
|
<NuxtLink to="/a-propos" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" style="color: var(--nav-text-muted);">À propos</NuxtLink>
|
||||||
<a href="https://liberapay.com/trans-former.fr/donate" target="_blank" rel="noopener noreferrer" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" style="color: var(--nav-text-muted);">Soutenir →</a>
|
<a href="https://liberapay.com/trans-former.fr/donate" target="_blank" rel="noopener noreferrer" class="block mx-3 my-2 px-4 py-2 rounded-lg text-sm font-semibold text-center transition-opacity hover:opacity-80" style="background: var(--nav-accent); color: var(--nav-text);">Soutenir</a>
|
||||||
<NuxtLink to="/signaler" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" style="color: var(--nav-text-muted);">Signaler</NuxtLink>
|
<NuxtLink to="/signaler" class="block px-4 py-2.5 text-sm transition-opacity hover:opacity-70" style="color: var(--nav-text-muted);">Signaler</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,9 +206,6 @@
|
|||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bandeau bas — transparence IA + soutien + compteurs semaine -->
|
|
||||||
<BandeauBas />
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,488 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- ═══════════════════════════════════════ BANDEAU BAS ═══════════════════ -->
|
|
||||||
<!-- DESKTOP uniquement (≥1024px) — mobile a le FAB séparé -->
|
|
||||||
<footer
|
|
||||||
v-if="!isMobile"
|
|
||||||
ref="bandeauEl"
|
|
||||||
class="bandeau-bas shrink-0"
|
|
||||||
:class="{ 'bandeau-collapsed': isCollapsed }"
|
|
||||||
aria-label="Informations projet AEP"
|
|
||||||
@mouseenter="onMouseEnter"
|
|
||||||
@mouseleave="onMouseLeave"
|
|
||||||
>
|
|
||||||
<!-- Contenu plein -->
|
|
||||||
<div class="bandeau-inner" :class="{ 'bandeau-inner--hidden': isCollapsed }">
|
|
||||||
|
|
||||||
<!-- ── GAUCHE : Transparence IA ──────────────────────────────────────── -->
|
|
||||||
<div class="bandeau-col">
|
|
||||||
<p class="bandeau-label">Transparence IA</p>
|
|
||||||
<template v-if="stats">
|
|
||||||
<p class="bandeau-value">
|
|
||||||
Coût IA ce mois : <strong>{{ stats.cout_mois_eur.toFixed(2) }} €</strong>
|
|
||||||
·
|
|
||||||
Tokens : <strong>{{ stats.tokens_mois.toLocaleString('fr-FR') }}</strong>
|
|
||||||
</p>
|
|
||||||
<!-- Jauge -->
|
|
||||||
<div class="jauge-track" aria-label="Budget IA consommé" role="progressbar" :aria-valuenow="jaugePct" aria-valuemin="0" aria-valuemax="100">
|
|
||||||
<div class="jauge-fill" :style="{ width: jaugePct + '%' }" />
|
|
||||||
</div>
|
|
||||||
<p class="bandeau-sub">
|
|
||||||
{{ stats.requetes_mois }} requête{{ stats.requetes_mois !== 1 ? 's' : '' }} ce mois
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="loading">
|
|
||||||
<p class="bandeau-sub">Chargement…</p>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<p class="bandeau-sub">Données indisponibles</p>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ── MILIEU : CTA Soutien ──────────────────────────────────────────── -->
|
|
||||||
<div class="bandeau-col bandeau-col--center">
|
|
||||||
<div class="soutenir-wrap">
|
|
||||||
<button
|
|
||||||
class="btn-soutenir"
|
|
||||||
type="button"
|
|
||||||
@click="modalOpen = true"
|
|
||||||
@mouseenter="tooltipVisible = true"
|
|
||||||
@mouseleave="tooltipVisible = false"
|
|
||||||
@focus="tooltipVisible = true"
|
|
||||||
@blur="tooltipVisible = false"
|
|
||||||
aria-label="Soutenir le projet AEP sur Liberapay"
|
|
||||||
>
|
|
||||||
Soutenir le projet
|
|
||||||
</button>
|
|
||||||
<!-- Tooltip au hover -->
|
|
||||||
<div v-if="tooltipVisible" class="soutenir-tooltip" role="tooltip">
|
|
||||||
1 € = 30 fiches mises en ligne
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ── DROITE : Compteurs semaine ────────────────────────────────────── -->
|
|
||||||
<div class="bandeau-col bandeau-col--right">
|
|
||||||
<p class="bandeau-label">Cette semaine</p>
|
|
||||||
<template v-if="stats">
|
|
||||||
<p class="bandeau-value">
|
|
||||||
{{ stats.fiches_semaine }} fiche{{ stats.fiches_semaine !== 1 ? 's' : '' }} ajoutée{{ stats.fiches_semaine !== 1 ? 's' : '' }}
|
|
||||||
</p>
|
|
||||||
<p class="bandeau-sub">
|
|
||||||
{{ stats.requetes_chatbot_semaine }} requête{{ stats.requetes_chatbot_semaine !== 1 ? 's' : '' }} chatbot
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<p class="bandeau-sub">—</p>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Barre fine (état collapsed) -->
|
|
||||||
<div class="bandeau-thin" :class="{ 'bandeau-thin--visible': isCollapsed }">
|
|
||||||
<span class="bandeau-thin-label">AEP · Transparence IA</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ── MODAL Liberapay ───────────────────────────────────────────────── -->
|
|
||||||
<Teleport to="body">
|
|
||||||
<Transition name="backdrop">
|
|
||||||
<div
|
|
||||||
v-if="modalOpen"
|
|
||||||
class="modal-backdrop"
|
|
||||||
@click="modalOpen = false"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</Transition>
|
|
||||||
<Transition name="modal">
|
|
||||||
<div
|
|
||||||
v-if="modalOpen"
|
|
||||||
class="modal-box"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
aria-label="Soutenir AEP sur Liberapay"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="modal-close"
|
|
||||||
type="button"
|
|
||||||
@click="modalOpen = false"
|
|
||||||
aria-label="Fermer"
|
|
||||||
>
|
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" aria-hidden="true">
|
|
||||||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<h2 class="modal-title">Soutenir AEP</h2>
|
|
||||||
<p class="modal-desc">
|
|
||||||
AEP est un outil libre, sans publicité, financé par les dons.
|
|
||||||
1 € finance environ 30 fiches mises en ligne.
|
|
||||||
</p>
|
|
||||||
<div class="modal-widget">
|
|
||||||
<iframe
|
|
||||||
src="https://liberapay.com/trans-former.fr/widgets/button.html"
|
|
||||||
width="95"
|
|
||||||
height="22"
|
|
||||||
style="border: 0;"
|
|
||||||
title="Faire un don sur Liberapay"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href="https://liberapay.com/trans-former.fr/donate"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="modal-link"
|
|
||||||
>
|
|
||||||
Faire un don sur Liberapay →
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Transition>
|
|
||||||
</Teleport>
|
|
||||||
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<!-- Mobile (< 1024px) : pas de FAB — Soutenir est dans le menu hamburger -->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
interface Stats {
|
|
||||||
cout_mois_eur: number
|
|
||||||
budget_mois: number
|
|
||||||
tokens_mois: number
|
|
||||||
co2_kg: number
|
|
||||||
requetes_mois: number
|
|
||||||
fiches_semaine: number
|
|
||||||
requetes_chatbot_semaine: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const stats = ref<Stats | null>(null)
|
|
||||||
const loading = ref(true)
|
|
||||||
const modalOpen = ref(false)
|
|
||||||
const tooltipVisible = ref(false)
|
|
||||||
|
|
||||||
// Desktop — replié par défaut, déploie au hover, replie immédiatement à la sortie
|
|
||||||
const bandeauEl = ref<HTMLElement | null>(null)
|
|
||||||
const isCollapsed = ref(true) // replié par défaut
|
|
||||||
|
|
||||||
const REFRESH_MS = 5 * 60 * 1000 // 5 minutes
|
|
||||||
|
|
||||||
// Détection mobile côté client
|
|
||||||
const isMobile = ref(false)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
isMobile.value = window.innerWidth < 1024
|
|
||||||
|
|
||||||
const handleResize = () => {
|
|
||||||
isMobile.value = window.innerWidth < 1024
|
|
||||||
}
|
|
||||||
window.addEventListener('resize', handleResize)
|
|
||||||
onUnmounted(() => window.removeEventListener('resize', handleResize))
|
|
||||||
|
|
||||||
fetchStats()
|
|
||||||
const interval = setInterval(fetchStats, REFRESH_MS)
|
|
||||||
onUnmounted(() => clearInterval(interval))
|
|
||||||
})
|
|
||||||
|
|
||||||
function onMouseEnter() {
|
|
||||||
isCollapsed.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMouseLeave() {
|
|
||||||
// Repli immédiat — pas de timer
|
|
||||||
isCollapsed.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchStats() {
|
|
||||||
try {
|
|
||||||
const res = await $fetch<Stats>('/api/stats')
|
|
||||||
stats.value = res
|
|
||||||
} catch {
|
|
||||||
stats.value = null
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const jaugePct = computed(() => {
|
|
||||||
if (!stats.value) return 0
|
|
||||||
return Math.min(100, Math.round((stats.value.cout_mois_eur / stats.value.budget_mois) * 100))
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* ── Bandeau bas ─────────────────────────────────────────────────────────── */
|
|
||||||
.bandeau-bas {
|
|
||||||
background: rgba(26, 34, 56, 0.7); /* opacité 70% */
|
|
||||||
color: var(--nav-text-on-primary);
|
|
||||||
font-family: var(--nav-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
|
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
||||||
transition: min-height 0.25s ease;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-collapsed {
|
|
||||||
min-height: 32px !important;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-inner {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 16px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
max-width: 1400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
min-height: 64px;
|
|
||||||
transition: opacity 0.2s ease, max-height 0.3s ease;
|
|
||||||
max-height: 200px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-inner--hidden {
|
|
||||||
opacity: 0;
|
|
||||||
max-height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Barre fine (collapsed) */
|
|
||||||
.bandeau-thin {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-thin--visible {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-thin-label {
|
|
||||||
font-size: 0.65rem;
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.08em;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Colonnes ────────────────────────────────────────────────────────────── */
|
|
||||||
.bandeau-col {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 3px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-col--center {
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
padding-top: 8px; /* décaler légèrement vers le bas pour mieux centrer dans la hauteur */
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-col--right {
|
|
||||||
align-items: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Typo ────────────────────────────────────────────────────────────────── */
|
|
||||||
.bandeau-label {
|
|
||||||
font-size: 0.65rem;
|
|
||||||
font-weight: 700;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.07em;
|
|
||||||
opacity: 0.65;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-value {
|
|
||||||
font-size: 0.775rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--nav-text-on-primary);
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-value strong {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bandeau-sub {
|
|
||||||
font-size: 0.68rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Jauge budget ────────────────────────────────────────────────────────── */
|
|
||||||
.jauge-track {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 180px;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
background: rgba(255, 255, 255, 0.18);
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 3px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.jauge-fill {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 2px;
|
|
||||||
background: var(--nav-accent);
|
|
||||||
transition: width 0.6s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Bouton soutenir + tooltip ───────────────────────────────────────────── */
|
|
||||||
.soutenir-wrap {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-soutenir {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 7px 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: none;
|
|
||||||
background: var(--nav-accent);
|
|
||||||
color: var(--nav-text);
|
|
||||||
font-size: 0.8rem;
|
|
||||||
font-weight: 700;
|
|
||||||
font-family: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap;
|
|
||||||
transition: opacity 0.15s, transform 0.1s;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-soutenir:hover { opacity: 0.88; transform: translateY(-1px); }
|
|
||||||
.btn-soutenir:active { opacity: 1; transform: translateY(0); }
|
|
||||||
|
|
||||||
.soutenir-tooltip {
|
|
||||||
position: absolute;
|
|
||||||
bottom: calc(100% + 8px);
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
background: var(--nav-primary-solid, #1a2238);
|
|
||||||
color: var(--nav-text-on-primary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 6px;
|
|
||||||
white-space: nowrap;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.soutenir-tooltip::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
border: 5px solid transparent;
|
|
||||||
border-top-color: var(--nav-primary-solid, #1a2238);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Modal ───────────────────────────────────────────────────────────────── */
|
|
||||||
.modal-backdrop {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 2000;
|
|
||||||
background: rgba(26, 34, 56, 0.55);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-box {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
z-index: 2001;
|
|
||||||
background: var(--nav-surface, #ffffff);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 28px 24px 24px;
|
|
||||||
width: min(380px, 90vw);
|
|
||||||
box-shadow: 0 8px 40px rgba(26, 34, 56, 0.22);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close {
|
|
||||||
position: absolute;
|
|
||||||
top: 14px;
|
|
||||||
right: 14px;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: none;
|
|
||||||
background: var(--nav-bg-alt, #eee9df);
|
|
||||||
color: var(--nav-text-muted, rgba(26,34,56,0.55));
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
.modal-close:hover { background: var(--nav-bg, #f8f6f1); }
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
font-size: 1.05rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--nav-text, #1a2238);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-desc {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: var(--nav-text-muted, rgba(26,34,56,0.55));
|
|
||||||
line-height: 1.6;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-widget {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 12px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-link {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
color: var(--nav-primary-solid, #1a2238);
|
|
||||||
text-decoration: underline;
|
|
||||||
transition: opacity 0.15s;
|
|
||||||
}
|
|
||||||
.modal-link:hover { opacity: 0.7; }
|
|
||||||
|
|
||||||
/* ── Transitions ─────────────────────────────────────────────────────────── */
|
|
||||||
.backdrop-enter-active, .backdrop-leave-active { transition: opacity 0.2s ease; }
|
|
||||||
.backdrop-enter-from, .backdrop-leave-to { opacity: 0; }
|
|
||||||
|
|
||||||
.modal-enter-active, .modal-leave-active { transition: opacity 0.2s ease, transform 0.2s ease; }
|
|
||||||
.modal-enter-from, .modal-leave-to { opacity: 0; transform: translate(-50%, -48%); }
|
|
||||||
|
|
||||||
.sheet-enter-active, .sheet-leave-active { transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1); }
|
|
||||||
.sheet-enter-from, .sheet-leave-to { transform: translateY(100%); }
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.btn-soutenir { transition: none; }
|
|
||||||
.jauge-fill { transition: none; }
|
|
||||||
.modal-enter-active, .modal-leave-active { transition: none; }
|
|
||||||
.backdrop-enter-active, .backdrop-leave-active { transition: none; }
|
|
||||||
.sheet-enter-active, .sheet-leave-active { transition: none; }
|
|
||||||
.bandeau-bas { transition: none; }
|
|
||||||
.bandeau-inner { transition: none; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -95,22 +95,8 @@
|
|||||||
L'IA est un outil. La question, c'est au service de quoi. Oui, elle est énergivore - et il faut l'assumer. Mais si c'est au service de l'émancipation, du collectif, de transformer nos infrastructures sociétales, alors on dit oui - en sachant que c'est une étape transitoire. L'infrastructure de l'IA elle-même peut évoluer : devenir plus locale, plus sobre, plus souveraine. C'est dans cette direction qu'on regarde.
|
L'IA est un outil. La question, c'est au service de quoi. Oui, elle est énergivore - et il faut l'assumer. Mais si c'est au service de l'émancipation, du collectif, de transformer nos infrastructures sociétales, alors on dit oui - en sachant que c'est une étape transitoire. L'infrastructure de l'IA elle-même peut évoluer : devenir plus locale, plus sobre, plus souveraine. C'est dans cette direction qu'on regarde.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="ia-grid">
|
|
||||||
<div class="ia-card">
|
|
||||||
<div class="ia-card-label">Enrichissement des fiches</div>
|
|
||||||
<div class="ia-card-model">Mistral Nemo</div>
|
|
||||||
<div class="ia-card-cost">~0,00003 €/fiche</div>
|
|
||||||
</div>
|
|
||||||
<div class="ia-card">
|
|
||||||
<div class="ia-card-label">Chatbot de recherche</div>
|
|
||||||
<div class="ia-card-model">Mistral Small</div>
|
|
||||||
<div class="ia-card-cost">~0,003 €/requête</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="ia-details">
|
<ul class="ia-details">
|
||||||
<li>10 € / mois investis au départ par le collectif - vos dons constituent la réserve pour faire vivre le projet et financer ses recherches</li>
|
<li>10 € / mois investis au départ par le collectif - vos dons constituent la réserve pour faire vivre le projet et financer ses recherches</li>
|
||||||
<li>Coût visible en direct dans le bandeau bas de la carte</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -390,49 +376,6 @@ function copyApiUrl() {
|
|||||||
|
|
||||||
/* ── IA grid ─────────────────────────────────────────────────────────────────── */
|
/* ── IA grid ─────────────────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
.ia-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 0.75rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.ia-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ia-card {
|
|
||||||
background: var(--nav-surface);
|
|
||||||
border: 1px solid rgba(26, 34, 56, 0.1);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 1rem 1.125rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ia-card-label {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
color: var(--nav-text-muted);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ia-card-model {
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--nav-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ia-card-cost {
|
|
||||||
font-size: 0.825rem;
|
|
||||||
color: var(--nav-text-muted);
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ia-details {
|
.ia-details {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
+1
-1
@@ -327,7 +327,7 @@ const fmhyGuide = [
|
|||||||
{ nom: 'DeepSeek', url: 'https://chat.deepseek.com/', desc: 'modèle de pointe, usage illimité gratuit' },
|
{ nom: 'DeepSeek', url: 'https://chat.deepseek.com/', desc: 'modèle de pointe, usage illimité gratuit' },
|
||||||
{ nom: 'Qwen Studio', url: 'https://chat.qwen.ai/', desc: 'chat IA (Qwen) illimité gratuit' },
|
{ nom: 'Qwen Studio', url: 'https://chat.qwen.ai/', desc: 'chat IA (Qwen) illimité gratuit' },
|
||||||
{ nom: 'Google AI Studio', url: 'https://aistudio.google.com/', desc: 'Gemini en accès généreux gratuit' },
|
{ nom: 'Google AI Studio', url: 'https://aistudio.google.com/', desc: 'Gemini en accès généreux gratuit' },
|
||||||
{ nom: 'Mistral Le Chat', url: 'https://chat.mistral.ai/', desc: 'LLM français, souverain, gratuit' },
|
{ nom: 'Mistral Le Chat', url: 'https://chat.mistral.ai/', desc: 'LLM français, gratuit' },
|
||||||
{ nom: 'LM Studio', url: 'https://lmstudio.ai/', desc: 'faire tourner des modèles en local, sans cloud' },
|
{ nom: 'LM Studio', url: 'https://lmstudio.ai/', desc: 'faire tourner des modèles en local, sans cloud' },
|
||||||
{ nom: 'Jan', url: 'https://jan.ai/', desc: 'application desktop libre pour IA locale' },
|
{ nom: 'Jan', url: 'https://jan.ai/', desc: 'application desktop libre pour IA locale' },
|
||||||
{ nom: 'Open WebUI', url: 'https://openwebui.com/', desc: 'interface web auto-hébergeable pour modèles locaux' }
|
{ nom: 'Open WebUI', url: 'https://openwebui.com/', desc: 'interface web auto-hébergeable pour modèles locaux' }
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{ "name": "ChatGPT (OpenAI)", "url": "https://chat.openai.com/", "desc": "LLM généraliste, référence." },
|
{ "name": "ChatGPT (OpenAI)", "url": "https://chat.openai.com/", "desc": "LLM généraliste, référence." },
|
||||||
{ "name": "Claude (Anthropic)", "url": "https://claude.ai/", "desc": "Excellent pour rédaction longue et analyse de documents." },
|
{ "name": "Claude (Anthropic)", "url": "https://claude.ai/", "desc": "Excellent pour rédaction longue et analyse de documents." },
|
||||||
{ "name": "Mistral Le Chat", "url": "https://chat.mistral.ai/", "desc": "LLM français, souverain, gratuit." },
|
{ "name": "Mistral Le Chat", "url": "https://chat.mistral.ai/", "desc": "LLM français, gratuit." },
|
||||||
{ "name": "Perplexity", "url": "https://www.perplexity.ai/", "desc": "Moteur de recherche IA avec sources citées." },
|
{ "name": "Perplexity", "url": "https://www.perplexity.ai/", "desc": "Moteur de recherche IA avec sources citées." },
|
||||||
{ "name": "Hugging Face", "url": "https://huggingface.co/", "desc": "Hub de modèles open source. Indispensable." },
|
{ "name": "Hugging Face", "url": "https://huggingface.co/", "desc": "Hub de modèles open source. Indispensable." },
|
||||||
{ "name": "LM Studio", "url": "https://lmstudio.ai/", "desc": "Faire tourner des LLM localement, sans cloud." }
|
{ "name": "LM Studio", "url": "https://lmstudio.ai/", "desc": "Faire tourner des LLM localement, sans cloud." }
|
||||||
|
|||||||
Reference in New Issue
Block a user