forked from LPK/librodrome
- typo : Bricolage Grotesque (titres) + Atkinson Hyperlegible (texte), Syne gardée pour le logo seul ; une seule source de polices (Bunny) - palettes : teinte propre à chaque axe dans les 4 ambiances ; pages d'axe en axis-scope, cartes sans bordure (canon design) - accueil : console des trois curseurs (tablist clavier), boîte à outils, bloc format éditorial + événement + reproduction ; ?v=a|b|c|0 - numérique : carte LPK ; bouquet rendu avec statut et légende - messages : sans bordure, deux colonnes en grand écran Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
363 lines
8.2 KiB
Vue
363 lines
8.2 KiB
Vue
<template>
|
|
<div class="format">
|
|
<header v-if="format && showHeader" class="format-head">
|
|
<h2 class="format-title">{{ format.title }}</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">
|
|
<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 {
|
|
display: grid;
|
|
gap: 1.25rem;
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.format-grid { grid-template-columns: 1.35fr 1fr; }
|
|
}
|
|
|
|
.format-card {
|
|
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>
|