|  | @@ -0,0 +1,210 @@
 | 
	
		
			
				|  |  | +import useSWR from "swr";
 | 
	
		
			
				|  |  | +import { useEffect, useState } from "react";
 | 
	
		
			
				|  |  | +import { useLockFn } from "ahooks";
 | 
	
		
			
				|  |  | +import { useTranslation } from "react-i18next";
 | 
	
		
			
				|  |  | +import {
 | 
	
		
			
				|  |  | +  Button,
 | 
	
		
			
				|  |  | +  Dialog,
 | 
	
		
			
				|  |  | +  DialogActions,
 | 
	
		
			
				|  |  | +  DialogContent,
 | 
	
		
			
				|  |  | +  DialogTitle,
 | 
	
		
			
				|  |  | +  List,
 | 
	
		
			
				|  |  | +  ListItem,
 | 
	
		
			
				|  |  | +  ListItemText,
 | 
	
		
			
				|  |  | +  styled,
 | 
	
		
			
				|  |  | +  TextField,
 | 
	
		
			
				|  |  | +} from "@mui/material";
 | 
	
		
			
				|  |  | +import { getVergeConfig, patchVergeConfig } from "../../services/cmds";
 | 
	
		
			
				|  |  | +import { defaultTheme } from "../../pages/_theme";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +interface Props {
 | 
	
		
			
				|  |  | +  open: boolean;
 | 
	
		
			
				|  |  | +  onClose: () => void;
 | 
	
		
			
				|  |  | +  onError?: (err: Error) => void;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const Item = styled(ListItem)(() => ({
 | 
	
		
			
				|  |  | +  padding: "5px 2px",
 | 
	
		
			
				|  |  | +}));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const Round = styled("div")(() => ({
 | 
	
		
			
				|  |  | +  width: "24px",
 | 
	
		
			
				|  |  | +  height: "24px",
 | 
	
		
			
				|  |  | +  borderRadius: "18px",
 | 
	
		
			
				|  |  | +  display: "inline-block",
 | 
	
		
			
				|  |  | +  marginRight: "8px",
 | 
	
		
			
				|  |  | +}));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const SettingTheme = (props: Props) => {
 | 
	
		
			
				|  |  | +  const { open, onClose, onError } = props;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const { t } = useTranslation();
 | 
	
		
			
				|  |  | +  const { data: vergeConfig, mutate } = useSWR(
 | 
	
		
			
				|  |  | +    "getVergeConfig",
 | 
	
		
			
				|  |  | +    getVergeConfig
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const { theme_setting } = vergeConfig ?? {};
 | 
	
		
			
				|  |  | +  const [theme, setTheme] = useState(theme_setting || {});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  useEffect(() => {
 | 
	
		
			
				|  |  | +    setTheme({ ...theme_setting } || {});
 | 
	
		
			
				|  |  | +  }, [theme_setting]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const textProps = {
 | 
	
		
			
				|  |  | +    size: "small",
 | 
	
		
			
				|  |  | +    autoComplete: "off",
 | 
	
		
			
				|  |  | +    sx: { width: 135 },
 | 
	
		
			
				|  |  | +  } as const;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleChange = (field: keyof typeof theme) => (e: any) => {
 | 
	
		
			
				|  |  | +    setTheme((t) => ({ ...t, [field]: e.target.value }));
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const onSave = useLockFn(async () => {
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      await patchVergeConfig({ theme_setting: theme });
 | 
	
		
			
				|  |  | +      mutate();
 | 
	
		
			
				|  |  | +    } catch (err: any) {
 | 
	
		
			
				|  |  | +      onError?.(err);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return (
 | 
	
		
			
				|  |  | +    <Dialog open={open} onClose={onClose}>
 | 
	
		
			
				|  |  | +      <DialogTitle>{t("Theme Setting")}</DialogTitle>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <DialogContent
 | 
	
		
			
				|  |  | +        sx={{ width: 400, maxHeight: 300, overflow: "auto", pb: 0 }}
 | 
	
		
			
				|  |  | +      >
 | 
	
		
			
				|  |  | +        <List sx={{ pt: 0 }}>
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Primary Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background: theme.primary_color || defaultTheme.primary_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.primary_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.primary_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("primary_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Secondary Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background:
 | 
	
		
			
				|  |  | +                  theme.secondary_color || defaultTheme.secondary_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.secondary_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.secondary_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("secondary_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Info Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background: theme.info_color || defaultTheme.info_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.info_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.info_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("info_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Error Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background: theme.error_color || defaultTheme.error_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.error_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.error_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("error_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Warning Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background: theme.warning_color || defaultTheme.warning_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.warning_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.warning_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("warning_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Success Color" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <Round
 | 
	
		
			
				|  |  | +              sx={{
 | 
	
		
			
				|  |  | +                background: theme.success_color || defaultTheme.success_color,
 | 
	
		
			
				|  |  | +              }}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.success_color}
 | 
	
		
			
				|  |  | +              placeholder={defaultTheme.success_color}
 | 
	
		
			
				|  |  | +              onChange={handleChange("success_color")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Font Family" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.font_family}
 | 
	
		
			
				|  |  | +              onChange={handleChange("font_family")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          <Item>
 | 
	
		
			
				|  |  | +            <ListItemText primary="Font Face" />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            <TextField
 | 
	
		
			
				|  |  | +              {...textProps}
 | 
	
		
			
				|  |  | +              value={theme.font_face}
 | 
	
		
			
				|  |  | +              onChange={handleChange("font_face")}
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </Item>
 | 
	
		
			
				|  |  | +        </List>
 | 
	
		
			
				|  |  | +      </DialogContent>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      <DialogActions>
 | 
	
		
			
				|  |  | +        <Button onClick={onClose}>{t("Cancel")}</Button>
 | 
	
		
			
				|  |  | +        <Button onClick={onSave} variant="contained">
 | 
	
		
			
				|  |  | +          {t("Save")}
 | 
	
		
			
				|  |  | +        </Button>
 | 
	
		
			
				|  |  | +      </DialogActions>
 | 
	
		
			
				|  |  | +    </Dialog>
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default SettingTheme;
 |