✨ feat(epic-4): chemins narratifs, easter eggs, challenge et contact
Epic 4: Chemins Narratifs, Challenge & Contact Stories implementees: - 4.1: Composant ChoiceCards pour choix narratifs binaires - 4.2: Sequence d'intro narrative avec Le Bug - 4.3: Chemins narratifs differencies avec useNarrativePath - 4.4: Table easter_eggs et systeme de detection (API + composable) - 4.5: Easter eggs UI (popup, notification, collection) - 4.6: Page challenge avec puzzle de code - 4.7: Page revelation "Monde de Code" - 4.8: Page contact avec formulaire et stats Fichiers crees: - Frontend: ChoiceCards, IntroSequence, ZoneEndChoice, EasterEggPopup, CodePuzzle, ChallengeSuccess, CodeWorld, et pages intro/challenge/revelation - API: EasterEggController, Model, Migration, Seeder Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
89
frontend/app/components/feature/CodeWorld.vue
Normal file
89
frontend/app/components/feature/CodeWorld.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="code-world font-mono text-sm md:text-base leading-relaxed">
|
||||
<pre
|
||||
class="text-sky-accent whitespace-pre overflow-x-auto max-w-full"
|
||||
:class="{ 'animate-reveal': !reducedMotion }"
|
||||
aria-hidden="true"
|
||||
><code>{{ visibleCode }}</code></pre>
|
||||
|
||||
<!-- Screen reader alternative -->
|
||||
<p class="sr-only">
|
||||
{{ $t('revelation.codeWorldAlt') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const emit = defineEmits<{
|
||||
complete: []
|
||||
}>()
|
||||
|
||||
const reducedMotion = usePreferredReducedMotion()
|
||||
|
||||
const asciiArt = `
|
||||
* . *
|
||||
* . . *
|
||||
___
|
||||
/ \\
|
||||
/ ^ \\
|
||||
/ ^ \\
|
||||
/____/ \\____\\
|
||||
| | | |
|
||||
| | | |
|
||||
___| |___| |___
|
||||
{ YOU }
|
||||
{ FOUND ME! }
|
||||
___________________
|
||||
`
|
||||
|
||||
const visibleCode = ref('')
|
||||
const lines = asciiArt.split('\n')
|
||||
let currentLine = 0
|
||||
|
||||
onMounted(() => {
|
||||
if (reducedMotion.value === 'reduce') {
|
||||
visibleCode.value = asciiArt
|
||||
emit('complete')
|
||||
} else {
|
||||
revealLines()
|
||||
}
|
||||
})
|
||||
|
||||
function revealLines() {
|
||||
if (currentLine < lines.length) {
|
||||
visibleCode.value += lines[currentLine] + '\n'
|
||||
currentLine++
|
||||
setTimeout(revealLines, 100)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
emit('complete')
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.code-world {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@keyframes reveal {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-reveal {
|
||||
animation: reveal 0.3s ease-out;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user