Files
librodrome/app/components/home/HomeFormat.vue
T
YvvandClaude Opus 5.5 f1dbf21723
ci/woodpecker/push/woodpecker Pipeline was successful
identité 6 : plus de lectrice derrière la carte du livre sur l'accueil (DA)
Descendue de 20 px sous la première ligne du chapeau, la lectrice ne montrait plus que sa
bulle. Elle ne peut pas non plus sortir par le côté de la carte, à cause de la marge de page
et de la gouttière, et l'accordéoniste occupe le seul dessus libre. DA, 03/11 après 19h : « Je
ne veux pas d'un oiseau réduit à un morceau ». Elle reste visible à 1440 px sur la page
commande, où elle se tient en marge droite : les 61 oiseaux restent visibles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:50:55 +01:00

373 lines
9.1 KiB
Vue

<template>
<div class="format">
<header v-if="format && showHeader" class="format-head">
<!-- The accordion player at the end of the title, on its baseline: on the event card it stood
at the height of the reader, and its ground line touched the card's link (rules c, h).
S and from 1200 px: the band above leaves 125 px, and a perched bird keeps a void of its
own height above it (rule f); 8 px under the baseline, within the 12 px of rule e -->
<h2 class="format-title">{{ format.title }}<UiOiseauPose nom="accordeoniste" pose="perche" bout left="16px" bottom="-8px" :w="72" retourne ton="accent" :seuil="1200" /></h2>
<p class="format-text">{{ format.text }}</p>
</header>
<div class="format-grid">
<!-- Éditorial : le livre et les chansons -->
<article v-if="book" class="format-card format-card--book">
<!-- No bird behind the book card (DA, 03/11 after 19h): lowered under the header's first
line, the reader only showed her bubble; the page margin and the gutter leave her no
side to come out by, and the free top of the card holds the accordion player. She
stands on the order page -->
<div
class="format-cover"
role="img"
:aria-label="book.coverAlt"
:style="{ backgroundImage: `url(${book.coverImage})` }"
/>
<div class="format-body">
<p class="format-kicker">{{ book.kicker }}</p>
<h3 class="format-card-title">{{ book.title }}</h3>
<p class="format-desc">{{ book.description }}</p>
<div class="format-actions">
<button type="button" class="fbtn fbtn--main" @click="$emit('open-player')">
<span class="i-lucide-play h-4 w-4" aria-hidden="true" />
{{ book.cta?.player }}
</button>
<button type="button" class="fbtn" @click="$emit('open-pdf')">
<span class="i-lucide-book-open h-4 w-4" aria-hidden="true" />
{{ book.cta?.pdf }}
</button>
<NuxtLink to="/economique/modele-eco" class="fbtn fbtn--quiet">
<span class="i-lucide-list h-4 w-4" aria-hidden="true" />
Présentation des chapitres
</NuxtLink>
<NuxtLink to="/economique/commande" class="fbtn fbtn--quiet">
<span class="i-lucide-shopping-bag h-4 w-4" aria-hidden="true" />
Commandez le livre
</NuxtLink>
</div>
</div>
</article>
<!-- Événementiel -->
<NuxtLink v-if="evenement" :to="evenement.to" class="format-card format-card--event">
<p class="format-kicker">
{{ evenement.teaser }}
<span v-if="evenement.gestation" class="format-state">en gestation</span>
</p>
<h3 class="format-card-title format-card-title--event">{{ evenement.subtitle }}</h3>
<p v-if="evenement.tagline" class="format-tagline">{{ evenement.tagline }}</p>
<ul v-if="evenement.config.length" class="format-config">
<li v-for="c in evenement.config" :key="c.label">
<span :class="`i-lucide-${c.icon}`" class="h-4 w-4" aria-hidden="true" />
<span>{{ c.label }}</span>
</li>
</ul>
<span class="format-more">
Voir l'événement
<span class="i-lucide-arrow-right h-4 w-4" aria-hidden="true" />
</span>
</NuxtLink>
</div>
<!-- Reproduction + à qui l'on s'adresse -->
<div v-if="evenement?.reproduction || hero?.addressees?.length" class="format-repro">
<p v-if="evenement?.reproduction" class="format-repro-line">
<span class="format-basins" aria-hidden="true"><i v-for="n in 5" :key="n" /></span>
{{ evenement.reproduction }}
</p>
<div v-if="hero?.addressees?.length" class="format-audience">
<p class="format-audience-label">{{ hero.audience }}</p>
<ul>
<li v-for="a in hero.addressees" :key="a.label">
<strong>{{ a.label }}</strong> {{ a.value }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup lang="ts">
withDefaults(defineProps<{
format?: { title: string, text: string }
book?: any
evenement?: any
hero?: any
showHeader?: boolean
}>(), {
showHeader: true,
})
defineEmits<{
'open-player': []
'open-pdf': []
}>()
</script>
<style scoped>
.format {
display: grid;
gap: 1.5rem;
}
.format-head {
max-width: 44rem;
}
.format-title {
margin: 0;
font-family: var(--font-display);
font-weight: 800;
font-size: clamp(1.75rem, 4.2vw, 2.75rem);
letter-spacing: -0.03em;
line-height: 1.05;
color: hsl(var(--color-text));
}
.format-text {
margin: 0.75rem 0 0;
font-size: 1.1rem;
line-height: 1.5;
color: hsl(var(--color-text) / 0.72);
}
.format-grid {
isolation: isolate;
display: grid;
gap: 1.25rem;
}
@media (min-width: 1024px) {
.format-grid { grid-template-columns: 1.35fr 1fr; }
}
.format-card {
position: relative;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1.5rem;
border-radius: 16px;
background: hsl(var(--color-surface));
}
.format-card--book {
flex-direction: row;
gap: 1.5rem;
}
.format-cover {
flex-shrink: 0;
width: clamp(6.5rem, 16vw, 10rem);
aspect-ratio: 1756 / 2480;
border-radius: 6px;
background-size: cover;
background-position: center;
box-shadow: 0 16px 30px -18px hsl(var(--color-text) / 0.6);
}
.format-body {
min-width: 0;
}
.format-kicker {
margin: 0;
font-family: var(--font-mono);
font-size: 0.72rem;
color: hsl(var(--axis-eco));
}
.format-card--event .format-kicker {
color: hsl(var(--axis-cit));
}
.format-state {
margin-left: 0.35rem;
color: hsl(var(--color-text) / 0.5);
}
.format-state::before {
content: '◌ ';
}
.format-card-title {
margin: 0.3rem 0 0;
font-family: var(--font-display);
font-weight: 800;
font-size: clamp(1.3rem, 2.4vw, 1.6rem);
letter-spacing: -0.02em;
line-height: 1.12;
color: hsl(var(--color-text));
}
.format-card-title--event {
font-weight: 700;
}
.format-desc {
margin: 0.5rem 0 0;
font-size: 0.95rem;
line-height: 1.5;
color: hsl(var(--color-text) / 0.72);
}
.format-actions {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: 1rem;
}
.fbtn {
display: inline-flex;
align-items: center;
gap: 0.4rem;
min-height: 2.5rem;
padding: 0.45rem 1rem;
border-radius: 20px;
font-size: 0.86rem;
font-weight: 700;
color: hsl(var(--color-text) / 0.85);
background: hsl(var(--color-text) / 0.07);
transition: transform 0.1s ease, background 0.2s ease;
}
.fbtn:hover { transform: translateY(-1px); background: hsl(var(--axis-eco) / 0.14); }
.fbtn:active { transform: translateY(0); }
.fbtn--main {
color: hsl(var(--color-bg));
background: hsl(var(--axis-eco));
}
.fbtn--main:hover { background: hsl(var(--axis-eco) / 0.88); }
.fbtn--quiet {
font-weight: 400;
background: transparent;
}
.format-card--event {
color: hsl(var(--color-text));
transition: transform 0.12s ease;
}
.format-card--event:hover {
transform: translateY(-3px);
}
.format-tagline {
margin: 0.2rem 0 0;
font-family: var(--font-display);
font-size: 1.05rem;
color: hsl(var(--color-text) / 0.7);
}
.format-config {
list-style: none;
margin: 0.75rem 0 0;
padding: 0;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem;
font-size: 0.85rem;
color: hsl(var(--color-text) / 0.78);
}
.format-config li {
display: flex;
align-items: center;
gap: 0.45rem;
}
.format-config li > span:first-child {
color: hsl(var(--axis-cit));
flex-shrink: 0;
}
.format-more {
display: inline-flex;
align-items: center;
gap: 0.35rem;
margin-top: auto;
padding-top: 1rem;
font-family: var(--font-display);
font-weight: 700;
color: hsl(var(--axis-cit));
}
/* Reproduction */
.format-repro {
display: grid;
gap: 1.25rem;
padding: 1.25rem 0 0;
}
@media (min-width: 768px) {
.format-repro {
grid-template-columns: 1fr 1fr;
align-items: start;
}
}
.format-repro-line {
margin: 0;
font-family: var(--font-display);
font-weight: 700;
font-size: clamp(1.15rem, 2.2vw, 1.4rem);
line-height: 1.25;
letter-spacing: -0.015em;
color: hsl(var(--color-text));
}
/* One basin, then its copies */
.format-basins {
display: flex;
gap: 0.35rem;
margin-bottom: 0.6rem;
}
.format-basins i {
display: block;
width: 0.8rem;
height: 0.8rem;
border-radius: 50%;
box-shadow: inset 0 0 0 1.5px hsl(var(--axis-cit) / 0.6);
}
.format-basins i:first-child {
background: hsl(var(--axis-cit));
box-shadow: none;
}
.format-audience-label {
margin: 0 0 0.5rem;
font-family: var(--font-mono);
font-size: 0.72rem;
color: hsl(var(--color-text) / 0.5);
}
.format-audience ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.3rem;
font-size: 0.95rem;
color: hsl(var(--color-text) / 0.7);
}
.format-audience strong {
color: hsl(var(--color-text));
}
@media (max-width: 640px) {
.format-card--book { flex-direction: column; }
.format-config { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.fbtn, .format-card--event { transition: none; }
}
</style>