feat: ajout de la gestion de l'expansion des volumes dans les composants MangaVolume et MangaVolumeList. Intégration de la synchronisation de l'état d'expansion avec les props, ainsi que des méthodes pour étendre ou réduire tous les volumes. Amélioration de l'interface utilisateur pour une navigation plus fluide entre les volumes.

This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2025-07-23 16:08:20 +02:00
parent 330a0fac34
commit 7f9d583c94
3 changed files with 103 additions and 14 deletions

View File

@@ -83,7 +83,7 @@
ChevronUpIcon, ChevronUpIcon,
MagnifyingGlassIcon MagnifyingGlassIcon
} from '@heroicons/vue/24/outline'; } from '@heroicons/vue/24/outline';
import { ref } from 'vue'; import { ref, watch } from 'vue';
import { useMangaStore } from '../../application/store/mangaStore'; import { useMangaStore } from '../../application/store/mangaStore';
import MangaChapterList from './MangaChapterList.vue'; import MangaChapterList from './MangaChapterList.vue';
@@ -106,13 +106,21 @@ import MangaChapterList from './MangaChapterList.vue';
} }
}); });
const emit = defineEmits(['toggle']);
const store = useMangaStore(); const store = useMangaStore();
const isOpen = ref(props.isOpen); const isOpen = ref(props.isOpen);
const isSearching = ref(false); const isSearching = ref(false);
const isDownloading = ref(false); const isDownloading = ref(false);
// Synchroniser l'état local avec la prop
watch(() => props.isOpen, (newValue) => {
isOpen.value = newValue;
});
const toggleVolume = () => { const toggleVolume = () => {
isOpen.value = !isOpen.value; isOpen.value = !isOpen.value;
emit('toggle', props.volume.number);
}; };
const handleSearch = async () => { const handleSearch = async () => {

View File

@@ -6,12 +6,14 @@
:volume="volume" :volume="volume"
:mangaSlug="mangaSlug" :mangaSlug="mangaSlug"
:mangaId="mangaId" :mangaId="mangaId"
:isOpen="index === 0" /> :isOpen="expandedVolumes.has(volume.number)"
@toggle="handleVolumeToggle" />
</div> </div>
</template> </template>
<script setup> <script setup>
import MangaVolume from './MangaVolume.vue'; import { ref, watch } from 'vue';
import MangaVolume from './MangaVolume.vue';
const props = defineProps({ const props = defineProps({
volumes: { volumes: {
@@ -25,6 +27,69 @@
mangaId: { mangaId: {
type: Number, type: Number,
required: true required: true
},
expandAll: {
type: Boolean,
default: false
} }
}); });
const emit = defineEmits(['update:expandAll']);
// Set pour stocker les numéros de volumes ouverts
const expandedVolumes = ref(new Set());
// Initialiser avec le premier volume ouvert par défaut
watch(() => props.volumes, (newVolumes) => {
if (newVolumes.length > 0 && expandedVolumes.value.size === 0) {
// Ouvrir le premier volume (volume 00) par défaut
expandedVolumes.value.add(newVolumes[0].number);
}
}, { immediate: true });
// Gérer l'expansion de tous les volumes
watch(() => props.expandAll, (shouldExpand) => {
if (shouldExpand) {
// Ouvrir tous les volumes
props.volumes.forEach(volume => {
expandedVolumes.value.add(volume.number);
});
} else {
// Fermer tous les volumes (y compris le volume 00)
expandedVolumes.value.clear();
}
});
const handleVolumeToggle = (volumeNumber) => {
if (expandedVolumes.value.has(volumeNumber)) {
expandedVolumes.value.delete(volumeNumber);
} else {
expandedVolumes.value.add(volumeNumber);
}
// Émettre l'état d'expansion
const allExpanded = props.volumes.length > 0 &&
props.volumes.every(volume => expandedVolumes.value.has(volume.number));
emit('update:expandAll', allExpanded);
};
// Méthode publique pour contrôler l'expansion
const expandAllVolumes = () => {
props.volumes.forEach(volume => {
expandedVolumes.value.add(volume.number);
});
emit('update:expandAll', true);
};
const collapseAllVolumes = () => {
expandedVolumes.value.clear();
// Ne plus garder le premier volume ouvert, tous les volumes sont fermés
emit('update:expandAll', false);
};
// Exposer les méthodes pour le composant parent
defineExpose({
expandAllVolumes,
collapseAllVolumes
});
</script> </script>

View File

@@ -27,7 +27,13 @@
<div v-else-if="errorVolumes" class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded"> <div v-else-if="errorVolumes" class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
{{ errorVolumes.message || 'Une erreur est survenue lors du chargement des volumes.' }} {{ errorVolumes.message || 'Une erreur est survenue lors du chargement des volumes.' }}
</div> </div>
<MangaVolumeList v-else :volumes="volumes" :manga-slug="currentManga.slug" :manga-id="mangaId" /> <MangaVolumeList
v-else
ref="volumeListRef"
:volumes="volumes"
:manga-slug="currentManga.slug"
:manga-id="mangaId"
v-model:expand-all="isAllExpanded" />
</div> </div>
<!-- Modale des sources préférées --> <!-- Modale des sources préférées -->
@@ -80,8 +86,8 @@
BookmarkIcon, BookmarkIcon,
BookmarkSlashIcon, BookmarkSlashIcon,
ChevronDoubleDownIcon, ChevronDoubleDownIcon,
ChevronDoubleUpIcon,
Cog6ToothIcon, Cog6ToothIcon,
DocumentArrowDownIcon,
PencilSquareIcon, PencilSquareIcon,
TrashIcon, TrashIcon,
WrenchIcon WrenchIcon
@@ -118,6 +124,10 @@ import { useMangaStore } from '../../application/store/mangaStore';
const isSavingChapters = ref(false); const isSavingChapters = ref(false);
const chaptersError = ref(null); const chaptersError = ref(null);
// État d'expansion des volumes
const isAllExpanded = ref(false);
const volumeListRef = ref(null);
const { const {
data: currentManga, data: currentManga,
isLoading: isLoadingDetails, isLoading: isLoadingDetails,
@@ -270,6 +280,17 @@ import { useMangaStore } from '../../application/store/mangaStore';
} }
}; };
// Fonction pour étendre/réduire tous les volumes
const handleExpandAll = () => {
if (!volumeListRef.value) return;
if (isAllExpanded.value) {
volumeListRef.value.collapseAllVolumes();
} else {
volumeListRef.value.expandAllVolumes();
}
};
const toolbarConfig = computed(() => ({ const toolbarConfig = computed(() => ({
leftSection: [ leftSection: [
{ {
@@ -286,12 +307,6 @@ import { useMangaStore } from '../../application/store/mangaStore';
type: 'button', type: 'button',
onClick: openManageChaptersModal onClick: openManageChaptersModal
}, },
{
icon: DocumentArrowDownIcon,
label: 'Manage cbz',
type: 'button',
onClick: () => console.log('Manage cbz')
},
{ {
icon: Cog6ToothIcon, icon: Cog6ToothIcon,
label: 'Preferred Sources', label: 'Preferred Sources',
@@ -322,10 +337,11 @@ import { useMangaStore } from '../../application/store/mangaStore';
onClick: () => console.log('Delete') onClick: () => console.log('Delete')
}, },
{ {
icon: ChevronDoubleDownIcon, icon: isAllExpanded.value ? ChevronDoubleUpIcon : ChevronDoubleDownIcon,
label: 'Expand all', label: isAllExpanded.value ? 'Collapse all' : 'Expand all',
type: 'button', type: 'button',
onClick: () => console.log('Expand all') onClick: handleExpandAll,
variant: isAllExpanded.value ? 'active' : 'default'
} }
] ]
})); }));