Compare commits

7 Commits

Author SHA1 Message Date
Leonmmcoset
921570f229 add beta notice 2025-10-20 22:01:54 +08:00
Leonmmcoset
48ec0d9fb4 qwq 2025-10-20 21:24:03 +08:00
Leonmmcoset
2e4d39be6d change borderRadius 2025-10-20 20:59:18 +08:00
Leonmmcoset
a3bd238885 awa 2025-10-20 20:30:35 +08:00
Leonmmcoset
991af83c2e change appbar 2025-10-20 20:16:09 +08:00
Leonmmcoset
56f11f62ea login page add menubar 2025-10-20 19:49:24 +08:00
Leonmmcoset
7b8f6c02e9 change textfield's theme 2025-10-19 22:28:27 +08:00
12 changed files with 75 additions and 42 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -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">

View File

@@ -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}

View File

@@ -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>,

View File

@@ -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 },

View File

@@ -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>

View File

@@ -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

View File

@@ -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>
); );

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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}