Story 3.4 : Barre de progression globale (XP bar) - ProgressBar.vue avec design RPG (bordure, graduations, glow) - Tooltip au hover avec liste des sections visitées - Animation fluide avec prefers-reduced-motion - ProgressIcon.vue pour mobile (cercle SVG + drawer) - Intégration dans AppHeader (visible si héros choisi) - Traductions progress.* FR/EN Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
117 lines
3.3 KiB
Vue
117 lines
3.3 KiB
Vue
<template>
|
|
<header
|
|
class="sticky top-0 z-50 transition-colors duration-300"
|
|
:class="scrolled ? 'bg-sky-dark/90 backdrop-blur-sm shadow-lg' : 'bg-transparent'"
|
|
>
|
|
<div class="max-w-7xl mx-auto px-4 py-3 flex items-center justify-between">
|
|
<NuxtLink :to="localePath('/')" class="text-xl font-narrative text-sky-accent font-bold">
|
|
Skycel
|
|
</NuxtLink>
|
|
|
|
<!-- Desktop nav -->
|
|
<nav class="hidden md:flex items-center gap-6" aria-label="Main navigation">
|
|
<NuxtLink
|
|
v-for="item in navItems"
|
|
:key="item.path"
|
|
:to="localePath(item.path)"
|
|
class="text-sm font-ui text-sky-text/70 hover:text-sky-accent transition-colors"
|
|
active-class="!text-sky-accent"
|
|
>
|
|
{{ $t(item.label) }}
|
|
</NuxtLink>
|
|
</nav>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<!-- Barre de progression XP (desktop) -->
|
|
<FeatureProgressBar
|
|
v-if="showProgressBar"
|
|
:percent="progressPercent"
|
|
class="hidden md:block"
|
|
/>
|
|
|
|
<UiLanguageSwitcher />
|
|
|
|
<!-- Mobile hamburger -->
|
|
<button
|
|
class="md:hidden text-sky-text p-1"
|
|
aria-label="Menu"
|
|
@click="mobileOpen = !mobileOpen"
|
|
>
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
v-if="!mobileOpen"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M4 6h16M4 12h16M4 18h16"
|
|
/>
|
|
<path
|
|
v-else
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile menu -->
|
|
<Transition name="slide-down">
|
|
<nav
|
|
v-if="mobileOpen"
|
|
class="md:hidden bg-sky-dark/95 backdrop-blur-sm border-t border-sky-text/10 px-4 py-4"
|
|
aria-label="Mobile navigation"
|
|
>
|
|
<NuxtLink
|
|
v-for="item in navItems"
|
|
:key="item.path"
|
|
:to="localePath(item.path)"
|
|
class="block py-2 text-sm font-ui text-sky-text/70 hover:text-sky-accent transition-colors"
|
|
active-class="!text-sky-accent"
|
|
@click="mobileOpen = false"
|
|
>
|
|
{{ $t(item.label) }}
|
|
</NuxtLink>
|
|
</nav>
|
|
</Transition>
|
|
</header>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useProgressionStore } from '~/stores/progression'
|
|
|
|
const localePath = useLocalePath()
|
|
const store = useProgressionStore()
|
|
|
|
const progressPercent = computed(() => store.progressPercent)
|
|
|
|
const showProgressBar = computed(() => {
|
|
return store.hero !== null
|
|
})
|
|
|
|
const mobileOpen = ref(false)
|
|
const scrolled = ref(false)
|
|
|
|
const navItems = [
|
|
{ path: '/projets', label: 'nav.projects' },
|
|
{ path: '/competences', label: 'nav.skills' },
|
|
{ path: '/parcours', label: 'nav.journey' },
|
|
{ path: '/temoignages', label: 'nav.testimonials' },
|
|
{ path: '/contact', label: 'nav.contact' },
|
|
]
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('scroll', handleScroll, { passive: true })
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('scroll', handleScroll)
|
|
})
|
|
|
|
function handleScroll() {
|
|
scrolled.value = window.scrollY > 20
|
|
}
|
|
</script>
|