diff --git a/tranga-website/.prettierrc b/tranga-website/.prettierrc index e74ed9f..9dbc052 100644 --- a/tranga-website/.prettierrc +++ b/tranga-website/.prettierrc @@ -1,6 +1,11 @@ { "trailingComma": "es5", "tabWidth": 4, - "semi": false, - "singleQuote": true + "singleQuote": true, + "printWidth": 80, + "semi": true, + "bracketSpacing": true, + "objectWrap": "collapse", + "bracketSameLine": true, + "singleAttributePerLine": true } diff --git a/tranga-website/README.md b/tranga-website/README.md index e802977..f4133b1 100644 --- a/tranga-website/README.md +++ b/tranga-website/README.md @@ -28,15 +28,15 @@ export default tseslint.config({ tsconfigRootDir: import.meta.dirname, }, }, -}) +}); ``` You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: ```js // eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' +import reactX from 'eslint-plugin-react-x'; +import reactDom from 'eslint-plugin-react-dom'; export default tseslint.config({ plugins: { @@ -50,5 +50,5 @@ export default tseslint.config({ ...reactX.configs['recommended-typescript'].rules, ...reactDom.configs.recommended.rules, }, -}) +}); ``` diff --git a/tranga-website/eslint.config.js b/tranga-website/eslint.config.js index 5f4c30d..bf91bc4 100644 --- a/tranga-website/eslint.config.js +++ b/tranga-website/eslint.config.js @@ -1,22 +1,16 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; export default tseslint.config( { ignores: ['dist'] }, { extends: [js.configs.recommended, ...tseslint.configs.recommended], files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, + languageOptions: { ecmaVersion: 2020, globals: globals.browser }, + plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh }, rules: { ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': [ @@ -25,4 +19,4 @@ export default tseslint.config( ], }, } -) +); diff --git a/tranga-website/index.html b/tranga-website/index.html index e2a298f..470f11d 100644 --- a/tranga-website/index.html +++ b/tranga-website/index.html @@ -2,12 +2,19 @@ - - + + Tranga
- + diff --git a/tranga-website/src/App.tsx b/tranga-website/src/App.tsx index b5c3d3c..23ddd03 100644 --- a/tranga-website/src/App.tsx +++ b/tranga-website/src/App.tsx @@ -1,14 +1,14 @@ -import Sheet from '@mui/joy/Sheet' -import Header from './Header.tsx' -import Settings from './Components/Settings/Settings.tsx' -import ApiProvider from './contexts/ApiContext.tsx' -import { useEffect, useState } from 'react' -import { ApiConfig } from './api/http-client.ts' -import MangaProvider from './contexts/MangaContext.tsx' -import MangaList from './Components/Mangas/MangaList.tsx' -import { Search } from './Search.tsx' -import MangaConnectorProvider from './contexts/MangaConnectorContext.tsx' -import LibraryProvider from './contexts/FileLibraryContext.tsx' +import Sheet from '@mui/joy/Sheet'; +import Header from './Header.tsx'; +import Settings from './Components/Settings/Settings.tsx'; +import ApiProvider from './contexts/ApiContext.tsx'; +import { useEffect, useState } from 'react'; +import { ApiConfig } from './api/http-client.ts'; +import MangaProvider from './contexts/MangaContext.tsx'; +import MangaList from './Components/Mangas/MangaList.tsx'; +import { Search } from './Search.tsx'; +import MangaConnectorProvider from './contexts/MangaConnectorContext.tsx'; +import LibraryProvider from './contexts/FileLibraryContext.tsx'; export default function App() { const [apiUri, setApiUri] = useState( @@ -17,13 +17,13 @@ export default function App() { 0, window.location.href.lastIndexOf('/') ) + '/api' - ) - const [apiConfig, setApiConfig] = useState({ baseUrl: apiUri }) + ); + const [apiConfig, setApiConfig] = useState({ baseUrl: apiUri }); useEffect(() => { - setApiConfig({ baseUrl: apiUri }) - }, [apiUri]) + setApiConfig({ baseUrl: apiUri }); + }, [apiUri]); - const [searchOpen, setSearchOpen] = useState(false) + const [searchOpen, setSearchOpen] = useState(false); return ( @@ -48,5 +48,5 @@ export default function App() { - ) + ); } diff --git a/tranga-website/src/Components/Inputs/TButton.tsx b/tranga-website/src/Components/Inputs/TButton.tsx index abb66c3..060e9f3 100644 --- a/tranga-website/src/Components/Inputs/TButton.tsx +++ b/tranga-website/src/Components/Inputs/TButton.tsx @@ -1,19 +1,19 @@ -import { Button } from '@mui/joy' -import TProps, { TColor, TDisabled, TState } from './TProps.ts' -import { MouseEventHandler, ReactNode, useState } from 'react' +import { Button } from '@mui/joy'; +import TProps, { TColor, TDisabled, TState } from './TProps.ts'; +import { MouseEventHandler, ReactNode, useState } from 'react'; export default function TButton(props: TButtonProps) { - const [state, setState] = useState(TState.clean) + const [state, setState] = useState(TState.clean); const clicked: MouseEventHandler = (e) => { - setState(TState.busy) - e.preventDefault() + setState(TState.busy); + e.preventDefault(); if (props.completionAction) props .completionAction(undefined) .then(() => setState(TState.success)) - .catch(() => setState(TState.failure)) - } + .catch(() => setState(TState.failure)); + }; return ( - ) + ); } export interface TButtonProps extends TProps { - children?: ReactNode + children?: ReactNode; } diff --git a/tranga-website/src/Components/Inputs/TInput.tsx b/tranga-website/src/Components/Inputs/TInput.tsx index b1926eb..1ca83c4 100644 --- a/tranga-website/src/Components/Inputs/TInput.tsx +++ b/tranga-website/src/Components/Inputs/TInput.tsx @@ -1,59 +1,59 @@ -import { Button, Input } from '@mui/joy' -import { MouseEventHandler, useEffect, useState } from 'react' -import * as React from 'react' -import TProps, { TColor, TDisabled, TState } from './TProps.ts' -import './loadingBorder.css' +import { Button, Input } from '@mui/joy'; +import { MouseEventHandler, useEffect, useState } from 'react'; +import * as React from 'react'; +import TProps, { TColor, TDisabled, TState } from './TProps.ts'; +import './loadingBorder.css'; export default function TInput(props: TInputProps) { - const [state, setState] = useState(TState.clean) + const [state, setState] = useState(TState.clean); const [value, setValue] = useState< string | number | readonly string[] | undefined - >(props.defaultValue) + >(props.defaultValue); const [initialValue, setInitialValue] = useState< string | number | readonly string[] | undefined - >(props.defaultValue) + >(props.defaultValue); - const timerRef = React.useRef>(undefined) + const timerRef = React.useRef>(undefined); const inputValueChanged = (e: React.ChangeEvent) => { - e.preventDefault() - setValue(e.target.value) - clearTimeout(timerRef.current) + e.preventDefault(); + setValue(e.target.value); + clearTimeout(timerRef.current); - if (!props.autoSubmit) return + if (!props.autoSubmit) return; timerRef.current = setTimeout(() => { - submit() - }, props.actionDelay ?? 1500) - } + submit(); + }, props.actionDelay ?? 1500); + }; const submitClicked: MouseEventHandler = (e) => { - e.preventDefault() - submit() - } + e.preventDefault(); + submit(); + }; const keyDownHandler = (e: React.KeyboardEvent) => { - if (e.key === 'Enter') submit() - } + if (e.key === 'Enter') submit(); + }; const submit = () => { - setState(TState.busy) - clearTimeout(timerRef.current) + setState(TState.busy); + clearTimeout(timerRef.current); if (props.completionAction) props .completionAction(value) .then(() => { - setState(TState.success) - setInitialValue(value) + setState(TState.success); + setInitialValue(value); }) - .catch(() => setState(TState.failure)) - } + .catch(() => setState(TState.failure)); + }; useEffect(() => { if (value == initialValue) { - setState(TState.clean) + setState(TState.clean); } - }, [value, initialValue]) + }, [value, initialValue]); return ( + className={'t-loadable'}> {props.submitButtonText ?? 'Submit'} ) } /> - ) + ); } export interface TInputProps extends TProps { - placeholder?: string - defaultValue?: string | number | readonly string[] - actionDelay?: number - autoSubmit?: boolean - submitButtonHidden?: boolean - submitButtonText?: string + placeholder?: string; + defaultValue?: string | number | readonly string[]; + actionDelay?: number; + autoSubmit?: boolean; + submitButtonHidden?: boolean; + submitButtonText?: string; } diff --git a/tranga-website/src/Components/Inputs/TProps.ts b/tranga-website/src/Components/Inputs/TProps.ts index 16e13d6..7134836 100644 --- a/tranga-website/src/Components/Inputs/TProps.ts +++ b/tranga-website/src/Components/Inputs/TProps.ts @@ -1,4 +1,4 @@ -import { ColorPaletteProp } from '@mui/joy' +import { ColorPaletteProp } from '@mui/joy'; export enum TState { clean, @@ -11,30 +11,30 @@ export enum TState { export const TDisabled = (state: TState): boolean => { switch (state) { case TState.busy: - return true + return true; default: - return false + return false; } -} +}; export const TColor = (state: TState): ColorPaletteProp => { switch (state) { case TState.clean: - return 'primary' + return 'primary'; case TState.dirty: - return 'warning' + return 'warning'; case TState.busy: - return 'neutral' + return 'neutral'; case TState.success: - return 'success' + return 'success'; case TState.failure: - return 'warning' + return 'warning'; } -} +}; export default interface TProps { - disabled?: boolean + disabled?: boolean; completionAction?: ( value?: string | number | readonly string[] - ) => Promise + ) => Promise; } diff --git a/tranga-website/src/Components/Mangas/MangaCard.tsx b/tranga-website/src/Components/Mangas/MangaCard.tsx index 12bef01..18f1ced 100644 --- a/tranga-website/src/Components/Mangas/MangaCard.tsx +++ b/tranga-website/src/Components/Mangas/MangaCard.tsx @@ -6,19 +6,19 @@ import { ColorPaletteProp, Skeleton, Typography, -} from '@mui/joy' -import { EventHandler, ReactNode, useContext } from 'react' -import './MangaCard.css' -import MangaConnectorIcon from './MangaConnectorIcon.tsx' +} from '@mui/joy'; +import { EventHandler, ReactNode, useContext } from 'react'; +import './MangaCard.css'; +import MangaConnectorIcon from './MangaConnectorIcon.tsx'; import { Manga, MangaReleaseStatus, MinimalManga, -} from '../../api/data-contracts.ts' -import { ApiContext } from '../../contexts/ApiContext.tsx' +} from '../../api/data-contracts.ts'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; export default function MangaCard(props: MangaCardProps): ReactNode { - const Api = useContext(ApiContext) + const Api = useContext(ApiContext); return ( - + )}> + - ) + ); } export interface MangaCardProps { - manga?: Manga | MinimalManga - onClick?: EventHandler + manga?: Manga | MinimalManga; + onClick?: EventHandler; } const stringWithRandomLength = (): string => { - return 'wow' -} + return 'wow'; +}; const releaseColor = (status: MangaReleaseStatus): ColorPaletteProp => { switch (status) { case MangaReleaseStatus.Cancelled: - return 'danger' + return 'danger'; case MangaReleaseStatus.Completed: - return 'success' + return 'success'; case MangaReleaseStatus.Unreleased: - return 'neutral' + return 'neutral'; case MangaReleaseStatus.Continuing: - return 'primary' + return 'primary'; case MangaReleaseStatus.OnHiatus: - return 'neutral' + return 'neutral'; default: - return 'neutral' + return 'neutral'; } -} +}; diff --git a/tranga-website/src/Components/Mangas/MangaConnectorIcon.tsx b/tranga-website/src/Components/Mangas/MangaConnectorIcon.tsx index 2b5de12..e7c11bf 100644 --- a/tranga-website/src/Components/Mangas/MangaConnectorIcon.tsx +++ b/tranga-website/src/Components/Mangas/MangaConnectorIcon.tsx @@ -1,33 +1,33 @@ -import { ReactNode, useContext, useEffect, useState } from 'react' -import { MangaConnector } from '../../api/data-contracts.ts' -import { Tooltip } from '@mui/joy' -import { ApiContext } from '../../contexts/ApiContext.tsx' +import { ReactNode, useContext, useEffect, useState } from 'react'; +import { MangaConnector } from '../../api/data-contracts.ts'; +import { Tooltip } from '@mui/joy'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; export default function MangaConnectorIcon({ mangaConnector, mangaConnectorName, }: { - mangaConnector?: MangaConnector - mangaConnectorName?: string + mangaConnector?: MangaConnector; + mangaConnectorName?: string; }): ReactNode { - const Api = useContext(ApiContext) + const Api = useContext(ApiContext); const [connector, setConnector] = useState( mangaConnector - ) + ); useEffect(() => { if (mangaConnector) { - setConnector(mangaConnector) - return + setConnector(mangaConnector); + return; } - if (!mangaConnectorName) return + if (!mangaConnectorName) return; Api.mangaConnectorDetail(mangaConnectorName).then((result) => { if (result.ok) { - setConnector(result.data) + setConnector(result.data); } - }) - }, [Api, mangaConnectorName, mangaConnector]) + }); + }, [Api, mangaConnectorName, mangaConnector]); return ( @@ -38,5 +38,5 @@ export default function MangaConnectorIcon({ style={{ borderRadius: '100%' }} /> - ) + ); } diff --git a/tranga-website/src/Components/Mangas/MangaList.tsx b/tranga-website/src/Components/Mangas/MangaList.tsx index b74d5d4..1f6b663 100644 --- a/tranga-website/src/Components/Mangas/MangaList.tsx +++ b/tranga-website/src/Components/Mangas/MangaList.tsx @@ -1,29 +1,31 @@ -import { Stack } from '@mui/joy' -import './MangaList.css' -import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react' +import { Stack } from '@mui/joy'; +import './MangaList.css'; +import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react'; import { Manga, MangaReleaseStatus, MinimalManga, -} from '../../api/data-contracts.ts' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import MangaCard from './MangaCard.tsx' +} from '../../api/data-contracts.ts'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import MangaCard from './MangaCard.tsx'; export default function MangaList({ openSearch, }: { - openSearch: () => void + openSearch: () => void; }): ReactNode { - const Api = useContext(ApiContext) - const [downloadingManga, setDownloadingManga] = useState([]) + const Api = useContext(ApiContext); + const [downloadingManga, setDownloadingManga] = useState( + [] + ); useEffect(() => { Api.mangaDownloadingList().then((data) => { if (data.ok) { - setDownloadingManga(data.data) + setDownloadingManga(data.data); } - }) - }, [Api]) + }); + }, [Api]); return ( @@ -38,7 +40,7 @@ export default function MangaList({ }} /> - ) + ); } export function MangaCardList(props: MangaCardListProps): ReactNode { @@ -52,24 +54,23 @@ export function MangaCardList(props: MangaCardListProps): ReactNode { px: 'var(--ModalDialog-padding)', overflowY: 'scroll', justifyItems: 'space-between', - }} - > + }}> {props.children} {props.manga.map((m) => ( { - if (props.mangaOnClick) props.mangaOnClick(m) + if (props.mangaOnClick) props.mangaOnClick(m); }} /> ))} - ) + ); } export interface MangaCardListProps { - manga: (Manga | MinimalManga)[] - children?: ReactNode - mangaOnClick?: Dispatch + manga: (Manga | MinimalManga)[]; + children?: ReactNode; + mangaOnClick?: Dispatch; } diff --git a/tranga-website/src/Components/Settings/ChapterNamingScheme.tsx b/tranga-website/src/Components/Settings/ChapterNamingScheme.tsx index 061fdc9..852ae40 100644 --- a/tranga-website/src/Components/Settings/ChapterNamingScheme.tsx +++ b/tranga-website/src/Components/Settings/ChapterNamingScheme.tsx @@ -1,26 +1,26 @@ -import { ReactNode, useContext } from 'react' -import { SettingsContext, SettingsItem } from './Settings.tsx' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import MarkdownPreview from '@uiw/react-markdown-preview' -import TInput from '../Inputs/TInput.tsx' +import { ReactNode, useContext } from 'react'; +import { SettingsContext, SettingsItem } from './Settings.tsx'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import MarkdownPreview from '@uiw/react-markdown-preview'; +import TInput from '../Inputs/TInput.tsx'; export default function ChapterNamingScheme(): ReactNode { - const settings = useContext(SettingsContext) - const Api = useContext(ApiContext) + const settings = useContext(SettingsContext); + const Api = useContext(ApiContext); const schemeChanged = async ( value: string | number | readonly string[] | undefined ) => { - if (typeof value != 'string') return Promise.reject() + if (typeof value != 'string') return Promise.reject(); try { const response = - await Api.settingsChapterNamingSchemePartialUpdate(value) - if (response.ok) return Promise.resolve() - else return Promise.reject() + await Api.settingsChapterNamingSchemePartialUpdate(value); + if (response.ok) return Promise.resolve(); + else return Promise.reject(); } catch { - return await Promise.reject() + return await Promise.reject(); } - } + }; return ( @@ -37,5 +37,5 @@ export default function ChapterNamingScheme(): ReactNode { actionDelay={5000} /> - ) + ); } diff --git a/tranga-website/src/Components/Settings/Download.tsx b/tranga-website/src/Components/Settings/Download.tsx index 7a70482..d3476f8 100644 --- a/tranga-website/src/Components/Settings/Download.tsx +++ b/tranga-website/src/Components/Settings/Download.tsx @@ -1,7 +1,7 @@ -import { SettingsItem } from './Settings.tsx' -import ImageCompression from './ImageCompression.tsx' -import DownloadLanguage from './DownloadLanguage.tsx' -import ChapterNamingScheme from './ChapterNamingScheme.tsx' +import { SettingsItem } from './Settings.tsx'; +import ImageCompression from './ImageCompression.tsx'; +import DownloadLanguage from './DownloadLanguage.tsx'; +import ChapterNamingScheme from './ChapterNamingScheme.tsx'; export default function Download() { return ( @@ -10,5 +10,5 @@ export default function Download() { - ) + ); } diff --git a/tranga-website/src/Components/Settings/DownloadLanguage.tsx b/tranga-website/src/Components/Settings/DownloadLanguage.tsx index ef3a828..3e0e665 100644 --- a/tranga-website/src/Components/Settings/DownloadLanguage.tsx +++ b/tranga-website/src/Components/Settings/DownloadLanguage.tsx @@ -1,25 +1,25 @@ -import { ReactNode, useContext } from 'react' -import { SettingsContext, SettingsItem } from './Settings.tsx' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import TInput from '../Inputs/TInput.tsx' +import { ReactNode, useContext } from 'react'; +import { SettingsContext, SettingsItem } from './Settings.tsx'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import TInput from '../Inputs/TInput.tsx'; export default function DownloadLanguage(): ReactNode { - const settings = useContext(SettingsContext) - const Api = useContext(ApiContext) + const settings = useContext(SettingsContext); + const Api = useContext(ApiContext); const languageChanged = async ( value: string | number | readonly string[] | undefined ) => { - if (typeof value != 'string') return Promise.reject() + if (typeof value != 'string') return Promise.reject(); try { const response = - await Api.settingsDownloadLanguagePartialUpdate(value) - if (response.ok) return Promise.resolve() - else return Promise.reject() + await Api.settingsDownloadLanguagePartialUpdate(value); + if (response.ok) return Promise.resolve(); + else return Promise.reject(); } catch { - return await Promise.reject() + return await Promise.reject(); } - } + }; return ( @@ -29,5 +29,5 @@ export default function DownloadLanguage(): ReactNode { completionAction={languageChanged} /> - ) + ); } diff --git a/tranga-website/src/Components/Settings/FlareSolverr.tsx b/tranga-website/src/Components/Settings/FlareSolverr.tsx index 08f17ab..a1713b0 100644 --- a/tranga-website/src/Components/Settings/FlareSolverr.tsx +++ b/tranga-website/src/Components/Settings/FlareSolverr.tsx @@ -1,24 +1,24 @@ -import { ReactNode, useContext } from 'react' -import { SettingsContext, SettingsItem } from './Settings.tsx' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import TInput from '../Inputs/TInput.tsx' +import { ReactNode, useContext } from 'react'; +import { SettingsContext, SettingsItem } from './Settings.tsx'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import TInput from '../Inputs/TInput.tsx'; export default function FlareSolverr(): ReactNode { - const settings = useContext(SettingsContext) - const Api = useContext(ApiContext) + const settings = useContext(SettingsContext); + const Api = useContext(ApiContext); const uriChanged = async ( value: string | number | readonly string[] | undefined ) => { - if (typeof value != 'string') return Promise.reject() + if (typeof value != 'string') return Promise.reject(); try { - const response = await Api.settingsFlareSolverrUrlCreate(value) - if (response.ok) return Promise.resolve() - else return Promise.reject() + const response = await Api.settingsFlareSolverrUrlCreate(value); + if (response.ok) return Promise.resolve(); + else return Promise.reject(); } catch (reason) { - return await Promise.reject(reason) + return await Promise.reject(reason); } - } + }; return ( @@ -28,5 +28,5 @@ export default function FlareSolverr(): ReactNode { completionAction={uriChanged} /> - ) + ); } diff --git a/tranga-website/src/Components/Settings/ImageCompression.tsx b/tranga-website/src/Components/Settings/ImageCompression.tsx index 43b3353..b93bcb7 100644 --- a/tranga-website/src/Components/Settings/ImageCompression.tsx +++ b/tranga-website/src/Components/Settings/ImageCompression.tsx @@ -1,17 +1,16 @@ -import { ReactNode, useContext } from 'react' -import { SettingsContext, SettingsItem } from './Settings.tsx' -import { Slider } from '@mui/joy' +import { ReactNode, useContext } from 'react'; +import { SettingsContext, SettingsItem } from './Settings.tsx'; +import { Slider } from '@mui/joy'; export default function ImageCompression(): ReactNode { - const settings = useContext(SettingsContext) + const settings = useContext(SettingsContext); return ( + defaultValue={settings?.imageCompression}> - ) + ); } diff --git a/tranga-website/src/Components/Settings/Maintenance.tsx b/tranga-website/src/Components/Settings/Maintenance.tsx index f61f2ee..116dbbe 100644 --- a/tranga-website/src/Components/Settings/Maintenance.tsx +++ b/tranga-website/src/Components/Settings/Maintenance.tsx @@ -1,20 +1,20 @@ -import { SettingsItem } from './Settings.tsx' -import { useContext } from 'react' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import TButton from '../Inputs/TButton.tsx' +import { SettingsItem } from './Settings.tsx'; +import { useContext } from 'react'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import TButton from '../Inputs/TButton.tsx'; export default function Maintenance() { - const Api = useContext(ApiContext) + const Api = useContext(ApiContext); const cleanUnusedManga = async (): Promise => { try { - const result = await Api.maintenanceCleanupNoDownloadMangaCreate() - if (result.ok) return Promise.resolve() - else return Promise.reject() + const result = await Api.maintenanceCleanupNoDownloadMangaCreate(); + if (result.ok) return Promise.resolve(); + else return Promise.reject(); } catch (reason) { - return await Promise.reject(reason) + return await Promise.reject(reason); } - } + }; return ( @@ -22,5 +22,5 @@ export default function Maintenance() { Cleanup unused Manga - ) + ); } diff --git a/tranga-website/src/Components/Settings/Services.tsx b/tranga-website/src/Components/Settings/Services.tsx index 94f6885..92d99fb 100644 --- a/tranga-website/src/Components/Settings/Services.tsx +++ b/tranga-website/src/Components/Settings/Services.tsx @@ -1,11 +1,11 @@ -import { SettingsItem } from './Settings.tsx' -import FlareSolverr from './FlareSolverr.tsx' -import { ReactNode } from 'react' +import { SettingsItem } from './Settings.tsx'; +import FlareSolverr from './FlareSolverr.tsx'; +import { ReactNode } from 'react'; export default function Services(): ReactNode { return ( - ) + ); } diff --git a/tranga-website/src/Components/Settings/Settings.tsx b/tranga-website/src/Components/Settings/Settings.tsx index 52289ed..77a3fad 100644 --- a/tranga-website/src/Components/Settings/Settings.tsx +++ b/tranga-website/src/Components/Settings/Settings.tsx @@ -1,4 +1,4 @@ -import ModalClose from '@mui/joy/ModalClose' +import ModalClose from '@mui/joy/ModalClose'; import { Accordion, AccordionDetails, @@ -9,63 +9,62 @@ import { DialogTitle, Modal, ModalDialog, -} from '@mui/joy' -import './Settings.css' -import * as React from 'react' +} from '@mui/joy'; +import './Settings.css'; +import * as React from 'react'; import { createContext, ReactNode, useContext, useEffect, useState, -} from 'react' -import { SxProps } from '@mui/joy/styles/types' -import ImageCompression from './ImageCompression.tsx' -import FlareSolverr from './FlareSolverr.tsx' -import DownloadLanguage from './DownloadLanguage.tsx' -import ChapterNamingScheme from './ChapterNamingScheme.tsx' -import Maintenance from './Maintenance.tsx' -import { ApiContext } from '../../contexts/ApiContext.tsx' -import { TrangaSettings } from '../../api/data-contracts.ts' -import TInput from '../Inputs/TInput.tsx' +} from 'react'; +import { SxProps } from '@mui/joy/styles/types'; +import ImageCompression from './ImageCompression.tsx'; +import FlareSolverr from './FlareSolverr.tsx'; +import DownloadLanguage from './DownloadLanguage.tsx'; +import ChapterNamingScheme from './ChapterNamingScheme.tsx'; +import Maintenance from './Maintenance.tsx'; +import { ApiContext } from '../../contexts/ApiContext.tsx'; +import { TrangaSettings } from '../../api/data-contracts.ts'; +import TInput from '../Inputs/TInput.tsx'; export const SettingsContext = createContext( undefined -) +); export default function Settings({ setApiUri, }: { - setApiUri: (uri: string) => void + setApiUri: (uri: string) => void; }) { - const Api = useContext(ApiContext) - const [settings, setSettings] = useState() + const Api = useContext(ApiContext); + const [settings, setSettings] = useState(); - const [open, setOpen] = React.useState(false) + const [open, setOpen] = React.useState(false); useEffect(() => { Api.settingsList().then((response) => { - setSettings(response.data) - }) - }, [Api]) + setSettings(response.data); + }); + }, [Api]); const apiUriChanged = ( value: string | number | readonly string[] | undefined ) => { - if (typeof value != 'string') return Promise.reject() - setApiUri(value) - return Promise.resolve() - } + if (typeof value != 'string') return Promise.reject(); + setApiUri(value); + return Promise.resolve(); + }; - const ModalStyle: SxProps = { - width: '80%', - height: '80%', - } + const ModalStyle: SxProps = { width: '80%', height: '80%' }; return ( - setOpen(false)}> + setOpen(false)}> Settings @@ -88,20 +87,20 @@ export default function Settings({ - ) + ); } export function SettingsItem({ title, children, }: { - title: string - children: ReactNode + title: string; + children: ReactNode; }) { return ( {title} {children} - ) + ); } diff --git a/tranga-website/src/Header.tsx b/tranga-website/src/Header.tsx index 4bdc4d9..53964ec 100644 --- a/tranga-website/src/Header.tsx +++ b/tranga-website/src/Header.tsx @@ -1,16 +1,16 @@ -import Sheet from '@mui/joy/Sheet' -import { Link, Stack, Typography } from '@mui/joy' -import { ReactElement, ReactNode, useContext } from 'react' -import './Header.css' -import { Article, GitHub } from '@mui/icons-material' -import { ApiContext } from './contexts/ApiContext.tsx' +import Sheet from '@mui/joy/Sheet'; +import { Link, Stack, Typography } from '@mui/joy'; +import { ReactElement, ReactNode, useContext } from 'react'; +import './Header.css'; +import { Article, GitHub } from '@mui/icons-material'; +import { ApiContext } from './contexts/ApiContext.tsx'; export default function Header({ children, }: { - children?: ReactNode + children?: ReactNode; }): ReactElement { - const Api = useContext(ApiContext) + const Api = useContext(ApiContext); return ( @@ -22,13 +22,11 @@ export default function Header({ alignItems: 'center', justifyContent: 'space-between', }} - useFlexGap - > + useFlexGap> + spacing={2}> {children} + direction={'row'}> + }}> Tranga @@ -65,35 +61,31 @@ export default function Header({ justifyContent: 'flex-end', }} direction={'row'} - spacing={2} - > + spacing={2}> + height={'min-content'}> Server + height={'min-content'}> Website + height={'min-content'}>
Swagger - ) + ); } diff --git a/tranga-website/src/MangaDetail.tsx b/tranga-website/src/MangaDetail.tsx index 7da15bf..bcd69bd 100644 --- a/tranga-website/src/MangaDetail.tsx +++ b/tranga-website/src/MangaDetail.tsx @@ -1,5 +1,5 @@ -import { Manga } from './api/data-contracts.ts' -import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react' +import { Manga } from './api/data-contracts.ts'; +import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react'; import { Card, CardCover, @@ -9,30 +9,32 @@ import { Stack, Typography, useTheme, -} from '@mui/joy' -import ModalClose from '@mui/joy/ModalClose' -import { ApiContext } from './contexts/ApiContext.tsx' -import { MangaContext } from './contexts/MangaContext.tsx' -import './Components/Mangas/MangaCard.css' -import MarkdownPreview from '@uiw/react-markdown-preview' +} from '@mui/joy'; +import ModalClose from '@mui/joy/ModalClose'; +import { ApiContext } from './contexts/ApiContext.tsx'; +import { MangaContext } from './contexts/MangaContext.tsx'; +import './Components/Mangas/MangaCard.css'; +import MarkdownPreview from '@uiw/react-markdown-preview'; export default function MangaDetail(props: MangaDetailProps): ReactNode { - const Api = useContext(ApiContext) - const Manga = useContext(MangaContext) + const Api = useContext(ApiContext); + const Manga = useContext(MangaContext); - const [manga, setManga] = useState(props.manga) + const [manga, setManga] = useState(props.manga); useEffect(() => { - if (!props.open) return - if (!props.mangaKey) return - if (props.manga != undefined) return - Manga.GetManga(props.mangaKey).then(setManga) - }, [Api, Manga, props]) + if (!props.open) return; + if (!props.mangaKey) return; + if (props.manga != undefined) return; + Manga.GetManga(props.mangaKey).then(setManga); + }, [Api, Manga, props]); - const theme = useTheme() + const theme = useTheme(); return ( - props.setOpen(false)}> + props.setOpen(false)}>
- + }}> + {manga?.name} @@ -59,9 +62,11 @@ export default function MangaDetail(props: MangaDetailProps): ReactNode { - + sx={{ maxWidth: 'calc(100% - 230px)', margin: '5px' }}> + {manga?.tags.map((tag) => ( + }}> {tag} ))} @@ -81,8 +85,7 @@ export default function MangaDetail(props: MangaDetailProps): ReactNode { sx={{ backgroundColor: theme.palette.success.plainColor, - }} - > + }}> {author.name} ))} @@ -93,8 +96,7 @@ export default function MangaDetail(props: MangaDetailProps): ReactNode { sx={{ backgroundColor: theme.palette.neutral.plainColor, - }} - > + }}> {link.provider} ))} @@ -116,20 +118,19 @@ export default function MangaDetail(props: MangaDetailProps): ReactNode { alignItems: 'flex-end', }} flexWrap={'nowrap'} - gap={1} - > + gap={1}> {props.actions}
- ) + ); } export interface MangaDetailProps { - manga?: Manga - mangaKey?: string - open: boolean - setOpen: Dispatch - actions?: ReactNode[] + manga?: Manga; + mangaKey?: string; + open: boolean; + setOpen: Dispatch; + actions?: ReactNode[]; } diff --git a/tranga-website/src/MangaDownloadDrawer.tsx b/tranga-website/src/MangaDownloadDrawer.tsx index b2c8439..fd4ee62 100644 --- a/tranga-website/src/MangaDownloadDrawer.tsx +++ b/tranga-website/src/MangaDownloadDrawer.tsx @@ -1,4 +1,4 @@ -import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react' +import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react'; import { Box, Card, @@ -10,56 +10,56 @@ import { Select, Stack, Typography, -} from '@mui/joy' -import ModalClose from '@mui/joy/ModalClose' -import { FileLibrary, Manga, MangaConnectorId } from './api/data-contracts.ts' -import { ApiContext } from './contexts/ApiContext.tsx' -import { MangaContext } from './contexts/MangaContext.tsx' -import { FileLibraryContext } from './contexts/FileLibraryContext.tsx' -import MangaConnectorIcon from './Components/Mangas/MangaConnectorIcon.tsx' -import TButton from './Components/Inputs/TButton.tsx' +} from '@mui/joy'; +import ModalClose from '@mui/joy/ModalClose'; +import { FileLibrary, Manga, MangaConnectorId } from './api/data-contracts.ts'; +import { ApiContext } from './contexts/ApiContext.tsx'; +import { MangaContext } from './contexts/MangaContext.tsx'; +import { FileLibraryContext } from './contexts/FileLibraryContext.tsx'; +import MangaConnectorIcon from './Components/Mangas/MangaConnectorIcon.tsx'; +import TButton from './Components/Inputs/TButton.tsx'; export default function MangaDownloadDrawer( props: MangaDownloadDrawerProps ): ReactNode { - const Api = useContext(ApiContext) - const Manga = useContext(MangaContext) - const Libraries = useContext(FileLibraryContext) + const Api = useContext(ApiContext); + const Manga = useContext(MangaContext); + const Libraries = useContext(FileLibraryContext); - const [manga, setManga] = useState(props.manga) - const [library, setLibrary] = useState() + const [manga, setManga] = useState(props.manga); + const [library, setLibrary] = useState(); const [downloadFromMap, setDownloadFromMap] = useState< Map - >(new Map()) + >(new Map()); useEffect(() => { - if (!props.open) return - if (!props.mangaKey) return - if (props.manga != undefined) return - Manga.GetManga(props.mangaKey).then(setManga) - }, [Api, Manga, props]) + if (!props.open) return; + if (!props.mangaKey) return; + if (props.manga != undefined) return; + Manga.GetManga(props.mangaKey).then(setManga); + }, [Api, Manga, props]); useEffect(() => { - const newMap = new Map() + const newMap = new Map(); setLibrary( Libraries.find((library) => library.key == manga?.fileLibraryId) - ) + ); manga?.mangaConnectorIds.forEach((id) => { - newMap.set(id, id.useForDownload) - }) - setDownloadFromMap(newMap) - }, [manga]) + newMap.set(id, id.useForDownload); + }); + setDownloadFromMap(newMap); + }, [manga]); const setDownload = async (): Promise => { - if (!manga) return Promise.reject() + if (!manga) return Promise.reject(); if (library) { const s = await Api.mangaChangeLibraryCreate( manga.key, library?.key ) .then((result) => result.ok) - .catch(() => false) - if (!s) return Promise.reject() + .catch(() => false); + if (!s) return Promise.reject(); } for (const kv of downloadFromMap) { const s = await Api.mangaSetAsDownloadFromCreate( @@ -68,28 +68,30 @@ export default function MangaDownloadDrawer( kv[1] ) .then((result) => result.ok) - .catch(() => false) - if (!s) return Promise.reject() + .catch(() => false); + if (!s) return Promise.reject(); } - return Promise.resolve() - } + return Promise.resolve(); + }; const onLibraryChange = (_: any, value: string | null) => { - setLibrary(Libraries.find((library) => library.key == value)) - } + setLibrary(Libraries.find((library) => library.key == value)); + }; return ( props.setOpen(false)} anchor="left" - size="md" - > + size="md"> Download {manga?.name} - + Select a Library to Download to: @@ -97,10 +99,11 @@ export default function MangaDownloadDrawer(