mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-09-10 20:08:19 +02:00
Reorganize Settings for faster access to individual settings (group them by category)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import {ReactNode, useContext, useState} from "react";
|
||||
import { ApiContext } from "../../apiClient/ApiContext";
|
||||
import {
|
||||
Button,
|
||||
Button, Card,
|
||||
Input,
|
||||
Modal,
|
||||
ModalDialog,
|
||||
@@ -9,30 +9,36 @@ import {
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
Tabs
|
||||
Tabs, Typography
|
||||
} from "@mui/joy";
|
||||
import ModalClose from "@mui/joy/ModalClose";
|
||||
import {GotifyRecord, NtfyRecord, PushoverRecord} from "../../apiClient/data-contracts.ts";
|
||||
import {LoadingState, StateColor, StateIndicator} from "../Loading.tsx";
|
||||
import * as React from "react";
|
||||
|
||||
export default function ({open, setOpen} : {open: boolean, setOpen: (open: boolean) => void}) {
|
||||
export default function () {
|
||||
const [notificationConnectorsOpen, setNotificationConnectorsOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={() => setOpen(false)}>
|
||||
<ModalDialog>
|
||||
<ModalClose />
|
||||
<Tabs sx={{width:'95%'}} defaultValue={"gotify"}>
|
||||
<TabList>
|
||||
<Tab value={"gotify"}>Gotify</Tab>
|
||||
<Tab value={"ntfy"}>Ntfy</Tab>
|
||||
<Tab value={"pushover"}>Pushover</Tab>
|
||||
</TabList>
|
||||
<Gotify />
|
||||
<Ntfy />
|
||||
<Pushover />
|
||||
</Tabs>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
<Card>
|
||||
<Typography>Notification Connectors</Typography>
|
||||
<Button onClick={() => setNotificationConnectorsOpen(true)}>Add</Button>
|
||||
<Modal open={notificationConnectorsOpen} onClose={() => setNotificationConnectorsOpen(false)}>
|
||||
<ModalDialog>
|
||||
<ModalClose />
|
||||
<Tabs sx={{width:'95%'}} defaultValue={"gotify"}>
|
||||
<TabList>
|
||||
<Tab value={"gotify"}>Gotify</Tab>
|
||||
<Tab value={"ntfy"}>Ntfy</Tab>
|
||||
<Tab value={"pushover"}>Pushover</Tab>
|
||||
</TabList>
|
||||
<Gotify />
|
||||
<Ntfy />
|
||||
<Pushover />
|
||||
</Tabs>
|
||||
</ModalDialog>
|
||||
</Modal>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import {ReactNode, useContext, useState} from "react";
|
||||
import {SettingsContext, SettingsItem} from "./Settings.tsx";
|
||||
import {SettingsContext} from "./Settings.tsx";
|
||||
import {ApiContext} from "../../apiClient/ApiContext.tsx";
|
||||
import {ColorPaletteProp, Input} from "@mui/joy";
|
||||
import {Card, ColorPaletteProp, Input, Typography} from "@mui/joy";
|
||||
import * as React from "react";
|
||||
import MarkdownPreview from "@uiw/react-markdown-preview";
|
||||
|
||||
@@ -27,9 +27,10 @@ export default function () : ReactNode {
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsItem title={"Chapter Naming Scheme"}>
|
||||
<MarkdownPreview style={{backgroundColor: "transparent"}} source={"Placeholders:\n * %M Obj Name\n * %V Volume\n * %C Chapter\n * %T Title\n * %A Author (first in list)\n * %I Chapter Internal ID\n * %i Obj Internal ID\n * %Y Year (Obj)\n *\n * ?_(...) replace _ with a value from above:\n * Everything inside the braces will only be added if the value of %_ is not null"} />
|
||||
<Card>
|
||||
<Typography>Chapter Naming Scheme</Typography>
|
||||
<Input color={scheme} defaultValue={settings?.chapterNamingScheme as string} placeholder={"Scheme"} onChange={schemeChanged} />
|
||||
</SettingsItem>
|
||||
<MarkdownPreview style={{backgroundColor: "transparent"}} source={"Placeholders:\n * %M Obj Name\n * %V Volume\n * %C Chapter\n * %T Title\n * %A Author (first in list)\n * %I Chapter Internal ID\n * %i Obj Internal ID\n * %Y Year (Obj)\n *\n * ?_(...) replace _ with a value from above:\n * Everything inside the braces will only be added if the value of %_ is not null"} />
|
||||
</Card>
|
||||
);
|
||||
}
|
14
tranga-website/src/Components/Settings/Download.tsx
Normal file
14
tranga-website/src/Components/Settings/Download.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import {SettingsItem} from "./Settings.tsx";
|
||||
import ImageCompression from "./ImageCompression.tsx";
|
||||
import DownloadLanguage from "./DownloadLanguage.tsx";
|
||||
import ChapterNamingScheme from "./ChapterNamingScheme.tsx";
|
||||
|
||||
export default function (){
|
||||
return (
|
||||
<SettingsItem title={"Download"}>
|
||||
<ImageCompression />
|
||||
<DownloadLanguage />
|
||||
<ChapterNamingScheme />
|
||||
</SettingsItem>
|
||||
)
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
import {ReactNode, useContext, useState} from "react";
|
||||
import {SettingsContext, SettingsItem} from "./Settings.tsx";
|
||||
import {SettingsContext} from "./Settings.tsx";
|
||||
import {ApiContext} from "../../apiClient/ApiContext.tsx";
|
||||
import {ColorPaletteProp, Input} from "@mui/joy";
|
||||
import {Card, ColorPaletteProp, Input, Typography} from "@mui/joy";
|
||||
import * as React from "react";
|
||||
|
||||
export default function () : ReactNode {
|
||||
@@ -26,8 +26,9 @@ export default function () : ReactNode {
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsItem title={"Download Language"}>
|
||||
<Card>
|
||||
<Typography>Download Language</Typography>
|
||||
<Input color={color} defaultValue={settings?.downloadLanguage as string} placeholder={"Language code (f.e. 'en')"} onChange={languageChanged} />
|
||||
</SettingsItem>
|
||||
</Card>
|
||||
);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import {ReactNode, useContext, useState} from "react";
|
||||
import {SettingsContext, SettingsItem} from "./Settings.tsx";
|
||||
import {ColorPaletteProp, Input} from "@mui/joy";
|
||||
import {ReactNode, useCallback, useContext, useState} from "react";
|
||||
import {SettingsContext} from "./Settings.tsx";
|
||||
import {Button, Card, ColorPaletteProp, Input, Typography} from "@mui/joy";
|
||||
import * as React from "react";
|
||||
import {ApiContext} from "../../apiClient/ApiContext.tsx";
|
||||
|
||||
@@ -8,26 +8,34 @@ export default function () : ReactNode {
|
||||
const settings = useContext(SettingsContext);
|
||||
const Api = useContext(ApiContext);
|
||||
|
||||
const [uriValue, setUriValue] = React.useState<string>(settings?.flareSolverrUrl as string);
|
||||
const [uriColor, setUriColor] = useState<ColorPaletteProp>("neutral");
|
||||
const timerRef = React.useRef<ReturnType<typeof setTimeout>>(undefined);
|
||||
const uriChanged = (e : React.ChangeEvent<HTMLInputElement>) => {
|
||||
clearTimeout(timerRef.current);
|
||||
setUriColor("warning");
|
||||
timerRef.current = setTimeout(() => {
|
||||
Api.settingsFlareSolverrUrlCreate(e.target.value)
|
||||
.then(response => {
|
||||
if (response.ok)
|
||||
setUriColor("success");
|
||||
else
|
||||
setUriColor("danger");
|
||||
})
|
||||
.catch(() => setUriColor("danger"));
|
||||
setUriValue(e.target.value);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
const changeUri = useCallback(() => {
|
||||
Api.settingsFlareSolverrUrlCreate(uriValue)
|
||||
.then(response => {
|
||||
if (response.ok)
|
||||
setUriColor("success");
|
||||
else
|
||||
setUriColor("danger");
|
||||
})
|
||||
.catch(() => setUriColor("danger"));
|
||||
}, [uriValue]);
|
||||
|
||||
return (
|
||||
<SettingsItem title={"FlareSolverr"}>
|
||||
<Input color={uriColor} defaultValue={settings?.flareSolverrUrl as string} type={"url"} placeholder={"URL"} onChange={uriChanged} />
|
||||
</SettingsItem>
|
||||
<Card>
|
||||
<Typography>FlareSolverr</Typography>
|
||||
<Input color={uriColor} value={uriValue} type={"url"} placeholder={"URL"} onChange={uriChanged}
|
||||
endDecorator={<Button onClick={changeUri}>Apply</Button>}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
@@ -1,13 +1,14 @@
|
||||
import {ReactNode, useContext} from "react";
|
||||
import {SettingsContext, SettingsItem} from "./Settings.tsx";
|
||||
import {Slider} from "@mui/joy";
|
||||
import {SettingsContext} from "./Settings.tsx";
|
||||
import {Card, Slider, Typography} from "@mui/joy";
|
||||
|
||||
export default function () : ReactNode {
|
||||
const settings = useContext(SettingsContext);
|
||||
|
||||
return (
|
||||
<SettingsItem title={"Image Compression"}>
|
||||
<Card>
|
||||
<Typography>Image Compression</Typography>
|
||||
<Slider sx={{marginTop: "20px"}} valueLabelDisplay={"auto"} defaultValue={settings?.imageCompression}></Slider>
|
||||
</SettingsItem>
|
||||
</Card>
|
||||
);
|
||||
}
|
@@ -19,9 +19,7 @@ export default function () {
|
||||
}).catch(_ => setUnusedMangaState(LoadingState.failure));
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<SettingsItem title={"Maintenance"}>
|
||||
<Button
|
||||
disabled={unusedMangaState == LoadingState.loading}
|
||||
|
@@ -1,16 +0,0 @@
|
||||
import {ReactNode} from "react";
|
||||
import {SettingsItem} from "./Settings.tsx";
|
||||
import {Button} from "@mui/joy";
|
||||
import NotificationConnectors from "./AddNotificationConnector.tsx";
|
||||
import * as React from "react";
|
||||
|
||||
export default function () : ReactNode {
|
||||
const [notificationConnectorsOpen, setNotificationConnectorsOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<SettingsItem title={"Notification Connectors"}>
|
||||
<Button onClick={() => setNotificationConnectorsOpen(true)}>Add Notification Connector</Button>
|
||||
<NotificationConnectors open={notificationConnectorsOpen} setOpen={setNotificationConnectorsOpen} />
|
||||
</SettingsItem>
|
||||
);
|
||||
}
|
15
tranga-website/src/Components/Settings/Services.tsx
Normal file
15
tranga-website/src/Components/Settings/Services.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import {SettingsItem} from "./Settings.tsx";
|
||||
import NotificationConnectors from "./AddNotificationConnector.tsx";
|
||||
import FlareSolverr from "./FlareSolverr.tsx";
|
||||
|
||||
export default function(){
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<SettingsItem title={"Services"} direction={"row"}>
|
||||
<FlareSolverr />
|
||||
<NotificationConnectors />
|
||||
</SettingsItem>
|
||||
);
|
||||
}
|
@@ -6,20 +6,17 @@ import {
|
||||
AccordionSummary, Button, ColorPaletteProp,
|
||||
DialogContent,
|
||||
DialogTitle, Input,
|
||||
Modal, ModalDialog
|
||||
Modal, ModalDialog, Stack
|
||||
} from "@mui/joy";
|
||||
import './Settings.css';
|
||||
import * as React from "react";
|
||||
import {createContext, Dispatch, ReactNode, useContext, useEffect, useState} from "react";
|
||||
import {TrangaSettings} from "../../apiClient/data-contracts.ts";
|
||||
import {ApiContext} from "../../apiClient/ApiContext.tsx";
|
||||
import NotificationConnectors from "./NotificationConnectors.tsx";
|
||||
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 Services from "./Services.tsx";
|
||||
import Download from './Download.tsx';
|
||||
|
||||
export const SettingsContext = createContext<TrangaSettings|undefined>(undefined);
|
||||
|
||||
@@ -69,11 +66,8 @@ export default function Settings({setApiUri} : {setApiUri: Dispatch<React.SetSta
|
||||
defaultValue={Api.baseUrl}
|
||||
onChange={apiUriChanged} />
|
||||
</SettingsItem>
|
||||
<ImageCompression />
|
||||
<FlareSolverr />
|
||||
<DownloadLanguage />
|
||||
<ChapterNamingScheme />
|
||||
<NotificationConnectors />
|
||||
<Download />
|
||||
<Services />
|
||||
<Maintenance />
|
||||
</AccordionGroup>
|
||||
</DialogContent>
|
||||
@@ -83,12 +77,17 @@ export default function Settings({setApiUri} : {setApiUri: Dispatch<React.SetSta
|
||||
);
|
||||
}
|
||||
|
||||
export function SettingsItem({title, children} : {title: string, children: ReactNode}) {
|
||||
export function SettingsItem({title, children, defaultExpanded, direction} : {title: string, children?: ReactNode, defaultExpanded?: boolean, direction?: "row" | "column"}) {
|
||||
const [expanded, setExpanded] = React.useState(defaultExpanded??false);
|
||||
const stackDirection = direction ?? "column";
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion expanded={expanded} onChange={(_, expanded) => setExpanded(expanded)}>
|
||||
<AccordionSummary>{title}</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{children}
|
||||
<Stack direction={stackDirection} spacing={1}>
|
||||
{children}
|
||||
</Stack>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
);
|
||||
|
Reference in New Issue
Block a user