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

@@ -1,11 +1,11 @@
<template>
<tr
class="border-b border-gray-200 hover:bg-gray-50 transition duration-150 ease-in-out"
class="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition duration-150 ease-in-out"
:class="{
'bg-yellow-50': job.status === 'pending',
'bg-blue-50': job.status === 'in_progress',
'bg-green-50': job.status === 'completed',
'bg-red-50': job.status === 'failed'
'bg-yellow-50 dark:bg-yellow-900/20': job.status === 'pending',
'bg-blue-50 dark:bg-blue-900/20': job.status === 'in_progress',
'bg-green-50 dark:bg-green-900/20': job.status === 'completed',
'bg-red-50 dark:bg-red-900/20': job.status === 'failed'
}">
<td class="py-4 px-4 text-center">
<input type="checkbox" class="form-checkbox h-5 w-5 text-green-600" />
@@ -20,37 +20,37 @@
<span
class="px-2 py-1 text-xs rounded-full"
:class="{
'bg-yellow-100 text-yellow-800': job.status === 'pending',
'bg-blue-100 text-blue-800': job.status === 'in_progress',
'bg-green-100 text-green-800': job.status === 'completed',
'bg-red-100 text-red-800': job.status === 'failed'
'bg-yellow-100 dark:bg-yellow-900/40 text-yellow-800 dark:text-yellow-300': job.status === 'pending',
'bg-blue-100 dark:bg-blue-900/40 text-blue-800 dark:text-blue-300': job.status === 'in_progress',
'bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300': job.status === 'completed',
'bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300': job.status === 'failed'
}">
{{ job.status }}
</span>
</td>
<td class="py-4 px-4">
<div v-if="job.error" class="text-sm text-red-600">
<div v-if="job.error" class="text-sm text-red-600 dark:text-red-400">
{{ job.error }}
</div>
<div v-else-if="job.context?.mangaTitle || job.context?.chapterNumber !== undefined || job.context?.sourceId"
class="text-sm text-gray-700 space-y-0.5">
class="text-sm text-gray-700 dark:text-gray-300 space-y-0.5">
<div v-if="job.context.mangaTitle" class="font-medium">
{{ job.context.mangaTitle }}
</div>
<div v-if="job.context.chapterNumber !== undefined" class="text-gray-500">
<div v-if="job.context.chapterNumber !== undefined" class="text-gray-500 dark:text-gray-400">
Chapitre {{ job.context.chapterNumber }}
</div>
<div v-if="job.context.sourceId" class="text-xs text-gray-400">
<div v-if="job.context.sourceId" class="text-xs text-gray-400 dark:text-gray-500">
Source : {{ job.context.sourceId }}
</div>
</div>
<div v-else class="text-sm text-gray-600">
<div v-else class="text-sm text-gray-600 dark:text-gray-400">
{{ formatDate(job.createdAt) }}
</div>
</td>
<td class="py-4 px-4">
<div v-if="job.status === 'in_progress'" class="mt-2">
<div class="relative bg-gray-200 rounded-full h-6 overflow-hidden">
<div class="relative bg-gray-200 dark:bg-gray-700 rounded-full h-6 overflow-hidden">
<div
class="absolute top-0 left-0 h-full bg-green-400 transition-all duration-300 ease-out"
:style="{ width: `${job.progress}%` }"></div>
@@ -59,7 +59,7 @@
</div>
</div>
</div>
<div v-else-if="job.status === 'completed'" class="relative bg-gray-200 rounded-full h-6 overflow-hidden">
<div v-else-if="job.status === 'completed'" class="relative bg-gray-200 dark:bg-gray-700 rounded-full h-6 overflow-hidden">
<div
class="absolute top-0 left-0 h-full bg-green-400 transition-all duration-300 ease-out"
style="width: 100%"></div>
@@ -67,7 +67,7 @@
100%
</div>
</div>
<div v-else-if="job.status === 'failed'" class="relative bg-gray-200 rounded-full h-6 overflow-hidden">
<div v-else-if="job.status === 'failed'" class="relative bg-gray-200 dark:bg-gray-700 rounded-full h-6 overflow-hidden">
<div
class="absolute top-0 left-0 h-full bg-red-400 transition-all duration-300 ease-out"
style="width: 100%"></div>
@@ -75,17 +75,17 @@
Erreur
</div>
</div>
<div v-else class="relative bg-gray-200 rounded-full h-6 overflow-hidden">
<div v-else class="relative bg-gray-200 dark:bg-gray-700 rounded-full h-6 overflow-hidden">
<div
class="absolute top-0 left-0 h-full bg-yellow-400 transition-all duration-300 ease-out"
style="width: 0%"></div>
<div class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-gray-600">
<div class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-gray-600 dark:text-gray-300">
En attente
</div>
</div>
<div v-if="job.maxAttempts > 1 || job.attempts > 0"
class="text-xs text-gray-400 mt-1 text-center">
class="text-xs text-gray-400 dark:text-gray-500 mt-1 text-center">
{{ job.attempts }} / {{ job.maxAttempts }} tentative{{ job.maxAttempts > 1 ? 's' : '' }}
</div>
</td>