diff --git a/assets/react/app/App.jsx b/assets/react/app/App.jsx index 2fa8c6a..b2dc2e5 100644 --- a/assets/react/app/App.jsx +++ b/assets/react/app/App.jsx @@ -7,6 +7,14 @@ import { ReaderPage } from './presentation/pages/ReaderPage.jsx'; import { MangaProvider } from './presentation/context/MangaContext.jsx'; import { ReaderProvider } from './presentation/context/ReaderContext.jsx'; +// Placeholder components for new routes +const PlaceholderPage = ({ title }) => ( +
+

{title}

+

Cette fonctionnalité sera bientôt disponible.

+
+); + function App() { return ( @@ -17,6 +25,23 @@ function App() { } /> } /> } /> + + } /> + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + } /> + } /> diff --git a/assets/react/app/presentation/components/Header.jsx b/assets/react/app/presentation/components/Header.jsx index a2e280e..1e0b4c7 100644 --- a/assets/react/app/presentation/components/Header.jsx +++ b/assets/react/app/presentation/components/Header.jsx @@ -1,9 +1,10 @@ import React from 'react'; +import { Link } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faBars } from '@fortawesome/free-solid-svg-icons'; import { SearchBar } from './SearchBar/SearchBar.jsx'; -export function Header({ onMenuClick, onMangaClick, onAddMangaClick }) { +export function Header({ onMenuClick }) { return (
); diff --git a/assets/react/app/presentation/components/MangaCard.jsx b/assets/react/app/presentation/components/MangaCard.jsx index 05384c4..a3aabe1 100644 --- a/assets/react/app/presentation/components/MangaCard.jsx +++ b/assets/react/app/presentation/components/MangaCard.jsx @@ -1,12 +1,19 @@ import React from 'react'; +import { useNavigate } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faStar } from '@fortawesome/free-solid-svg-icons'; -export function MangaCard({ manga, onClick }) { +export function MangaCard({ manga }) { + const navigate = useNavigate(); + + const handleClick = () => { + navigate(`/manga/${manga.slug}`); + }; + return (
onClick?.(manga.slug)} + onClick={handleClick} >
{mangas.map((manga) => ( ))}
diff --git a/assets/react/app/presentation/components/SearchBar/SearchBar.jsx b/assets/react/app/presentation/components/SearchBar/SearchBar.jsx index d72a1f8..36ff23a 100644 --- a/assets/react/app/presentation/components/SearchBar/SearchBar.jsx +++ b/assets/react/app/presentation/components/SearchBar/SearchBar.jsx @@ -1,4 +1,5 @@ import React, { useState, useRef, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSearch, faPlus } from '@fortawesome/free-solid-svg-icons'; import { ApiMangaRepository } from '../../../infrastructure/api/apiMangaRepository.js'; @@ -7,7 +8,8 @@ import { SearchMangas } from '../../../application/useCases/searchMangas.js'; const mangaRepository = new ApiMangaRepository(); const searchMangas = new SearchMangas(mangaRepository); -export function SearchBar({ onMangaClick, onAddMangaClick }) { +export function SearchBar() { + const navigate = useNavigate(); const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [isOpen, setIsOpen] = useState(false); @@ -50,6 +52,20 @@ export function SearchBar({ onMangaClick, onAddMangaClick }) { return () => clearTimeout(timeoutId); }, [query]); + const handleMangaClick = (slug) => { + navigate(`/manga/${slug}`); + setIsOpen(false); + setQuery(''); + setHasSearched(false); + }; + + const handleAddMangaClick = () => { + navigate(`/add${query ? `?q=${encodeURIComponent(query)}` : ''}`); + setIsOpen(false); + setQuery(''); + setHasSearched(false); + }; + return (
@@ -82,12 +98,7 @@ export function SearchBar({ onMangaClick, onAddMangaClick }) { {results.map((manga) => ( + ); + } + + return ( + -
- - {item.text} -
- {hasSubItems ? ( - - ) : item.badge ? ( - - {item.badge} + {linkItem.icon && } + {linkItem.text} + + ); + }; + + return ( +
+ {item.to || item.onClick ? ( + renderLink(item, "flex items-center px-4 py-2 text-gray-300 hover:text-green-600 transition-colors duration-150") + ) : ( + - + {hasSubItems && ( + + )} + + )} + {hasSubItems && isExpanded && (
- {item.subItems.map((subItem, index) => ( - { - e.preventDefault(); - if (subItem.onClick) { - subItem.onClick(); - } else if (subItem.href !== '#') { - window.location.href = subItem.href; - } - }} - className="block py-2 text-gray-300 hover:text-green-600 transition-colors duration-150" - > - {subItem.icon && ( - - )} - {subItem.text} - - ))} + {item.subItems.map((subItem, index) => { + const link = renderLink( + subItem, + "block py-2 text-gray-300 hover:text-green-600 transition-colors duration-150" + ); + + return React.cloneElement(link, { key: `${subItem.text}-${index}` }); + })}
)}
diff --git a/assets/react/app/presentation/components/Toolbar/ToolbarButton.jsx b/assets/react/app/presentation/components/Toolbar/ToolbarButton.jsx index 6d6832c..6f1c91a 100644 --- a/assets/react/app/presentation/components/Toolbar/ToolbarButton.jsx +++ b/assets/react/app/presentation/components/Toolbar/ToolbarButton.jsx @@ -1,10 +1,23 @@ import React from 'react'; +import { useNavigate } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -export function ToolbarButton({ icon, label, onClick, active = false }) { +export function ToolbarButton({ icon, label, onClick, navigateTo, navigateBack = false, active = false }) { + const navigate = useNavigate(); + + const handleClick = () => { + if (navigateBack) { + navigate(-1, { replace: true }); + } else if (navigateTo) { + navigate(navigateTo, { replace: true }); + } else if (onClick) { + onClick(); + } + }; + return (
@@ -182,6 +192,14 @@ export function MangaDetailPage() { ))}
)} + + {!manga && ( +
+
+ Chargement des chapitres... +
+
+ )} ); } \ No newline at end of file diff --git a/assets/react/app/presentation/pages/ReaderPage.jsx b/assets/react/app/presentation/pages/ReaderPage.jsx index 41fe33b..84114d3 100644 --- a/assets/react/app/presentation/pages/ReaderPage.jsx +++ b/assets/react/app/presentation/pages/ReaderPage.jsx @@ -1,6 +1,7 @@ import React, { useEffect, useState, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useReader } from '../context/ReaderContext'; +import { Toolbar } from '../components/Toolbar/Toolbar.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowLeft, @@ -104,6 +105,25 @@ export function ReaderPage() { } }; + const toolbarConfig = { + leftSection: [ + { icon: faArrowLeft, navigateBack: true } + ], + rightSection: [ + { + icon: mode === 'classic' ? faScroll : faBookOpen, + onClick: () => setMode(mode === 'classic' ? 'scrolling' : 'classic'), + label: `Mode ${mode === 'classic' ? 'défilement' : 'page par page'}` + }, + { + icon: isFullscreen ? faCompress : faExpand, + onClick: toggleFullscreen, + label: isFullscreen ? 'Quitter le plein écran' : 'Plein écran' + }, + { icon: faList, onClick: () => {}, label: 'Chapitres' } + ] + }; + if (loading || (!currentPageData && mode === 'classic' && pages.length === 0)) { return (
@@ -135,39 +155,12 @@ export function ReaderPage() {
-
- - {context && ( -
- Manga title - - - Chapter {context.number} -
- )} -
-
- - - -
+ + {context && ( +
+ Chapitre {context.number} +
+ )}
@@ -243,4 +236,4 @@ export function ReaderPage() { )}
); -} +} \ No newline at end of file