Refonte accueil : hero typo statique, axes icônes, menu italic, page numérique

- Hero : 5 lignes typographiques alternées (bold/light/accent/caps/italic),
  citations et axes dans un bloc discret dépliable
- Icônes axes : Ğ1 custom, balance (éco don), graphe (WoT), marteau (décision),
  pictos plus lumineux (glow)
- Menu : Autonomie en italique + grand, Événement majuscule
- Page /autonomie renommée /numerique avec redirect 301
- Sceau hexagramme 益 Yì dans le layout, BookSection dans /modele-eco
- Fonts Syne + Space Grotesk, dark theme éclairci
- Popup GrateWizard agrandie (480×860)
- Actions AxisBlock : primary côte à côte, secondary séparé dessous

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-03 06:34:30 +01:00
parent 082a17d09b
commit fbc2867163
17 changed files with 615 additions and 336 deletions

View File

@@ -1,109 +0,0 @@
export interface TypewriterSentence {
text: string
style?: 'title' | 'citation' | 'text'
stays?: boolean
separator?: boolean
}
interface SequenceOptions {
fadeMs?: number
holdMs?: number
gapMs?: number
}
export function useTypewriter(sentences: TypewriterSentence[], options: SequenceOptions = {}) {
const {
fadeMs = 1000,
holdMs = 2800,
gapMs = 300,
} = options
const currentText = ref('')
const currentStyle = ref<string>('title')
const isVisible = ref(false)
const lockedSentences = ref<TypewriterSentence[]>([])
const isComplete = ref(false)
let currentIdx = -1
let timer: ReturnType<typeof setTimeout> | null = null
function clearTimer() {
if (timer) {
clearTimeout(timer)
timer = null
}
}
function next() {
currentIdx++
if (currentIdx >= sentences.length) {
currentText.value = ''
isComplete.value = true
return
}
const sentence = sentences[currentIdx]
if (sentence.separator) {
lockedSentences.value = [...lockedSentences.value, { text: '', separator: true }]
}
// Set text while invisible
currentText.value = sentence.text
currentStyle.value = sentence.style || 'title'
// Fade in on next frame
requestAnimationFrame(() => {
isVisible.value = true
})
// After fade-in + hold → fade out
timer = setTimeout(() => {
isVisible.value = false
// After fade-out completes → lock if stays, then next
timer = setTimeout(() => {
if (sentence.stays) {
lockedSentences.value = [...lockedSentences.value, { ...sentence }]
}
timer = setTimeout(next, gapMs)
}, fadeMs)
}, fadeMs + holdMs)
}
function start() {
next()
}
function skipToEnd() {
clearTimer()
isVisible.value = false
currentText.value = ''
const locked: TypewriterSentence[] = []
for (const sentence of sentences) {
if (sentence.separator) {
locked.push({ text: '', separator: true })
}
if (sentence.stays) {
locked.push({ ...sentence })
}
}
lockedSentences.value = locked
currentIdx = sentences.length - 1
isComplete.value = true
}
onUnmounted(clearTimer)
return {
currentText: readonly(currentText),
currentStyle: readonly(currentStyle),
isVisible,
lockedSentences: readonly(lockedSentences),
isComplete: readonly(isComplete),
start,
skipToEnd,
}
}