From 9c47c717d0022385f6f5d514a5868a0217c5dbc9 Mon Sep 17 00:00:00 2001 From: "ext.jeremy.guillot@maxicoffee.domains" Date: Sun, 15 Mar 2026 16:50:02 +0100 Subject: [PATCH] =?UTF-8?q?style(reader):=20am=C3=A9liorer=20la=20toolbar?= =?UTF-8?q?=20et=20l'UI=20du=20mode=20scroll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Corriger la troncature de la toolbar (max-height 4rem → 5rem) - Animer la toolbar en translateY pour un effet "bloc uni" avec le header - Corriger le bug d'auto-hide du header après switch simple → scroll - Augmenter la taille du titre de chapitre dans la toolbar (text-sm font-medium) - Harmoniser le bouton scroll-to-top avec le style des ToolbarButtons - Ajouter support de prop `class` sur les labels de ToolbarSection --- .../presentation/components/ChapterReader.vue | 158 ++------- .../components/InfiniteReader.vue | 39 +-- .../presentation/components/ReaderPage.vue | 43 ++- .../components/ReaderSettings.vue | 317 ++---------------- .../presentation/components/ReaderToolbar.vue | 178 ++++++++++ .../components/SingleModeReader.vue | 48 +-- .../reader/presentation/pages/ChapterPage.vue | 72 ++-- .../app/shared/components/layout/Layout.vue | 7 +- .../vue/app/shared/components/ui/Toolbar.vue | 3 + .../shared/components/ui/ToolbarButton.vue | 8 +- .../shared/components/ui/ToolbarSection.vue | 6 +- assets/vue/app/shared/stores/headerStore.js | 51 +-- .../QueryHandler/GetChapterContextHandler.php | 13 +- .../Response/ChapterContextResponse.php | 6 + .../Reader/Domain/Model/ChapterContext.php | 6 + .../State/Provider/ChapterContextProvider.php | 1 + .../Persistence/LegacyChapterRepository.php | 1 + .../Feature/Reader/GetChapterContextTest.php | 1 + 18 files changed, 396 insertions(+), 562 deletions(-) create mode 100644 assets/vue/app/domain/reader/presentation/components/ReaderToolbar.vue diff --git a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue index 7276ec3..8e46e22 100644 --- a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue +++ b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue @@ -9,19 +9,6 @@
- - - -
@@ -68,8 +35,6 @@ import { useHeaderStore } from '../../../../shared/stores/headerStore'; import { useUserPreferencesStore } from '../../../../domain/setting/application/store/userPreferencesStore'; import { useReaderStore } from '../../application/store/readerStore'; import InfiniteReader from './InfiniteReader.vue'; -import ReaderControls from './ReaderControls.vue'; -import ReaderSettings from './ReaderSettings.vue'; import SingleModeReader from './SingleModeReader.vue'; const props = defineProps({ @@ -87,28 +52,20 @@ import SingleModeReader from './SingleModeReader.vue'; const headerStore = useHeaderStore(); const prefs = useUserPreferencesStore(); - // Référence vers InfiniteReader pour accéder à ses méthodes const infiniteReaderRef = ref(null); - // État pour la visibilité des boutons (géré par InfiniteReader en mode infini, localement en mode simple) - const showFloatingButtons = ref(false); - const settingsOpen = ref(false); // Nouvel état pour gérer l'ouverture des paramètres - let localButtonsTimer = null; - // Actions de l'interface lecteur const toggleReadingMode = () => { const newMode = store.readingMode === 'single' ? 'infinite' : 'single'; store.setReadingMode(newMode); prefs.setReadingMode(newMode === 'infinite' ? 'scroll' : 'single'); - // Gérer la visibilité selon le mode if (newMode === 'single') { headerStore.disableAutoHide(); - // En mode simple : toujours visible - showFloatingButtons.value = true; - clearTimeout(localButtonsTimer); // Annuler tout timer local + headerStore.disableReaderToolbarAutoHide(); } else { - // En mode infini : utiliser la logique d'InfiniteReader + headerStore.enableReaderToolbarAutoHide(); + headerStore.enableAutoHide(); showButtonsWithTimer(); } }; @@ -117,100 +74,40 @@ import SingleModeReader from './SingleModeReader.vue'; const newDir = store.readingDirection === 'ltr' ? 'rtl' : 'ltr'; store.setReadingDirection(newDir); prefs.setReadingDirection(newDir); - resetButtonsTimer(); }; - const zoomIn = () => { - store.setZoom(Math.min(store.zoom + 0.1, 2)); - resetButtonsTimer(); - }; + const zoomIn = () => store.setZoom(Math.min(store.zoom + 0.1, 2)); + const zoomOut = () => store.setZoom(Math.max(store.zoom - 0.1, 0.5)); - const zoomOut = () => { - store.setZoom(Math.max(store.zoom - 0.1, 0.5)); - resetButtonsTimer(); - }; + const handleZoomChange = (zoom) => store.setZoom(zoom); - const handleZoomChange = (zoom) => { - store.setZoom(zoom); - resetButtonsTimer(); - }; + const handleDoublePageModeChange = (mode) => store.setDoublePageMode(mode); + const handleDoublePageAutoDetectChange = (enabled) => store.setDoublePageAutoDetect(enabled); + const handleDetectionThresholdChange = (threshold) => store.setDoublePageDetectionThreshold(threshold); + const handleResetPreferences = () => store.resetPreferences(); - // Fonctions pour les doubles pages - const handleDoublePageModeChange = (mode) => { - store.setDoublePageMode(mode); - resetButtonsTimer(); - }; - - const handleDoublePageAutoDetectChange = (enabled) => { - store.setDoublePageAutoDetect(enabled); - resetButtonsTimer(); - }; - - const handleDetectionThresholdChange = (threshold) => { - store.setDoublePageDetectionThreshold(threshold); - resetButtonsTimer(); - }; - - const handleResetPreferences = () => { - store.resetPreferences(); - resetButtonsTimer(); - }; - - // Fonction pour afficher les boutons avec timer (avec fallback pour mode simple) const showButtonsWithTimer = () => { if (store.readingMode === 'infinite' && infiniteReaderRef.value) { - // Mode infini : utiliser la logique d'InfiniteReader infiniteReaderRef.value.showButtonsWithTimer(); - } else { - // Mode simple : toujours visible, pas de timer - showFloatingButtons.value = true; } }; - // Fonction centralisée pour réinitialiser le timer const resetButtonsTimer = () => { if (store.readingMode === 'infinite' && infiniteReaderRef.value) { - // Mode infini : utiliser la logique d'InfiniteReader infiniteReaderRef.value.resetButtonsTimer(); - } else { - // Mode simple : toujours visible, pas de timer - showFloatingButtons.value = true; } }; - // Gestionnaire pour les changements de visibilité des boutons - const handleButtonsVisibilityChange = (visible) => { - if (store.readingMode === 'infinite') { - showFloatingButtons.value = visible; - } - // En mode simple, on ignore les changements et on reste toujours visible - }; - const handleKeyPress = event => { if (store.readingMode === 'single') { if (event.key === 'ArrowRight') { store.nextPage(); - showButtonsWithTimer(); // Afficher les boutons lors de la navigation clavier } else if (event.key === 'ArrowLeft') { store.previousPage(); - showButtonsWithTimer(); // Afficher les boutons lors de la navigation clavier } } }; - const handleChapterSelected = (chapterId) => { - // La navigation est déjà gérée par le ChapterSelector via le store - // Cette fonction est là pour d'éventuelles actions supplémentaires - console.log('Chapitre sélectionné:', chapterId); - resetButtonsTimer(); - }; - - // Gestion des paramètres via le bouton intégré - const toggleSettings = () => { - settingsOpen.value = !settingsOpen.value; - resetButtonsTimer(); // Réinitialiser le timer lors de l'interaction - }; - watch( () => props.chapterId, newId => { @@ -222,38 +119,46 @@ import SingleModeReader from './SingleModeReader.vue'; ); onMounted(() => { - // Charger les préférences sauvegardées store.loadPreferences(); - window.addEventListener('keydown', handleKeyPress); - // Auto-hide header si activé dans les préférences if (prefs.autoHideHeaderReader) { headerStore.enableAutoHide(); } - // Auto-fullscreen si activé dans les préférences + if (store.readingMode === 'infinite') { + headerStore.enableReaderToolbarAutoHide(); + } + if (prefs.autoFullscreen && document.documentElement.requestFullscreen) { document.documentElement.requestFullscreen().catch(() => {}); } - - // Afficher les boutons au démarrage - showButtonsWithTimer(); }); onUnmounted(() => { window.removeEventListener('keydown', handleKeyPress); - // S'assurer que l'auto-hide est désactivé en quittant le lecteur headerStore.disableAutoHide(); - // Nettoyer le timer local - clearTimeout(localButtonsTimer); + headerStore.disableReaderToolbarAutoHide(); + }); + + defineExpose({ + toggleReadingMode, + toggleReadingDirection, + zoomIn, + zoomOut, + handleZoomChange, + handleDoublePageModeChange, + handleDoublePageAutoDetectChange, + handleDetectionThresholdChange, + handleResetPreferences, + resetButtonsTimer, + showButtonsWithTimer, }); diff --git a/assets/vue/app/domain/reader/presentation/components/ReaderPage.vue b/assets/vue/app/domain/reader/presentation/components/ReaderPage.vue index 33ac8a0..733a2f5 100644 --- a/assets/vue/app/domain/reader/presentation/components/ReaderPage.vue +++ b/assets/vue/app/domain/reader/presentation/components/ReaderPage.vue @@ -1,5 +1,8 @@