identité : le kit du studio DA intégré, les 61 oiseaux posés sur la page
Copie du kit kit-site (empreinte vérifiée) : logotype dans l'en-tête, signe §, favicons et icônes, og-default (?v=3), frise du pied de page, 61 oiseaux. Les shadoks positionnés à la main (HomeShadoks et les règles des 10 pages) cèdent la place à UiOiseauPose : chaque oiseau se pose sur une arête réelle (perché, marge gauche ou droite, derrière une carte, libre), currentColor, largeur 72 px au moins, opacité 0,18-0,28 près du texte et 0,10-0,14 derrière, jamais deux fois sur une page, calligraphe et typographe jamais en miroir. Sous 768 px, un oiseau par page au plus ; seuls ceux derrière une carte dérivent un peu, et plus du tout en mouvement réduit. Consignes d'Yvv du 03/11 inscrites dans docs/consignes-yvv.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
<div class="format-grid">
|
||||
<!-- Éditorial : le livre et les chansons -->
|
||||
<article v-if="book" class="format-card format-card--book">
|
||||
<!-- The reader peeks over the book card: only her head and book show -->
|
||||
<UiOiseauPose nom="lectrice" pose="derriere" left="76%" bottom="calc(100% - 48px)" :w="104" />
|
||||
<div
|
||||
class="format-cover"
|
||||
role="img"
|
||||
@@ -41,6 +43,8 @@
|
||||
|
||||
<!-- Événementiel -->
|
||||
<NuxtLink v-if="evenement" :to="evenement.to" class="format-card format-card--event">
|
||||
<!-- The accordion player stands on the event card -->
|
||||
<UiOiseauPose nom="accordeoniste" pose="perche" right="66px" :w="84" retourne ton="accent" />
|
||||
<p class="format-kicker">
|
||||
{{ evenement.teaser }}
|
||||
<span v-if="evenement.gestation" class="format-state">en gestation</span>
|
||||
@@ -123,6 +127,7 @@ defineEmits<{
|
||||
}
|
||||
|
||||
.format-grid {
|
||||
isolation: isolate;
|
||||
display: grid;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
@@ -132,6 +137,7 @@ defineEmits<{
|
||||
}
|
||||
|
||||
.format-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<div class="va">
|
||||
<!-- Hero : the headline, and the three cursors to push -->
|
||||
<section class="va-hero">
|
||||
<HomeShadoks />
|
||||
<div class="container-content va-hero-grid">
|
||||
<div class="va-intro">
|
||||
<h1 class="va-h1">
|
||||
@@ -20,7 +19,11 @@
|
||||
</div>
|
||||
|
||||
<div class="va-console">
|
||||
<p class="va-console-title">{{ heading[2] }}</p>
|
||||
<p class="va-console-title">
|
||||
{{ heading[2] }}
|
||||
<!-- The DJ stands on the console board, looking at the faders -->
|
||||
<UiOiseauPose nom="dj" pose="perche" right="2rem" bottom="-0.75rem" :w="80" retourne ton="accent" mobile />
|
||||
</p>
|
||||
<HomeConsole
|
||||
v-model="active"
|
||||
:axes="axes"
|
||||
@@ -61,6 +64,7 @@
|
||||
<div class="container-content">
|
||||
<h2 class="va-h2">{{ toolboxTitle }}</h2>
|
||||
<HomeToolbox
|
||||
:oiseaux="toolboxOiseaux"
|
||||
:axes="axes"
|
||||
:lpk="lpk"
|
||||
:bouquet="bouquet"
|
||||
@@ -76,6 +80,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { AxisKey } from '~/composables/useHomeData'
|
||||
import type { OiseauPlace } from '~/utils/oiseauPose'
|
||||
|
||||
defineEmits<{
|
||||
'open-player': []
|
||||
@@ -97,6 +102,14 @@ const axesLine = computed(() =>
|
||||
.filter(Boolean)
|
||||
.map(text => ({ text, hue: AXIS_WORDS[text] })))
|
||||
const active = ref<AxisKey>('numerique')
|
||||
|
||||
// The governance crew stands in the empty space under the citoyenne column of the toolbox
|
||||
const toolboxOiseaux: Partial<Record<AxisKey, OiseauPlace[]>> = {
|
||||
politique: [
|
||||
{ nom: 'capitaine', pose: 'libre', left: 'calc(34% - 75px)', bottom: '-190px', w: 150, op: 0.24 },
|
||||
{ nom: 'matelot', pose: 'libre', left: 'calc(80% - 40px)', bottom: '-300px', w: 80, op: 0.26, retourne: true },
|
||||
],
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -184,6 +197,7 @@ const active = ref<AxisKey>('numerique')
|
||||
}
|
||||
|
||||
.va-console-title {
|
||||
position: relative;
|
||||
margin: 0 0 0.75rem;
|
||||
font-family: var(--font-display);
|
||||
font-weight: 700;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
<!-- Formulaire -->
|
||||
<UiScrollReveal>
|
||||
<div class="message-form-card">
|
||||
<!-- The postwoman stands on the message form -->
|
||||
<UiOiseauPose nom="factrice" pose="perche" right="30px" :w="88" retourne />
|
||||
<h3 class="font-display text-lg font-bold form-title mb-4">Laisser un message</h3>
|
||||
|
||||
<form v-if="!submitted" class="space-y-3" @submit.prevent="send">
|
||||
@@ -167,6 +169,7 @@ function formatDate(iso: string) {
|
||||
|
||||
/* ── Carte formulaire ── */
|
||||
.message-form-card {
|
||||
position: relative;
|
||||
background: hsl(var(--color-surface));
|
||||
border-radius: 16px;
|
||||
padding: 1.5rem;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<div class="shadoks" aria-hidden="true">
|
||||
<!-- Shadok bird decoration -->
|
||||
<svg class="shadok-bird" viewBox="0 0 180 260" fill="none" aria-hidden="true">
|
||||
<ellipse cx="90" cy="100" rx="45" ry="40" fill="currentColor" opacity="0.85"/>
|
||||
<circle cx="130" cy="60" r="22" fill="currentColor" opacity="0.8"/>
|
||||
<path d="M110 85 Q125 70 128 63" stroke="currentColor" stroke-width="8" stroke-linecap="round" opacity="0.7" fill="none"/>
|
||||
<circle cx="136" cy="55" r="5" fill="currentColor" opacity="0.3"/>
|
||||
<circle cx="137" cy="54" r="2" fill="currentColor" opacity="0.6"/>
|
||||
<polygon points="150,58 175,50 152,65" fill="currentColor" opacity="0.6"/>
|
||||
<line x1="75" y1="138" x2="60" y2="230" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<line x1="105" y1="138" x2="115" y2="230" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<circle cx="66" cy="190" r="4" fill="currentColor" opacity="0.4"/>
|
||||
<circle cx="111" cy="190" r="4" fill="currentColor" opacity="0.4"/>
|
||||
<path d="M60 230 L45 233 M60 230 L55 236 M60 230 L65 235" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
|
||||
<path d="M115 230 L100 233 M115 230 L110 236 M115 230 L120 235" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
|
||||
<path d="M48 95 Q20 80 15 65" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5" fill="none"/>
|
||||
<path d="M48 100 Q22 92 10 85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4" fill="none"/>
|
||||
<path d="M48 105 Q25 102 12 100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3" fill="none"/>
|
||||
</svg>
|
||||
|
||||
<!-- Shadok boulanger -->
|
||||
<svg class="shadok-boulanger" viewBox="0 0 240 300" fill="none" aria-hidden="true">
|
||||
<ellipse cx="120" cy="155" rx="40" ry="48" fill="currentColor" opacity="0.85"/>
|
||||
<circle cx="120" cy="92" r="25" fill="currentColor" opacity="0.8"/>
|
||||
<ellipse cx="120" cy="68" rx="18" ry="22" fill="currentColor" opacity="0.35"/>
|
||||
<rect x="105" y="78" width="30" height="5" rx="1" fill="currentColor" opacity="0.4"/>
|
||||
<path d="M110 88 Q114 84 118 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
|
||||
<path d="M124 88 Q128 84 132 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
|
||||
<path d="M112 102 Q120 108 128 102" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.35"/>
|
||||
<line x1="160" y1="145" x2="190" y2="135" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<rect x="185" y="125" width="40" height="10" rx="5" fill="currentColor" opacity="0.4" transform="rotate(-15 205 130)"/>
|
||||
<line x1="80" y1="148" x2="55" y2="175" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<line x1="105" y1="200" x2="95" y2="258" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<line x1="135" y1="200" x2="145" y2="258" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<rect x="30" y="180" width="50" height="40" rx="4" fill="currentColor" opacity="0.25"/>
|
||||
<rect x="35" y="185" width="40" height="20" rx="2" fill="currentColor" opacity="0.15"/>
|
||||
<ellipse cx="55" cy="195" rx="12" ry="6" fill="currentColor" opacity="0.12"/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.shadoks {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.shadok-bird {
|
||||
position: absolute;
|
||||
right: 3%;
|
||||
top: 6%;
|
||||
width: clamp(90px, 10vw, 150px);
|
||||
opacity: 0.22;
|
||||
color: hsl(var(--axis-num));
|
||||
animation: shadok-float 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.shadok-boulanger {
|
||||
position: absolute;
|
||||
left: 1.5%;
|
||||
bottom: 4%;
|
||||
width: clamp(80px, 9vw, 140px);
|
||||
opacity: 0.2;
|
||||
color: hsl(var(--axis-eco));
|
||||
animation: shadok-float 9s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
@keyframes shadok-float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.shadoks { display: none; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.shadok-bird, .shadok-boulanger { animation: none; }
|
||||
}
|
||||
</style>
|
||||
@@ -9,6 +9,7 @@
|
||||
:style="{ '--hue': `var(${axis.hue})` }"
|
||||
:aria-labelledby="`tb-${uid}-${axis.key}`"
|
||||
>
|
||||
<UiOiseauPose v-for="o in oiseaux?.[axis.key] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" class="toolbox-oiseau" />
|
||||
<header class="toolbox-head">
|
||||
<p class="toolbox-lever">{{ axis.lever }}</p>
|
||||
<h3 :id="`tb-${uid}-${axis.key}`" class="toolbox-title">
|
||||
@@ -61,7 +62,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HomeAxis } from '~/composables/useHomeData'
|
||||
import type { AxisKey, HomeAxis } from '~/composables/useHomeData'
|
||||
import type { OiseauPlace } from '~/utils/oiseauPose'
|
||||
|
||||
withDefaults(defineProps<{
|
||||
axes: HomeAxis[]
|
||||
@@ -70,6 +72,8 @@ withDefaults(defineProps<{
|
||||
gratewizard?: { title: string, subtitle: string }
|
||||
showPromise?: boolean
|
||||
anchors?: boolean
|
||||
/** Birds standing by an axis column (home page) */
|
||||
oiseaux?: Partial<Record<AxisKey, OiseauPlace[]>>
|
||||
}>(), {
|
||||
showPromise: true,
|
||||
anchors: false,
|
||||
@@ -106,7 +110,13 @@ function onAction(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/* The birds under a column only make sense with the three columns side by side */
|
||||
@container (max-width: 59.99rem) {
|
||||
.toolbox-oiseau { display: none; }
|
||||
}
|
||||
|
||||
.toolbox-axis {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -1,44 +1,7 @@
|
||||
<template>
|
||||
<footer class="footer-wrap border-t border-[hsl(var(--color-text)/0.1)] bg-[hsl(var(--color-surface))]">
|
||||
<!-- Shadok pattern -->
|
||||
<svg class="footer-shadok-pattern" viewBox="0 0 400 80" fill="none" aria-hidden="true">
|
||||
<g transform="translate(20,10)">
|
||||
<ellipse cx="15" cy="25" rx="12" ry="14" fill="currentColor" opacity="0.2"/>
|
||||
<circle cx="15" cy="10" r="7" fill="currentColor" opacity="0.16"/>
|
||||
<line x1="10" y1="38" x2="8" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
|
||||
<line x1="20" y1="38" x2="22" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
|
||||
</g>
|
||||
<g transform="translate(80,15)">
|
||||
<ellipse cx="15" cy="22" rx="10" ry="12" fill="currentColor" opacity="0.16"/>
|
||||
<circle cx="15" cy="8" r="6" fill="currentColor" opacity="0.13"/>
|
||||
<line x1="10" y1="33" x2="8" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
|
||||
<line x1="20" y1="33" x2="22" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
|
||||
</g>
|
||||
<g transform="translate(140,8)">
|
||||
<ellipse cx="15" cy="25" rx="11" ry="13" fill="currentColor" opacity="0.18"/>
|
||||
<circle cx="15" cy="10" r="6.5" fill="currentColor" opacity="0.15"/>
|
||||
<line x1="10" y1="37" x2="7" y2="54" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
|
||||
<line x1="20" y1="37" x2="23" y2="54" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
|
||||
</g>
|
||||
<g transform="translate(210,18)">
|
||||
<ellipse cx="15" cy="20" rx="10" ry="11" fill="currentColor" opacity="0.14"/>
|
||||
<circle cx="15" cy="7" r="5.5" fill="currentColor" opacity="0.11"/>
|
||||
<line x1="10" y1="30" x2="9" y2="44" stroke="currentColor" stroke-width="1.5" opacity="0.1"/>
|
||||
<line x1="20" y1="30" x2="21" y2="44" stroke="currentColor" stroke-width="1.5" opacity="0.1"/>
|
||||
</g>
|
||||
<g transform="translate(270,12)">
|
||||
<ellipse cx="15" cy="24" rx="12" ry="14" fill="currentColor" opacity="0.18"/>
|
||||
<circle cx="15" cy="9" r="7" fill="currentColor" opacity="0.15"/>
|
||||
<line x1="10" y1="37" x2="7" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
|
||||
<line x1="20" y1="37" x2="23" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
|
||||
</g>
|
||||
<g transform="translate(340,16)">
|
||||
<ellipse cx="15" cy="22" rx="10" ry="12" fill="currentColor" opacity="0.16"/>
|
||||
<circle cx="15" cy="8" r="6" fill="currentColor" opacity="0.13"/>
|
||||
<line x1="10" y1="33" x2="8" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
|
||||
<line x1="20" y1="33" x2="22" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
|
||||
</g>
|
||||
</svg>
|
||||
<!-- The frieze of the birds (studio DA), standing on the bottom edge -->
|
||||
<UiOiseau nom="frise" class="footer-shadok-pattern" />
|
||||
<div class="container-content px-4 py-8 relative z-1">
|
||||
<div class="flex flex-col items-center gap-4 md:flex-row md:justify-between">
|
||||
<!-- Credits -->
|
||||
@@ -72,13 +35,14 @@ const { data: site } = await useSiteContent()
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* The whole frieze fits in the footer (mask: contain), never cropped; pale under the links */
|
||||
.footer-shadok-pattern {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0.75rem;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
height: calc(100% - 0.75rem);
|
||||
opacity: 0.12;
|
||||
pointer-events: none;
|
||||
color: hsl(var(--color-primary));
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
<header class="sticky top-0 z-40 border-b border-[hsl(var(--color-text)/0.08)] bg-[hsl(var(--color-bg)/0.85)] backdrop-blur-xl">
|
||||
<div class="container-content flex h-[var(--header-height)] items-center justify-between px-4">
|
||||
<!-- Logo -->
|
||||
<NuxtLink to="/" class="logo-link flex items-center gap-2.5">
|
||||
<UiSectionSign class="logo-icon" />
|
||||
<span class="logo-text">{{ site?.identity.name }}</span>
|
||||
<NuxtLink to="/" class="logo-link flex items-center" :aria-label="site?.identity.name || 'Le librodrome'">
|
||||
<UiLogotype class="logo-lockup" />
|
||||
</NuxtLink>
|
||||
|
||||
<!-- Desktop navigation -->
|
||||
@@ -72,31 +71,20 @@ const AXIS_HUES = ['--axis-num', '--axis-eco', '--axis-cit']
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
/* The validated lockup (studio DA, 27/10): the Geste already leans 25°, no rotation on hover */
|
||||
.logo-lockup {
|
||||
height: 2.3rem;
|
||||
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);
|
||||
.logo-link:hover .logo-lockup {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.logo-icon { transition: none; }
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-family: var(--font-logo);
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
letter-spacing: 0.04em;
|
||||
background-image: linear-gradient(to right, hsl(var(--color-primary)), hsl(var(--color-accent)));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
.logo-lockup { transition: none; }
|
||||
}
|
||||
|
||||
.nav-prefix {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
// One of the 61 birds (studio DA, validated 2026-10-28), drawn from /images/oiseaux/<nom>.svg as a
|
||||
// mask filled with currentColor : it takes the colour the page gives it, like the shadoks did.
|
||||
// The classes of the figure it replaces keep its place, size, opacity and animation.
|
||||
import { OISEAUX } from '~/utils/oiseaux'
|
||||
|
||||
const props = defineProps<{ nom: string }>()
|
||||
const o = computed(() => OISEAUX[props.nom])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
v-if="o"
|
||||
class="oiseau"
|
||||
aria-hidden="true"
|
||||
:style="{ aspectRatio: o.ratio, '--oiseau': `url(/images/oiseaux/${props.nom}.svg)` }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.oiseau {
|
||||
display: block;
|
||||
background-color: currentColor;
|
||||
-webkit-mask: var(--oiseau) center / contain no-repeat;
|
||||
mask: var(--oiseau) center / contain no-repeat;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
// A bird of the librodrome placed on its block (composition of 03/11, docs/consignes-yvv.md):
|
||||
// it stands on a real edge of the page, next to the content its trade is about.
|
||||
// The host block is the positioning context: position relative, overflow visible.
|
||||
//
|
||||
// Poses
|
||||
// perche on the block's top edge (bottom: 100%), x with left / right
|
||||
// marge-g beside the block, on its left; feet at the block's bottom, raised by `bottom`
|
||||
// marge-d the same, on its right
|
||||
// derriere large and pale, behind the block (z-index -1): only what sticks out shows.
|
||||
// Needs a stacking context above the block (isolation: isolate) and a block
|
||||
// that creates none itself (no z-index, transform, opacity, filter).
|
||||
// libre placed only by left / right / top / bottom (an empty area next to its block)
|
||||
//
|
||||
// Birds in the margin, behind a block or free need room around the column: they show from
|
||||
// 1200 px wide, the perched ones from 768 px (`seuil` overrides); under 768 px, only a bird
|
||||
// marked `mobile`.
|
||||
//
|
||||
// Drawing rules of the studio DA (kit README, §2.5): one colour (currentColor), proportions
|
||||
// intact and never cropped, 72 px wide at least, opacity 0.18-0.28 next to text and 0.10-0.14
|
||||
// large behind a card, mirror allowed except for the calligraphe and the typographe.
|
||||
// Birds standing on an edge do not move; only the one behind a card drifts a little (Yvv, 03/11).
|
||||
import { OISEAUX } from '~/utils/oiseaux'
|
||||
|
||||
type Pose = 'perche' | 'marge-g' | 'marge-d' | 'derriere' | 'libre'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
nom: string
|
||||
pose?: Pose
|
||||
/** Width in px: S 72-90, M 108-156, L 200-250 */
|
||||
w?: number
|
||||
left?: string
|
||||
right?: string
|
||||
top?: string
|
||||
bottom?: string
|
||||
/** Gap between the block and a bird in the margin */
|
||||
ecart?: string
|
||||
retourne?: boolean
|
||||
/** Shown under 768 px (one bird per page at most) */
|
||||
mobile?: boolean
|
||||
/** Shown under 768 px only: the phone place of a bird placed elsewhere on wider screens */
|
||||
mobileSeul?: boolean
|
||||
/** Narrowest window (px) where the bird shows: 1200 by default for the margin, behind
|
||||
* and free poses, 768 for a perched bird */
|
||||
seuil?: 768 | 1200
|
||||
ton?: 'primary' | 'accent'
|
||||
op?: number
|
||||
}>(), { pose: 'perche', w: 80, ecart: '2.5rem', ton: 'primary' })
|
||||
|
||||
/** These two write and compose from left to right: never mirrored */
|
||||
const NO_MIRROR = new Set(['calligraphe', 'typographe'])
|
||||
|
||||
const sol = computed(() => OISEAUX[props.nom]?.sol ?? 5)
|
||||
|
||||
const style = computed(() => {
|
||||
const s: Record<string, string> = { 'width': `${Math.max(72, props.w)}px`, '--sol': `${sol.value}%` }
|
||||
if (props.pose === 'perche') s.bottom = '100%'
|
||||
if (props.pose === 'marge-g') s.right = `calc(100% + ${props.ecart})`
|
||||
if (props.pose === 'marge-d') s.left = `calc(100% + ${props.ecart})`
|
||||
if (props.pose === 'marge-g' || props.pose === 'marge-d') s.bottom = '0px'
|
||||
for (const k of ['left', 'right', 'top', 'bottom'] as const) {
|
||||
if (props[k] !== undefined) s[k] = props[k]!
|
||||
}
|
||||
if (props.op !== undefined) s.opacity = String(props.op)
|
||||
return s
|
||||
})
|
||||
|
||||
const classes = computed(() => [
|
||||
'oiseau-pose',
|
||||
`oiseau-pose--${props.pose}`,
|
||||
{
|
||||
'oiseau-pose--retourne': props.retourne && !NO_MIRROR.has(props.nom),
|
||||
'oiseau-pose--mobile': props.mobile || props.mobileSeul,
|
||||
'oiseau-pose--mobile-seul': props.mobileSeul,
|
||||
'oiseau-pose--large': (props.seuil ?? (props.pose === 'perche' ? 768 : 1200)) >= 1200,
|
||||
'oiseau-pose--accent': props.ton === 'accent',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiOiseau :nom="nom" :class="classes" :style="style" :data-oiseau="nom" :data-pose="pose" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.oiseau-pose {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
color: hsl(var(--color-primary));
|
||||
opacity: 0.24;
|
||||
/* The drawing's ground line lands on the edge */
|
||||
transform: translateY(var(--sol));
|
||||
}
|
||||
|
||||
.oiseau-pose--accent {
|
||||
color: hsl(var(--color-accent));
|
||||
}
|
||||
|
||||
.oiseau-pose--perche {
|
||||
opacity: 0.28;
|
||||
}
|
||||
|
||||
.oiseau-pose--derriere {
|
||||
z-index: -1;
|
||||
opacity: 0.12;
|
||||
animation: oiseau-derive 12s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.oiseau-pose--retourne {
|
||||
scale: -1 1;
|
||||
}
|
||||
|
||||
@keyframes oiseau-derive {
|
||||
from { translate: 0 0; }
|
||||
to { translate: 0 -6px; }
|
||||
}
|
||||
|
||||
@media (max-width: 1199px) {
|
||||
.oiseau-pose--large {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.oiseau-pose--mobile-seul {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.oiseau-pose:not(.oiseau-pose--mobile) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.oiseau-pose--derriere {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user