feat: ajout de la gestion de l'auto-hide du header et amélioration de la réactivité des composants en fonction de la taille de la fenêtre, ainsi que des optimisations CSS pour une meilleure expérience utilisateur sur mobile.
This commit is contained in:
parent
4848a1736f
commit
ebcca466a9
@@ -1,8 +1,16 @@
|
||||
<template>
|
||||
<header class="bg-green-600 h-16 flex items-center fixed w-full z-50">
|
||||
<button
|
||||
<header
|
||||
:class="[
|
||||
'bg-green-600 h-16 flex items-center fixed w-full z-50 transition-transform duration-300 ease-in-out',
|
||||
headerStore.shouldShowHeader ? 'translate-y-0' : '-translate-y-full'
|
||||
]"
|
||||
>
|
||||
<button
|
||||
@click="$emit('menu-click')"
|
||||
class="ml-4 text-white p-2 md:hidden"
|
||||
:class="[
|
||||
'ml-4 text-white p-2',
|
||||
showMenuButton ? '' : 'md:hidden'
|
||||
]"
|
||||
>
|
||||
<Bars3Icon class="h-6 w-6" />
|
||||
</button>
|
||||
@@ -17,7 +25,17 @@
|
||||
|
||||
<script setup>
|
||||
import { Bars3Icon } from '@heroicons/vue/24/outline';
|
||||
import { useHeaderStore } from '../../stores/headerStore';
|
||||
import SearchBar from './SearchBar.vue';
|
||||
|
||||
const headerStore = useHeaderStore();
|
||||
|
||||
defineProps({
|
||||
showMenuButton: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
defineEmits(['menu-click']);
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-gray-50 flex">
|
||||
<Header
|
||||
:show-menu-button="isReaderMode"
|
||||
@menu-click="toggleSidebar"
|
||||
@manga-click="$emit('manga-click', $event)"
|
||||
@add-manga-click="$emit('add-manga-click', $event)" />
|
||||
<Sidebar :is-open="isSidebarOpen" @close="closeSidebar" @add-manga-click="$emit('add-manga-click', $event)" />
|
||||
<Sidebar
|
||||
:is-open="isSidebarOpen"
|
||||
:force-mobile-behavior="isReaderMode"
|
||||
@close="closeSidebar"
|
||||
@add-manga-click="$emit('add-manga-click', $event)" />
|
||||
|
||||
<main class="flex-1 pt-16 md:ml-60">
|
||||
<main :class="[
|
||||
'flex-1 pt-16',
|
||||
isReaderMode ? '' : 'md:ml-60'
|
||||
]">
|
||||
<RouterView></RouterView>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import Header from './Header.vue';
|
||||
import Sidebar from './Sidebar.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import Header from './Header.vue';
|
||||
import Sidebar from './Sidebar.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const isSidebarOpen = ref(false);
|
||||
|
||||
// Détecte si on est en mode Reader
|
||||
const isReaderMode = computed(() => {
|
||||
return route.name === 'reader';
|
||||
});
|
||||
|
||||
const toggleSidebar = () => {
|
||||
isSidebarOpen.value = !isSidebarOpen.value;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<aside
|
||||
:class="[
|
||||
'fixed top-16 left-0 w-60 bg-gray-600 text-white transform transition-transform duration-300 ease-in-out z-40 h-full',
|
||||
isOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'
|
||||
isOpen ? 'translate-x-0' : '-translate-x-full',
|
||||
!forceMobileBehavior ? 'md:translate-x-0' : ''
|
||||
]"
|
||||
role="navigation"
|
||||
aria-label="Menu principal">
|
||||
@@ -23,22 +24,26 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
BookOpenIcon,
|
||||
PlusIcon,
|
||||
ArrowDownTrayIcon,
|
||||
GlobeAltIcon,
|
||||
ArrowsRightLeftIcon,
|
||||
CalendarIcon,
|
||||
ClockIcon,
|
||||
Cog6ToothIcon,
|
||||
ComputerDesktopIcon
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import MenuGroup from './sidebar/MenuGroup.vue';
|
||||
ArrowDownTrayIcon,
|
||||
ArrowsRightLeftIcon,
|
||||
BookOpenIcon,
|
||||
CalendarIcon,
|
||||
ClockIcon,
|
||||
Cog6ToothIcon,
|
||||
ComputerDesktopIcon,
|
||||
GlobeAltIcon,
|
||||
PlusIcon
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import MenuGroup from './sidebar/MenuGroup.vue';
|
||||
|
||||
const props = defineProps({
|
||||
isOpen: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
forceMobileBehavior: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
73
assets/vue/app/shared/stores/headerStore.js
Normal file
73
assets/vue/app/shared/stores/headerStore.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useHeaderStore = defineStore('header', {
|
||||
state: () => ({
|
||||
isHeaderVisible: true,
|
||||
isAutoHideEnabled: false,
|
||||
lastScrollY: 0,
|
||||
scrollDirection: 'up'
|
||||
}),
|
||||
|
||||
getters: {
|
||||
shouldShowHeader: (state) => {
|
||||
// Si l'auto-hide n'est pas activé, toujours afficher le header
|
||||
if (!state.isAutoHideEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Si l'auto-hide est activé, suivre la visibilité
|
||||
return state.isHeaderVisible;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
enableAutoHide() {
|
||||
this.isAutoHideEnabled = true;
|
||||
},
|
||||
|
||||
disableAutoHide() {
|
||||
this.isAutoHideEnabled = false;
|
||||
this.isHeaderVisible = true; // Toujours visible quand désactivé
|
||||
},
|
||||
|
||||
updateScrollDirection(scrollY) {
|
||||
// Éviter les calculs inutiles si pas d'auto-hide
|
||||
if (!this.isAutoHideEnabled) {
|
||||
this.lastScrollY = scrollY;
|
||||
return;
|
||||
}
|
||||
|
||||
// Détecter la direction du scroll avec un seuil pour éviter les micro-mouvements
|
||||
const scrollDifference = Math.abs(scrollY - this.lastScrollY);
|
||||
|
||||
if (scrollDifference < 5) {
|
||||
// Mouvement trop petit, on ignore
|
||||
return;
|
||||
}
|
||||
|
||||
if (scrollY > this.lastScrollY && scrollY > 100) {
|
||||
// Scroll vers le bas et suffisamment de scroll
|
||||
if (this.scrollDirection !== 'down') {
|
||||
this.scrollDirection = 'down';
|
||||
this.isHeaderVisible = false;
|
||||
}
|
||||
} else if (scrollY < this.lastScrollY) {
|
||||
// Scroll vers le haut
|
||||
if (this.scrollDirection !== 'up') {
|
||||
this.scrollDirection = 'up';
|
||||
this.isHeaderVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.lastScrollY = scrollY;
|
||||
},
|
||||
|
||||
showHeader() {
|
||||
this.isHeaderVisible = true;
|
||||
},
|
||||
|
||||
hideHeader() {
|
||||
this.isHeaderVisible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user