Files
Mangarr/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue

138 lines
4.1 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">
<ReaderControls
v-if="store.readingMode === 'single'"
:current-page="store.currentPage"
:total-pages="store.totalPages"
:is-first-page="store.isFirstPage"
:is-last-page="store.isLastPage"
:available-chapters="availableChapters"
@previous="store.previousPage"
@next="store.nextPage"
@chapter-selected="handleChapterSelected" />
<template v-if="store.readingMode === 'single'">
<SingleModeReader
:page-data="store.currentPageData"
:page-number="store.currentPage + 1"
:zoom="store.zoom" />
</template>
<template v-else>
<InfiniteReader :pages="store.pages" :zoom="store.zoom" @page-visible="store.handlePageVisible" />
</template>
<ReaderSettings
:reading-mode="store.readingMode"
:reading-direction="store.readingDirection"
:zoom="store.zoom"
@toggle-reading-mode="toggleReadingMode"
@toggle-reading-direction="toggleReadingDirection"
@zoom-in="zoomIn"
@zoom-out="zoomOut" />
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, watch } from 'vue';
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({
chapterId: {
type: String,
required: true
},
availableChapters: {
type: Array,
default: () => []
}
});
const store = useReaderStore();
const toggleReadingMode = () => {
store.setReadingMode(store.readingMode === 'single' ? 'infinite' : 'single');
};
const toggleReadingDirection = () => {
store.setReadingDirection(store.readingDirection === 'ltr' ? 'rtl' : 'ltr');
};
const zoomIn = () => {
store.setZoom(Math.min(store.zoom + 0.1, 2));
};
const zoomOut = () => {
store.setZoom(Math.max(store.zoom - 0.1, 0.5));
};
const handleKeyPress = event => {
if (store.readingMode === 'single') {
if (event.key === 'ArrowRight') {
store.nextPage();
} else if (event.key === 'ArrowLeft') {
store.previousPage();
}
}
};
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);
};
watch(
() => props.chapterId,
newId => {
if (newId) {
store.loadChapter(newId);
}
},
{ immediate: true }
);
onMounted(() => {
window.addEventListener('keydown', handleKeyPress);
});
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyPress);
});
</script>
<style lang="postcss" scoped>
.chapter-reader {
@apply w-full h-full flex flex-col items-center justify-center 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 h-full flex flex-col;
}
.rtl {
direction: rtl;
}
</style>