Compare commits
7 Commits
8bfc183b66
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
921570f229 | ||
|
|
48ec0d9fb4 | ||
|
|
2e4d39be6d | ||
|
|
a3bd238885 | ||
|
|
991af83c2e | ||
|
|
56f11f62ea | ||
|
|
7b8f6c02e9 |
35
src/App.tsx
35
src/App.tsx
@@ -2,7 +2,7 @@ import { createTheme, CssBaseline, GlobalStyles, styled, ThemeProvider, useMedia
|
|||||||
import { grey } from "@mui/material/colors";
|
import { grey } from "@mui/material/colors";
|
||||||
import { ThemeOptions } from "@mui/material/styles/createTheme";
|
import { ThemeOptions } from "@mui/material/styles/createTheme";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { enqueueSnackbar, MaterialDesignContent, SnackbarProvider } from "notistack";
|
import { enqueueSnackbar, MaterialDesignContent, SnackbarProvider, useSnackbar } from "notistack";
|
||||||
import { Suspense, useEffect, useMemo } from "react";
|
import { Suspense, useEffect, useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Outlet } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
@@ -21,7 +21,7 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
...themeConfig,
|
...themeConfig,
|
||||||
shape: {
|
shape: {
|
||||||
...themeConfig.shape,
|
...themeConfig.shape,
|
||||||
borderRadius: 12,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
MuiCssBaseline: {
|
MuiCssBaseline: {
|
||||||
@@ -31,6 +31,18 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiBackdrop: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
"&.MuiBackdrop-invisible": {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
backdropFilter: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
MuiTooltip: {
|
MuiTooltip: {
|
||||||
defaultProps: {
|
defaultProps: {
|
||||||
enterDelay: 500,
|
enterDelay: 500,
|
||||||
@@ -63,7 +75,7 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
MuiListItemButton: {
|
MuiListItemButton: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
borderRadius: 12,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -82,7 +94,7 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
MuiMenu: {
|
MuiMenu: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
paper: {
|
paper: {
|
||||||
borderRadius: "8px",
|
borderRadius: "4px",
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
padding: "4px 0",
|
padding: "4px 0",
|
||||||
@@ -106,7 +118,7 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
MuiMenuItem: {
|
MuiMenuItem: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
borderRadius: "8px",
|
borderRadius: "4px",
|
||||||
margin: "0px 4px",
|
margin: "0px 4px",
|
||||||
paddingLeft: "8px",
|
paddingLeft: "8px",
|
||||||
paddingRight: "8px",
|
paddingRight: "8px",
|
||||||
@@ -127,7 +139,7 @@ export const applyThemeWithOverrides = (themeConfig: ThemeOptions): ThemeOptions
|
|||||||
"&:hover:not(.Mui-disabled, .Mui-error):before": {
|
"&:hover:not(.Mui-disabled, .Mui-error):before": {
|
||||||
borderBottom: "none",
|
borderBottom: "none",
|
||||||
},
|
},
|
||||||
borderRadius: 12,
|
borderRadius: 4,
|
||||||
// '&:hover:not(.Mui-disabled, .Mui-error):before': {
|
// '&:hover:not(.Mui-disabled, .Mui-error):before': {
|
||||||
// borderBottom: '2px solid var(--TextField-brandBorderHoverColor)',
|
// borderBottom: '2px solid var(--TextField-brandBorderHoverColor)',
|
||||||
// },
|
// },
|
||||||
@@ -271,7 +283,7 @@ const getPreferredTheme = (
|
|||||||
|
|
||||||
const StyledMaterialDesignContent = styled(MaterialDesignContent)(({ theme }) => ({
|
const StyledMaterialDesignContent = styled(MaterialDesignContent)(({ theme }) => ({
|
||||||
"&.notistack-MuiContent": {
|
"&.notistack-MuiContent": {
|
||||||
borderRadius: 12,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
"&.notistack-MuiContent-success": {
|
"&.notistack-MuiContent-success": {
|
||||||
backgroundColor: theme.palette.success.main,
|
backgroundColor: theme.palette.success.main,
|
||||||
@@ -288,6 +300,15 @@ const AppContent = () => {
|
|||||||
const title = useAppSelector((state) => state.siteConfig.basic.config.title);
|
const title = useAppSelector((state) => state.siteConfig.basic.config.title);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 显示测试网站提示
|
||||||
|
enqueueSnackbar("请注意,本网站是测试网站", {
|
||||||
|
variant: "warning",
|
||||||
|
autoHideDuration: 5000,
|
||||||
|
});
|
||||||
|
}, [enqueueSnackbar]);
|
||||||
const scrollBar = {
|
const scrollBar = {
|
||||||
"&::-webkit-scrollbar-button": {
|
"&::-webkit-scrollbar-button": {
|
||||||
width: 0,
|
width: 0,
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ const HeadlessFooterPreview = ({ footer, bottom }: { footer?: string; bottom?: s
|
|||||||
maxHeight: "40px",
|
maxHeight: "40px",
|
||||||
mb: 2,
|
mb: 2,
|
||||||
}}
|
}}
|
||||||
|
style={{ display: "flex", justifyContent: "center", alignItems: "center" }}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ const ThemeOptionEditDialog = ({ open, onClose, id, config, onSave }: ThemeOptio
|
|||||||
label={t("settings.previewTitle")}
|
label={t("settings.previewTitle")}
|
||||||
icon={<Setting fontSize="small" color="action" />}
|
icon={<Setting fontSize="small" color="action" />}
|
||||||
/>
|
/>
|
||||||
<TextField label={t("settings.previewTextField")} variant="outlined" size="small" />
|
<TextField label={t("settings.previewTextField")} variant="filled" size="small" />
|
||||||
<Box>
|
<Box>
|
||||||
<Badge badgeContent={10} color="secondary">
|
<Badge badgeContent={10} color="secondary">
|
||||||
<Button variant="contained" color="primary">
|
<Button variant="contained" color="primary">
|
||||||
@@ -195,7 +195,7 @@ const ThemeOptionEditDialog = ({ open, onClose, id, config, onSave }: ThemeOptio
|
|||||||
label={t("settings.previewTitle")}
|
label={t("settings.previewTitle")}
|
||||||
icon={<Setting fontSize="small" color="action" />}
|
icon={<Setting fontSize="small" color="action" />}
|
||||||
/>
|
/>
|
||||||
<TextField label={t("settings.previewTextField")} variant="outlined" size="small" />
|
<TextField label={t("settings.previewTextField")} variant="filled" size="small" />
|
||||||
<Box>
|
<Box>
|
||||||
<Badge badgeContent={10} color="secondary">
|
<Badge badgeContent={10} color="secondary">
|
||||||
<Button variant="contained" color="primary">
|
<Button variant="contained" color="primary">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const DefaultCaptcha = ({ onStateChange, generation, noLabel, ...rest }: Default
|
|||||||
pr: 0.5,
|
pr: 0.5,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
variant={"outlined"}
|
variant={"filled"}
|
||||||
label={noLabel ? undefined : t("login.captcha")}
|
label={noLabel ? undefined : t("login.captcha")}
|
||||||
onChange={(e) => setCaptcha(e.target.value)}
|
onChange={(e) => setCaptcha(e.target.value)}
|
||||||
value={captcha}
|
value={captcha}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const OutlineIconTextField = ({ icon, ...rest }: OutlineIconTextFieldProp
|
|||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
{...rest}
|
{...rest}
|
||||||
|
variant="standard"
|
||||||
slotProps={{
|
slotProps={{
|
||||||
input: {
|
input: {
|
||||||
startAdornment: !isMobile && <InputAdornment position="start">{icon}</InputAdornment>,
|
startAdornment: !isMobile && <InputAdornment position="start">{icon}</InputAdornment>,
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ const DirectLinks = () => {
|
|||||||
label={t("modals.sourceLink")}
|
label={t("modals.sourceLink")}
|
||||||
multiline
|
multiline
|
||||||
value={contents}
|
value={contents}
|
||||||
variant="outlined"
|
variant="filled"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{
|
slotProps={{
|
||||||
htmlInput: { readonly: true },
|
htmlInput: { readonly: true },
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ const ShareSettingContent = ({ setting, file, editing, onSettingChange }: ShareS
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
value={setting.password ?? ""}
|
value={setting.password ?? ""}
|
||||||
onChange={(e) => {
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const value = e.target.value.trim();
|
const value = e.target.value.trim();
|
||||||
if (!/^[a-zA-Z0-9]*$/.test(value) || value.length > 32) return;
|
if (!/^[a-zA-Z0-9]*$/.test(value) || value.length > 32) return;
|
||||||
onSettingChange({ ...setting, password: value });
|
onSettingChange({ ...setting, password: value });
|
||||||
@@ -292,7 +292,7 @@ const ShareSettingContent = ({ setting, file, editing, onSettingChange }: ShareS
|
|||||||
getOptionLabel={(option: string | valueOption) => (typeof option === "string" ? option : t(option.label))}
|
getOptionLabel={(option: string | valueOption) => (typeof option === "string" ? option : t(option.label))}
|
||||||
disableClearable
|
disableClearable
|
||||||
options={expireOptions}
|
options={expireOptions}
|
||||||
renderInput={(params) => <TextField sx={{ width: 150 }} {...params} variant={"standard"} />}
|
renderInput={(params) => <TextField sx={{ width: 150 }} {...params} variant={"filled"} />}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Typography>{t("application:modals.expireSuffix")}</Typography>
|
<Typography>{t("application:modals.expireSuffix")}</Typography>
|
||||||
@@ -368,7 +368,7 @@ const ShareSettingContent = ({ setting, file, editing, onSettingChange }: ShareS
|
|||||||
}
|
}
|
||||||
disableClearable
|
disableClearable
|
||||||
options={downloadOptions}
|
options={downloadOptions}
|
||||||
renderInput={(params) => <TextField sx={{ width: 200 }} {...params} variant={"standard"} />}
|
renderInput={(params) => <TextField sx={{ width: 200 }} {...params} variant={"filled"} />}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Typography>{t("application:modals.expireSuffix")}</Typography>
|
<Typography>{t("application:modals.expireSuffix")}</Typography>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Box, Container, Grid, Paper } from "@mui/material";
|
import { Box, Container, Grid, Paper, AppBar, Toolbar, IconButton, Typography, Button } from "@mui/material";
|
||||||
|
import MenuIcon from "@mui/icons-material/Menu";
|
||||||
import { Outlet, useNavigation } from "react-router-dom";
|
import { Outlet, useNavigation } from "react-router-dom";
|
||||||
import { useAppDispatch, useAppSelector } from "../../redux/hooks.ts";
|
import { useAppDispatch, useAppSelector } from "../../redux/hooks.ts";
|
||||||
import AutoHeight from "../Common/AutoHeight.tsx";
|
import AutoHeight from "../Common/AutoHeight.tsx";
|
||||||
@@ -40,6 +41,35 @@ const HeadlessFrame = () => {
|
|||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<AppBar
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#f5f5f5",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Toolbar>
|
||||||
|
{/* <IconButton
|
||||||
|
size="large"
|
||||||
|
edge="start"
|
||||||
|
color="inherit"
|
||||||
|
aria-label="menu"
|
||||||
|
sx={{ mr: 2 }}
|
||||||
|
>
|
||||||
|
<MenuIcon />
|
||||||
|
</IconButton> */}
|
||||||
|
{/* <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
||||||
|
News
|
||||||
|
</Typography> */}
|
||||||
|
<Logo
|
||||||
|
sx={{
|
||||||
|
maxWidth: "40%",
|
||||||
|
maxHeight: "40px",
|
||||||
|
mb: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
</Box>
|
||||||
<Container maxWidth={"xs"}>
|
<Container maxWidth={"xs"}>
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Box, BoxProps, Typography, useTheme } from "@mui/material";
|
import { Box, BoxProps, Typography, useTheme } from "@mui/material";
|
||||||
import LogoIcon from "./assets/logo.svg";
|
import Logo from "../Common/Logo";
|
||||||
import LogoIconDark from "./assets/logo_light.svg";
|
|
||||||
|
|
||||||
export interface PoweredByProps extends BoxProps {}
|
export interface PoweredByProps extends BoxProps {}
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ const PoweredBy = ({ ...rest }: PoweredByProps) => {
|
|||||||
<Box
|
<Box
|
||||||
component="a"
|
component="a"
|
||||||
marginBottom={2}
|
marginBottom={2}
|
||||||
href="https://cloudreve.org"
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -38,16 +36,8 @@ const PoweredBy = ({ ...rest }: PoweredByProps) => {
|
|||||||
}}
|
}}
|
||||||
fontWeight={500}
|
fontWeight={500}
|
||||||
>
|
>
|
||||||
Powered by
|
Powered by Miaostars
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
|
||||||
component="img"
|
|
||||||
alt="Cloudreve"
|
|
||||||
sx={{
|
|
||||||
height: 20,
|
|
||||||
}}
|
|
||||||
src={theme.palette.mode === "dark" ? LogoIconDark : LogoIcon}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function PasskeyLoginButton({ autoComplete, ...rest }: PasskeyLog
|
|||||||
window.PublicKeyCredential &&
|
window.PublicKeyCredential &&
|
||||||
PublicKeyCredential.isConditionalMediationAvailable
|
PublicKeyCredential.isConditionalMediationAvailable
|
||||||
) {
|
) {
|
||||||
PublicKeyCredential.isConditionalMediationAvailable().then((v) => {
|
PublicKeyCredential.isConditionalMediationAvailable().then(() => {
|
||||||
if (!abortRef.current.signal.aborted) startLogin(true)();
|
if (!abortRef.current.signal.aborted) startLogin(true)();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -43,12 +43,7 @@ export default function PasskeyLoginButton({ autoComplete, ...rest }: PasskeyLog
|
|||||||
|
|
||||||
const startLogin = (conditional: boolean) => async () => {
|
const startLogin = (conditional: boolean) => async () => {
|
||||||
if (!navigator.credentials || !window.PublicKeyCredential) {
|
if (!navigator.credentials || !window.PublicKeyCredential) {
|
||||||
enqueueSnackbar({
|
enqueueSnackbar(t("setting.browserNotSupported"), { variant: "error", action: DefaultCloseAction });
|
||||||
message: t("setting.browserNotSupported"),
|
|
||||||
variant: "warning",
|
|
||||||
action: DefaultCloseAction,
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,12 +37,7 @@ const PasskeyList = (props: PasskeyProps) => {
|
|||||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||||
const addPasskey = async () => {
|
const addPasskey = async () => {
|
||||||
if (!navigator.credentials || !window.PublicKeyCredential) {
|
if (!navigator.credentials || !window.PublicKeyCredential) {
|
||||||
enqueueSnackbar({
|
dispatch(confirmOperation(t("setting.browserNotSupported")));
|
||||||
message: t("setting.browserNotSupported"),
|
|
||||||
variant: "warning",
|
|
||||||
action: DefaultCloseAction,
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi
|
|||||||
<Stack direction="row" spacing={1} sx={{ mb: 1 }}>
|
<Stack direction="row" spacing={1} sx={{ mb: 1 }}>
|
||||||
<TextField
|
<TextField
|
||||||
label={t("download.filterByName")}
|
label={t("download.filterByName")}
|
||||||
variant="outlined"
|
variant="filled"
|
||||||
size="small"
|
size="small"
|
||||||
value={filterText}
|
value={filterText}
|
||||||
onChange={(e) => setFilterText(e.target.value)}
|
onChange={(e) => setFilterText(e.target.value)}
|
||||||
@@ -184,7 +184,7 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi
|
|||||||
<>
|
<>
|
||||||
<TableCell component="th" scope="row" sx={{ height: 33, minWidth: 50 }}>
|
<TableCell component="th" scope="row" sx={{ height: 33, minWidth: 50 }}>
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
onChange={(e) => {
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setFileSelected(value, e.target.checked);
|
setFileSelected(value, e.target.checked);
|
||||||
}}
|
}}
|
||||||
disabled={!downloading || readonly}
|
disabled={!downloading || readonly}
|
||||||
|
|||||||
Reference in New Issue
Block a user