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(
- )
+ );
}
export interface MangaDownloadDrawerProps {
- manga?: Manga
- mangaKey?: string
- open: boolean
- setOpen: Dispatch
+ manga?: Manga;
+ mangaKey?: string;
+ open: boolean;
+ setOpen: Dispatch;
}
diff --git a/tranga-website/src/Search.tsx b/tranga-website/src/Search.tsx
index e6b49a3..0e33b0c 100644
--- a/tranga-website/src/Search.tsx
+++ b/tranga-website/src/Search.tsx
@@ -1,4 +1,4 @@
-import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react'
+import { Dispatch, ReactNode, useContext, useEffect, useState } from 'react';
import {
Button,
List,
@@ -10,89 +10,91 @@ import {
StepIndicator,
Stepper,
Typography,
-} from '@mui/joy'
-import ModalClose from '@mui/joy/ModalClose'
-import { MangaConnectorContext } from './contexts/MangaConnectorContext.tsx'
-import MangaConnectorIcon from './Components/Mangas/MangaConnectorIcon.tsx'
-import TInput from './Components/Inputs/TInput.tsx'
-import { ApiContext } from './contexts/ApiContext.tsx'
-import { MangaCardList } from './Components/Mangas/MangaList.tsx'
-import { MangaConnector, MinimalManga } from './api/data-contracts.ts'
-import MangaDetail from './MangaDetail.tsx'
-import MangaDownloadDrawer from './MangaDownloadDrawer.tsx'
+} from '@mui/joy';
+import ModalClose from '@mui/joy/ModalClose';
+import { MangaConnectorContext } from './contexts/MangaConnectorContext.tsx';
+import MangaConnectorIcon from './Components/Mangas/MangaConnectorIcon.tsx';
+import TInput from './Components/Inputs/TInput.tsx';
+import { ApiContext } from './contexts/ApiContext.tsx';
+import { MangaCardList } from './Components/Mangas/MangaList.tsx';
+import { MangaConnector, MinimalManga } from './api/data-contracts.ts';
+import MangaDetail from './MangaDetail.tsx';
+import MangaDownloadDrawer from './MangaDownloadDrawer.tsx';
export function Search(props: SearchModalProps): ReactNode {
- const Api = useContext(ApiContext)
- const MangaConnectors = useContext(MangaConnectorContext)
+ const Api = useContext(ApiContext);
+ const MangaConnectors = useContext(MangaConnectorContext);
useEffect(() => {
if (props.open) {
- setSelectedConnector(undefined)
- setSearchResults([])
+ setSelectedConnector(undefined);
+ setSearchResults([]);
}
- }, [props])
+ }, [props]);
- const [selectedConnector, setSelectedConnector] = useState()
- const [searchResults, setSearchResults] = useState([])
+ const [selectedConnector, setSelectedConnector] =
+ useState();
+ const [searchResults, setSearchResults] = useState([]);
const startSearch = async (
value: string | number | readonly string[] | undefined
): Promise => {
- if (typeof value != 'string') return Promise.reject()
- setSearchResults([])
+ if (typeof value != 'string') return Promise.reject();
+ setSearchResults([]);
if (isUrl(value)) {
try {
- const result = await Api.searchUrlCreate(value)
+ const result = await Api.searchUrlCreate(value);
if (result.ok) {
- setSearchResults([result.data])
- return Promise.resolve()
- } else return Promise.reject()
+ setSearchResults([result.data]);
+ return Promise.resolve();
+ } else return Promise.reject();
} catch (reason) {
- return await Promise.reject(reason)
+ return await Promise.reject(reason);
}
} else {
- if (!selectedConnector) return Promise.reject()
+ if (!selectedConnector) return Promise.reject();
try {
const result2 = await Api.searchDetail(
selectedConnector?.key,
value
- )
+ );
if (result2.ok) {
- setSearchResults(result2.data)
- return Promise.resolve()
- } else return Promise.reject()
+ setSearchResults(result2.data);
+ return Promise.resolve();
+ } else return Promise.reject();
} catch (reason1) {
- return await Promise.reject(reason1)
+ return await Promise.reject(reason1);
}
}
- }
+ };
const [selectedManga, setSelectedManga] = useState<
MinimalManga | undefined
- >(undefined)
- const [mangaDetailOpen, setMangaDetailOpen] = useState(false)
+ >(undefined);
+ const [mangaDetailOpen, setMangaDetailOpen] = useState(false);
const [mangaDownloadDrawerOpen, setMangaDownloadDrawerOpen] =
- useState(false)
+ useState(false);
function openMangaDetail(manga: MinimalManga) {
- setSelectedManga(manga)
- setMangaDetailOpen(true)
+ setSelectedManga(manga);
+ setMangaDetailOpen(true);
}
function openMangaDownloadDrawer() {
- setMangaDetailOpen(false)
- setMangaDownloadDrawerOpen(true)
+ setMangaDetailOpen(false);
+ setMangaDownloadDrawerOpen(true);
}
return (
- props.setOpen(false)}>
+ props.setOpen(false)}>
1}
- >
+ indicator={1}>
Select a connector
@@ -100,8 +102,7 @@ export function Search(props: SearchModalProps): ReactNode {
{MangaConnectors.map((c) => (
setSelectedConnector(c)}
- >
+ onClick={() => setSelectedConnector(c)}>
+ }>
{c.name}
@@ -122,8 +122,7 @@ export function Search(props: SearchModalProps): ReactNode {
2}
- >
+ indicator={2}>
Enter a search term or URL
@@ -154,19 +153,19 @@ export function Search(props: SearchModalProps): ReactNode {
/>
- )
+ );
}
export interface SearchModalProps {
- open: boolean
- setOpen: Dispatch
+ open: boolean;
+ setOpen: Dispatch;
}
function isUrl(str: string): boolean {
try {
- new URL(str)
- return true
+ new URL(str);
+ return true;
} catch {
- return false
+ return false;
}
}
diff --git a/tranga-website/src/api/V2.ts b/tranga-website/src/api/V2.ts
index f03c80d..ac6b397 100644
--- a/tranga-website/src/api/V2.ts
+++ b/tranga-website/src/api/V2.ts
@@ -30,8 +30,8 @@ import {
TrangaSettings,
Worker,
WorkerExecutionState,
-} from './data-contracts'
-import { ContentType, HttpClient, RequestParams } from './http-client'
+} from './data-contracts';
+import { ContentType, HttpClient, RequestParams } from './http-client';
export class V2<
SecurityDataType = unknown,
@@ -50,7 +50,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -66,7 +66,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -81,7 +81,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -95,7 +95,7 @@ export class V2<
path: `/v2/FileLibrary/${fileLibraryId}`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -115,7 +115,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -135,7 +135,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -150,7 +150,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -169,7 +169,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -187,7 +187,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -204,7 +204,7 @@ export class V2<
path: `/v2/LibraryConnector/${libraryConnectorId}`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -218,7 +218,7 @@ export class V2<
path: `/v2/Maintenance/CleanupNoDownloadManga`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -233,7 +233,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -248,7 +248,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -263,7 +263,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -280,7 +280,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -295,7 +295,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -309,7 +309,7 @@ export class V2<
path: `/v2/Manga/${mangaId}`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -327,7 +327,7 @@ export class V2<
path: `/v2/Manga/${mangaIdFrom}/MergeInto/${mangaIdInto}`,
method: 'PATCH',
...params,
- })
+ });
/**
* No description
*
@@ -343,12 +343,12 @@ export class V2<
* If width is provided, height needs to also be provided
* @format int32
*/
- width?: number
+ width?: number;
/**
* If height is provided, width needs to also be provided
* @format int32
*/
- height?: number
+ height?: number;
},
params: RequestParams = {}
) =>
@@ -358,7 +358,7 @@ export class V2<
query: query,
format: 'blob',
...params,
- })
+ });
/**
* No description
*
@@ -373,7 +373,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -391,7 +391,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -409,7 +409,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -427,7 +427,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -445,7 +445,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -465,7 +465,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -483,7 +483,7 @@ export class V2<
path: `/v2/Manga/${mangaId}/ChangeLibrary/${libraryId}`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -502,7 +502,7 @@ export class V2<
path: `/v2/Manga/${mangaId}/SetAsDownloadFrom/${mangaConnectorName}/${isRequested}`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -521,7 +521,7 @@ export class V2<
method: 'POST',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -536,7 +536,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -551,7 +551,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -566,7 +566,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -584,7 +584,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -599,7 +599,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -614,7 +614,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -632,7 +632,7 @@ export class V2<
path: `/v2/MangaConnector/${mangaConnectorName}/SetEnabled/${enabled}`,
method: 'PATCH',
...params,
- })
+ });
/**
* No description
*
@@ -647,7 +647,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -662,7 +662,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -684,7 +684,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -706,7 +706,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -724,7 +724,7 @@ export class V2<
path: `/v2/MetadataFetcher/${metadataFetcherName}/Unlink/${mangaId}`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -739,7 +739,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* @description Formatting placeholders: "%title" and "%text" can be placed in url, header-values and body and will be replaced when notifications are sent
*
@@ -759,7 +759,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -774,7 +774,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -788,7 +788,7 @@ export class V2<
path: `/v2/NotificationConnector/${name}`,
method: 'DELETE',
...params,
- })
+ });
/**
* @description Priority needs to be between 0 and 10
*
@@ -808,7 +808,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* @description Priority needs to be between 1 and 5
*
@@ -828,7 +828,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* @description https://pushover.net/api
*
@@ -848,7 +848,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -863,7 +863,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -878,7 +878,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -896,7 +896,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -911,7 +911,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -929,7 +929,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -948,7 +948,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -965,7 +965,7 @@ export class V2<
type: ContentType.Json,
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -980,7 +980,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -994,7 +994,7 @@ export class V2<
path: `/v2/Settings/UserAgent`,
method: 'GET',
...params,
- })
+ });
/**
* No description
*
@@ -1013,7 +1013,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -1027,7 +1027,7 @@ export class V2<
path: `/v2/Settings/UserAgent`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -1040,17 +1040,17 @@ export class V2<
this.request<
{
/** @format int32 */
- Default?: number
+ Default?: number;
/** @format int32 */
- MangaDexFeed?: number
+ MangaDexFeed?: number;
/** @format int32 */
- MangaImage?: number
+ MangaImage?: number;
/** @format int32 */
- MangaCover?: number
+ MangaCover?: number;
/** @format int32 */
- MangaDexImage?: number
+ MangaDexImage?: number;
/** @format int32 */
- MangaInfo?: number
+ MangaInfo?: number;
},
any
>({
@@ -1058,7 +1058,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* @description NOT IMPLEMENTED
*
@@ -1072,7 +1072,7 @@ export class V2<
path: `/v2/Settings/RequestLimits`,
method: 'PATCH',
...params,
- })
+ });
/**
* No description
*
@@ -1087,7 +1087,7 @@ export class V2<
method: 'DELETE',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1109,7 +1109,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -1129,7 +1129,7 @@ export class V2<
method: 'DELETE',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1143,7 +1143,7 @@ export class V2<
path: `/v2/Settings/ImageCompressionLevel`,
method: 'GET',
...params,
- })
+ });
/**
* No description
*
@@ -1160,7 +1160,7 @@ export class V2<
path: `/v2/Settings/ImageCompressionLevel/${level}`,
method: 'PATCH',
...params,
- })
+ });
/**
* No description
*
@@ -1174,7 +1174,7 @@ export class V2<
path: `/v2/Settings/BWImages`,
method: 'GET',
...params,
- })
+ });
/**
* No description
*
@@ -1191,7 +1191,7 @@ export class V2<
path: `/v2/Settings/BWImages/${enabled}`,
method: 'PATCH',
...params,
- })
+ });
/**
* @description Placeholders: %M Obj Name %V Volume %C Chapter %T Title %A Author (first in list) %I Chapter Internal ID %i Obj Internal ID %Y Year (Obj) ?_(...) replace _ with a value from above: Everything inside the braces will only be added if the value of %_ is not null
*
@@ -1205,7 +1205,7 @@ export class V2<
path: `/v2/Settings/ChapterNamingScheme`,
method: 'GET',
...params,
- })
+ });
/**
* @description Placeholders: %M Obj Name %V Volume %C Chapter %T Title %A Author (first in list) %Y Year (Obj) ?_(...) replace _ with a value from above: Everything inside the braces will only be added if the value of %_ is not null
*
@@ -1224,7 +1224,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -1243,7 +1243,7 @@ export class V2<
body: data,
type: ContentType.Json,
...params,
- })
+ });
/**
* No description
*
@@ -1257,7 +1257,7 @@ export class V2<
path: `/v2/Settings/FlareSolverr/Url`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -1271,7 +1271,7 @@ export class V2<
path: `/v2/Settings/FlareSolverr/Test`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -1285,7 +1285,7 @@ export class V2<
path: `/v2/Settings/DownloadLanguage`,
method: 'GET',
...params,
- })
+ });
/**
* No description
*
@@ -1302,7 +1302,7 @@ export class V2<
path: `/v2/Settings/DownloadLanguage/${language}`,
method: 'PATCH',
...params,
- })
+ });
/**
* No description
*
@@ -1317,7 +1317,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1332,7 +1332,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1350,7 +1350,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1365,7 +1365,7 @@ export class V2<
method: 'GET',
format: 'json',
...params,
- })
+ });
/**
* No description
*
@@ -1379,7 +1379,7 @@ export class V2<
path: `/v2/Worker/${workerId}`,
method: 'DELETE',
...params,
- })
+ });
/**
* No description
*
@@ -1393,7 +1393,7 @@ export class V2<
path: `/v2/Worker/${workerId}/Start`,
method: 'POST',
...params,
- })
+ });
/**
* No description
*
@@ -1407,5 +1407,5 @@ export class V2<
path: `/v2/Worker/${workerId}/Stop`,
method: 'POST',
...params,
- })
+ });
}
diff --git a/tranga-website/src/api/data-contracts.ts b/tranga-website/src/api/data-contracts.ts
index 5e38db7..1a162cf 100644
--- a/tranga-website/src/api/data-contracts.ts
+++ b/tranga-website/src/api/data-contracts.ts
@@ -47,12 +47,12 @@ export interface AltTitle {
* Language of the Title
* @minLength 1
*/
- language: string
+ language: string;
/**
* Title
* @minLength 1
*/
- title: string
+ title: string;
}
/** The API.Schema.MangaContext.Author DTO */
@@ -61,13 +61,13 @@ export interface Author {
* Name of the Author.
* @minLength 1
*/
- name: string
+ name: string;
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
/** API.Schema.MangaContext.Chapter DTO */
@@ -76,32 +76,32 @@ export interface Chapter {
* Identifier of the Manga this Chapter belongs to
* @minLength 1
*/
- mangaId: string
+ mangaId: string;
/**
* Volume number
* @format int32
*/
- volume: number
+ volume: number;
/**
* Chapter number
* @minLength 1
*/
- chapterNumber: string
+ chapterNumber: string;
/**
* Title of the Chapter
* @minLength 1
*/
- title: string
+ title: string;
/** Whether Chapter is Downloaded (on disk) */
- downloaded: boolean
+ downloaded: boolean;
/** Ids of the Manga on MangaConnectors */
- mangaConnectorIds: MangaConnectorId[]
+ mangaConnectorIds: MangaConnectorId[];
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
export interface FileLibrary {
@@ -109,45 +109,45 @@ export interface FileLibrary {
* @minLength 0
* @maxLength 256
*/
- basePath: string
+ basePath: string;
/**
* @minLength 0
* @maxLength 512
*/
- libraryName: string
+ libraryName: string;
/**
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
export interface GotifyRecord {
- name?: string | null
- endpoint?: string | null
- appToken?: string | null
+ name?: string | null;
+ endpoint?: string | null;
+ appToken?: string | null;
/** @format int32 */
- priority?: number
+ priority?: number;
}
export interface LibraryConnector {
- libraryType: LibraryType
+ libraryType: LibraryType;
/**
* @format uri
* @minLength 0
* @maxLength 256
*/
- baseUrl: string
+ baseUrl: string;
/**
* @minLength 0
* @maxLength 256
*/
- auth: string
+ auth: string;
/**
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
/** API.Schema.MangaContext.Link DTO */
@@ -156,18 +156,18 @@ export interface Link {
* Name of the Provider
* @minLength 1
*/
- provider: string
+ provider: string;
/**
* Url
* @minLength 1
*/
- url: string
+ url: string;
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
/** API.Schema.MangaContext.Manga DTO */
@@ -176,67 +176,67 @@ export interface Manga {
* Chapter cutoff for Downloads (Chapters before this will not be downloaded)
* @format float
*/
- ignoreChaptersBefore: number
+ ignoreChaptersBefore: number;
/**
* Release Year
* @format int32
*/
- year?: number | null
+ year?: number | null;
/** Release Language */
- originalLanguage?: string | null
+ originalLanguage?: string | null;
/** Keys of ChapterDTOs */
- chapterIds: string[]
+ chapterIds: string[];
/** Author-names */
- authors: Author[]
+ authors: Author[];
/** Manga Tags */
- tags: string[]
+ tags: string[];
/** Links for more Metadata */
- links: Link[]
+ links: Link[];
/** Alt Titles of Manga */
- altTitles: AltTitle[]
+ altTitles: AltTitle[];
/**
* Id of the Library the Manga gets downloaded to
* @minLength 1
*/
- fileLibraryId: string
+ fileLibraryId: string;
/**
* Name of the Manga
* @minLength 1
*/
- name: string
+ name: string;
/**
* Description of the Manga
* @minLength 1
*/
- description: string
- releaseStatus: MangaReleaseStatus
+ description: string;
+ releaseStatus: MangaReleaseStatus;
/** Ids of the Manga on MangaConnectors */
- mangaConnectorIds: MangaConnectorId[]
+ mangaConnectorIds: MangaConnectorId[];
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
export interface MangaConnector {
- name?: string | null
+ name?: string | null;
/** Whether Connector is used for Searches and Downloads */
- enabled: boolean
+ enabled: boolean;
/** Languages supported by the Connector */
- supportedLanguages: string[]
+ supportedLanguages: string[];
/**
* Url of the Website Icon
* @minLength 1
*/
- iconUrl: string
+ iconUrl: string;
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
/** API.Schema.MangaContext.MangaConnectorId`1 DTO */
@@ -245,36 +245,36 @@ export interface MangaConnectorId {
* Name of the Connector
* @minLength 1
*/
- mangaConnectorName: string
+ mangaConnectorName: string;
/**
* Key of the referenced DTO
* @minLength 1
*/
- foreignKey: string
+ foreignKey: string;
/** Website Link for reference, if any */
- websiteUrl?: string | null
+ websiteUrl?: string | null;
/** Whether this Link is used for downloads */
- useForDownload: boolean
+ useForDownload: boolean;
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
export interface MetadataEntry {
- mangaId?: string | null
- metadataFetcherName?: string | null
- identifier?: string | null
+ mangaId?: string | null;
+ metadataFetcherName?: string | null;
+ identifier?: string | null;
}
export interface MetadataSearchResult {
- identifier?: string | null
- name?: string | null
- url?: string | null
- description?: string | null
- coverUrl?: string | null
+ identifier?: string | null;
+ name?: string | null;
+ url?: string | null;
+ description?: string | null;
+ coverUrl?: string | null;
}
/** Shortened Version of API.Controllers.DTOs.Manga */
@@ -283,21 +283,21 @@ export interface MinimalManga {
* Name of the Manga
* @minLength 1
*/
- name: string
+ name: string;
/**
* Description of the Manga
* @minLength 1
*/
- description: string
- releaseStatus: MangaReleaseStatus
+ description: string;
+ releaseStatus: MangaReleaseStatus;
/** Ids of the Manga on MangaConnectors */
- mangaConnectorIds: MangaConnectorId[]
+ mangaConnectorIds: MangaConnectorId[];
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
export interface NotificationConnector {
@@ -305,59 +305,59 @@ export interface NotificationConnector {
* @minLength 0
* @maxLength 64
*/
- name: string
+ name: string;
/**
* @format uri
* @minLength 0
* @maxLength 2048
*/
- url: string
- headers: Record
+ url: string;
+ headers: Record;
/**
* @minLength 0
* @maxLength 8
*/
- httpMethod: string
+ httpMethod: string;
/**
* @minLength 0
* @maxLength 4096
*/
- body: string
+ body: string;
}
export interface NtfyRecord {
- name?: string | null
- endpoint?: string | null
- username?: string | null
- password?: string | null
- topic?: string | null
+ name?: string | null;
+ endpoint?: string | null;
+ username?: string | null;
+ password?: string | null;
+ topic?: string | null;
/** @format int32 */
- priority?: number
+ priority?: number;
}
export interface ProblemDetails {
- type?: string | null
- title?: string | null
+ type?: string | null;
+ title?: string | null;
/** @format int32 */
- status?: number | null
- detail?: string | null
- instance?: string | null
- [key: string]: any
+ status?: number | null;
+ detail?: string | null;
+ instance?: string | null;
+ [key: string]: any;
}
export interface PushoverRecord {
- name?: string | null
- appToken?: string | null
- user?: string | null
+ name?: string | null;
+ appToken?: string | null;
+ user?: string | null;
}
export interface TrangaSettings {
- downloadLocation?: string | null
- userAgent?: string | null
+ downloadLocation?: string | null;
+ userAgent?: string | null;
/** @format int32 */
- imageCompression?: number
- blackWhiteImages?: boolean
- flareSolverrUrl?: string | null
+ imageCompression?: number;
+ blackWhiteImages?: boolean;
+ flareSolverrUrl?: string | null;
/**
* Placeholders:
* %M Obj Name
@@ -372,39 +372,39 @@ export interface TrangaSettings {
* ?_(...) replace _ with a value from above:
* Everything inside the braces will only be added if the value of %_ is not null
*/
- chapterNamingScheme?: string | null
+ chapterNamingScheme?: string | null;
/** @format int32 */
- workCycleTimeoutMs?: number
+ workCycleTimeoutMs?: number;
requestLimits?: {
/** @format int32 */
- Default?: number
+ Default?: number;
/** @format int32 */
- MangaDexFeed?: number
+ MangaDexFeed?: number;
/** @format int32 */
- MangaImage?: number
+ MangaImage?: number;
/** @format int32 */
- MangaCover?: number
+ MangaCover?: number;
/** @format int32 */
- MangaDexImage?: number
+ MangaDexImage?: number;
/** @format int32 */
- MangaInfo?: number
- } | null
- downloadLanguage?: string | null
+ MangaInfo?: number;
+ } | null;
+ downloadLanguage?: string | null;
}
/** API.Workers.BaseWorker DTO */
export interface Worker {
/** Workers this worker depends on having ran. */
- dependencies: string[]
+ dependencies: string[];
/** Workers that have not yet ran, that need to run for this Worker to run. */
- missingDependencies: string[]
+ missingDependencies: string[];
/** Worker can run. */
- dependenciesFulfilled: boolean
- state: WorkerExecutionState
+ dependenciesFulfilled: boolean;
+ state: WorkerExecutionState;
/**
* Unique Identifier of the DTO
* @minLength 16
* @maxLength 64
*/
- key: string
+ key: string;
}
diff --git a/tranga-website/src/api/http-client.ts b/tranga-website/src/api/http-client.ts
index cea23f4..a4b9646 100644
--- a/tranga-website/src/api/http-client.ts
+++ b/tranga-website/src/api/http-client.ts
@@ -10,49 +10,49 @@
* ---------------------------------------------------------------
*/
-export type QueryParamsType = Record
-export type ResponseFormat = keyof Omit
+export type QueryParamsType = Record;
+export type ResponseFormat = keyof Omit;
export interface FullRequestParams extends Omit {
/** set parameter to `true` for call `securityWorker` for this request */
- secure?: boolean
+ secure?: boolean;
/** request path */
- path: string
+ path: string;
/** content type of request body */
- type?: ContentType
+ type?: ContentType;
/** query params */
- query?: QueryParamsType
+ query?: QueryParamsType;
/** format of response (i.e. response.json() -> format: "json") */
- format?: ResponseFormat
+ format?: ResponseFormat;
/** request body */
- body?: unknown
+ body?: unknown;
/** base url */
- baseUrl?: string
+ baseUrl?: string;
/** request cancellation token */
- cancelToken?: CancelToken
+ cancelToken?: CancelToken;
}
export type RequestParams = Omit<
FullRequestParams,
'body' | 'method' | 'query' | 'path'
->
+>;
export interface ApiConfig {
- baseUrl?: string
- baseApiParams?: Omit
+ baseUrl?: string;
+ baseApiParams?: Omit;
securityWorker?: (
securityData: SecurityDataType | null
- ) => Promise | RequestParams | void
- customFetch?: typeof fetch
+ ) => Promise | RequestParams | void;
+ customFetch?: typeof fetch;
}
export interface HttpResponse
extends Response {
- data: D
- error: E
+ data: D;
+ error: E;
}
-type CancelToken = Symbol | string | number
+type CancelToken = Symbol | string | number;
export enum ContentType {
Json = 'application/json',
@@ -63,59 +63,59 @@ export enum ContentType {
}
export class HttpClient {
- public baseUrl: string = ''
- private securityData: SecurityDataType | null = null
- private securityWorker?: ApiConfig['securityWorker']
- private abortControllers = new Map()
+ public baseUrl: string = '';
+ private securityData: SecurityDataType | null = null;
+ private securityWorker?: ApiConfig['securityWorker'];
+ private abortControllers = new Map();
private customFetch = (...fetchParams: Parameters) =>
- fetch(...fetchParams)
+ fetch(...fetchParams);
private baseApiParams: RequestParams = {
credentials: 'same-origin',
headers: {},
redirect: 'follow',
referrerPolicy: 'no-referrer',
- }
+ };
constructor(apiConfig: ApiConfig = {}) {
- Object.assign(this, apiConfig)
+ Object.assign(this, apiConfig);
}
public setSecurityData = (data: SecurityDataType | null) => {
- this.securityData = data
- }
+ this.securityData = data;
+ };
protected encodeQueryParam(key: string, value: any) {
- const encodedKey = encodeURIComponent(key)
- return `${encodedKey}=${encodeURIComponent(typeof value === 'number' ? value : `${value}`)}`
+ const encodedKey = encodeURIComponent(key);
+ return `${encodedKey}=${encodeURIComponent(typeof value === 'number' ? value : `${value}`)}`;
}
protected addQueryParam(query: QueryParamsType, key: string) {
- return this.encodeQueryParam(key, query[key])
+ return this.encodeQueryParam(key, query[key]);
}
protected addArrayQueryParam(query: QueryParamsType, key: string) {
- const value = query[key]
- return value.map((v: any) => this.encodeQueryParam(key, v)).join('&')
+ const value = query[key];
+ return value.map((v: any) => this.encodeQueryParam(key, v)).join('&');
}
protected toQueryString(rawQuery?: QueryParamsType): string {
- const query = rawQuery || {}
+ const query = rawQuery || {};
const keys = Object.keys(query).filter(
(key) => 'undefined' !== typeof query[key]
- )
+ );
return keys
.map((key) =>
Array.isArray(query[key])
? this.addArrayQueryParam(query, key)
: this.addQueryParam(query, key)
)
- .join('&')
+ .join('&');
}
protected addQueryParams(rawQuery?: QueryParamsType): string {
- const queryString = this.toQueryString(rawQuery)
- return queryString ? `?${queryString}` : ''
+ const queryString = this.toQueryString(rawQuery);
+ return queryString ? `?${queryString}` : '';
}
private contentFormatters: Record any> = {
@@ -135,7 +135,7 @@ export class HttpClient {
: input,
[ContentType.FormData]: (input: any) =>
Object.keys(input || {}).reduce((formData, key) => {
- const property = input[key]
+ const property = input[key];
formData.append(
key,
property instanceof Blob
@@ -143,11 +143,11 @@ export class HttpClient {
: typeof property === 'object' && property !== null
? JSON.stringify(property)
: `${property}`
- )
- return formData
+ );
+ return formData;
}, new FormData()),
[ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
- }
+ };
protected mergeRequestParams(
params1: RequestParams,
@@ -162,33 +162,33 @@ export class HttpClient {
...(params1.headers || {}),
...((params2 && params2.headers) || {}),
},
- }
+ };
}
protected createAbortSignal = (
cancelToken: CancelToken
): AbortSignal | undefined => {
if (this.abortControllers.has(cancelToken)) {
- const abortController = this.abortControllers.get(cancelToken)
+ const abortController = this.abortControllers.get(cancelToken);
if (abortController) {
- return abortController.signal
+ return abortController.signal;
}
- return void 0
+ return void 0;
}
- const abortController = new AbortController()
- this.abortControllers.set(cancelToken, abortController)
- return abortController.signal
- }
+ const abortController = new AbortController();
+ this.abortControllers.set(cancelToken, abortController);
+ return abortController.signal;
+ };
public abortRequest = (cancelToken: CancelToken) => {
- const abortController = this.abortControllers.get(cancelToken)
+ const abortController = this.abortControllers.get(cancelToken);
if (abortController) {
- abortController.abort()
- this.abortControllers.delete(cancelToken)
+ abortController.abort();
+ this.abortControllers.delete(cancelToken);
}
- }
+ };
public request = async ({
body,
@@ -207,12 +207,12 @@ export class HttpClient {
: this.baseApiParams.secure) &&
this.securityWorker &&
(await this.securityWorker(this.securityData))) ||
- {}
- const requestParams = this.mergeRequestParams(params, secureParams)
- const queryString = query && this.toQueryString(query)
+ {};
+ const requestParams = this.mergeRequestParams(params, secureParams);
+ const queryString = query && this.toQueryString(query);
const payloadFormatter =
- this.contentFormatters[type || ContentType.Json]
- const responseFormat = format || requestParams.format
+ this.contentFormatters[type || ContentType.Json];
+ const responseFormat = format || requestParams.format;
return this.customFetch(
`${baseUrl || this.baseUrl || ''}${path}${queryString ? `?${queryString}` : ''}`,
@@ -234,32 +234,32 @@ export class HttpClient {
: payloadFormatter(body),
}
).then(async (response) => {
- const r = response.clone() as HttpResponse
- r.data = null as unknown as T
- r.error = null as unknown as E
+ const r = response.clone() as HttpResponse;
+ r.data = null as unknown as T;
+ r.error = null as unknown as E;
const data = !responseFormat
? r
: await response[responseFormat]()
.then((data) => {
if (r.ok) {
- r.data = data
+ r.data = data;
} else {
- r.error = data
+ r.error = data;
}
- return r
+ return r;
})
.catch((e) => {
- r.error = e
- return r
- })
+ r.error = e;
+ return r;
+ });
if (cancelToken) {
- this.abortControllers.delete(cancelToken)
+ this.abortControllers.delete(cancelToken);
}
- if (!response.ok) throw data
- return data
- })
- }
+ if (!response.ok) throw data;
+ return data;
+ });
+ };
}
diff --git a/tranga-website/src/contexts/ApiContext.tsx b/tranga-website/src/contexts/ApiContext.tsx
index d4a2103..db7b2d9 100644
--- a/tranga-website/src/contexts/ApiContext.tsx
+++ b/tranga-website/src/contexts/ApiContext.tsx
@@ -1,20 +1,20 @@
-import { V2 } from '../api/V2.ts'
-import { createContext, ReactNode, useEffect, useState } from 'react'
-import { ApiConfig } from '../api/http-client.ts'
+import { V2 } from '../api/V2.ts';
+import { createContext, ReactNode, useEffect, useState } from 'react';
+import { ApiConfig } from '../api/http-client.ts';
-export const ApiContext = createContext(new V2())
+export const ApiContext = createContext(new V2());
export default function ApiProvider({
apiConfig,
children,
}: {
- apiConfig: ApiConfig
- children: ReactNode
+ apiConfig: ApiConfig;
+ children: ReactNode;
}) {
- const [api, setApi] = useState(new V2(apiConfig))
+ const [api, setApi] = useState(new V2(apiConfig));
useEffect(() => {
- setApi(new V2(apiConfig))
- }, [apiConfig])
+ setApi(new V2(apiConfig));
+ }, [apiConfig]);
- return {children}
+ return {children};
}
diff --git a/tranga-website/src/contexts/FileLibraryContext.tsx b/tranga-website/src/contexts/FileLibraryContext.tsx
index 774e83e..43db36a 100644
--- a/tranga-website/src/contexts/FileLibraryContext.tsx
+++ b/tranga-website/src/contexts/FileLibraryContext.tsx
@@ -4,28 +4,28 @@ import {
useContext,
useEffect,
useState,
-} from 'react'
-import { FileLibrary } from '../api/data-contracts.ts'
-import { ApiContext } from './ApiContext.tsx'
+} from 'react';
+import { FileLibrary } from '../api/data-contracts.ts';
+import { ApiContext } from './ApiContext.tsx';
-export const FileLibraryContext = createContext([])
+export const FileLibraryContext = createContext([]);
export default function LibraryProvider({
children,
}: {
- children: ReactNode
+ children: ReactNode;
}): ReactNode {
- const Api = useContext(ApiContext)
+ const Api = useContext(ApiContext);
- const [state, setState] = useState([])
+ const [state, setState] = useState([]);
useEffect(() => {
Api.fileLibraryList().then((result) => {
if (result.ok) {
- setState(result.data)
+ setState(result.data);
}
- })
- }, [Api])
+ });
+ }, [Api]);
- return {children}
+ return {children};
}
diff --git a/tranga-website/src/contexts/MangaConnectorContext.tsx b/tranga-website/src/contexts/MangaConnectorContext.tsx
index 7a09930..d86e816 100644
--- a/tranga-website/src/contexts/MangaConnectorContext.tsx
+++ b/tranga-website/src/contexts/MangaConnectorContext.tsx
@@ -4,30 +4,30 @@ import {
useContext,
useEffect,
useState,
-} from 'react'
-import { MangaConnector } from '../api/data-contracts.ts'
-import { ApiContext } from './ApiContext.tsx'
+} from 'react';
+import { MangaConnector } from '../api/data-contracts.ts';
+import { ApiContext } from './ApiContext.tsx';
-export const MangaConnectorContext = createContext([])
+export const MangaConnectorContext = createContext([]);
export default function MangaConnectorProvider({
children,
}: {
- children: ReactNode
+ children: ReactNode;
}) {
- const Api = useContext(ApiContext)
+ const Api = useContext(ApiContext);
- const [state, setState] = useState([])
+ const [state, setState] = useState([]);
useEffect(() => {
Api.mangaConnectorList().then((result) => {
if (result.ok) {
- setState(result.data)
+ setState(result.data);
}
- })
- }, [Api])
+ });
+ }, [Api]);
return (
{children}
- )
+ );
}
diff --git a/tranga-website/src/contexts/MangaContext.tsx b/tranga-website/src/contexts/MangaContext.tsx
index 2be5740..c12ab36 100644
--- a/tranga-website/src/contexts/MangaContext.tsx
+++ b/tranga-website/src/contexts/MangaContext.tsx
@@ -1,43 +1,43 @@
-import { createContext, ReactNode, useContext } from 'react'
-import { ApiContext } from './ApiContext.tsx'
-import { Manga } from '../api/data-contracts.ts'
-import { V2 } from '../api/V2.ts'
+import { createContext, ReactNode, useContext } from 'react';
+import { ApiContext } from './ApiContext.tsx';
+import { Manga } from '../api/data-contracts.ts';
+import { V2 } from '../api/V2.ts';
export const MangaContext = createContext({
GetManga: () => Promise.reject(),
-})
-const manga: Map = new Map()
-const promises: Map> = new Map()
+});
+const manga: Map = new Map();
+const promises: Map> = new Map();
export default function MangaProvider({ children }: { children: ReactNode }) {
- const Api = useContext(ApiContext)
+ const Api = useContext(ApiContext);
return (
getManga(k, Api) }}>
{children}
- )
+ );
}
function getManga(key: string, Api: V2): Promise {
- if (manga.has(key)) return Promise.resolve(manga.get(key))
+ if (manga.has(key)) return Promise.resolve(manga.get(key));
- if (promises.has(key)) return promises.get(key)!
+ if (promises.has(key)) return promises.get(key)!;
const newPromise = Api.mangaDetail(key)
.then((data) => {
if (data.ok) {
- manga.set(key, data.data)
- return data.data
- } else return undefined
+ manga.set(key, data.data);
+ return data.data;
+ } else return undefined;
})
.catch(() => {
- return undefined
- })
- promises.set(key, newPromise)
- return newPromise
+ return undefined;
+ });
+ promises.set(key, newPromise);
+ return newPromise;
}
export interface M {
- GetManga(key: string): Promise
+ GetManga(key: string): Promise;
}
diff --git a/tranga-website/src/main.tsx b/tranga-website/src/main.tsx
index 90e2c5b..9a04fa5 100644
--- a/tranga-website/src/main.tsx
+++ b/tranga-website/src/main.tsx
@@ -1,12 +1,12 @@
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.tsx'
+import { createRoot } from 'react-dom/client';
+import './index.css';
+import App from './App.tsx';
// @ts-expect-error font
-import '@fontsource/inter'
-import { CssVarsProvider } from '@mui/joy/styles'
-import CssBaseline from '@mui/joy/CssBaseline'
-import { StrictMode } from 'react'
-import { trangaTheme } from './theme.ts'
+import '@fontsource/inter';
+import { CssVarsProvider } from '@mui/joy/styles';
+import CssBaseline from '@mui/joy/CssBaseline';
+import { StrictMode } from 'react';
+import { trangaTheme } from './theme.ts';
export default function MyApp() {
return (
@@ -19,7 +19,7 @@ export default function MyApp() {
- )
+ );
}
-createRoot(document.getElementById('root')!).render()
+createRoot(document.getElementById('root')!).render();
diff --git a/tranga-website/src/theme.ts b/tranga-website/src/theme.ts
index 71fd148..e42e210 100644
--- a/tranga-website/src/theme.ts
+++ b/tranga-website/src/theme.ts
@@ -1,4 +1,4 @@
-import { extendTheme } from '@mui/joy/styles'
+import { extendTheme } from '@mui/joy/styles';
export const trangaTheme = extendTheme({
colorSchemes: {
@@ -80,8 +80,6 @@ export const trangaTheme = extendTheme({
},
},
},
- dark: {
- palette: {},
- },
+ dark: { palette: {} },
},
-})
+});
diff --git a/tranga-website/vite.config.ts b/tranga-website/vite.config.ts
index 3bf4a11..5da3bdc 100644
--- a/tranga-website/vite.config.ts
+++ b/tranga-website/vite.config.ts
@@ -1,10 +1,8 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
- server: {
- host: '127.0.0.1',
- },
-})
+ server: { host: '127.0.0.1' },
+});