From 201cfbbb507f7bc0bd0eb87068a53faa4a2d7bf4 Mon Sep 17 00:00:00 2001 From: Yvv Date: Tue, 29 Sep 2026 05:59:33 +0200 Subject: [PATCH] =?UTF-8?q?design=20:=20accueil=20console=20seul,=20vrai?= =?UTF-8?q?=20=C2=A7,=20curseurs=20anim=C3=A9s,=20statuts,=20lecteur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - accueil : la console devient l'accueil unique (variantes B/C, sélecteur et ancien accueil retirés) ; curseurs qui montent de l'asservissement et dérivent seuls, un axe mis en avant à tour de rôle, arrêt au clic, immobiles en prefers-reduced-motion ; « AUTONOMIE » devant chaque axe, leviers mis en valeur, ligne des trois autonomies en couleurs - logo : § de Playfair Display (SIL OFL) vectorisé, composant partagé UiSectionSign (en-tête, page événement) + favicon.svg - UiStatusBadge (production / développement / gestation) sur l'accueil, les pages d'axe et les pages projet - liens libreDecision / SejeteralO fixés sur la prod (plus de repli localhost) - logiciel libre : bouton v1 dans la carte projet en tête de page - couverture du livre : recadrage corrigé (BookSection) - texte courant en Public Sans (zéros non barrés) - lecteur : la pastille persistante ne masque plus la navigation du BookPlayer ; lecture directe du MP3 (les .ogg n'existent pas : 404) Co-Authored-By: Claude Opus 5.5 --- app/app.config.ts | 4 +- app/assets/css/main.css | 9 +- app/components/book/BookPlayer.vue | 9 + app/components/home/AxisBlock.vue | 379 -------------- app/components/home/AxisGrid.vue | 237 --------- app/components/home/BookSection.vue | 6 +- app/components/home/HeroSection.vue | 120 ----- app/components/home/HomeConsole.vue | 209 +++++--- ...HomeVariantConsole.vue => HomeLanding.vue} | 39 +- app/components/home/HomeToolItem.vue | 18 +- app/components/home/HomeToolbox.vue | 8 +- app/components/home/HomeVariantEtabli.vue | 492 ------------------ app/components/home/HomeVariantParcours.vue | 321 ------------ app/components/home/HomeVariantSwitch.vue | 71 --- app/components/home/TypewriterText.vue | 279 ---------- app/components/layout/TheHeader.vue | 31 +- app/components/player/PlayerPersistent.vue | 6 + app/components/ui/SectionSign.vue | 16 + app/components/ui/StatusBadge.vue | 69 +++ app/composables/useAudioPlayer.ts | 24 +- app/composables/useHomeData.ts | 11 +- app/composables/useSiteContent.ts | 1 - app/pages/citoyenne/[slug].vue | 5 +- app/pages/citoyenne/index.vue | 11 +- app/pages/economique/index.vue | 11 +- app/pages/economique/monnaie-libre.vue | 1 + .../economique/productions-collectives.vue | 7 +- app/pages/evenement.vue | 24 +- app/pages/index.vue | 31 +- app/pages/numerique/[slug].vue | 39 +- app/pages/numerique/index.vue | 16 +- nuxt.config.ts | 3 +- public/favicon.svg | 9 + 33 files changed, 416 insertions(+), 2100 deletions(-) delete mode 100644 app/components/home/AxisBlock.vue delete mode 100644 app/components/home/AxisGrid.vue delete mode 100644 app/components/home/HeroSection.vue rename app/components/home/{HomeVariantConsole.vue => HomeLanding.vue} (77%) delete mode 100644 app/components/home/HomeVariantEtabli.vue delete mode 100644 app/components/home/HomeVariantParcours.vue delete mode 100644 app/components/home/HomeVariantSwitch.vue delete mode 100644 app/components/home/TypewriterText.vue create mode 100644 app/components/ui/SectionSign.vue create mode 100644 app/components/ui/StatusBadge.vue create mode 100644 public/favicon.svg diff --git a/app/app.config.ts b/app/app.config.ts index f899a6e..4cab6a7 100644 --- a/app/app.config.ts +++ b/app/app.config.ts @@ -21,9 +21,9 @@ export default defineAppConfig({ }, }, libredecision: { - url: import.meta.dev ? 'http://localhost:3002' : 'https://decision.librodrome.org', + url: 'https://decision.librodrome.org', }, sejeteral0: { - url: import.meta.dev ? 'http://localhost:3009' : 'https://collectivites.librodrome.org', + url: 'https://collectivites.librodrome.org', }, }) diff --git a/app/assets/css/main.css b/app/assets/css/main.css index c20a663..fb2a669 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -16,7 +16,7 @@ --sidebar-width: 280px; --font-display: 'Bricolage Grotesque', system-ui, sans-serif; - --font-sans: 'Atkinson Hyperlegible', system-ui, sans-serif; + --font-sans: 'Public Sans', system-ui, sans-serif; --font-logo: 'Syne', sans-serif; /* One hue per axis — overridden by each palette (stores/palette.ts) */ @@ -29,6 +29,13 @@ --ease-in-out-expo: cubic-bezier(0.87, 0, 0.13, 1); } +/* Fader level of the home console — registered so it can transition smoothly */ +@property --level { + syntax: ''; + inherits: true; + initial-value: 0; +} + *, *::before, *::after { diff --git a/app/components/book/BookPlayer.vue b/app/components/book/BookPlayer.vue index 5ac31a5..3e8cf4e 100644 --- a/app/components/book/BookPlayer.vue +++ b/app/components/book/BookPlayer.vue @@ -378,6 +378,15 @@ function onTouchEnd(e: TouchEvent) { } // ── Lifecycle ── +// While the reader is open, the persistent mini player (above it) lifts up +// so it does not cover the reader navigation. +if (import.meta.client) { + watch(isOpen, (open) => { + document.documentElement.classList.toggle('book-player-open', open) + }, { immediate: true }) + onUnmounted(() => document.documentElement.classList.remove('book-player-open')) +} + watch(isOpen, async (open) => { if (open) { showSommaire.value = false diff --git a/app/components/home/AxisBlock.vue b/app/components/home/AxisBlock.vue deleted file mode 100644 index a235edc..0000000 --- a/app/components/home/AxisBlock.vue +++ /dev/null @@ -1,379 +0,0 @@ - - - - - diff --git a/app/components/home/AxisGrid.vue b/app/components/home/AxisGrid.vue deleted file mode 100644 index 92ea63b..0000000 --- a/app/components/home/AxisGrid.vue +++ /dev/null @@ -1,237 +0,0 @@ - - - - - diff --git a/app/components/home/BookSection.vue b/app/components/home/BookSection.vue index 5ebe77c..ac835ae 100644 --- a/app/components/home/BookSection.vue +++ b/app/components/home/BookSection.vue @@ -89,9 +89,9 @@ const titleLine2 = computed(() => titleParts.value[1]) .book-cover-3d { width: 100%; max-width: 360px; - aspect-ratio: 3 / 4; - background-size: 200% auto; - background-position: right center; + aspect-ratio: 1756 / 2480; + background-size: cover; + background-position: center; background-repeat: no-repeat; border-radius: 0.75rem; overflow: hidden; diff --git a/app/components/home/HeroSection.vue b/app/components/home/HeroSection.vue deleted file mode 100644 index 99fcb82..0000000 --- a/app/components/home/HeroSection.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - - - diff --git a/app/components/home/HomeConsole.vue b/app/components/home/HomeConsole.vue index 00574f4..d74fba4 100644 --- a/app/components/home/HomeConsole.vue +++ b/app/components/home/HomeConsole.vue @@ -1,17 +1,25 @@ + + {{ action.note }} + @@ -113,16 +116,15 @@ a.tool-name:hover { color: hsl(var(--hue)); } -.tool-state { +.tool-status { margin-left: 0.4rem; - font-family: var(--font-mono); - font-size: 0.64rem; - color: hsl(var(--color-text) / 0.5); - white-space: nowrap; } -.tool-state::before { - content: '◌ '; +.tool-note { + align-self: center; + font-family: var(--font-mono); + font-size: 0.66rem; + color: hsl(var(--axis-cit)); } .tool-desc { diff --git a/app/components/home/HomeToolbox.vue b/app/components/home/HomeToolbox.vue index f24a9f9..cc67fa5 100644 --- a/app/components/home/HomeToolbox.vue +++ b/app/components/home/HomeToolbox.vue @@ -23,14 +23,14 @@ - + - {{ lpk.name }} {{ lpk.fullName }} — {{ lpk.text }} + {{ lpk.name }} {{ lpk.text }} {{ s.name }} @@ -65,7 +65,7 @@ import type { HomeAxis } from '~/composables/useHomeData' withDefaults(defineProps<{ axes: HomeAxis[] - lpk?: { name: string, fullName: string, text: string, to: string } + lpk?: { name: string, text: string, to: string } bouquet?: { title: string, inService: { name?: string }[], stacks: unknown[] } | null gratewizard?: { title: string, subtitle: string } showPromise?: boolean @@ -153,7 +153,7 @@ function onAction(id: string) { gap: 0.5rem; } -/* LPK */ +/* LaPlanK */ .toolbox-lpk { display: flex; flex-direction: column; diff --git a/app/components/home/HomeVariantEtabli.vue b/app/components/home/HomeVariantEtabli.vue deleted file mode 100644 index 34cd621..0000000 --- a/app/components/home/HomeVariantEtabli.vue +++ /dev/null @@ -1,492 +0,0 @@ - - - - - diff --git a/app/components/home/HomeVariantParcours.vue b/app/components/home/HomeVariantParcours.vue deleted file mode 100644 index d59dff9..0000000 --- a/app/components/home/HomeVariantParcours.vue +++ /dev/null @@ -1,321 +0,0 @@ - - - - - diff --git a/app/components/home/HomeVariantSwitch.vue b/app/components/home/HomeVariantSwitch.vue deleted file mode 100644 index 6d0b85b..0000000 --- a/app/components/home/HomeVariantSwitch.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - - - diff --git a/app/components/home/TypewriterText.vue b/app/components/home/TypewriterText.vue deleted file mode 100644 index 49e82ca..0000000 --- a/app/components/home/TypewriterText.vue +++ /dev/null @@ -1,279 +0,0 @@ - - - - - diff --git a/app/components/layout/TheHeader.vue b/app/components/layout/TheHeader.vue index e2ddaf1..0742f6d 100644 --- a/app/components/layout/TheHeader.vue +++ b/app/components/layout/TheHeader.vue @@ -3,22 +3,7 @@
- + {{ site?.identity.name }} @@ -88,9 +73,19 @@ const AXIS_HUES = ['--axis-num', '--axis-eco', '--axis-cit'] } .logo-icon { - width: 1.6rem; - height: 2rem; + width: auto; + height: 2.1rem; flex-shrink: 0; + transform: rotate(-8deg); + transition: transform 0.2s ease; +} + +.logo-link:hover .logo-icon { + transform: rotate(0deg) scale(1.08); +} + +@media (prefers-reduced-motion: reduce) { + .logo-icon { transition: none; } } .logo-text { diff --git a/app/components/player/PlayerPersistent.vue b/app/components/player/PlayerPersistent.vue index 1d8acb1..77e9602 100644 --- a/app/components/player/PlayerPersistent.vue +++ b/app/components/player/PlayerPersistent.vue @@ -179,6 +179,7 @@ onClickOutside(widgetRef, () => { .mini-player { position: fixed; bottom: 1rem; + transition: bottom 0.3s ease; right: max(1rem, calc((100vw - 80rem) / 2)); z-index: 70; display: flex; @@ -186,6 +187,11 @@ onClickOutside(widgetRef, () => { align-items: flex-end; } +/* Book player open: stay above its navigation bar */ +:global(html.book-player-open .mini-player) { + bottom: 5.5rem; +} + /* ═══════════════════════════════════════ PILL ═══════════════════════════════════════ */ diff --git a/app/components/ui/SectionSign.vue b/app/components/ui/SectionSign.vue new file mode 100644 index 0000000..a8f0302 --- /dev/null +++ b/app/components/ui/SectionSign.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/ui/StatusBadge.vue b/app/components/ui/StatusBadge.vue new file mode 100644 index 0000000..f205656 --- /dev/null +++ b/app/components/ui/StatusBadge.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/app/composables/useAudioPlayer.ts b/app/composables/useAudioPlayer.ts index f4f455b..4a9ed53 100644 --- a/app/composables/useAudioPlayer.ts +++ b/app/composables/useAudioPlayer.ts @@ -71,11 +71,9 @@ export function useAudioPlayer() { store.setSong(song) firedMilestones.clear() - // Try OGG first, fall back to MP3 - const oggPath = song.file.replace(/\.mp3$/, '.ogg') - const canOgg = el.canPlayType('audio/ogg; codecs=vorbis') - - el.src = canOgg ? oggPath : song.file + // Only MP3 files are published (no .ogg on disk nor in production): + // asking for OGG first cost a 404 and a delay on every track. + el.src = song.file el.volume = store.volume try { @@ -84,20 +82,8 @@ export function useAudioPlayer() { startTimeUpdate() trackAudioPlay(song.id, song.title) } - catch { - // If OGG failed, try MP3 - if (el.src !== song.file) { - el.src = song.file - try { - await el.play() - store.play() - startTimeUpdate() - trackAudioPlay(song.id, song.title) - } - catch (err) { - console.error('Playback failed:', err) - } - } + catch (err) { + console.error('Playback failed:', err) } } diff --git a/app/composables/useHomeData.ts b/app/composables/useHomeData.ts index 9c23c11..cabc236 100644 --- a/app/composables/useHomeData.ts +++ b/app/composables/useHomeData.ts @@ -13,6 +13,8 @@ export interface HomeAction { secondary?: boolean to?: string href?: string + /** Short status line shown under the button (e.g. the v1 in production) */ + note?: string } export interface HomeTool { @@ -21,6 +23,9 @@ export interface HomeTool { to?: string href?: string gestation?: boolean + /** « En production », « En développement »… — wins over `gestation` */ + status?: string + since?: string icon?: string presentation?: { title: string, text: string } actions?: HomeAction[] @@ -86,9 +91,9 @@ export async function useHomeData() { }) const lpk = computed(() => (site.value as any)?.lpk as - { name: string, fullName: string, text: string, role: string, to: string } | undefined) + { name: string, text: string, role: string, to: string } | undefined) - /** Bouquet sweethomeCloud, flattened — the stacks served by LPK */ + /** Bouquet sweetHome, flattened — the stacks served by LaPlanK */ const bouquet = computed(() => { const section = ((cloud.value as any)?.sections ?? []).find((s: any) => s.type === 'territoire') const b = section?.bouquet @@ -139,6 +144,8 @@ export async function useHomeData() { evenement, book: computed(() => (home.value as any)?.book), format: computed(() => (home.value as any)?.format as { title: string, text: string } | undefined), + toolboxTitle: computed(() => (home.value as any)?.toolbox?.title as string | undefined), + consoleLabels: computed(() => (home.value as any)?.console as { prefix: string, top: string, bottom: string } | undefined), gratewizard: computed(() => (home.value as any)?.gratewizard), } } diff --git a/app/composables/useSiteContent.ts b/app/composables/useSiteContent.ts index 40cd199..4416fbe 100644 --- a/app/composables/useSiteContent.ts +++ b/app/composables/useSiteContent.ts @@ -16,7 +16,6 @@ interface SiteContent { } lpk?: { name: string - fullName: string text: string role: string to: string diff --git a/app/pages/citoyenne/[slug].vue b/app/pages/citoyenne/[slug].vue index 636d00d..62b8d9e 100644 --- a/app/pages/citoyenne/[slug].vue +++ b/app/pages/citoyenne/[slug].vue @@ -86,10 +86,7 @@

{{ content.project.text }}

- -
- En gestation - +
diff --git a/app/pages/citoyenne/index.vue b/app/pages/citoyenne/index.vue index 9769066..ba23bca 100644 --- a/app/pages/citoyenne/index.vue +++ b/app/pages/citoyenne/index.vue @@ -352,6 +352,7 @@

Décision collective

+

Se donner les moyens de la décision collective. @@ -376,10 +377,7 @@

Tarifs de l'eau

- -
- En gestation - +

Application pour obtenir justice sociale et incitation dynamique à la réduction. @@ -404,6 +402,10 @@ definePageMeta({ }) const { data: content } = await usePageContent('citoyenne') +const statusOf = (id: string) => { + const item = ((content.value as any)?.items ?? []).find((i: any) => i.id === id) ?? {} + return { status: item.status, since: item.since, gestation: item.gestation } +} const appConfig = useAppConfig() const decisionUrl = (appConfig.libredecision as { url: string })?.url ?? '#' @@ -449,6 +451,7 @@ useSeoPage({ .item-header { display: flex; + flex-wrap: wrap; align-items: center; gap: 0.75rem; } diff --git a/app/pages/economique/index.vue b/app/pages/economique/index.vue index 819ef1a..b1de775 100644 --- a/app/pages/economique/index.vue +++ b/app/pages/economique/index.vue @@ -396,6 +396,7 @@

Monnaie libre

+

La Ğ1 (June) : une monnaie co-créée par ses membres, sans dette ni intérêt. Le dividende universel comme base. @@ -424,10 +425,7 @@

Productions collectives

- -
- En gestation - +

Une plateforme pour faciliter la création d'équipes et la réalisation de productions à l'échelle des bassins de vie. Passer la seconde. @@ -451,6 +449,10 @@ definePageMeta({ }) const { data: content } = await usePageContent('economique') +const statusOf = (id: string) => { + const item = ((content.value as any)?.items ?? []).find((i: any) => i.id === id) ?? {} + return { status: item.status, since: item.since, gestation: item.gestation } +} useSeoPage({ title: content.value?.meta?.title ?? 'Autonomie économique', @@ -484,6 +486,7 @@ const showPdfReader = ref(false) .item-header { display: flex; + flex-wrap: wrap; align-items: center; gap: 0.75rem; } diff --git a/app/pages/economique/monnaie-libre.vue b/app/pages/economique/monnaie-libre.vue index 64cabff..de52be7 100644 --- a/app/pages/economique/monnaie-libre.vue +++ b/app/pages/economique/monnaie-libre.vue @@ -17,6 +17,7 @@

{{ content?.description }}

+ diff --git a/app/pages/economique/productions-collectives.vue b/app/pages/economique/productions-collectives.vue index ebe62e6..c3b8932 100644 --- a/app/pages/economique/productions-collectives.vue +++ b/app/pages/economique/productions-collectives.vue @@ -18,10 +18,9 @@ {{ content?.description }}

- -
- En gestation - +
+ +
diff --git a/app/pages/evenement.vue b/app/pages/evenement.vue index 641c063..ba82940 100644 --- a/app/pages/evenement.vue +++ b/app/pages/evenement.vue @@ -332,20 +332,16 @@

{{ content?.kicker }}

{{ content?.title }}

+

+ {{ evtContent.format }} +

{{ evtContent.subtitle }}

@@ -447,6 +443,14 @@ useSeoPage({