feat: dark mode complet + préférences utilisateur

- Ajout du store userPreferencesStore (thème, vue, tri, pagination, lecteur)
- Page UserPreferencesPage pour configurer toutes les préférences
- Câblage des prefs dans HomePage (viewMode, sortBy, itemsPerPage), readerStore (fallback prefs), ChapterReader (autoHide, autoFullscreen, sync), useNotifications (toastDuration)
- Thème sombre (dark: Tailwind) sur tous les composants Vue : Layout, Pagination, NotificationToast, MangaCard, MangaVolume, MangaDetails, AddManga, HomePage, ActivityPage, JobItem, MangaDeleteModal, MangaEditModal, MangaPreferredSourcesModal, ManageChaptersModal, MangaChapterList, MangaChapter, ConversionPage, FileUploadArea, ConversionProgress, NewImportPage, FileImportCard, MangaMatchCard, StatusBadge, ImportResults
- i18n partiellement initialisé

Jeremy Guillot
This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2026-03-12 20:38:29 +01:00
parent 48d819ba72
commit ec1ef8fe68
36 changed files with 2832 additions and 317 deletions

View File

@@ -5,32 +5,32 @@
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm transition-opacity" @click="handleClose"></div>
<!-- Modal avec style Material Design -->
<div class="inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-5xl sm:w-full border border-gray-100">
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-5xl sm:w-full border border-gray-100 dark:border-gray-700">
<!-- Header Material Design -->
<div class="bg-gradient-to-r from-green-50 to-emerald-50 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100 dark:border-gray-700">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<FolderIcon class="h-5 w-5 text-green-600" />
</div>
<div>
<h3 class="text-xl font-medium text-gray-900 leading-6">
<h3 class="text-xl font-medium text-gray-900 dark:text-gray-100 leading-6">
Gérer les chapitres
</h3>
<p class="text-sm text-gray-600 mt-1">{{ manga?.title }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">{{ manga?.title }}</p>
</div>
</div>
<button
@click="handleClose"
class="w-8 h-8 rounded-full bg-gray-100 hover:bg-gray-200 flex items-center justify-center transition-colors duration-200"
class="w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 flex items-center justify-center transition-colors duration-200"
>
<XMarkIcon class="h-5 w-5 text-gray-600" />
<XMarkIcon class="h-5 w-5 text-gray-600 dark:text-gray-300" />
</button>
</div>
</div>
<!-- Content avec style Material Design -->
<div class="bg-white px-6 py-6 sm:px-8 sm:py-8">
<div class="bg-white dark:bg-gray-800 px-6 py-6 sm:px-8 sm:py-8">
<div v-if="isLoading" class="flex justify-center items-center h-32">
<div class="relative">
<div class="w-8 h-8 border-4 border-green-200 rounded-full"></div>
@@ -38,7 +38,7 @@
</div>
</div>
<div v-else-if="error" class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-xl mb-6 flex items-center space-x-2">
<div v-else-if="error" class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-700 text-red-700 dark:text-red-400 px-4 py-3 rounded-xl mb-6 flex items-center space-x-2">
<div class="w-5 h-5 bg-red-100 rounded-full flex items-center justify-center">
<XMarkIcon class="h-3 w-3 text-red-600" />
</div>
@@ -47,7 +47,7 @@
<div v-else class="space-y-6">
<!-- Actions avec style Material Design -->
<div class="flex items-center justify-between bg-gray-50 rounded-xl p-4">
<div class="flex items-center justify-between bg-gray-50 dark:bg-gray-700/50 rounded-xl p-4">
<div class="flex items-center space-x-3">
<button
@click="showCreateVolumeModal = true"
@@ -58,7 +58,7 @@
</button>
<button
@click="showUnassignedChapters = !showUnassignedChapters"
class="text-gray-600 hover:text-gray-800 text-sm font-medium hover:bg-gray-100 px-3 py-2 rounded-lg transition-colors duration-200"
class="text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100 text-sm font-medium hover:bg-gray-100 dark:hover:bg-gray-700 px-3 py-2 rounded-lg transition-colors duration-200"
>
{{ showUnassignedChapters ? 'Masquer' : 'Afficher' }} les chapitres non assignés
</button>
@@ -88,17 +88,17 @@
</button>
</div>
</div>
<div class="text-sm text-gray-500 bg-white px-3 py-1.5 rounded-lg border border-gray-200">
<div class="text-sm text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-600">
{{ totalChapters }} chapitres, {{ volumes.length }} volumes
</div>
</div>
<!-- Arborescence avec style Material Design -->
<div class="bg-white border border-gray-200 rounded-xl overflow-hidden shadow-sm">
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden shadow-sm">
<!-- Chapitres non assignés -->
<div v-if="showUnassignedChapters && unassignedChapters.length > 0" class="bg-gradient-to-r from-gray-50 to-gray-100 border-b border-gray-200">
<div v-if="showUnassignedChapters && unassignedChapters.length > 0" class="bg-gradient-to-r from-gray-50 to-gray-100 dark:from-gray-700/50 dark:to-gray-700/30 border-b border-gray-200 dark:border-gray-600">
<div class="px-6 py-4">
<h4 class="text-sm font-semibold text-gray-700 mb-3 flex items-center space-x-2">
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3 flex items-center space-x-2">
<DocumentIcon class="h-4 w-4 text-gray-500" />
<span>Chapitres non assignés ({{ unassignedChapters.length }})</span>
</h4>
@@ -119,11 +119,11 @@
/>
</div>
<DocumentIcon class="h-5 w-5 text-gray-400" />
<span class="text-sm font-medium text-gray-700 w-12 bg-gray-100 px-2 py-1 rounded text-center">{{ chapter.number }}</span>
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-12 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-center">{{ chapter.number }}</span>
<div class="flex-1">
<div v-if="!chapter.isEditing" class="flex items-center">
<span
class="text-sm text-gray-900 cursor-pointer hover:text-green-600 transition-colors duration-200"
class="text-sm text-gray-900 dark:text-gray-100 cursor-pointer hover:text-green-600 dark:hover:text-green-400 transition-colors duration-200"
@click="startEditingTitle(chapter)"
>
{{ chapter.title || 'Sans titre' }}
@@ -173,22 +173,22 @@
</div>
<!-- Volumes avec style Material Design -->
<div class="divide-y divide-gray-100">
<div class="divide-y divide-gray-100 dark:divide-gray-700">
<div
v-for="volume in volumes"
:key="volume.number"
class="bg-white"
class="bg-white dark:bg-gray-800"
>
<!-- En-tête du volume Material Design -->
<div class="px-6 py-4 bg-gradient-to-r from-green-50 to-emerald-50 border-b border-green-100">
<div class="px-6 py-4 bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 border-b border-green-100 dark:border-green-900/30">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
<FolderIcon class="h-4 w-4 text-green-600" />
</div>
<div>
<span class="text-sm font-semibold text-green-900">Volume {{ volume.number }}</span>
<span class="text-xs text-green-600 ml-2">({{ volume.chapters.length }} chapitres)</span>
<span class="text-sm font-semibold text-green-900 dark:text-green-300">Volume {{ volume.number }}</span>
<span class="text-xs text-green-600 dark:text-green-400 ml-2">({{ volume.chapters.length }} chapitres)</span>
</div>
</div>
<div class="flex items-center space-x-2">
@@ -211,10 +211,10 @@
<!-- Chapitres du volume -->
<div v-if="volume.isExpanded" class="px-6 py-4">
<div v-if="volume.chapters.length === 0" class="text-center py-8 text-gray-500">
<DocumentIcon class="h-12 w-12 text-gray-300 mx-auto mb-3" />
<div v-if="volume.chapters.length === 0" class="text-center py-8 text-gray-500 dark:text-gray-400">
<DocumentIcon class="h-12 w-12 text-gray-300 dark:text-gray-600 mx-auto mb-3" />
<p class="text-sm">Aucun chapitre assigné à ce volume.</p>
<p class="text-xs text-gray-400 mt-1">Utilisez le bouton "Assigner" sur les chapitres non assignés pour les ajouter.</p>
<p class="text-xs text-gray-400 dark:text-gray-500 mt-1">Utilisez le bouton "Assigner" sur les chapitres non assignés pour les ajouter.</p>
</div>
<div v-else class="space-y-2">
<div
@@ -233,11 +233,11 @@
/>
</div>
<DocumentIcon class="h-5 w-5 text-gray-400" />
<span class="text-sm font-medium text-gray-700 w-12 bg-gray-100 px-2 py-1 rounded text-center">{{ chapter.number }}</span>
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-12 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-center">{{ chapter.number }}</span>
<div class="flex-1">
<div v-if="!chapter.isEditing" class="flex items-center">
<span
class="text-sm text-gray-900 cursor-pointer hover:text-green-600 transition-colors duration-200"
class="text-sm text-gray-900 dark:text-gray-100 cursor-pointer hover:text-green-600 dark:hover:text-green-400 transition-colors duration-200"
@click="startEditingTitle(chapter)"
>
{{ chapter.title || 'Sans titre' }}
@@ -291,12 +291,12 @@
</div>
<!-- Footer Material Design -->
<div class="bg-gray-50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200">
<div class="bg-gray-50 dark:bg-gray-700/50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:justify-end sm:space-x-3 space-y-3 sm:space-y-0">
<button
@click="handleClose"
:disabled="isSaving"
class="w-full sm:w-auto inline-flex justify-center items-center rounded-lg border border-gray-300 bg-white px-6 py-2.5 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 transition-all duration-200 shadow-sm hover:shadow-md"
class="w-full sm:w-auto inline-flex justify-center items-center rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-6 py-2.5 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 transition-all duration-200 shadow-sm hover:shadow-md"
>
Annuler
</button>
@@ -320,24 +320,24 @@
<div v-if="showCreateVolumeModal" class="fixed inset-0 z-60 overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm transition-opacity" @click="showCreateVolumeModal = false"></div>
<div class="inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100">
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100 dark:border-gray-700">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100 dark:border-gray-700">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<PlusIcon class="h-5 w-5 text-green-600" />
</div>
<h3 class="text-lg font-medium text-gray-900">Créer un nouveau volume</h3>
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">Créer un nouveau volume</h3>
</div>
</div>
<div class="bg-white px-6 py-6 sm:px-8 sm:py-6">
<div class="bg-white dark:bg-gray-800 px-6 py-6 sm:px-8 sm:py-6">
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Numéro du volume</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Numéro du volume</label>
<input
v-model="newVolumeNumber"
type="number"
min="1"
class="block w-full border border-gray-300 rounded-lg px-4 py-3 text-sm focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-colors duration-200"
class="block w-full border border-gray-300 dark:border-gray-600 rounded-lg px-4 py-3 text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-colors duration-200"
placeholder="Ex: 1"
/>
</div>
@@ -351,7 +351,7 @@
</div>
</div>
</div>
<div class="bg-gray-50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200">
<div class="bg-gray-50 dark:bg-gray-700/50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:justify-end sm:space-x-3 space-y-3 sm:space-y-0">
<button
@click="showCreateVolumeModal = false"
@@ -376,8 +376,8 @@
<div v-if="showAssignModal" class="fixed inset-0 z-60 overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm transition-opacity" @click="showAssignModal = false"></div>
<div class="inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100">
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100 dark:border-gray-700">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100 dark:border-gray-700">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<DocumentIcon class="h-5 w-5 text-green-600" />
@@ -385,7 +385,7 @@
<h3 class="text-lg font-medium text-gray-900">Assigner le chapitre {{ selectedChapter?.number }}</h3>
</div>
</div>
<div class="bg-white px-6 py-6 sm:px-8 sm:py-6">
<div class="bg-white dark:bg-gray-800 px-6 py-6 sm:px-8 sm:py-6">
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Volume</label>
@@ -401,7 +401,7 @@
</div>
</div>
</div>
<div class="bg-gray-50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200">
<div class="bg-gray-50 dark:bg-gray-700/50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:justify-end sm:space-x-3 space-y-3 sm:space-y-0">
<button
@click="showAssignModal = false"
@@ -426,8 +426,8 @@
<div v-if="showMoveToVolumeModal" class="fixed inset-0 z-60 overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-black/40 backdrop-blur-sm transition-opacity" @click="showMoveToVolumeModal = false"></div>
<div class="inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100">
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full border border-gray-100 dark:border-gray-700">
<div class="bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 px-6 pt-6 pb-4 sm:px-8 sm:pb-6 border-b border-gray-100 dark:border-gray-700">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
<ArrowPathIcon class="h-5 w-5 text-green-600" />
@@ -435,7 +435,7 @@
<h3 class="text-lg font-medium text-gray-900">Déplacer {{ selectedChapters.length }} chapitre(s)</h3>
</div>
</div>
<div class="bg-white px-6 py-6 sm:px-8 sm:py-6">
<div class="bg-white dark:bg-gray-800 px-6 py-6 sm:px-8 sm:py-6">
<div class="space-y-4">
<div class="bg-green-50 p-4 rounded-lg border border-green-200">
<p class="text-sm text-green-800 font-medium">
@@ -457,7 +457,7 @@
</div>
</div>
</div>
<div class="bg-gray-50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200">
<div class="bg-gray-50 dark:bg-gray-700/50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:justify-end sm:space-x-3 space-y-3 sm:space-y-0">
<button
@click="showMoveToVolumeModal = false"
@@ -491,7 +491,7 @@
<h3 class="text-lg font-medium text-gray-900">Séparer le volume 00</h3>
</div>
</div>
<div class="bg-white px-6 py-6 sm:px-8 sm:py-6">
<div class="bg-white dark:bg-gray-800 px-6 py-6 sm:px-8 sm:py-6">
<div class="space-y-4">
<div class="bg-green-50 p-4 rounded-lg border border-green-200">
<p class="text-sm text-green-800 font-medium">
@@ -517,7 +517,7 @@
</div>
</div>
</div>
<div class="bg-gray-50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200">
<div class="bg-gray-50 dark:bg-gray-700/50 px-6 py-4 sm:px-8 sm:py-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row sm:justify-end sm:space-x-3 space-y-3 sm:space-y-0">
<button
@click="showSplitVolumeZeroModal = false"

View File

@@ -1,7 +1,7 @@
<template>
<RouterLink
:to="{ name: 'manga-details', params: { id: manga.id } }"
class="bg-white rounded-lg shadow-md overflow-hidden cursor-pointer transition-transform hover:scale-105 block">
class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden cursor-pointer transition-transform hover:scale-105 block">
<div class="relative pb-[150%]">
<img
:src="manga.thumbnailUrl || 'https://via.placeholder.com/300x400'"
@@ -9,11 +9,11 @@
class="absolute inset-0 w-full h-full object-cover bg-gray-100" />
</div>
<div class="p-2">
<h3 class="text-lg font-semibold text-gray-800 mb-1">{{ manga.title }}</h3>
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-100 mb-1">{{ manga.title }}</h3>
<div class="flex items-center">
<span class="text-sm text-gray-500">{{ manga.publicationYear }}</span>
<span class="text-sm text-gray-500 dark:text-gray-400">{{ manga.publicationYear }}</span>
</div>
<div class="mt-1 text-sm text-gray-500"> Added: {{ formatDate(manga.createdAt) }} </div>
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400"> Added: {{ formatDate(manga.createdAt) }} </div>
</div>
</RouterLink>
</template>

View File

@@ -1,11 +1,12 @@
<template>
<tr class="border-t hover:bg-green-100">
<td class="px-4 py-2" :class="{ 'text-green-500': chapter.isAvailable }">
<tr class="border-t dark:border-gray-700 hover:bg-green-100 dark:hover:bg-green-900/20">
<td class="px-4 py-2 text-gray-900 dark:text-gray-100" :class="{ 'text-green-500 dark:text-green-400': chapter.isAvailable }">
{{ String(chapter.number).padStart(2, '0') }}
</td>
<td class="px-4 py-2 w-full text-left">
<td class="px-4 py-2 w-full text-left text-gray-900 dark:text-gray-100">
<router-link
v-if="chapter.isAvailable"
class="hover:text-green-500 dark:hover:text-green-400"
:to="{
name: 'reader',
params: {
@@ -14,7 +15,7 @@
}">
{{ chapter.title || 'Sans titre' }}
</router-link>
<span v-else>{{ chapter.title || 'Sans titre' }}</span>
<span v-else class="text-gray-500 dark:text-gray-400">{{ chapter.title || 'Sans titre' }}</span>
</td>
<td class="px-4 py-2 flex justify-end gap-2">
<button v-if="!chapter.isAvailable" @click="handleSearch" :class="buttonClass">

View File

@@ -1,8 +1,8 @@
<template>
<div class="p-2 border-t">
<div class="p-2 border-t dark:border-gray-700">
<table class="min-w-full table-auto">
<thead>
<tr>
<tr class="text-gray-700 dark:text-gray-300">
<th class="px-4 py-2 text-left">#</th>
<th class="px-4 py-2 text-left">Titre</th>
<th class="px-4 py-2 text-right">Actions</th>

View File

@@ -10,7 +10,7 @@
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<div class="fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-75 dark:bg-opacity-80 transition-opacity" />
</TransitionChild>
<div class="fixed inset-0 z-10 overflow-y-auto">
@@ -24,15 +24,15 @@
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white px-6 pb-6 pt-6 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 px-6 pb-6 pt-6 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<div class="mb-6">
<DialogTitle as="h3" class="text-lg font-semibold leading-6 text-gray-900">
<DialogTitle as="h3" class="text-lg font-semibold leading-6 text-gray-900 dark:text-gray-100">
Supprimer le manga
</DialogTitle>
</div>
<!-- Error state -->
<div v-if="error" class="mb-6 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
<div v-if="error" class="mb-6 bg-red-100 dark:bg-red-900/20 border border-red-400 dark:border-red-700 text-red-700 dark:text-red-400 px-4 py-3 rounded">
{{ error.message || 'Une erreur est survenue lors de la suppression.' }}
</div>
@@ -40,19 +40,19 @@
<div class="mb-6">
<div class="flex items-center mb-4">
<ExclamationTriangleIcon class="h-6 w-6 text-red-500 mr-3" />
<span class="text-sm font-medium text-gray-900">Action irréversible</span>
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">Action irréversible</span>
</div>
<p class="text-sm text-gray-600 mb-4">
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
Êtes-vous sûr de vouloir supprimer le manga <strong>"{{ manga?.title }}"</strong> ?
</p>
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-4">
<div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-700 rounded-md p-4">
<div class="flex">
<ExclamationTriangleIcon class="h-5 w-5 text-yellow-400" />
<div class="ml-3">
<h3 class="text-sm font-medium text-yellow-800">
<h3 class="text-sm font-medium text-yellow-800 dark:text-yellow-300">
Attention
</h3>
<div class="mt-2 text-sm text-yellow-700">
<div class="mt-2 text-sm text-yellow-700 dark:text-yellow-400">
<p>Cette action supprimera définitivement :</p>
<ul class="list-disc list-inside mt-1 space-y-1">
<li>Le manga et toutes ses métadonnées</li>
@@ -69,7 +69,7 @@
<div class="mt-6 flex justify-end space-x-3">
<button
type="button"
class="inline-flex justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
class="inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 shadow-sm hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
@click="closeModal"
:disabled="isLoading"
>

View File

@@ -10,7 +10,7 @@
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<div class="fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-75 dark:bg-opacity-80 transition-opacity" />
</TransitionChild>
<div class="fixed inset-0 z-10 overflow-y-auto">
@@ -24,15 +24,15 @@
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white px-6 pb-6 pt-6 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-4xl">
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 px-6 pb-6 pt-6 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-4xl">
<div class="mb-6">
<DialogTitle as="h3" class="text-lg font-semibold leading-6 text-gray-900">
<DialogTitle as="h3" class="text-lg font-semibold leading-6 text-gray-900 dark:text-gray-100">
Edit Manga
</DialogTitle>
</div>
<!-- Error state -->
<div v-if="error" class="mb-6 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
<div v-if="error" class="mb-6 bg-red-100 dark:bg-red-900/20 border border-red-400 dark:border-red-700 text-red-700 dark:text-red-400 px-4 py-3 rounded">
{{ error.message || 'Une erreur est survenue lors de la sauvegarde.' }}
</div>
@@ -41,49 +41,49 @@
<!-- Titre et Slug -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Titre</label>
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Titre</label>
<input
id="title"
v-model="formData.title"
type="text"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="Titre du manga"
/>
</div>
<div>
<label for="slug" class="block text-sm font-medium text-gray-700 mb-2">Slug</label>
<label for="slug" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Slug</label>
<input
id="slug"
:value="manga?.slug || ''"
type="text"
disabled
class="block w-full rounded-md border-gray-300 bg-gray-50 shadow-sm sm:text-sm text-gray-500"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-600 shadow-sm sm:text-sm text-gray-500 dark:text-gray-400"
/>
</div>
</div>
<!-- Année de publication -->
<div>
<label for="publicationYear" class="block text-sm font-medium text-gray-700 mb-2">Année de publication</label>
<label for="publicationYear" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Année de publication</label>
<input
id="publicationYear"
v-model.number="formData.publicationYear"
type="number"
min="1900"
:max="new Date().getFullYear()"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="2023"
/>
</div>
<!-- Description -->
<div>
<label for="description" class="block text-sm font-medium text-gray-700 mb-2">Description</label>
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Description</label>
<textarea
id="description"
v-model="formData.description"
rows="4"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="Description du manga"
/>
</div>
@@ -91,22 +91,22 @@
<!-- Auteur et Statut -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="author" class="block text-sm font-medium text-gray-700 mb-2">Auteur</label>
<label for="author" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Auteur</label>
<input
id="author"
v-model="formData.author"
type="text"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="Auteur du manga"
/>
</div>
<div>
<label for="status" class="block text-sm font-medium text-gray-700 mb-2">Statut</label>
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Statut</label>
<input
id="status"
v-model="formData.status"
type="text"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="ongoing"
/>
</div>
@@ -114,7 +114,7 @@
<!-- Note -->
<div>
<label for="rating" class="block text-sm font-medium text-gray-700 mb-2">Note</label>
<label for="rating" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Note</label>
<input
id="rating"
v-model.number="formData.rating"
@@ -122,20 +122,20 @@
min="0"
max="10"
step="0.001"
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="9.541"
/>
</div>
<!-- Slugs alternatifs -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Slugs alternatifs</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Slugs alternatifs</label>
<div class="space-y-2">
<div v-if="formData.alternativeSlugs.length > 0" class="flex flex-wrap gap-2">
<span
v-for="(slug, index) in formData.alternativeSlugs"
:key="index"
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800"
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300"
>
{{ slug }}
<button
@@ -158,7 +158,7 @@
<input
v-model="newAlternativeSlug"
type="text"
class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="flex-1 rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="Nouveau slug alternatif"
@keyup.enter="addAlternativeSlug"
/>
@@ -175,19 +175,19 @@
<!-- Genres -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Genres</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Genres</label>
<div class="space-y-3">
<div v-if="formData.genres.length > 0" class="grid grid-cols-2 md:grid-cols-4 gap-2">
<span
v-for="(genre, index) in formData.genres"
:key="index"
class="inline-flex items-center justify-between px-3 py-1 rounded-md text-sm font-medium bg-gray-100 text-gray-800"
class="inline-flex items-center justify-between px-3 py-1 rounded-md text-sm font-medium bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200"
>
{{ genre }}
<button
type="button"
@click="removeGenre(index)"
class="ml-2 inline-flex items-center justify-center w-4 h-4 text-gray-400 hover:text-gray-600"
class="ml-2 inline-flex items-center justify-center w-4 h-4 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300"
>
<XMarkIcon class="w-3 h-3" />
</button>
@@ -204,7 +204,7 @@
<input
v-model="newGenre"
type="text"
class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
class="flex-1 rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
placeholder="Nouveau genre"
@keyup.enter="addGenre"
/>
@@ -224,7 +224,7 @@
<div class="mt-8 flex justify-end space-x-3">
<button
type="button"
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-600"
@click="closeModal"
:disabled="isSaving"
>

View File

@@ -10,7 +10,7 @@
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<div class="fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-75 dark:bg-opacity-80 transition-opacity" />
</TransitionChild>
<div class="fixed inset-0 z-10 overflow-y-auto">
@@ -24,17 +24,17 @@
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
<DialogPanel class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-blue-100">
<Cog6ToothIcon class="h-6 w-6 text-blue-600" aria-hidden="true" />
</div>
<div class="mt-3 text-center sm:mt-5">
<DialogTitle as="h3" class="text-base font-semibold leading-6 text-gray-900">
<DialogTitle as="h3" class="text-base font-semibold leading-6 text-gray-900 dark:text-gray-100">
Sources préférées
</DialogTitle>
<div class="mt-2">
<p class="text-sm text-gray-500">
<p class="text-sm text-gray-500 dark:text-gray-400">
Configurez l'ordre de priorité des sources pour ce manga. Glissez-déposez les sources pour les réorganiser.
</p>
</div>
@@ -47,13 +47,13 @@
</div>
<!-- Error state -->
<div v-else-if="error" class="mt-5 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
<div v-else-if="error" class="mt-5 bg-red-100 dark:bg-red-900/20 border border-red-400 dark:border-red-700 text-red-700 dark:text-red-400 px-4 py-3 rounded">
{{ error.message || 'Une erreur est survenue lors du chargement des sources.' }}
</div>
<!-- Sources list -->
<div v-else class="mt-5">
<div v-if="localSources.length === 0" class="text-center py-8 text-gray-500">
<div v-if="localSources.length === 0" class="text-center py-8 text-gray-500 dark:text-gray-400">
Aucune source disponible
</div>
<div v-else class="space-y-3">
@@ -63,10 +63,10 @@
:class="[
'group relative flex items-center p-4 rounded-lg border-2 transition-all duration-200 cursor-grab active:cursor-grabbing select-none',
{
'bg-gradient-to-r from-blue-50 to-indigo-50 border-blue-300 shadow-md': index === 0,
'bg-gradient-to-r from-green-50 to-emerald-50 border-green-300': index === 1,
'bg-gradient-to-r from-yellow-50 to-amber-50 border-yellow-300': index === 2,
'bg-gray-50 border-gray-200': index > 2,
'bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 border-blue-300 dark:border-blue-700 shadow-md': index === 0,
'bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 border-green-300 dark:border-green-700': index === 1,
'bg-gradient-to-r from-yellow-50 to-amber-50 dark:from-yellow-900/20 dark:to-amber-900/20 border-yellow-300 dark:border-yellow-700': index === 2,
'bg-gray-50 dark:bg-gray-700/50 border-gray-200 dark:border-gray-600': index > 2,
'scale-105 shadow-lg border-blue-400': draggedIndex === index,
'opacity-50': dragOverIndex === index && draggedIndex !== index,
'scale-95 active:scale-95': isPressed === index
@@ -102,10 +102,10 @@
<div :class="[
'flex items-center space-x-1 px-3 py-1 rounded-full text-xs font-semibold',
{
'bg-blue-100 text-blue-800': index === 0,
'bg-green-100 text-green-800': index === 1,
'bg-yellow-100 text-yellow-800': index === 2,
'bg-gray-100 text-gray-600': index > 2
'bg-blue-100 dark:bg-blue-900/40 text-blue-800 dark:text-blue-300': index === 0,
'bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300': index === 1,
'bg-yellow-100 dark:bg-yellow-900/40 text-yellow-800 dark:text-yellow-300': index === 2,
'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300': index > 2
}
]">
<span v-if="index === 0">🥇 Priorité haute</span>
@@ -117,14 +117,14 @@
<!-- Informations de la source -->
<div class="flex-1 min-w-0">
<div class="font-semibold text-gray-900 truncate">{{ source.name }}</div>
<div class="text-sm text-gray-600 truncate">
<div class="font-semibold text-gray-900 dark:text-gray-100 truncate">{{ source.name }}</div>
<div class="text-sm text-gray-600 dark:text-gray-400 truncate">
<a :href="source.baseUrl" target="_blank" class="hover:text-blue-600 hover:underline">{{ source.baseUrl }}</a>
</div>
</div>
<!-- Indicateur de drag -->
<div class="ml-4 text-gray-400 group-hover:text-gray-600 transition-colors duration-200">
<div class="ml-4 text-gray-400 dark:text-gray-500 group-hover:text-gray-600 dark:group-hover:text-gray-300 transition-colors duration-200">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9h8M8 15h8" />
</svg>
@@ -148,7 +148,7 @@
</button>
<button
type="button"
class="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:col-start-1 sm:mt-0"
class="mt-3 inline-flex w-full justify-center rounded-md bg-white dark:bg-gray-700 px-3 py-2 text-sm font-semibold text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 sm:col-start-1 sm:mt-0"
@click="closeModal"
:disabled="isSaving"
>

View File

@@ -1,13 +1,13 @@
<template>
<div class="bg-white rounded-sm shadow mb-2">
<div class="bg-white dark:bg-gray-800 rounded-sm shadow mb-2">
<!-- En-tête du volume -->
<div class="relative bg-white p-3 sm:p-4 rounded-t-sm">
<div class="relative bg-white dark:bg-gray-800 p-3 sm:p-4 rounded-t-sm">
<!-- Layout mobile/desktop -->
<div class="flex items-center justify-between">
<!-- Partie gauche -->
<div class="flex items-center space-x-1 sm:space-x-4 flex-1 min-w-0">
<BookmarkIcon class="h-6 w-6 sm:h-8 sm:w-8 text-gray-500 flex-shrink-0" />
<h2 class="text-lg sm:text-xl font-semibold w-20 sm:w-28 flex-shrink-0">Vol {{ String(volume.number).padStart(2, '0') }}</h2>
<BookmarkIcon class="h-6 w-6 sm:h-8 sm:w-8 text-gray-500 dark:text-gray-400 flex-shrink-0" />
<h2 class="text-lg sm:text-xl font-semibold w-20 sm:w-28 flex-shrink-0 dark:text-gray-100">Vol {{ String(volume.number).padStart(2, '0') }}</h2>
<div class="flex items-center">
<span
:class="[
@@ -65,7 +65,7 @@
<MangaChapterList v-show="isOpen" :chapters="volume.chapters" :manga-slug="mangaSlug" :manga-id="mangaId" />
<!-- Chevron de fermeture -->
<div v-show="isOpen" class="flex justify-center p-2 bg-white rounded-b-sm">
<div v-show="isOpen" class="flex justify-center p-2 bg-white dark:bg-gray-800 rounded-b-sm">
<button @click="toggleVolume" class="w-8 h-8 flex items-center justify-center">
<ChevronUpIcon
class="h-5 w-5 sm:h-6 sm:w-6 bg-gray-400 rounded-full p-1 text-white hover:bg-green-500 cursor-pointer"