Files
Mangarr/assets/vue/app/domain/reader/presentation/components/ReaderSettings.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

216 lines
8.2 KiB
Vue

<template>
<div class="reader-settings">
<Transition
enter-active-class="transition-all duration-300 ease-out"
leave-active-class="transition-all duration-300 ease-in"
enter-from-class="opacity-0 translate-y-4 scale-95"
enter-to-class="opacity-100 translate-y-0 scale-100"
leave-from-class="opacity-100 translate-y-0 scale-100"
leave-to-class="opacity-0 translate-y-4 scale-95"
>
<div v-show="open" class="settings-panel" ref="panelRef">
<!-- Paramètres des doubles pages (mobile uniquement) -->
<div class="settings-section" v-if="isMobile">
<h3 class="section-title">
<svg class="w-5 h-5 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Doubles pages (Mobile)
</h3>
<div class="setting-item">
<label class="setting-label">
<input
type="checkbox"
:checked="doublePageSettings.autoDetect"
@change="onDoublePageAutoDetectChange($event.target.checked)"
class="setting-checkbox"
/>
<span>Détection automatique</span>
</label>
<p class="setting-description">
Détecter et optimiser automatiquement l'affichage des doubles pages sur mobile
</p>
</div>
<div v-if="doublePageSettings.autoDetect" class="setting-item">
<label class="setting-label">Mode d'affichage</label>
<select
:value="doublePageMode"
@change="onDoublePageModeChange($event.target.value)"
class="setting-select"
>
<option value="rotate">Rotation suggérée</option>
<option value="scroll">Défilement horizontal</option>
<option value="normal">Affichage normal</option>
</select>
<p class="setting-description">
<span v-if="doublePageMode === 'rotate'">Suggère de tourner l'appareil pour une meilleure lecture</span>
<span v-else-if="doublePageMode === 'scroll'">Permet le défilement horizontal pour naviguer dans la page (commence à droite)</span>
<span v-else>Affichage standard sans optimisation spéciale</span>
</p>
</div>
<div v-if="doublePageSettings.autoDetect" class="setting-item">
<label class="setting-label">
Sensibilité de détection: {{ doublePageSettings.detectionThreshold.toFixed(1) }}
</label>
<input
type="range"
:value="doublePageSettings.detectionThreshold"
@input="onDetectionThresholdChange($event.target.value)"
min="1.0"
max="2.5"
step="0.1"
class="setting-slider"
/>
<p class="setting-description">
Plus la valeur est faible, plus la détection est sensible (1.4 recommandé)
</p>
</div>
</div>
<!-- Réinitialiser -->
<div class="settings-section">
<div class="setting-actions">
<button @click="onResetPreferences" class="action-button reset">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Réinitialiser les préférences
</button>
</div>
</div>
</div>
</Transition>
</div>
</template>
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
const props = defineProps({
doublePageMode: {
type: String,
default: 'rotate'
},
doublePageSettings: {
type: Object,
default: () => ({
autoDetect: true,
mobileOnly: true,
detectionThreshold: 1.4
})
},
open: {
type: Boolean,
default: false
}
});
const emit = defineEmits([
'toggleSettings',
'doublePageModeChange',
'doublePageAutoDetectChange',
'detectionThresholdChange',
'resetPreferences',
]);
const isMobile = computed(() => window.innerWidth < 768);
const panelRef = ref(null);
const handleClickOutside = (event) => {
if (props.open && panelRef.value && !panelRef.value.contains(event.target)) {
emit('toggleSettings');
}
};
onMounted(() => document.addEventListener('click', handleClickOutside, true));
onUnmounted(() => document.removeEventListener('click', handleClickOutside, true));
const onDoublePageModeChange = (mode) => emit('doublePageModeChange', mode);
const onDoublePageAutoDetectChange = (enabled) => emit('doublePageAutoDetectChange', enabled);
const onDetectionThresholdChange = (threshold) => emit('detectionThresholdChange', parseFloat(threshold));
const onResetPreferences = () => {
emit('resetPreferences');
emit('toggleSettings');
};
</script>
<style lang="postcss" scoped>
.reader-settings {
@apply relative;
}
.settings-panel {
@apply fixed top-20 right-4 z-40 w-80 max-w-[calc(100vw-2rem)] bg-gray-800 rounded-lg shadow-xl border border-gray-700 max-h-[80vh] overflow-y-auto;
}
@media (max-width: 480px) {
.settings-panel {
width: 90vw;
max-width: calc(100vw - 1rem);
right: 0.5rem;
}
}
.settings-section {
@apply p-4 border-b border-gray-700 last:border-b-0;
}
.section-title {
@apply text-white font-semibold text-lg mb-3 flex items-center;
}
.setting-item {
@apply mb-4 last:mb-0;
}
.setting-label {
@apply flex items-center gap-2 text-white font-medium text-sm mb-2 cursor-pointer;
}
.setting-checkbox {
@apply w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2;
}
.setting-select {
@apply w-full bg-gray-700 border border-gray-600 text-white text-sm rounded-lg px-3 py-2 focus:ring-blue-500 focus:border-blue-500;
}
.setting-slider {
@apply w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer mb-2;
}
.setting-slider::-webkit-slider-thumb {
@apply appearance-none w-4 h-4 bg-blue-600 rounded-full cursor-pointer;
}
.setting-slider::-moz-range-thumb {
@apply w-4 h-4 bg-blue-600 rounded-full cursor-pointer border-none;
}
.setting-description {
@apply text-gray-400 text-xs leading-relaxed;
}
.setting-actions {
@apply flex gap-2;
}
.action-button {
@apply flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors;
}
.action-button.reset {
@apply bg-red-600 hover:bg-red-700 text-white;
}
@media (max-width: 768px) {
.settings-panel {
@apply right-2 w-72;
}
}
</style>