Move "core" folder out of "features" into "base"

This commit is contained in:
schroda
2025-08-16 02:48:46 +02:00
parent f4c06d474d
commit 9e5af57a5f
311 changed files with 712 additions and 727 deletions

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
import { useTranslation } from 'react-i18next';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
type Action = {
show?: boolean;
title?: string;
contain?: boolean;
};
type Actions = {
extra?: Action;
cancel?: Action;
confirm?: Action;
};
export const ConfirmDialog = ({
title,
message,
actions: passedActions,
onExtra,
onCancel,
onConfirm,
}: {
title: string;
message: string;
actions?: Actions;
onExtra?: () => void;
onCancel: () => void;
onConfirm: () => void;
}) => {
const { t } = useTranslation();
const actions = {
extra: {
show: passedActions?.extra?.show ?? false,
title: passedActions?.extra?.title ?? '',
contain: passedActions?.extra?.contain ?? false,
},
cancel: {
show: passedActions?.cancel?.show ?? true,
title: passedActions?.cancel?.title ?? t('global.button.cancel'),
contain: passedActions?.cancel?.contain ?? false,
},
confirm: {
show: passedActions?.confirm?.show ?? true,
title: passedActions?.confirm?.title ?? t('global.button.ok'),
contain:
!passedActions?.extra?.contain &&
!passedActions?.cancel?.contain &&
!passedActions?.confirm?.contain &&
true,
},
} satisfies Actions;
return (
<Dialog open onClose={onCancel}>
<DialogTitle>{title}</DialogTitle>
<DialogContent
sx={{
whiteSpace: 'pre-line',
}}
>
{message}
</DialogContent>
<DialogActions>
<Stack
sx={{
flexDirection: 'row',
justifyContent: actions.extra.show ? 'space-between' : 'end',
width: '100%',
gap: 1,
}}
>
{actions.extra.show && (
<Button onClick={onExtra} variant={actions.extra.contain ? 'contained' : undefined}>
{actions.extra.title}
</Button>
)}
<Stack
sx={{
flexDirection: 'row',
gap: 1,
}}
>
{actions.cancel.show && (
<Button onClick={onCancel} variant={actions.cancel.contain ? 'contained' : undefined}>
{actions.cancel.title}
</Button>
)}
{actions.confirm.show && (
<Button onClick={onConfirm} variant={actions.confirm.contain ? 'contained' : undefined}>
{actions.confirm.title}
</Button>
)}
</Stack>
</Stack>
</DialogActions>
</Dialog>
);
};

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import Drawer from '@mui/material/Drawer';
import Box from '@mui/material/Box';
import React from 'react';
interface IProps {
open: boolean;
onClose: () => void;
children: React.ReactNode;
minHeight?: number;
}
export const OptionsPanel: React.FC<IProps> = ({ open, onClose, children, minHeight }) => (
<Drawer
anchor="bottom"
open={open}
onClose={onClose}
PaperProps={{
style: {
maxWidth: 600,
marginLeft: 'auto',
marginRight: 'auto',
minHeight,
},
}}
>
<Box>{children}</Box>
</Drawer>
);

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import Stack from '@mui/material/Stack';
import Tab from '@mui/material/Tab';
import Tabs from '@mui/material/Tabs';
import React, { useState } from 'react';
import { TabPanel } from '@/base/components/tabs/TabPanel.tsx';
import { OptionsPanel } from '@/base/components/modals/OptionsPanel.tsx';
interface IProps<T = string> {
open: boolean;
onClose: () => void;
tabs: T[];
tabTitle: (key: T) => React.ReactNode;
tabContent: (key: T) => React.ReactNode;
minHeight?: number;
}
export const OptionsTabs = <T extends string = string>({
open,
onClose,
tabs,
tabTitle,
tabContent,
minHeight,
}: IProps<T>) => {
const [tabNum, setTabNum] = useState(0);
return (
<OptionsPanel open={open} onClose={onClose} minHeight={minHeight}>
<Tabs
value={tabNum}
variant="fullWidth"
onChange={(e, newTab) => setTabNum(newTab)}
indicatorColor="primary"
textColor="primary"
>
{tabs.map((tab, tabIndex) => (
<Tab key={tab} value={tabIndex} label={tabTitle(tab)} />
))}
</Tabs>
{tabs.map((tab, tabIndex) => (
<TabPanel key={tab} index={tabIndex} currentIndex={tabNum}>
<Stack sx={{ px: 3, py: 1, minHeight }}>{tabContent(tab)}</Stack>
</TabPanel>
))}
</OptionsPanel>
);
};