Files
Mangarr/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue
ext.jeremy.guillot@maxicoffee.domains 9c47c717d0 style(reader): améliorer la toolbar et l'UI du mode scroll
- 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
2026-03-15 16:50:02 +01:00

180 lines
5.5 KiB
Vue

<template>
<div class="chapter-reader" :class="{ rtl: store.readingDirection === 'rtl' }">
<div v-if="store.isLoading" class="loading">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
</div>
<div v-else-if="store.error" class="error">
{{ store.error }}
</div>
<div v-else class="reader-content">
<template v-if="store.readingMode === 'single'">
<SingleModeReader
:page-data="store.currentPageData"
:page-number="store.currentPage + 1"
:zoom="store.zoom"
:double-page-mode="store.effectiveDoublePageMode"
@button-click="showButtonsWithTimer" />
</template>
<template v-else>
<InfiniteReader
:pages="store.pages"
:zoom="store.zoom"
:double-page-mode="store.effectiveDoublePageMode"
@page-visible="store.handlePageVisible"
ref="infiniteReaderRef" />
</template>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref, watch } from 'vue';
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 SingleModeReader from './SingleModeReader.vue';
const props = defineProps({
chapterId: {
type: String,
required: true
},
availableChapters: {
type: Array,
default: () => []
}
});
const store = useReaderStore();
const headerStore = useHeaderStore();
const prefs = useUserPreferencesStore();
const infiniteReaderRef = ref(null);
// Actions de l'interface lecteur
const toggleReadingMode = () => {
const newMode = store.readingMode === 'single' ? 'infinite' : 'single';
store.setReadingMode(newMode);
prefs.setReadingMode(newMode === 'infinite' ? 'scroll' : 'single');
if (newMode === 'single') {
headerStore.disableAutoHide();
headerStore.disableReaderToolbarAutoHide();
} else {
headerStore.enableReaderToolbarAutoHide();
headerStore.enableAutoHide();
showButtonsWithTimer();
}
};
const toggleReadingDirection = () => {
const newDir = store.readingDirection === 'ltr' ? 'rtl' : 'ltr';
store.setReadingDirection(newDir);
prefs.setReadingDirection(newDir);
};
const zoomIn = () => store.setZoom(Math.min(store.zoom + 0.1, 2));
const zoomOut = () => store.setZoom(Math.max(store.zoom - 0.1, 0.5));
const handleZoomChange = (zoom) => store.setZoom(zoom);
const handleDoublePageModeChange = (mode) => store.setDoublePageMode(mode);
const handleDoublePageAutoDetectChange = (enabled) => store.setDoublePageAutoDetect(enabled);
const handleDetectionThresholdChange = (threshold) => store.setDoublePageDetectionThreshold(threshold);
const handleResetPreferences = () => store.resetPreferences();
const showButtonsWithTimer = () => {
if (store.readingMode === 'infinite' && infiniteReaderRef.value) {
infiniteReaderRef.value.showButtonsWithTimer();
}
};
const resetButtonsTimer = () => {
if (store.readingMode === 'infinite' && infiniteReaderRef.value) {
infiniteReaderRef.value.resetButtonsTimer();
}
};
const handleKeyPress = event => {
if (store.readingMode === 'single') {
if (event.key === 'ArrowRight') {
store.nextPage();
} else if (event.key === 'ArrowLeft') {
store.previousPage();
}
}
};
watch(
() => props.chapterId,
newId => {
if (newId) {
store.loadChapter(newId);
}
},
{ immediate: true }
);
onMounted(() => {
store.loadPreferences();
window.addEventListener('keydown', handleKeyPress);
if (prefs.autoHideHeaderReader) {
headerStore.enableAutoHide();
}
if (store.readingMode === 'infinite') {
headerStore.enableReaderToolbarAutoHide();
}
if (prefs.autoFullscreen && document.documentElement.requestFullscreen) {
document.documentElement.requestFullscreen().catch(() => {});
}
});
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyPress);
headerStore.disableAutoHide();
headerStore.disableReaderToolbarAutoHide();
});
defineExpose({
toggleReadingMode,
toggleReadingDirection,
zoomIn,
zoomOut,
handleZoomChange,
handleDoublePageModeChange,
handleDoublePageAutoDetectChange,
handleDetectionThresholdChange,
handleResetPreferences,
resetButtonsTimer,
showButtonsWithTimer,
});
</script>
<style lang="postcss" scoped>
.chapter-reader {
@apply w-full h-full flex flex-col bg-gray-900 text-white;
}
.loading {
@apply flex items-center justify-center h-full;
}
.error {
@apply text-red-500 text-xl;
}
.reader-content {
@apply w-full flex-1 flex flex-col min-h-0;
}
.rtl {
direction: rtl;
}
</style>