From b4f0811bca186204c1f9d1cb632a46df89fe0a05 Mon Sep 17 00:00:00 2001 From: jerem Date: Sat, 29 Jun 2024 18:13:43 +0200 Subject: [PATCH] Added: - toolbar refactor --- assets/controllers/toolbar_controller.js | 70 ++++++--- src/Controller/ImportController.php | 14 +- src/Controller/MangaController.php | 13 +- .../Toolbar/Definition/ChapterListToolbar.php | 21 +++ .../Toolbar/Definition/MangaListToolbar.php | 37 +++++ src/Manager/Toolbar/Definition/Toolbar.php | 31 ++++ .../Element/AbstractToolbarElement.php | 37 +++++ src/Manager/Toolbar/Element/ToolbarButton.php | 14 ++ .../Toolbar/Element/ToolbarDivider.php | 15 ++ .../Toolbar/Element/ToolbarDropdown.php | 24 +++ .../Toolbar/Element/ToolbarElement.php | 12 ++ .../Toolbar/Factory/ToolbarFactory.php | 19 +++ src/Manager/ToolbarManager.php | 11 +- src/Repository/MangaRepository.php | 21 +-- src/Service/MangadexProvider.php | 1 + templates/activity/index.html.twig | 45 +----- templates/components/Toolbar.html.twig | 39 ++++- templates/manga/index.html.twig | 142 +++++++++++------- templates/manga/show_chapters.html.twig | 57 ++----- templates/menu/menu.html.twig | 2 +- 20 files changed, 432 insertions(+), 193 deletions(-) create mode 100644 src/Manager/Toolbar/Definition/ChapterListToolbar.php create mode 100644 src/Manager/Toolbar/Definition/MangaListToolbar.php create mode 100644 src/Manager/Toolbar/Definition/Toolbar.php create mode 100644 src/Manager/Toolbar/Element/AbstractToolbarElement.php create mode 100644 src/Manager/Toolbar/Element/ToolbarButton.php create mode 100644 src/Manager/Toolbar/Element/ToolbarDivider.php create mode 100644 src/Manager/Toolbar/Element/ToolbarDropdown.php create mode 100644 src/Manager/Toolbar/Element/ToolbarElement.php create mode 100644 src/Manager/Toolbar/Factory/ToolbarFactory.php diff --git a/assets/controllers/toolbar_controller.js b/assets/controllers/toolbar_controller.js index e4eeadd..00f5526 100644 --- a/assets/controllers/toolbar_controller.js +++ b/assets/controllers/toolbar_controller.js @@ -5,55 +5,79 @@ export default class extends Controller { static targets = ["dropdown"] static values = { currentSort: String, - currentOrder: String + currentOrder: String, + currentStatus: String } - refresh() { - console.log("Refreshing...") + refreshMetadata() { + console.log("Refreshing..."); } - syncRss() { - console.log("Syncing RSS...") - } - - search() { - console.log("Searching...") + searchLastChapter() { + console.log("Searching last chapter..."); } import() { - console.log("Importing...") + console.log("Importing..."); } editMangas() { - console.log("Editing mangas...") + console.log("Editing mangas..."); + } + + editManga() { + console.log("Editing manga..."); + } + + deleteMangas() { + console.log("Deleting mangas..."); + } + + deleteManga() { + console.log("Deleting manga..."); } showOptions() { - console.log("Showing options...") + console.log("Showing options..."); } - changeView() { - console.log("Changing view...") + changeView(event) { + event.preventDefault(); + const viewOption = event.currentTarget.dataset.view; + + const url = new URL(window.location); + url.searchParams.set('view', viewOption); + + window.location = url.toString(); } sort(event) { event.preventDefault() - const sortOption = event.currentTarget.dataset.sortOption - let order = 'asc' + const sortOption = event.currentTarget.dataset.sort; + let order = 'asc'; if (sortOption === this.currentSortValue && this.currentOrderValue === 'asc') { - order = 'desc' + order = 'desc'; } - const url = new URL(window.location) - url.searchParams.set('sort', sortOption) - url.searchParams.set('order', order) + const url = new URL(window.location); + url.searchParams.set('sort', sortOption); + url.searchParams.set('order', order); - window.location = url.toString() + window.location = url.toString(); } - filter() { - console.log("Filtering...") + filter(event) { + event.preventDefault(); + const filterOption = event.currentTarget.dataset.filter; + + const url = new URL(window.location); + url.searchParams.set('status', filterOption); + + // Réinitialiser la page à 1 si on utilise la pagination + // url.searchParams.set('page', '1'); + + window.location = url.toString(); } } diff --git a/src/Controller/ImportController.php b/src/Controller/ImportController.php index 6996d4d..55219df 100644 --- a/src/Controller/ImportController.php +++ b/src/Controller/ImportController.php @@ -33,7 +33,7 @@ class ImportController extends AbstractController } - #[Route('/import', name: 'app_import')] + #[Route('/manga/import', name: 'app_manga_import')] public function index(Request $request, SessionInterface $session): Response { if ($request->isMethod('post')) { @@ -73,7 +73,7 @@ class ImportController extends AbstractController $filePath = $session->get('import_file_path'); $originalFileName = $session->get('import_original_file_name'); if (!$filePath || !$originalFileName) { - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } $metadata = $this->cbzService->extractMetadata($filePath, $originalFileName); @@ -82,7 +82,7 @@ class ImportController extends AbstractController 'type' => 'error', 'message' => 'Impossible de détecter le titre du manga.' ]); - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } $mangas = $this->mangaRepository->findBySlug($metadata['title']); @@ -130,7 +130,7 @@ class ImportController extends AbstractController public function confirm(Request $request, SessionInterface $session): Response { if (!$request->isMethod('POST')) { - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } $action = $request->request->get('action'); @@ -145,7 +145,7 @@ class ImportController extends AbstractController 'type' => 'error', 'message' => 'Manga non trouvé.' ]); - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } $filePath = $session->get('import_file_path'); @@ -154,7 +154,7 @@ class ImportController extends AbstractController 'type' => 'error', 'message' => 'Fichier d\'import non trouvé.' ]); - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } $originalFileName = $session->get('import_original_file_name'); @@ -192,6 +192,6 @@ class ImportController extends AbstractController ]); } - return $this->redirectToRoute('app_import'); + return $this->redirectToRoute('app_manga_import'); } } diff --git a/src/Controller/MangaController.php b/src/Controller/MangaController.php index 0629ffc..5e29666 100644 --- a/src/Controller/MangaController.php +++ b/src/Controller/MangaController.php @@ -4,6 +4,7 @@ namespace App\Controller; use App\Entity\Chapter; use App\Entity\Manga; +use App\Manager\Toolbar\Factory\ToolbarFactory; use App\Manager\ToolbarManager; use App\Message\DownloadChapter; use App\Repository\ChapterRepository; @@ -36,7 +37,7 @@ class MangaController extends AbstractController private readonly MangaUpdatesMetadataProvider $mangaUpdatesDbProvider, private readonly MessageBusInterface $bus, private readonly CbzService $cbzService, - private readonly ToolbarManager $toolbarManager + private readonly ToolbarFactory $toolbarFactory ) { } @@ -46,12 +47,16 @@ class MangaController extends AbstractController { $sort = $request->query->get('sort', 'title'); $order = $request->query->get('order', 'asc'); + $status = $request->query->get('status', 'all'); + $view = $request->query->get('view', 'poster'); - $mangas = $this->mangaRepository->findAllSorted($sort, $order); + $mangas = $this->mangaRepository->findAllSortedAndFiltered($sort, $order, $status); return $this->render('manga/index.html.twig', [ 'mangas' => $mangas, - 'toolbarItems' => $this->toolbarManager->getToolbarItems(), + 'toolbar' => $this->toolbarFactory->createToolbar('manga_list')->getGroups(), + 'currentStatus' => $status, + 'currentView' => $view, ]); } @@ -94,7 +99,7 @@ class MangaController extends AbstractController return $this->render('manga/show_chapters.html.twig', [ 'chapters_by_volume' => $chaptersByVolume, 'manga' => $manga, - 'toolbarItems' => $this->toolbarManager->getToolbarItems(), + 'toolbar' => $this->toolbarFactory->createToolbar('chapter_list')->getGroups(), ]); } diff --git a/src/Manager/Toolbar/Definition/ChapterListToolbar.php b/src/Manager/Toolbar/Definition/ChapterListToolbar.php new file mode 100644 index 0000000..a075e7d --- /dev/null +++ b/src/Manager/Toolbar/Definition/ChapterListToolbar.php @@ -0,0 +1,21 @@ +addToLeftGroup(new ToolbarButton('keyboard', 'Rename chapters', 'renameChapters')) + ->addToLeftGroup(new ToolbarButton('file-zipper', 'Manage cbz', 'manageCbz')) + ->addToLeftGroup(new ToolbarButton('history', 'History', 'history')) + ->addToLeftGroup(new ToolbarDivider()) + ->addToLeftGroup(new ToolbarButton('bookmark', 'Monitoring', 'monitoring')) + ->addToLeftGroup(new ToolbarButton('wrench', 'Edit', 'edit')) + ->addToLeftGroup(new ToolbarButton('trash-can', 'Delete', 'delete')) + ->addToRightGroup(new ToolbarButton('chevron-down', 'Expand all', 'expandAll')); + } +} diff --git a/src/Manager/Toolbar/Definition/MangaListToolbar.php b/src/Manager/Toolbar/Definition/MangaListToolbar.php new file mode 100644 index 0000000..63ebf16 --- /dev/null +++ b/src/Manager/Toolbar/Definition/MangaListToolbar.php @@ -0,0 +1,37 @@ +addToLeftGroup(new ToolbarButton('arrows-rotate', 'Refresh metadata', 'refreshMetadata')) + ->addToLeftGroup(new ToolbarButton('search', 'Search last chapter', 'searchLastChapter')) + ->addToLeftGroup(new ToolbarDivider()) + ->addToLeftGroup(new ToolbarButton('plus', 'Add Manga', 'addManga')) + + ->addToRightGroup(new ToolbarButton('th-large', 'Options', 'options')) + ->addToRightGroup(new ToolbarDivider()) + ->addToRightGroup(new ToolbarDropdown('eye', 'View', 'changeView', [ + ['text' => 'Poster View', 'action' => 'changeView', 'data' => ['view' => 'poster']], + ['text' => 'Table View', 'action' => 'changeView', 'data' => ['view' => 'table']], + ['text' => 'Resume View', 'action' => 'changeView', 'data' => ['view' => 'resume']] + ])) + ->addToRightGroup(new ToolbarDropdown('sort', 'Sort', 'sort', [ + ['text' => 'Par titre', 'action' => 'sort', 'data' => ['sort' => 'title']], + ['text' => 'Par année de publication', 'action' => 'sort', 'data' => ['sort' => 'publicationYear']], + ['text' => 'Par date d\'ajout', 'action' => 'sort', 'data' => ['sort' => 'createdAt']] + ])) + ->addToRightGroup(new ToolbarDropdown('filter', 'Filter', 'filter', [ + ['text' => 'Tous les mangas', 'action' => 'filter', 'data' => ['filter' => 'all']], + ['text' => 'Mangas en cours', 'action' => 'filter', 'data' => ['filter' => 'ongoing']], + ['text' => 'Mangas terminés', 'action' => 'filter', 'data' => ['filter' => 'completed']] + ])) + ; + } +} diff --git a/src/Manager/Toolbar/Definition/Toolbar.php b/src/Manager/Toolbar/Definition/Toolbar.php new file mode 100644 index 0000000..4bf64bf --- /dev/null +++ b/src/Manager/Toolbar/Definition/Toolbar.php @@ -0,0 +1,31 @@ +leftGroup[] = $element; + return $this; + } + + public function addToRightGroup(ToolbarElement $element): self + { + $this->rightGroup[] = $element; + return $this; + } + + public function getGroups(): array + { + return [ + 'leftGroup' => $this->leftGroup, + 'rightGroup' => $this->rightGroup, + ]; + } +} diff --git a/src/Manager/Toolbar/Element/AbstractToolbarElement.php b/src/Manager/Toolbar/Element/AbstractToolbarElement.php new file mode 100644 index 0000000..f47de3d --- /dev/null +++ b/src/Manager/Toolbar/Element/AbstractToolbarElement.php @@ -0,0 +1,37 @@ +icon = $icon; + $this->text = $text; + $this->action = $action; + } + + public function getIcon(): string + { + return $this->icon; + } + + public function getText(): string|array + { + return $this->text; + } + + public function getAction(): string + { + return $this->action; + } + + public function getAdditionalProperties(): array + { + return []; + } +} diff --git a/src/Manager/Toolbar/Element/ToolbarButton.php b/src/Manager/Toolbar/Element/ToolbarButton.php new file mode 100644 index 0000000..ac7c40b --- /dev/null +++ b/src/Manager/Toolbar/Element/ToolbarButton.php @@ -0,0 +1,14 @@ +items = $items; + } + + public function getType(): string + { + return 'dropdown'; + } + + public function getAdditionalProperties(): array + { + return ['items' => $this->items]; + } +} diff --git a/src/Manager/Toolbar/Element/ToolbarElement.php b/src/Manager/Toolbar/Element/ToolbarElement.php new file mode 100644 index 0000000..db3bcd4 --- /dev/null +++ b/src/Manager/Toolbar/Element/ToolbarElement.php @@ -0,0 +1,12 @@ + new MangaListToolbar(), + 'chapter_list' => new ChapterListToolbar(), + default => throw new \InvalidArgumentException("Unknown toolbar type: $type"), + }; + } +} diff --git a/src/Manager/ToolbarManager.php b/src/Manager/ToolbarManager.php index 0693638..4c2ff30 100644 --- a/src/Manager/ToolbarManager.php +++ b/src/Manager/ToolbarManager.php @@ -25,17 +25,18 @@ class ToolbarManager private function getFilterItems(): array { return [ - ['text' => 'Tous les genres', 'action' => 'filter', 'data' => ['filter-option' => 'allGenres']], - ['text' => 'Mangas terminés', 'action' => 'filter', 'data' => ['filter-option' => 'completed']], - ['text' => 'Mangas en cours', 'action' => 'filter', 'data' => ['filter-option' => 'ongoing']] + ['text' => 'Tous les mangas', 'action' => 'filter', 'data' => ['filter-option' => 'all']], + ['text' => 'Mangas en cours', 'action' => 'filter', 'data' => ['filter-option' => 'ongoing']], + ['text' => 'Mangas terminés', 'action' => 'filter', 'data' => ['filter-option' => 'completed']] ]; } private function getViewOptions(): array { return [ - ['text' => 'Vue grille', 'action' => 'changeView', 'data' => ['view-option' => 'grid']], - ['text' => 'Vue liste', 'action' => 'changeView', 'data' => ['view-option' => 'list']] + ['text' => 'Vue poster', 'action' => 'changeView', 'data' => ['view-option' => 'poster']], + ['text' => 'Vue résumé', 'action' => 'changeView', 'data' => ['view-option' => 'resume']], + ['text' => 'Vue table', 'action' => 'changeView', 'data' => ['view-option' => 'table']] ]; } } diff --git a/src/Repository/MangaRepository.php b/src/Repository/MangaRepository.php index 29fce6b..b4930a2 100644 --- a/src/Repository/MangaRepository.php +++ b/src/Repository/MangaRepository.php @@ -103,23 +103,14 @@ class MangaRepository extends ServiceEntityRepository return $query->getQuery()->getOneOrNullResult(); } - public function findAllSorted(string $sort = 'title', string $order = 'asc'): array + public function findAllSortedAndFiltered($sort = 'title', $order = 'asc', $status = 'all') { - $qb = $this->createQueryBuilder('m'); + $qb = $this->createQueryBuilder('m') + ->orderBy('m.' . $sort, $order); - switch ($sort) { - case 'title': - $qb->orderBy('m.title', $order); - break; - case 'publicationYear': - $qb->orderBy('m.publicationYear', $order); - break; - case 'createdAt': - $qb->orderBy('m.createdAt', $order); - break; - // Ajoutez d'autres cas pour les différentes options de tri - default: - $qb->orderBy('m.title', 'asc'); + if ($status !== 'all') { + $qb->andWhere('m.status = :status') + ->setParameter('status', $status); } return $qb->getQuery()->getResult(); diff --git a/src/Service/MangadexProvider.php b/src/Service/MangadexProvider.php index 3fd5896..7994b27 100644 --- a/src/Service/MangadexProvider.php +++ b/src/Service/MangadexProvider.php @@ -42,6 +42,7 @@ readonly class MangadexProvider implements MetadataProviderInterface ->setSlug($this->slugger->slug($result['attributes']['title']['en'])->lower()) ->setDescription($result['attributes']['description']['fr'] ?? $result['attributes']['description']['en'] ?? '') ->setPublicationYear($result['attributes']['year']) + ->setStatus($result['attributes']['status']) ; $tags = []; foreach($result['attributes']['tags'] as $tag){ diff --git a/templates/activity/index.html.twig b/templates/activity/index.html.twig index af2dd64..caf457e 100644 --- a/templates/activity/index.html.twig +++ b/templates/activity/index.html.twig @@ -1,41 +1,8 @@ {% extends 'base.html.twig' %} {% block toolbar %} - {% set left_group %} - - - - - - - - - {% endset %} - - {% set right_group %} - - - - - - {% endset %} - - + {% if toolbar is defined %} + + {% endif %} {% endblock %} {% block body %}
@@ -80,8 +47,8 @@
-{#
#} -{# Total des enregistrements: {{ status|length }}#} -{#
#} + {#
#} + {# Total des enregistrements: {{ status|length }} #} + {#
#} {% endblock %} diff --git a/templates/components/Toolbar.html.twig b/templates/components/Toolbar.html.twig index 05644c8..3955645 100644 --- a/templates/components/Toolbar.html.twig +++ b/templates/components/Toolbar.html.twig @@ -2,10 +2,45 @@
- {{ left_group|raw }} + {% for element in toolbar.leftGroup %} + {% if element.type == 'button' %} + + {% elseif element.type == 'divider' %} + + {% elseif element.type == 'dropdown' %} + + {% endif %} + {% endfor %}
- {{ right_group|raw }} + {% for element in toolbar.rightGroup %} + {% if element.type == 'button' %} + + {% elseif element.type == 'divider' %} + + {% elseif element.type == 'dropdown' %} + + {% endif %} + {% endfor %}
+ diff --git a/templates/manga/index.html.twig b/templates/manga/index.html.twig index 1fa75a2..8647db9 100644 --- a/templates/manga/index.html.twig +++ b/templates/manga/index.html.twig @@ -1,62 +1,94 @@ {% extends 'base.html.twig' %} {% block toolbar %} - {% set left_group %} - - - - - - - - - {% endset %} - - {% set right_group %} - - - - - - {% endset %} - - + {% if toolbar %} + + {% endif %} {% endblock %} {% block body %} -
- {% for manga in mangas %} -
- - {{ manga.title }} - -
-
-

{{ manga.title }}

-

{{ manga.publicationYear }}

+ {% if currentView == 'poster' %} + {# Vue poster actuelle #} +
+ {% for manga in mangas %} +
+ + {{ manga.title }} + +
+
+

{{ manga.title }}

+

{{ manga.publicationYear }}

+
+

Added: {{ manga.createdAt|date('M d, Y') }}

-

Added: {{ manga.createdAt|date('M d, Y') }}

-
- {% else %} -

Aucun manga trouvé.

- {% endfor %} -
+ {% else %} +

Aucun manga trouvé.

+ {% endfor %} +
+ {% elseif currentView == 'resume' %} + {# Vue résumé #} +
+ {% for manga in mangas %} +
+ {{ manga.title }} +
+
+

{{ manga.title }}

+

{{ manga.publicationYear }}

+

{{ manga.description|truncate(200) }}

+
+

Added: {{ manga.createdAt|date('M d, Y') }}

+
+
+ {% else %} +

Aucun manga trouvé.

+ {% endfor %} +
+ {% elseif currentView == 'table' %} +
+ + + + + {# #} + + + + + {% for manga in mangas %} + + + {# #} + + + {% else %} + + + + {% endfor %} + +
Manga TitleVolumesChapters
+
+ {{ manga.title }} +
+
#} + {# {{ manga.volumes|length }} #} + {# + {% set total_chapters = manga.chapters|length %} + {% set available_chapters = manga.chapters|filter(chapter => chapter.cbzPath is not null)|length %} +
+
+
+
+ {{ available_chapters }} / {{ total_chapters }} +
+
Aucun manga trouvé.
+
+ {% endif %} {% endblock %} diff --git a/templates/manga/show_chapters.html.twig b/templates/manga/show_chapters.html.twig index 2bf8b98..ec977e5 100644 --- a/templates/manga/show_chapters.html.twig +++ b/templates/manga/show_chapters.html.twig @@ -1,41 +1,8 @@ {% extends 'base.html.twig' %} {% block toolbar %} - {% set left_group %} - - - - - - - - - {% endset %} - - {% set right_group %} - - - - - - {% endset %} - - + {% if toolbar is defined %} + + {% endif %} {% endblock %} {% block body %}
@@ -100,18 +67,21 @@

Volume {{ '%02d'|format(volume) }}

- + {{ available_chapters|length }} / {{ total_chapters }}
{{ chapters|length }} Chapters - +
-
+
@@ -134,7 +104,8 @@ @@ -169,7 +140,8 @@ data-url="{{ path('add_chapter', {id: chapter.id}) }}" > - + {% else %} @@ -179,7 +151,8 @@ {% endif %} - + diff --git a/templates/menu/menu.html.twig b/templates/menu/menu.html.twig index 78f1c05..36e9db0 100644 --- a/templates/menu/menu.html.twig +++ b/templates/menu/menu.html.twig @@ -9,7 +9,7 @@ {% if app.request.get('_route') starts with 'app_manga' %} {% endif %}
- +