From 16e46a7c24726a2f10b148c46bdc535923b59a67 Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 20:54:39 +0100 Subject: [PATCH 01/24] chore: Update .gitignore and README with installation instructions Added .idea/ to .gitignore. Updated README with Deno and Tauri CLI installation instructions. --- .gitignore | 3 +++ README.md | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index edcc0c2..c463bf4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ dist/ # Zed Editor .zed/ + +# intelij idea +.idea/ diff --git a/README.md b/README.md index 48d5468..7f3a7d9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,21 @@ ## Development -I assume you have installed Rust, Cargo, Tauri and Deno. +I assume you have installed Rust, Cargo. + +### Install Deno + +```bash +curl -fsSL https://deno.land/x/install/install.sh | sh +``` + +### Then install Tauri CLI + +```bash +cargo install tauri-cli --version "^2.0.0" --locked +``` + +### Run the app ```bash cargo tauri dev From cfad7b7f096213753aa426ea1a737661fc38d1f8 Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 20:58:52 +0100 Subject: [PATCH 02/24] feat: Update component imports and add global styles Refactored component imports in App.tsx for Browse, Extensions, NavBar, NavItem, More. Added Youn page import. Included global CSS reset in new global.css file. --- src-www/App.tsx | 14 +++++++++----- src-www/style/global.css | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 src-www/style/global.css diff --git a/src-www/App.tsx b/src-www/App.tsx index 6d67745..b6bca02 100644 --- a/src-www/App.tsx +++ b/src-www/App.tsx @@ -1,10 +1,14 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; -import Browse from "./pages/Browse.tsx"; -import NavBar from "./components/NavBar.tsx"; -import NavItem from "./components/NavItem.tsx"; -import Extensions from "./pages/Extensions.tsx"; -import More from "./pages/More.tsx"; +import Browse from "./pages/Browse/Browse"; +import ExtensionBrowser from "./pages/Browse/ExtensionBrowse"; +import NavBar from "./components/NavBar"; +import NavItem from "./components/NavItem"; +import Extensions from "./pages/Extensions"; +import More from "./pages/More"; +import Youn from "./pages/Youn"; + +import "./style/global.css"; const router = createBrowserRouter([ { diff --git a/src-www/style/global.css b/src-www/style/global.css new file mode 100644 index 0000000..412a3c2 --- /dev/null +++ b/src-www/style/global.css @@ -0,0 +1,6 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: "Roboto", sans-serif; +} From 36270a7ff374f96e6fc0cf0a9d56b9393b07653a Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 21:00:44 +0100 Subject: [PATCH 03/24] feat: Update Browse page with Link component - Updated Browse page to use the Link component from react-router-dom for navigation. Removed redundant code for listing extensions. --- src-www/pages/Browse.tsx | 56 ------------------------------- src-www/pages/Browse/Browse.tsx | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 56 deletions(-) delete mode 100644 src-www/pages/Browse.tsx create mode 100644 src-www/pages/Browse/Browse.tsx diff --git a/src-www/pages/Browse.tsx b/src-www/pages/Browse.tsx deleted file mode 100644 index 6c22121..0000000 --- a/src-www/pages/Browse.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useEffect, useState } from "react"; - -import { Extension } from "../types/extension.ts"; -import { getIconUrl } from "../services/extensions.service.ts"; -import { getExtensions } from "../tauri.ts"; - -export default function Browse() { - const [extensions, setExtensions] = useState([]); - - useEffect(() => { - getExtensions().then(setExtensions); - }, []); - - const listExtensions = extensions.map((extension: Extension) => { - return ( -
  • - -
    - - {extension.source.name} - -
    - {extension.source.language} -
    -
    - - Browse - -
  • - ); - }); - - return ( -
      - {listExtensions} -
    - ); -} diff --git a/src-www/pages/Browse/Browse.tsx b/src-www/pages/Browse/Browse.tsx new file mode 100644 index 0000000..e7ffd6b --- /dev/null +++ b/src-www/pages/Browse/Browse.tsx @@ -0,0 +1,58 @@ +import { invoke } from "@tauri-apps/api/core"; +import { useEffect, useState } from "react"; + +import { Extension, Source } from "../../types/extension"; +import { Link } from "react-router-dom"; + +export default function Browse() { + const [extensions, setExtensions] = useState>([]); + + useEffect(() => { + invoke>("get_extensions").then((data) => { + setExtensions(data.map(([id, source, iconPath]) => { + return new Extension(id, source, iconPath); + })); + }); + }, []); + + return ( +
      + {extensions.map((extension: Extension) => { + return ( +
    • + +
      + + {extension.name} + +
      + {extension.language} +
      +
      + + Browse + +
    • + ); + })} +
    + ); +} From b994263da095d0a3a8b51c2cbca2467dff5f93af Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 21:02:35 +0100 Subject: [PATCH 04/24] feat: Add ExtensionBrowse component and loader styles - Added a new component for browsing extensions - Implemented loading animation styles for infinite scroll loader --- src-www/App.tsx | 4 + src-www/pages/Browse/ExtensionBrowse.tsx | 149 +++++++++++++++++++++++ src-www/style/loader.css | 29 +++++ 3 files changed, 182 insertions(+) create mode 100644 src-www/pages/Browse/ExtensionBrowse.tsx create mode 100644 src-www/style/loader.css diff --git a/src-www/App.tsx b/src-www/App.tsx index b6bca02..7b7fbfd 100644 --- a/src-www/App.tsx +++ b/src-www/App.tsx @@ -15,6 +15,10 @@ const router = createBrowserRouter([ path: "/", element: , }, + { + path: "/browse/:id", + element: , + }, { path: "/extensions", element: , diff --git a/src-www/pages/Browse/ExtensionBrowse.tsx b/src-www/pages/Browse/ExtensionBrowse.tsx new file mode 100644 index 0000000..aa22137 --- /dev/null +++ b/src-www/pages/Browse/ExtensionBrowse.tsx @@ -0,0 +1,149 @@ +import { useEffect, useState } from "react"; +import { Extension } from "../../types/extension"; +import { Manga } from "../../types/manga"; +import { useLocation } from "react-router-dom"; + +import "../../style/loader.css"; + +export default function ExtensionBrowse() { + const { state } = useLocation(); + const extension = state.extension as Extension; + globalThis.addEventListener("scroll", handleScroll); + + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + const [mangas, setMangas] = useState>([]); + const [pagination, setPagination] = useState(1); + + // Récupérer l'extension + useEffect(() => { + console.log("Extension :", extension); + }, []); + + useEffect(() => { + if (!extension || !extension.getMangaList) { + return setError( + "L'extension n'est pas valide. Veuillez passer par la page d'accueil.", + ); + } + + // Récupérer la liste des mangas pour l'extension + extension.getMangaList([], pagination).then((data) => { + setMangas([...mangas, ...data[0]]); + setLoading(false); + console.log("Mangas chargés :", data); + }).catch((error) => { + console.error("Erreur lors du chargement des mangas :", error); + setError("Une erreur est survenue lors du chargement des mangas."); + }); + }, [extension, pagination]); + + function handleScroll() { + if ( + document.body.scrollHeight - 300 < + globalThis.scrollY + globalThis.innerHeight + ) { + setLoading(true); + setPagination(pagination + 1); + } + } + + // Afficher un message d'erreur si nécessaire + if (error) { + return ( +
    +

    {error}

    +
    + ); + } + + return ( +
    + {/* En-tête de l'extension */} +
    + {extension.name} +

    {extension.name}

    +
    + + {/* Grille des mangas avec image et titre */} + + + {/* infinie scroll loading */} + {loading && + // center the loader + +
    +
    + Chargement... +
    +
    +
    } +
    + ); +} diff --git a/src-www/style/loader.css b/src-www/style/loader.css new file mode 100644 index 0000000..90bf734 --- /dev/null +++ b/src-www/style/loader.css @@ -0,0 +1,29 @@ +/* HTML:
    */ +.loader { + width: 70px; + aspect-ratio: 1; + background: + radial-gradient(farthest-side, #81e4da 90%, #0000) center/16px 16px, + radial-gradient(farthest-side, #7eb7b2 90%, #0000) bottom/12px 12px; + background-repeat: no-repeat; + animation: l17 1s infinite linear; + position: relative; +} +.loader::before { + content: ""; + position: absolute; + width: 8px; + aspect-ratio: 1; + inset: auto 0 16px; + margin: auto; + background: #496a67; + border-radius: 50%; + transform-origin: 50% calc(100% + 10px); + animation: inherit; + animation-duration: 0.5s; +} +@keyframes l17 { + 100% { + transform: rotate(1turn); + } +} From f8aa4024130fc8c23c21ebcdb60bc1fda93e5886 Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:21:21 +0100 Subject: [PATCH 05/24] feat: Add global background color Added a background color to the body element in global.css file. --- src-www/public/fallback-img.jpg | Bin 0 -> 13161 bytes src-www/style/global.css | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 src-www/public/fallback-img.jpg diff --git a/src-www/public/fallback-img.jpg b/src-www/public/fallback-img.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d84a9b47a785bbbe139b1b194eb4c9317878e47c GIT binary patch literal 13161 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 J5)kKK{|!ToFERiC literal 0 HcmV?d00001 diff --git a/src-www/style/global.css b/src-www/style/global.css index 412a3c2..92db9f9 100644 --- a/src-www/style/global.css +++ b/src-www/style/global.css @@ -4,3 +4,7 @@ padding: 0; font-family: "Roboto", sans-serif; } + +body { + background-color: #f5f5f5; +} From 62bd9e923d3616fa284af96a4ae3c7b8ab250442 Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:21:32 +0100 Subject: [PATCH 06/24] feat: Update import path for App component Update import path for the App component in index.tsx. --- src-www/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-www/index.tsx b/src-www/index.tsx index e0a4c24..272085d 100644 --- a/src-www/index.tsx +++ b/src-www/index.tsx @@ -1,5 +1,5 @@ import ReactDOM from "react-dom/client"; -import App from "./App.tsx"; +import App from "./App"; ReactDOM.createRoot(document.getElementById("root")!).render(); From 7fc794288d60837a9f3864fb0f890524365f430a Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:21:42 +0100 Subject: [PATCH 07/24] feat: Update import and add new route for MangaDetails Updated import statement to use 'MangaDetails' instead of 'Youn'. Added a new route '/read/:id' with the element . --- src-www/App.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src-www/App.tsx b/src-www/App.tsx index 7b7fbfd..bd650d7 100644 --- a/src-www/App.tsx +++ b/src-www/App.tsx @@ -6,7 +6,7 @@ import NavBar from "./components/NavBar"; import NavItem from "./components/NavItem"; import Extensions from "./pages/Extensions"; import More from "./pages/More"; -import Youn from "./pages/Youn"; +import MangaDetails from "./pages/MangaDetails"; import "./style/global.css"; @@ -17,7 +17,11 @@ const router = createBrowserRouter([ }, { path: "/browse/:id", - element: , + element: , + }, + { + path: "/read/:id", + element: , }, { path: "/extensions", From e810ba0c662c0efc496e81b80bf239c944496798 Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:21:52 +0100 Subject: [PATCH 08/24] chore: Update dependencies versions Update dependency versions in deno.json for various packages. --- deno.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/deno.json b/deno.json index 5f98fea..b6486b0 100644 --- a/deno.json +++ b/deno.json @@ -20,16 +20,16 @@ "lib": ["dom", "deno.ns"] }, "imports": { - "@tauri-apps/api": "npm:@tauri-apps/api@^2.0.2", - "@tauri-apps/plugin-store": "npm:@tauri-apps/plugin-store@^2.1.0", - "@types/react": "npm:@types/react@^18.3.11", - "@types/react-dom": "npm:@types/react-dom@^18.3.1", - "@types/react-router-dom": "npm:@types/react-router-dom@^5.3.3", - "@vitejs/plugin-react": "npm:@vitejs/plugin-react@^4.3.2", - "react": "npm:react@^18.3.1", - "react-dom": "npm:react-dom@^18.3.1", - "react-router-dom": "npm:react-router-dom@^6.27.0", - "vite": "npm:vite@^5.4.9" + "@tauri-apps/api": "npm:@tauri-apps/api@2.0.2", + "@tauri-apps/plugin-store": "npm:@tauri-apps/plugin-store@2.1.0", + "@types/react": "npm:@types/react@18.3.11", + "@types/react-dom": "npm:@types/react-dom@18.3.1", + "@types/react-router-dom": "npm:@types/react-router-dom@5.3.3", + "@vitejs/plugin-react": "npm:@vitejs/plugin-react@4.3.2", + "react": "npm:react@18.3.1", + "react-dom": "npm:react-dom@18.3.1", + "react-router-dom": "npm:react-router-dom@6.27.0", + "vite": "npm:vite@5.4.9" }, "nodeModulesDir": "auto" } From 97e6391f97c5042f4802cc2f6117486cd7d4165b Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:22:05 +0100 Subject: [PATCH 09/24] feat: Add MangaImage component for displaying manga images Added a new component to display manga images with fallback image support. --- src-www/components/MangaImage.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src-www/components/MangaImage.tsx diff --git a/src-www/components/MangaImage.tsx b/src-www/components/MangaImage.tsx new file mode 100644 index 0000000..d042f87 --- /dev/null +++ b/src-www/components/MangaImage.tsx @@ -0,0 +1,20 @@ +import fallback from "../public/fallback-img.jpg"; + +function MangaImage({ src, alt, fallBackSrc = fallback }) { + return ( + {alt} (e.currentTarget.src = fallBackSrc)} + /> + ); +} + +export default MangaImage; From 32bb1188a7af7dd09a5cb6f4ef854fb70a83262d Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:22:10 +0100 Subject: [PATCH 10/24] feat: Add Source to Extension, Implement MangaImage component - Added Source import to Extension - Implemented MangaImage component in ExtensionBrowse page for manga covers. --- src-www/pages/Browse/ExtensionBrowse.tsx | 75 +++++++++++++++++------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/src-www/pages/Browse/ExtensionBrowse.tsx b/src-www/pages/Browse/ExtensionBrowse.tsx index aa22137..fbcff5c 100644 --- a/src-www/pages/Browse/ExtensionBrowse.tsx +++ b/src-www/pages/Browse/ExtensionBrowse.tsx @@ -1,15 +1,20 @@ import { useEffect, useState } from "react"; -import { Extension } from "../../types/extension"; +import { Extension, Source } from "../../types/extension"; import { Manga } from "../../types/manga"; -import { useLocation } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; import "../../style/loader.css"; +import MangaImage from "../../components/MangaImage"; +import { invoke } from "@tauri-apps/api/core"; export default function ExtensionBrowse() { - const { state } = useLocation(); - const extension = state.extension as Extension; globalThis.addEventListener("scroll", handleScroll); + const id = useParams().id; + console.log("extensionId", id); + + const [extension, setExtension] = useState(null); + const [error, setError] = useState(null); const [loading, setLoading] = useState(true); @@ -18,11 +23,17 @@ export default function ExtensionBrowse() { // Récupérer l'extension useEffect(() => { - console.log("Extension :", extension); + getExtension(id).then((extension) => { + setExtension(extension); + console.log("Extension :", extension); + }); }, []); useEffect(() => { - if (!extension || !extension.getMangaList) { + if (!extension) { + return; + } + if (!extension.getMangaList) { return setError( "L'extension n'est pas valide. Veuillez passer par la page d'accueil.", ); @@ -32,7 +43,7 @@ export default function ExtensionBrowse() { extension.getMangaList([], pagination).then((data) => { setMangas([...mangas, ...data[0]]); setLoading(false); - console.log("Mangas chargés :", data); + console.log("pagination " + pagination + " :", data); }).catch((error) => { console.error("Erreur lors du chargement des mangas :", error); setError("Une erreur est survenue lors du chargement des mangas."); @@ -44,8 +55,11 @@ export default function ExtensionBrowse() { document.body.scrollHeight - 300 < globalThis.scrollY + globalThis.innerHeight ) { + if (loading) return; + setLoading(true); setPagination(pagination + 1); + console.log("scoll active"); } } @@ -58,6 +72,25 @@ export default function ExtensionBrowse() { ); } + // if extension is not loaded yet + if (!extension) { + return ( +
    +
    + Chargement... +
    +
    +
    + ); + } + return (
    {/* En-tête de l'extension */} @@ -90,19 +123,12 @@ export default function ExtensionBrowse() { {mangas.map((manga) => (
  • {/* Image de couverture */} - - + - + {/* Titre du manga */} {/* infinie scroll loading */} - {loading && - // center the loader - + {loading && // center the loader
    ); } + +// todo : use memo to avoid re-rendering +async function getExtension(extensionId: string) { + let extensionsList = await invoke>( + "get_extensions", + ); + let extension = extensionsList.find(([id, source, iconPath]) => + id === extensionId + ); + return new Extension(extension[0], extension[1], extension[2]); +} From 7b3c531b00fe0895c69570f5409d8bda6938e14c Mon Sep 17 00:00:00 2001 From: Breval Date: Wed, 6 Nov 2024 22:22:14 +0100 Subject: [PATCH 11/24] feat: Add MangaDetails component for displaying manga details and list Implemented a new component to show manga details, including cover images and titles in a grid layout. Added functionality for infinite scrolling to load more manga entries dynamically. --- src-www/pages/MangaDetails.tsx | 145 +++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src-www/pages/MangaDetails.tsx diff --git a/src-www/pages/MangaDetails.tsx b/src-www/pages/MangaDetails.tsx new file mode 100644 index 0000000..a6fd168 --- /dev/null +++ b/src-www/pages/MangaDetails.tsx @@ -0,0 +1,145 @@ +import { useEffect, useState } from "react"; +import { Extension, Source } from "../types/extension"; +import { Manga } from "../types/manga"; +import { Link, useLocation } from "react-router-dom"; + +import "../style/loader.css"; +import MangaImage from "../components/MangaImage"; +import { invoke } from "@tauri-apps/api/core"; + +export default function MangaDetails() { + const { state } = useLocation(); + const extension = state.extension as Extension; + globalThis.addEventListener("scroll", handleScroll); + + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + const [mangas, setMangas] = useState>([]); + const [pagination, setPagination] = useState(1); + + // Récupérer l'extension + useEffect(() => { + console.log("Extension :", extension); + }, []); + + useEffect(() => { + if (!extension || !extension.getMangaList) { + return setError( + "L'extension n'est pas valide. Veuillez passer par la page d'accueil.", + ); + } + + // Récupérer la liste des mangas pour l'extension + extension.getMangaList([], pagination).then((data) => { + setMangas([...mangas, ...data[0]]); + setLoading(false); + console.log("pagination " + pagination + " :", data); + }).catch((error) => { + console.error("Erreur lors du chargement des mangas :", error); + setError("Une erreur est survenue lors du chargement des mangas."); + }); + }, [extension, pagination]); + + function handleScroll() { + if ( + document.body.scrollHeight - 300 < + globalThis.scrollY + globalThis.innerHeight + ) { + if (loading) return; + + setLoading(true); + setPagination(pagination + 1); + console.log("scoll active"); + } + } + + // Afficher un message d'erreur si nécessaire + if (error) { + return ( +
    +

    {error}

    +
    + ); + } + + return ( +
    + ); +} From 3c0e2fb136849c0f5cdaa30dd1e60f6a76f50f7a Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 02:24:56 +0100 Subject: [PATCH 12/24] feat: Update Browse component rendering logic Refactor Browse component to use new service functions for fetching extensions and icon URLs. Simplified useEffect hook for better readability and maintainability. --- deno.json | 2 +- src-www/pages/Browse/Browse.tsx | 102 ++++++++++++++++---------------- 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/deno.json b/deno.json index b6486b0..3a35829 100644 --- a/deno.json +++ b/deno.json @@ -9,7 +9,7 @@ "tasks": { "dev": "deno run -A npm:vite dev", "build": "deno run -A npm:vite build", - "check": "deno check src-www/", + "check": "deno check src-www/ --unstable-sloppy-imports" , "lint": "deno lint && deno fmt --check", "format": "deno lint --fix && deno fmt" }, diff --git a/src-www/pages/Browse/Browse.tsx b/src-www/pages/Browse/Browse.tsx index e7ffd6b..7c0b5a3 100644 --- a/src-www/pages/Browse/Browse.tsx +++ b/src-www/pages/Browse/Browse.tsx @@ -1,58 +1,56 @@ -import { invoke } from "@tauri-apps/api/core"; -import { useEffect, useState } from "react"; +import {useEffect, useState} from "react"; -import { Extension, Source } from "../../types/extension"; -import { Link } from "react-router-dom"; +import {Extension} from "../../types/extension.ts"; +import {getIconUrl} from "../../services/extensions.service.ts"; +import {getExtensions} from "../../tauri.ts"; +import {Link} from "react-router-dom"; export default function Browse() { - const [extensions, setExtensions] = useState>([]); + const [extensions, setExtensions] = useState([]); - useEffect(() => { - invoke>("get_extensions").then((data) => { - setExtensions(data.map(([id, source, iconPath]) => { - return new Extension(id, source, iconPath); - })); - }); - }, []); + useEffect(() => { + getExtensions().then(setExtensions); + }, []); - return ( -
      - {extensions.map((extension: Extension) => { - return ( -
    • - -
      - - {extension.name} - -
      - {extension.language} -
      -
      - - Browse - -
    • - ); - })} -
    - ); + + return ( +
      + {extensions.map((extension: Extension) => { + return ( +
    • + +
      + + {extension.source.name} + +
      + {extension.source.language} +
      +
      + + Browse + +
    • + ); + })} +
    + ); } From 39308f32c7fe1ab6b464625587e16078bd2ce607 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 02:34:10 +0100 Subject: [PATCH 13/24] feat: Update import paths for extensions and services Update import paths to remove file extensions and adjust folder structure for better organization. --- src-www/pages/Browse/Browse.tsx | 6 +++--- src-www/{tauri.ts => services/tauri.service.ts} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src-www/{tauri.ts => services/tauri.service.ts} (89%) diff --git a/src-www/pages/Browse/Browse.tsx b/src-www/pages/Browse/Browse.tsx index 7c0b5a3..83a655a 100644 --- a/src-www/pages/Browse/Browse.tsx +++ b/src-www/pages/Browse/Browse.tsx @@ -1,8 +1,8 @@ import {useEffect, useState} from "react"; -import {Extension} from "../../types/extension.ts"; -import {getIconUrl} from "../../services/extensions.service.ts"; -import {getExtensions} from "../../tauri.ts"; +import {Extension} from "../../types/extension"; +import {getIconUrl} from "../../services/extensions.service"; +import {getExtensions} from "../../tauri"; import {Link} from "react-router-dom"; export default function Browse() { diff --git a/src-www/tauri.ts b/src-www/services/tauri.service.ts similarity index 89% rename from src-www/tauri.ts rename to src-www/services/tauri.service.ts index f07bb67..5d1164e 100644 --- a/src-www/tauri.ts +++ b/src-www/services/tauri.service.ts @@ -1,7 +1,7 @@ import { invoke } from "@tauri-apps/api/core"; -import { Extension, Source } from "./types/extension.ts"; -import { Manifest } from "./types/manifest.ts"; +import { Extension, Source } from "../types/extension"; +import { Manifest } from "../types/manifest"; export async function getExtensions(): Promise { return (await invoke<[string, Source, string][]>("get_extensions")) From 863f0b32a54bb753bd34a453e4573b9f5c051f1b Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:42:12 +0100 Subject: [PATCH 14/24] chore: Update dependencies versions - Updated various npm package versions in deno.json and deno.lock files. --- deno.json | 2 +- deno.lock | 290 +++++++++++++++++++++--------------------------------- 2 files changed, 113 insertions(+), 179 deletions(-) diff --git a/deno.json b/deno.json index 3a35829..4b28dee 100644 --- a/deno.json +++ b/deno.json @@ -9,7 +9,7 @@ "tasks": { "dev": "deno run -A npm:vite dev", "build": "deno run -A npm:vite build", - "check": "deno check src-www/ --unstable-sloppy-imports" , + "check": "deno check src-www/ --unstable-sloppy-imports", "lint": "deno lint && deno fmt --check", "format": "deno lint --fix && deno fmt" }, diff --git a/deno.lock b/deno.lock index 1db2986..cc544a6 100644 --- a/deno.lock +++ b/deno.lock @@ -1,18 +1,17 @@ { "version": "4", "specifiers": { - "npm:@tauri-apps/api@^2.0.2": "2.0.2", - "npm:@tauri-apps/plugin-store@^2.1.0": "2.1.0", - "npm:@types/node@*": "22.5.4", - "npm:@types/react-dom@^18.3.1": "18.3.1", - "npm:@types/react-router-dom@^5.3.3": "5.3.3", - "npm:@types/react@^18.3.11": "18.3.11", - "npm:@vitejs/plugin-react@^4.3.2": "4.3.2_vite@5.4.9_@babel+core@7.25.8", - "npm:react-dom@^18.3.1": "18.3.1_react@18.3.1", - "npm:react-router-dom@^6.27.0": "6.27.0_react@18.3.1_react-dom@18.3.1__react@18.3.1", - "npm:react@^18.3.1": "18.3.1", - "npm:vite@*": "5.4.9_@types+node@22.5.4", - "npm:vite@^5.4.9": "5.4.9_@types+node@22.5.4" + "npm:@tauri-apps/api@2.0.2": "2.0.2", + "npm:@tauri-apps/plugin-store@2.1.0": "2.1.0", + "npm:@types/react-dom@18.3.1": "18.3.1", + "npm:@types/react-router-dom@5.3.3": "5.3.3", + "npm:@types/react@18.3.11": "18.3.11", + "npm:@vitejs/plugin-react@4.3.2": "4.3.2_vite@5.4.9_@babel+core@7.26.0", + "npm:react-dom@18.3.1": "18.3.1_react@18.3.1", + "npm:react-router-dom@6.27.0": "6.27.0_react@18.3.1_react-dom@18.3.1__react@18.3.1", + "npm:react@18.3.1": "18.3.1", + "npm:vite@*": "5.4.9", + "npm:vite@5.4.9": "5.4.9" }, "npm": { "@ampproject/remapping@2.3.0": { @@ -22,18 +21,19 @@ "@jridgewell/trace-mapping" ] }, - "@babel/code-frame@7.25.7": { - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "@babel/code-frame@7.26.0": { + "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", "dependencies": [ - "@babel/highlight", + "@babel/helper-validator-identifier", + "js-tokens", "picocolors" ] }, - "@babel/compat-data@7.25.8": { - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==" + "@babel/compat-data@7.26.0": { + "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==" }, - "@babel/core@7.25.8": { - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", + "@babel/core@7.26.0": { + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dependencies": [ "@ampproject/remapping", "@babel/code-frame", @@ -52,17 +52,18 @@ "semver" ] }, - "@babel/generator@7.25.7": { - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "@babel/generator@7.26.0": { + "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", "dependencies": [ + "@babel/parser", "@babel/types", "@jridgewell/gen-mapping", "@jridgewell/trace-mapping", "jsesc" ] }, - "@babel/helper-compilation-targets@7.25.7": { - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", + "@babel/helper-compilation-targets@7.25.9": { + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dependencies": [ "@babel/compat-data", "@babel/helper-validator-option", @@ -71,88 +72,71 @@ "semver" ] }, - "@babel/helper-module-imports@7.25.7": { - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "@babel/helper-module-imports@7.25.9": { + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dependencies": [ "@babel/traverse", "@babel/types" ] }, - "@babel/helper-module-transforms@7.25.7_@babel+core@7.25.8": { - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", + "@babel/helper-module-transforms@7.26.0_@babel+core@7.26.0": { + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dependencies": [ "@babel/core", "@babel/helper-module-imports", - "@babel/helper-simple-access", "@babel/helper-validator-identifier", "@babel/traverse" ] }, - "@babel/helper-plugin-utils@7.25.7": { - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==" - }, - "@babel/helper-simple-access@7.25.7": { - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dependencies": [ - "@babel/traverse", - "@babel/types" - ] + "@babel/helper-plugin-utils@7.25.9": { + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==" }, - "@babel/helper-string-parser@7.25.7": { - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==" + "@babel/helper-string-parser@7.25.9": { + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" }, - "@babel/helper-validator-identifier@7.25.7": { - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==" + "@babel/helper-validator-identifier@7.25.9": { + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" }, - "@babel/helper-validator-option@7.25.7": { - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==" + "@babel/helper-validator-option@7.25.9": { + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==" }, - "@babel/helpers@7.25.7": { - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", + "@babel/helpers@7.26.0": { + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dependencies": [ "@babel/template", "@babel/types" ] }, - "@babel/highlight@7.25.7": { - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", - "dependencies": [ - "@babel/helper-validator-identifier", - "chalk", - "js-tokens", - "picocolors" - ] - }, - "@babel/parser@7.25.8": { - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "@babel/parser@7.26.1": { + "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", "dependencies": [ "@babel/types" ] }, - "@babel/plugin-transform-react-jsx-self@7.25.7_@babel+core@7.25.8": { - "integrity": "sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==", + "@babel/plugin-transform-react-jsx-self@7.25.9_@babel+core@7.26.0": { + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", "dependencies": [ "@babel/core", "@babel/helper-plugin-utils" ] }, - "@babel/plugin-transform-react-jsx-source@7.25.7_@babel+core@7.25.8": { - "integrity": "sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==", + "@babel/plugin-transform-react-jsx-source@7.25.9_@babel+core@7.26.0": { + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", "dependencies": [ "@babel/core", "@babel/helper-plugin-utils" ] }, - "@babel/template@7.25.7": { - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "@babel/template@7.25.9": { + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dependencies": [ "@babel/code-frame", "@babel/parser", "@babel/types" ] }, - "@babel/traverse@7.25.7": { - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "@babel/traverse@7.25.9": { + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "dependencies": [ "@babel/code-frame", "@babel/generator", @@ -163,12 +147,11 @@ "globals" ] }, - "@babel/types@7.25.8": { - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "@babel/types@7.26.0": { + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "dependencies": [ "@babel/helper-string-parser", - "@babel/helper-validator-identifier", - "to-fast-properties" + "@babel/helper-validator-identifier" ] }, "@esbuild/aix-ppc64@0.21.5": { @@ -267,53 +250,59 @@ "@remix-run/router@1.20.0": { "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==" }, - "@rollup/rollup-android-arm-eabi@4.24.0": { - "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==" + "@rollup/rollup-android-arm-eabi@4.24.2": { + "integrity": "sha512-ufoveNTKDg9t/b7nqI3lwbCG/9IJMhADBNjjz/Jn6LxIZxD7T5L8l2uO/wD99945F1Oo8FvgbbZJRguyk/BdzA==" }, - "@rollup/rollup-android-arm64@4.24.0": { - "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==" + "@rollup/rollup-android-arm64@4.24.2": { + "integrity": "sha512-iZoYCiJz3Uek4NI0J06/ZxUgwAfNzqltK0MptPDO4OR0a88R4h0DSELMsflS6ibMCJ4PnLvq8f7O1d7WexUvIA==" }, - "@rollup/rollup-darwin-arm64@4.24.0": { - "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==" + "@rollup/rollup-darwin-arm64@4.24.2": { + "integrity": "sha512-/UhrIxobHYCBfhi5paTkUDQ0w+jckjRZDZ1kcBL132WeHZQ6+S5v9jQPVGLVrLbNUebdIRpIt00lQ+4Z7ys4Rg==" }, - "@rollup/rollup-darwin-x64@4.24.0": { - "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==" + "@rollup/rollup-darwin-x64@4.24.2": { + "integrity": "sha512-1F/jrfhxJtWILusgx63WeTvGTwE4vmsT9+e/z7cZLKU8sBMddwqw3UV5ERfOV+H1FuRK3YREZ46J4Gy0aP3qDA==" }, - "@rollup/rollup-linux-arm-gnueabihf@4.24.0": { - "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==" + "@rollup/rollup-freebsd-arm64@4.24.2": { + "integrity": "sha512-1YWOpFcGuC6iGAS4EI+o3BV2/6S0H+m9kFOIlyFtp4xIX5rjSnL3AwbTBxROX0c8yWtiWM7ZI6mEPTI7VkSpZw==" }, - "@rollup/rollup-linux-arm-musleabihf@4.24.0": { - "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==" + "@rollup/rollup-freebsd-x64@4.24.2": { + "integrity": "sha512-3qAqTewYrCdnOD9Gl9yvPoAoFAVmPJsBvleabvx4bnu1Kt6DrB2OALeRVag7BdWGWLhP1yooeMLEi6r2nYSOjg==" }, - "@rollup/rollup-linux-arm64-gnu@4.24.0": { - "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==" + "@rollup/rollup-linux-arm-gnueabihf@4.24.2": { + "integrity": "sha512-ArdGtPHjLqWkqQuoVQ6a5UC5ebdX8INPuJuJNWRe0RGa/YNhVvxeWmCTFQ7LdmNCSUzVZzxAvUznKaYx645Rig==" }, - "@rollup/rollup-linux-arm64-musl@4.24.0": { - "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==" + "@rollup/rollup-linux-arm-musleabihf@4.24.2": { + "integrity": "sha512-B6UHHeNnnih8xH6wRKB0mOcJGvjZTww1FV59HqJoTJ5da9LCG6R4SEBt6uPqzlawv1LoEXSS0d4fBlHNWl6iYw==" }, - "@rollup/rollup-linux-powerpc64le-gnu@4.24.0": { - "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==" + "@rollup/rollup-linux-arm64-gnu@4.24.2": { + "integrity": "sha512-kr3gqzczJjSAncwOS6i7fpb4dlqcvLidqrX5hpGBIM1wtt0QEVtf4wFaAwVv8QygFU8iWUMYEoJZWuWxyua4GQ==" }, - "@rollup/rollup-linux-riscv64-gnu@4.24.0": { - "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==" + "@rollup/rollup-linux-arm64-musl@4.24.2": { + "integrity": "sha512-TDdHLKCWgPuq9vQcmyLrhg/bgbOvIQ8rtWQK7MRxJ9nvaxKx38NvY7/Lo6cYuEnNHqf6rMqnivOIPIQt6H2AoA==" }, - "@rollup/rollup-linux-s390x-gnu@4.24.0": { - "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==" + "@rollup/rollup-linux-powerpc64le-gnu@4.24.2": { + "integrity": "sha512-xv9vS648T3X4AxFFZGWeB5Dou8ilsv4VVqJ0+loOIgDO20zIhYfDLkk5xoQiej2RiSQkld9ijF/fhLeonrz2mw==" }, - "@rollup/rollup-linux-x64-gnu@4.24.0": { - "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==" + "@rollup/rollup-linux-riscv64-gnu@4.24.2": { + "integrity": "sha512-tbtXwnofRoTt223WUZYiUnbxhGAOVul/3StZ947U4A5NNjnQJV5irKMm76G0LGItWs6y+SCjUn/Q0WaMLkEskg==" }, - "@rollup/rollup-linux-x64-musl@4.24.0": { - "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==" + "@rollup/rollup-linux-s390x-gnu@4.24.2": { + "integrity": "sha512-gc97UebApwdsSNT3q79glOSPdfwgwj5ELuiyuiMY3pEWMxeVqLGKfpDFoum4ujivzxn6veUPzkGuSYoh5deQ2Q==" }, - "@rollup/rollup-win32-arm64-msvc@4.24.0": { - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==" + "@rollup/rollup-linux-x64-gnu@4.24.2": { + "integrity": "sha512-jOG/0nXb3z+EM6SioY8RofqqmZ+9NKYvJ6QQaa9Mvd3RQxlH68/jcB/lpyVt4lCiqr04IyaC34NzhUqcXbB5FQ==" }, - "@rollup/rollup-win32-ia32-msvc@4.24.0": { - "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==" + "@rollup/rollup-linux-x64-musl@4.24.2": { + "integrity": "sha512-XAo7cJec80NWx9LlZFEJQxqKOMz/lX3geWs2iNT5CHIERLFfd90f3RYLLjiCBm1IMaQ4VOX/lTC9lWfzzQm14Q==" }, - "@rollup/rollup-win32-x64-msvc@4.24.0": { - "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==" + "@rollup/rollup-win32-arm64-msvc@4.24.2": { + "integrity": "sha512-A+JAs4+EhsTjnPQvo9XY/DC0ztaws3vfqzrMNMKlwQXuniBKOIIvAAI8M0fBYiTCxQnElYu7mLk7JrhlQ+HeOw==" + }, + "@rollup/rollup-win32-ia32-msvc@4.24.2": { + "integrity": "sha512-ZhcrakbqA1SCiJRMKSU64AZcYzlZ/9M5LaYil9QWxx9vLnkQ9Vnkve17Qn4SjlipqIIBFKjBES6Zxhnvh0EAEw==" + }, + "@rollup/rollup-win32-x64-msvc@4.24.2": { + "integrity": "sha512-2mLH46K1u3r6uwc95hU+OR9q/ggYMpnS7pSp83Ece1HUQgF9Nh/QwTK5rcgbFnV9j+08yBrU5sA/P0RK2MSBNA==" }, "@tauri-apps/api@2.0.2": { "integrity": "sha512-3wSwmG+1kr6WrgAFKK5ijkNFPp8TT3FLj3YHUb5EwMO+3FxX4uWlfSWkeeBy+Kc1RsKzugtYLuuya+98Flj+3w==" @@ -359,12 +348,6 @@ "@types/history@4.7.11": { "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" }, - "@types/node@22.5.4": { - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", - "dependencies": [ - "undici-types" - ] - }, "@types/prop-types@15.7.13": { "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, @@ -396,7 +379,7 @@ "csstype" ] }, - "@vitejs/plugin-react@4.3.2_vite@5.4.9_@babel+core@7.25.8": { + "@vitejs/plugin-react@4.3.2_vite@5.4.9_@babel+core@7.26.0": { "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==", "dependencies": [ "@babel/core", @@ -404,17 +387,11 @@ "@babel/plugin-transform-react-jsx-source", "@types/babel__core", "react-refresh", - "vite@5.4.9" - ] - }, - "ansi-styles@3.2.1": { - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": [ - "color-convert" + "vite" ] }, - "browserslist@4.24.0": { - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "browserslist@4.24.2": { + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dependencies": [ "caniuse-lite", "electron-to-chromium", @@ -422,25 +399,8 @@ "update-browserslist-db" ] }, - "caniuse-lite@1.0.30001669": { - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==" - }, - "chalk@2.4.2": { - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": [ - "ansi-styles", - "escape-string-regexp", - "supports-color" - ] - }, - "color-convert@1.9.3": { - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": [ - "color-name" - ] - }, - "color-name@1.1.3": { - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "caniuse-lite@1.0.30001673": { + "integrity": "sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==" }, "convert-source-map@2.0.0": { "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" @@ -454,8 +414,8 @@ "ms" ] }, - "electron-to-chromium@1.5.40": { - "integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==" + "electron-to-chromium@1.5.47": { + "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==" }, "esbuild@0.21.5": { "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", @@ -488,9 +448,6 @@ "escalade@3.2.0": { "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, - "escape-string-regexp@1.0.5": { - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, "fsevents@2.3.3": { "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==" }, @@ -500,9 +457,6 @@ "globals@11.12.0": { "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, - "has-flag@3.0.0": { - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, "js-tokens@4.0.0": { "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, @@ -577,13 +531,15 @@ "loose-envify" ] }, - "rollup@4.24.0": { - "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "rollup@4.24.2": { + "integrity": "sha512-do/DFGq5g6rdDhdpPq5qb2ecoczeK6y+2UAjdJ5trjQJj5f1AiVdLRWRc9A9/fFukfvJRgM0UXzxBIYMovm5ww==", "dependencies": [ "@rollup/rollup-android-arm-eabi", "@rollup/rollup-android-arm64", "@rollup/rollup-darwin-arm64", "@rollup/rollup-darwin-x64", + "@rollup/rollup-freebsd-arm64", + "@rollup/rollup-freebsd-x64", "@rollup/rollup-linux-arm-gnueabihf", "@rollup/rollup-linux-arm-musleabihf", "@rollup/rollup-linux-arm64-gnu", @@ -612,19 +568,7 @@ "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, - "supports-color@5.5.0": { - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": [ - "has-flag" - ] - }, - "to-fast-properties@2.0.0": { - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" - }, - "undici-types@6.19.8": { - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" - }, - "update-browserslist-db@1.1.1_browserslist@4.24.0": { + "update-browserslist-db@1.1.1_browserslist@4.24.2": { "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dependencies": [ "browserslist", @@ -641,32 +585,22 @@ "rollup" ] }, - "vite@5.4.9_@types+node@22.5.4": { - "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", - "dependencies": [ - "@types/node", - "esbuild", - "fsevents", - "postcss", - "rollup" - ] - }, "yallist@3.1.1": { "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } }, "workspace": { "dependencies": [ - "npm:@tauri-apps/api@^2.0.2", - "npm:@tauri-apps/plugin-store@^2.1.0", - "npm:@types/react-dom@^18.3.1", - "npm:@types/react-router-dom@^5.3.3", - "npm:@types/react@^18.3.11", - "npm:@vitejs/plugin-react@^4.3.2", - "npm:react-dom@^18.3.1", - "npm:react-router-dom@^6.27.0", - "npm:react@^18.3.1", - "npm:vite@^5.4.9" + "npm:@tauri-apps/api@2.0.2", + "npm:@tauri-apps/plugin-store@2.1.0", + "npm:@types/react-dom@18.3.1", + "npm:@types/react-router-dom@5.3.3", + "npm:@types/react@18.3.11", + "npm:@vitejs/plugin-react@4.3.2", + "npm:react-dom@18.3.1", + "npm:react-router-dom@6.27.0", + "npm:react@18.3.1", + "npm:vite@5.4.9" ] } } From 11b9cfb1c775fcbc93f10dd7baa5cf28873099ee Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:42:20 +0100 Subject: [PATCH 15/24] feat: Update route paths in App component Refactored route paths in the App component to include extensionId and mangaId for better navigation. --- src-www/App.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src-www/App.tsx b/src-www/App.tsx index bd650d7..d6a93e8 100644 --- a/src-www/App.tsx +++ b/src-www/App.tsx @@ -16,11 +16,11 @@ const router = createBrowserRouter([ element: , }, { - path: "/browse/:id", - element: , + path: "/browse/:extensionId", + element: , }, { - path: "/read/:id", + path: "/browse/:extensionId/:mangaId", element: , }, { From 239b99d1721fb39250531e30b92fdf5edbe73c5e Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:42:29 +0100 Subject: [PATCH 16/24] feat: Add memoization to getExtension function Add memoization to the getExtension function to avoid re-rendering. --- src-www/services/extensions.service.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src-www/services/extensions.service.ts b/src-www/services/extensions.service.ts index 5923131..1208c6e 100644 --- a/src-www/services/extensions.service.ts +++ b/src-www/services/extensions.service.ts @@ -1,19 +1,27 @@ import { convertFileSrc, invoke } from "@tauri-apps/api/core"; -import { Chapter } from "../types/chapter.ts"; -import { Filter } from "../types/filter.ts"; -import { Manga, MangaList } from "../types/manga.ts"; -import { Page } from "../types/page.ts"; +import { Chapter } from "../types/chapter"; +import { Filter } from "../types/filter"; +import { Manga, MangaList } from "../types/manga"; +import { Page } from "../types/page"; +import { getExtensions } from "./tauri.service"; export function getIconUrl(iconPath: string): string { return convertFileSrc(iconPath); } +// todo : use memo to avoid re-rendering +export async function getExtension(extensionId: string) { + return await getExtensions().then((extensions) => + extensions.find((extension) => extension.id === extensionId) + ); +} + export async function getMangaList( extensionId: string, filters: Filter[], page: number, -): Promise { +): Promise<[Manga[],boolean]> { return await invoke("get_manga_list", { extensionId: extensionId, filters: filters, From 113a4763fae28bd7fd9dd07a2caa704804dd2a79 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:42:56 +0100 Subject: [PATCH 17/24] fix: Update import paths in Extensions.tsx Updated import paths for Manifest and store to remove file extensions. Replaced import path for tauri.ts with services/tauri.service. --- src-www/pages/Extensions.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src-www/pages/Extensions.tsx b/src-www/pages/Extensions.tsx index 82ccf7e..4d59911 100644 --- a/src-www/pages/Extensions.tsx +++ b/src-www/pages/Extensions.tsx @@ -1,12 +1,12 @@ import { useEffect, useState } from "react"; -import { Manifest } from "../types/manifest.ts"; -import { store } from "../store.ts"; +import { Manifest } from "../types/manifest"; +import { store } from "../store"; import { getRepositoryExtensions, installExtension, uninstallExtension, -} from "../tauri.ts"; +} from "../services/tauri.service"; export default function Extensions() { const [repositoryUrl, setRepositoryUrl] = useState(""); From 397a138d694ec4a9b2eb2652ea29d53a46b7f753 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:43:28 +0100 Subject: [PATCH 18/24] feat: Improve fallback image handling Refactored the MangaImage component to handle fallback image source more efficiently. --- src-www/components/MangaImage.tsx | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src-www/components/MangaImage.tsx b/src-www/components/MangaImage.tsx index d042f87..d9d20fc 100644 --- a/src-www/components/MangaImage.tsx +++ b/src-www/components/MangaImage.tsx @@ -1,20 +1,18 @@ -import fallback from "../public/fallback-img.jpg"; - -function MangaImage({ src, alt, fallBackSrc = fallback }) { - return ( - {alt} (e.currentTarget.src = fallBackSrc)} - /> - ); +function MangaImage({ src, alt, fallBackSrc = "/fallback-img.jpg" }: { src: string; alt: string; fallBackSrc?: string }) { + return ( + {alt} (e.currentTarget.src = fallBackSrc)} + /> + ); } export default MangaImage; From 4d41d01a9ce670ec5d7ff2e871320eabbb5eb589 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:43:34 +0100 Subject: [PATCH 19/24] feat: Refactor Browse component for improved readability - Updated import statements for better consistency - Reorganized code structure for easier understanding --- src-www/pages/Browse/Browse.tsx | 99 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/src-www/pages/Browse/Browse.tsx b/src-www/pages/Browse/Browse.tsx index 83a655a..8a82070 100644 --- a/src-www/pages/Browse/Browse.tsx +++ b/src-www/pages/Browse/Browse.tsx @@ -1,56 +1,55 @@ -import {useEffect, useState} from "react"; +import { useEffect, useState } from "react"; -import {Extension} from "../../types/extension"; -import {getIconUrl} from "../../services/extensions.service"; -import {getExtensions} from "../../tauri"; -import {Link} from "react-router-dom"; +import { Extension } from "../../types/extension"; +import { getIconUrl } from "../../services/extensions.service"; +import { getExtensions } from "../../services/tauri.service"; +import { Link } from "react-router-dom"; export default function Browse() { - const [extensions, setExtensions] = useState([]); + const [extensions, setExtensions] = useState([]); - useEffect(() => { - getExtensions().then(setExtensions); - }, []); + useEffect(() => { + getExtensions().then(setExtensions); + }, []); - - return ( -
      - {extensions.map((extension: Extension) => { - return ( -
    • - -
      - - {extension.source.name} - -
      - {extension.source.language} -
      -
      - - Browse - -
    • - ); - })} -
    - ); + return ( +
      + {extensions.map((extension: Extension) => { + return ( +
    • + +
      + + {extension.source.name} + +
      + {extension.source.language} +
      +
      + + Browse + +
    • + ); + })} +
    + ); } From dcf6d72dd54c4cf815f31374d1a46a7ad32c0db9 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:43:40 +0100 Subject: [PATCH 20/24] feat: Refactor ExtensionBrowse component for improved functionality - Restructured component logic for better readability and maintainability - Updated useEffect hooks to handle extension loading and manga pagination efficiently --- src-www/pages/Browse/ExtensionBrowse.tsx | 280 +++++++++-------------- 1 file changed, 111 insertions(+), 169 deletions(-) diff --git a/src-www/pages/Browse/ExtensionBrowse.tsx b/src-www/pages/Browse/ExtensionBrowse.tsx index fbcff5c..5e29611 100644 --- a/src-www/pages/Browse/ExtensionBrowse.tsx +++ b/src-www/pages/Browse/ExtensionBrowse.tsx @@ -1,184 +1,126 @@ -import { useEffect, useState } from "react"; -import { Extension, Source } from "../../types/extension"; -import { Manga } from "../../types/manga"; -import { Link, useParams } from "react-router-dom"; - +import {useEffect, useState} from "react"; +import {Extension} from "../../types/extension"; +import {Manga, MangaList} from "../../types/manga"; +import {Link, useParams} from "react-router-dom"; +import {getExtension, getIconUrl, getMangaList,} from "../../services/extensions.service"; import "../../style/loader.css"; import MangaImage from "../../components/MangaImage"; -import { invoke } from "@tauri-apps/api/core"; export default function ExtensionBrowse() { - globalThis.addEventListener("scroll", handleScroll); - - const id = useParams().id; - console.log("extensionId", id); - - const [extension, setExtension] = useState(null); - - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - - const [mangas, setMangas] = useState>([]); - const [pagination, setPagination] = useState(1); - - // Récupérer l'extension - useEffect(() => { - getExtension(id).then((extension) => { - setExtension(extension); - console.log("Extension :", extension); - }); - }, []); - - useEffect(() => { - if (!extension) { - return; - } - if (!extension.getMangaList) { - return setError( - "L'extension n'est pas valide. Veuillez passer par la page d'accueil.", - ); - } - - // Récupérer la liste des mangas pour l'extension - extension.getMangaList([], pagination).then((data) => { - setMangas([...mangas, ...data[0]]); - setLoading(false); - console.log("pagination " + pagination + " :", data); - }).catch((error) => { - console.error("Erreur lors du chargement des mangas :", error); - setError("Une erreur est survenue lors du chargement des mangas."); - }); - }, [extension, pagination]); - - function handleScroll() { - if ( - document.body.scrollHeight - 300 < - globalThis.scrollY + globalThis.innerHeight - ) { - if (loading) return; - - setLoading(true); - setPagination(pagination + 1); - console.log("scoll active"); - } - } + const {extensionId} = useParams(); + const [extension, setExtension] = useState(null); + const [mangas, setMangas] = useState>([]); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [pagination, setPagination] = useState(1); + + // Charger l'extension une seule fois au démarrage + useEffect(() => { + if (!extensionId) return; + getExtension(extensionId) + .then(setExtension) + .catch(() => setError("Erreur lors du chargement de l'extension.")); + }, [extensionId]); + + // Charger la liste de mangas pour chaque pagination + useEffect(() => { + if (!extension) return; + + setLoading(true); // Activer le chargement pendant la requête + getMangaList(extension.id, [], pagination) + .then((data) => setMangas([...mangas, ...data[0]])) + .catch(() => setError("Erreur lors du chargement des mangas.")) + .finally(() => setLoading(false)); + }, [extension, pagination]); + + // Gestion du scroll infini + useEffect(() => { + const handleScroll = () => { + if (document.body.scrollHeight - 300 < globalThis.scrollY + globalThis.innerHeight) { + if (!loading) { + setPagination(pagination + 1); + } + } + }; + globalThis.addEventListener("scroll", handleScroll); + return () => globalThis.removeEventListener("scroll", handleScroll); + }, [loading]); + + // Afficher un message d'erreur si nécessaire + if (error) return ; + + // Si l'extension est encore en chargement + if (!extension) return ; + + return (
    + + + {loading && } +
    ); +} - // Afficher un message d'erreur si nécessaire - if (error) { - return ( -
    -

    {error}

    -
    - ); - } +// Composant de message d'erreur +const ErrorMessage = ({error}: { error: string }) => (
    +

    {error}

    +
    ); - // if extension is not loaded yet - if (!extension) { - return ( -
    (
    -
    - Chargement... -
    + > +
    Chargement...
    -
    - ); - } +
    ); - return ( -
    - {/* En-tête de l'extension */} -
    +// En-tête de l'extension avec le nom et l'icône +const ExtensionHeader = ({extension}: { extension: Extension }) => (
    {extension.name} -

    {extension.name}

    -
    +

    {extension.source.name}

    +
    ); - {/* Grille des mangas avec image et titre */} -
      ; extensionId: string },) => (
        - {mangas.map((manga) => ( -
      • - {/* Image de couverture */} - - - - {/* Titre du manga */} - -

        - {manga.title} -

        -
        -
      • - ))} -
      - - {/* infinie scroll loading */} - {loading && // center the loader -
      -
      - Chargement... -
      -
      -
      } -
    - ); -} - -// todo : use memo to avoid re-rendering -async function getExtension(extensionId: string) { - let extensionsList = await invoke>( - "get_extensions", - ); - let extension = extensionsList.find(([id, source, iconPath]) => - id === extensionId - ); - return new Extension(extension[0], extension[1], extension[2]); -} + > + {mangas.map((manga) => (
  • + + + + +

    + {manga.title} +

    +
    +
  • ))} + ); From 418b19a0343c28e3946d6d0db2f3df8f1636d847 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:43:50 +0100 Subject: [PATCH 21/24] feat: Refactor MangaDetails component for improved readability and data fetching - Restructured component logic for better organization - Updated data fetching to use service function instead of direct API call --- src-www/pages/MangaDetails.tsx | 239 +++++++++++++++------------------ 1 file changed, 112 insertions(+), 127 deletions(-) diff --git a/src-www/pages/MangaDetails.tsx b/src-www/pages/MangaDetails.tsx index a6fd168..26918e5 100644 --- a/src-www/pages/MangaDetails.tsx +++ b/src-www/pages/MangaDetails.tsx @@ -1,145 +1,130 @@ -import { useEffect, useState } from "react"; -import { Extension, Source } from "../types/extension"; -import { Manga } from "../types/manga"; -import { Link, useLocation } from "react-router-dom"; +import {useEffect, useState} from "react"; +import {Manga, ReadingMode} from "../types/manga"; +import {Link, useParams} from "react-router-dom"; import "../style/loader.css"; import MangaImage from "../components/MangaImage"; -import { invoke } from "@tauri-apps/api/core"; +import {getMangaDetails} from "../services/extensions.service"; export default function MangaDetails() { - const { state } = useLocation(); - const extension = state.extension as Extension; - globalThis.addEventListener("scroll", handleScroll); + const {extensionId, mangaId} = useParams< + { extensionId: string; mangaId: string } + >(); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [manga, setManga] = useState(null); - const [mangas, setMangas] = useState>([]); - const [pagination, setPagination] = useState(1); + // Récupérer le manga + useEffect(() => { + if (!extensionId || !mangaId) { + setError("Erreur lors de la récupération des détails du manga."); + setLoading(false); + return; + } + getMangaDetails(extensionId, mangaId) + .then((data) => { + setManga(data); + setLoading(false); + }) + .catch((err) => { + setError( + "Erreur lors de la récupération des détails du manga. : " + err, + ); + setLoading(false); + }); + }, [extensionId, mangaId]); - // Récupérer l'extension - useEffect(() => { - console.log("Extension :", extension); - }, []); - - useEffect(() => { - if (!extension || !extension.getMangaList) { - return setError( - "L'extension n'est pas valide. Veuillez passer par la page d'accueil.", - ); + if (loading) { + return ( +
    +
    Chargement...
    +
    +
    + ); } - // Récupérer la liste des mangas pour l'extension - extension.getMangaList([], pagination).then((data) => { - setMangas([...mangas, ...data[0]]); - setLoading(false); - console.log("pagination " + pagination + " :", data); - }).catch((error) => { - console.error("Erreur lors du chargement des mangas :", error); - setError("Une erreur est survenue lors du chargement des mangas."); - }); - }, [extension, pagination]); - - function handleScroll() { - if ( - document.body.scrollHeight - 300 < - globalThis.scrollY + globalThis.innerHeight - ) { - if (loading) return; + if (error) { + return ( +
    + {error} +
    + ); + } - setLoading(true); - setPagination(pagination + 1); - console.log("scoll active"); + if (!manga) { + return null; } - } - // Afficher un message d'erreur si nécessaire - if (error) { return ( -
    -

    {error}

    -
    - ); - } +
    + {/* Titre et couverture du manga */} +
    + +
    +

    + {manga.title} +

    +
    + Statut : {manga.status} +
    +
    + Lecture : {manga.readingMode === ReadingMode.RightToLeft + ? "Droite à Gauche" + : "Gauche à Droite"} +
    +
    +
    - return ( -
    - {/* En-tête de l'extension */} -
    - {extension.name} -

    {extension.name}

    -
    + {/* Informations sur le manga */} +
    +

    Détails

    +

    + Auteur : {manga.authorName} +

    +

    + Artiste : {manga.artistName} +

    +

    + Catégories : {manga.categories.join(", ")} +

    +

    + Note de Contenu : {manga.contentRating} +

    +
    - {/* Grille des mangas avec image et titre */} -
      - {mangas.map((manga) => ( -
    • - {/* Image de couverture */} - - - - {/* Titre du manga */} - -

      - {manga.title} -

      -
      -
    • - ))} -
    + {/* Description */} +
    +

    + Description +

    +

    {manga.description}

    +
    - {/* infinie scroll loading */} - {loading && // center the loader -
    -
    - Chargement... -
    -
    -
    } -
    - ); + {/* Lien vers le site source */} +
    + + Lire sur le site source + +
    +
    + ); } From 1190187f857df18a4aad0439125be05f7abccef7 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:48:04 +0100 Subject: [PATCH 22/24] feat: Update return type of getMangaList function Refactor the return type of the getMangaList function to use a new interface MangaList instead of an array. Update enums in manga.ts for consistency. --- src-www/services/extensions.service.ts | 2 +- src-www/types/manga.ts | 50 +++++++++++++------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src-www/services/extensions.service.ts b/src-www/services/extensions.service.ts index 1208c6e..17aa90b 100644 --- a/src-www/services/extensions.service.ts +++ b/src-www/services/extensions.service.ts @@ -21,7 +21,7 @@ export async function getMangaList( extensionId: string, filters: Filter[], page: number, -): Promise<[Manga[],boolean]> { +): Promise { return await invoke("get_manga_list", { extensionId: extensionId, filters: filters, diff --git a/src-www/types/manga.ts b/src-www/types/manga.ts index deeede4..4df0b8a 100644 --- a/src-www/types/manga.ts +++ b/src-www/types/manga.ts @@ -1,38 +1,36 @@ export enum Status { - Unknown, - Ongoing, - Completed, - Hiatus, - Cancelled, + Unknown, + Ongoing, + Completed, + Hiatus, + Cancelled, } export enum ContentRating { - Safe, - Suggestive, - Nsfw, + Safe, + Suggestive, + Nsfw, } export enum ReadingMode { - RightToLeft, - LeftToRight, - Vertical, - Scroll, + RightToLeft, + LeftToRight, + Vertical, + Scroll, } export interface Manga { - id: string; - title: string; - url: string; - description: string; - coverUrl: string; - authorName: string; - artistName: string; - categories: string[]; - status: Status; - contentRating: ContentRating; - readingMode: ReadingMode; + id: string; + title: string; + url: string; + description: string; + coverUrl: string; + authorName: string; + artistName: string; + categories: string[]; + status: Status; + contentRating: ContentRating; + readingMode: ReadingMode; } -export interface MangaList { - data: [Manga[], boolean]; -} +export type MangaList = [Manga[], boolean]; \ No newline at end of file From e5ce2b0e8b2d22dc6018fe64733cf6677163863f Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:51:15 +0100 Subject: [PATCH 23/24] fix: Removed unused import of MangaList Removed an unused import statement for MangaList in ExtensionBrowse.tsx. --- src-www/pages/Browse/ExtensionBrowse.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-www/pages/Browse/ExtensionBrowse.tsx b/src-www/pages/Browse/ExtensionBrowse.tsx index 5e29611..69dacce 100644 --- a/src-www/pages/Browse/ExtensionBrowse.tsx +++ b/src-www/pages/Browse/ExtensionBrowse.tsx @@ -1,6 +1,6 @@ import {useEffect, useState} from "react"; import {Extension} from "../../types/extension"; -import {Manga, MangaList} from "../../types/manga"; +import {Manga} from "../../types/manga"; import {Link, useParams} from "react-router-dom"; import {getExtension, getIconUrl, getMangaList,} from "../../services/extensions.service"; import "../../style/loader.css"; From 2728a746aad9ebb910edc3f6121f176f73ad1026 Mon Sep 17 00:00:00 2001 From: Breval Date: Thu, 7 Nov 2024 03:53:14 +0100 Subject: [PATCH 24/24] feat: Improve component structure and readability - Refactored the MangaImage component for better code formatting and readability. - Reorganized the ExtensionBrowse component to enhance clarity and maintainability. - Updated the MangaDetails component for improved structure and consistency. --- src-www/components/MangaImage.tsx | 36 ++-- src-www/pages/Browse/ExtensionBrowse.tsx | 236 +++++++++++++---------- src-www/pages/MangaDetails.tsx | 228 +++++++++++----------- src-www/types/manga.ts | 48 ++--- 4 files changed, 289 insertions(+), 259 deletions(-) diff --git a/src-www/components/MangaImage.tsx b/src-www/components/MangaImage.tsx index d9d20fc..edad0f8 100644 --- a/src-www/components/MangaImage.tsx +++ b/src-www/components/MangaImage.tsx @@ -1,18 +1,24 @@ -function MangaImage({ src, alt, fallBackSrc = "/fallback-img.jpg" }: { src: string; alt: string; fallBackSrc?: string }) { - return ( - {alt} (e.currentTarget.src = fallBackSrc)} - /> - ); +function MangaImage( + { src, alt, fallBackSrc = "/fallback-img.jpg" }: { + src: string; + alt: string; + fallBackSrc?: string; + }, +) { + return ( + {alt} (e.currentTarget.src = fallBackSrc)} + /> + ); } export default MangaImage; diff --git a/src-www/pages/Browse/ExtensionBrowse.tsx b/src-www/pages/Browse/ExtensionBrowse.tsx index 69dacce..601966c 100644 --- a/src-www/pages/Browse/ExtensionBrowse.tsx +++ b/src-www/pages/Browse/ExtensionBrowse.tsx @@ -1,126 +1,150 @@ -import {useEffect, useState} from "react"; -import {Extension} from "../../types/extension"; -import {Manga} from "../../types/manga"; -import {Link, useParams} from "react-router-dom"; -import {getExtension, getIconUrl, getMangaList,} from "../../services/extensions.service"; +import { useEffect, useState } from "react"; +import { Extension } from "../../types/extension"; +import { Manga } from "../../types/manga"; +import { Link, useParams } from "react-router-dom"; +import { + getExtension, + getIconUrl, + getMangaList, +} from "../../services/extensions.service"; import "../../style/loader.css"; import MangaImage from "../../components/MangaImage"; export default function ExtensionBrowse() { - const {extensionId} = useParams(); - const [extension, setExtension] = useState(null); - const [mangas, setMangas] = useState>([]); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - const [pagination, setPagination] = useState(1); + const { extensionId } = useParams(); + const [extension, setExtension] = useState(null); + const [mangas, setMangas] = useState>([]); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [pagination, setPagination] = useState(1); - // Charger l'extension une seule fois au démarrage - useEffect(() => { - if (!extensionId) return; - getExtension(extensionId) - .then(setExtension) - .catch(() => setError("Erreur lors du chargement de l'extension.")); - }, [extensionId]); + // Charger l'extension une seule fois au démarrage + useEffect(() => { + if (!extensionId) return; + getExtension(extensionId) + .then(setExtension) + .catch(() => setError("Erreur lors du chargement de l'extension.")); + }, [extensionId]); - // Charger la liste de mangas pour chaque pagination - useEffect(() => { - if (!extension) return; + // Charger la liste de mangas pour chaque pagination + useEffect(() => { + if (!extension) return; - setLoading(true); // Activer le chargement pendant la requête - getMangaList(extension.id, [], pagination) - .then((data) => setMangas([...mangas, ...data[0]])) - .catch(() => setError("Erreur lors du chargement des mangas.")) - .finally(() => setLoading(false)); - }, [extension, pagination]); + setLoading(true); // Activer le chargement pendant la requête + getMangaList(extension.id, [], pagination) + .then((data) => setMangas([...mangas, ...data[0]])) + .catch(() => setError("Erreur lors du chargement des mangas.")) + .finally(() => setLoading(false)); + }, [extension, pagination]); - // Gestion du scroll infini - useEffect(() => { - const handleScroll = () => { - if (document.body.scrollHeight - 300 < globalThis.scrollY + globalThis.innerHeight) { - if (!loading) { - setPagination(pagination + 1); - } - } - }; - globalThis.addEventListener("scroll", handleScroll); - return () => globalThis.removeEventListener("scroll", handleScroll); - }, [loading]); + // Gestion du scroll infini + useEffect(() => { + const handleScroll = () => { + if ( + document.body.scrollHeight - 300 < + globalThis.scrollY + globalThis.innerHeight + ) { + if (!loading) { + setPagination(pagination + 1); + } + } + }; + globalThis.addEventListener("scroll", handleScroll); + return () => globalThis.removeEventListener("scroll", handleScroll); + }, [loading]); - // Afficher un message d'erreur si nécessaire - if (error) return ; + // Afficher un message d'erreur si nécessaire + if (error) return ; - // Si l'extension est encore en chargement - if (!extension) return ; + // Si l'extension est encore en chargement + if (!extension) return ; - return (
    - - - {loading && } -
    ); + return ( +
    + + + {loading && } +
    + ); } // Composant de message d'erreur -const ErrorMessage = ({error}: { error: string }) => (
    -

    {error}

    -
    ); +const ErrorMessage = ({ error }: { error: string }) => ( +
    +

    {error}

    +
    +); // Composant de loader -const Loader = () => (
    -
    Chargement...
    -
    -
    ); +const Loader = () => ( +
    +
    Chargement...
    +
    +
    +); // En-tête de l'extension avec le nom et l'icône -const ExtensionHeader = ({extension}: { extension: Extension }) => (
    - {extension.source.name} -

    {extension.source.name}

    -
    ); +const ExtensionHeader = ({ extension }: { extension: Extension }) => ( +
    + {extension.source.name} +

    {extension.source.name}

    +
    +); // Grille de mangas -const MangaGrid = ({mangas, extensionId}: { mangas: Array; extensionId: string },) => (); +const MangaGrid = ( + { mangas, extensionId }: { mangas: Array; extensionId: string }, +) => ( + +); diff --git a/src-www/pages/MangaDetails.tsx b/src-www/pages/MangaDetails.tsx index 26918e5..530cff8 100644 --- a/src-www/pages/MangaDetails.tsx +++ b/src-www/pages/MangaDetails.tsx @@ -1,130 +1,130 @@ -import {useEffect, useState} from "react"; -import {Manga, ReadingMode} from "../types/manga"; -import {Link, useParams} from "react-router-dom"; +import { useEffect, useState } from "react"; +import { Manga, ReadingMode } from "../types/manga"; +import { Link, useParams } from "react-router-dom"; import "../style/loader.css"; import MangaImage from "../components/MangaImage"; -import {getMangaDetails} from "../services/extensions.service"; +import { getMangaDetails } from "../services/extensions.service"; export default function MangaDetails() { - const {extensionId, mangaId} = useParams< - { extensionId: string; mangaId: string } - >(); + const { extensionId, mangaId } = useParams< + { extensionId: string; mangaId: string } + >(); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - const [manga, setManga] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [manga, setManga] = useState(null); - // Récupérer le manga - useEffect(() => { - if (!extensionId || !mangaId) { - setError("Erreur lors de la récupération des détails du manga."); - setLoading(false); - return; - } - getMangaDetails(extensionId, mangaId) - .then((data) => { - setManga(data); - setLoading(false); - }) - .catch((err) => { - setError( - "Erreur lors de la récupération des détails du manga. : " + err, - ); - setLoading(false); - }); - }, [extensionId, mangaId]); - - if (loading) { - return ( -
    -
    Chargement...
    -
    -
    - ); + // Récupérer le manga + useEffect(() => { + if (!extensionId || !mangaId) { + setError("Erreur lors de la récupération des détails du manga."); + setLoading(false); + return; } - - if (error) { - return ( -
    - {error} -
    + getMangaDetails(extensionId, mangaId) + .then((data) => { + setManga(data); + setLoading(false); + }) + .catch((err) => { + setError( + "Erreur lors de la récupération des détails du manga. : " + err, ); - } - - if (!manga) { - return null; - } + setLoading(false); + }); + }, [extensionId, mangaId]); + if (loading) { return ( -
    - {/* Titre et couverture du manga */} -
    - -
    -

    - {manga.title} -

    -
    - Statut : {manga.status} -
    -
    - Lecture : {manga.readingMode === ReadingMode.RightToLeft - ? "Droite à Gauche" - : "Gauche à Droite"} -
    -
    -
    +
    +
    Chargement...
    +
    +
    + ); + } - {/* Informations sur le manga */} -
    -

    Détails

    -

    - Auteur : {manga.authorName} -

    -

    - Artiste : {manga.artistName} -

    -

    - Catégories : {manga.categories.join(", ")} -

    -

    - Note de Contenu : {manga.contentRating} -

    -
    + if (error) { + return ( +
    + {error} +
    + ); + } - {/* Description */} -
    -

    - Description -

    -

    {manga.description}

    -
    + if (!manga) { + return null; + } - {/* Lien vers le site source */} -
    - - Lire sur le site source - -
    + return ( +
    + {/* Titre et couverture du manga */} +
    + +
    +

    + {manga.title} +

    +
    + Statut : {manga.status} +
    +
    + Lecture : {manga.readingMode === ReadingMode.RightToLeft + ? "Droite à Gauche" + : "Gauche à Droite"} +
    - ); +
    + + {/* Informations sur le manga */} +
    +

    Détails

    +

    + Auteur : {manga.authorName} +

    +

    + Artiste : {manga.artistName} +

    +

    + Catégories : {manga.categories.join(", ")} +

    +

    + Note de Contenu : {manga.contentRating} +

    +
    + + {/* Description */} +
    +

    + Description +

    +

    {manga.description}

    +
    + + {/* Lien vers le site source */} +
    + + Lire sur le site source + +
    +
    + ); } diff --git a/src-www/types/manga.ts b/src-www/types/manga.ts index 4df0b8a..3877f5b 100644 --- a/src-www/types/manga.ts +++ b/src-www/types/manga.ts @@ -1,36 +1,36 @@ export enum Status { - Unknown, - Ongoing, - Completed, - Hiatus, - Cancelled, + Unknown, + Ongoing, + Completed, + Hiatus, + Cancelled, } export enum ContentRating { - Safe, - Suggestive, - Nsfw, + Safe, + Suggestive, + Nsfw, } export enum ReadingMode { - RightToLeft, - LeftToRight, - Vertical, - Scroll, + RightToLeft, + LeftToRight, + Vertical, + Scroll, } export interface Manga { - id: string; - title: string; - url: string; - description: string; - coverUrl: string; - authorName: string; - artistName: string; - categories: string[]; - status: Status; - contentRating: ContentRating; - readingMode: ReadingMode; + id: string; + title: string; + url: string; + description: string; + coverUrl: string; + authorName: string; + artistName: string; + categories: string[]; + status: Status; + contentRating: ContentRating; + readingMode: ReadingMode; } -export type MangaList = [Manga[], boolean]; \ No newline at end of file +export type MangaList = [Manga[], boolean];