mirror of
				https://github.com/Vomitblood/stort.git
				synced 2025-11-04 20:57:22 +08:00 
			
		
		
		
	added settings panel
This commit is contained in:
		
							parent
							
								
									562ed7c4d1
								
							
						
					
					
						commit
						78d3ec8a55
					
				
							
								
								
									
										32
									
								
								.github/workflows/build-validation.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								.github/workflows/build-validation.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
name: Test Build Frontend
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - "*"
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    container:
 | 
			
		||||
      image: oven/bun
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout Repository
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
 | 
			
		||||
      - name: Install Rustup and Cargo
 | 
			
		||||
        run: |
 | 
			
		||||
          apt update
 | 
			
		||||
          apt install curl -y
 | 
			
		||||
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
 | 
			
		||||
          . "/root/.cargo/env"
 | 
			
		||||
 | 
			
		||||
      - name: bun install
 | 
			
		||||
        run: |
 | 
			
		||||
          bun install
 | 
			
		||||
 | 
			
		||||
      - name: bun run tauri build
 | 
			
		||||
        run: |
 | 
			
		||||
          NO_STRIP=true bun run tauri build
 | 
			
		||||
          echo "winning ranks"
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
    "endOfLine": "lf",
 | 
			
		||||
    "htmlWhitespaceSensitivity": "css",
 | 
			
		||||
    "jsxBracketSameLine": false,
 | 
			
		||||
    "jsxSingleQuote": true,
 | 
			
		||||
    "jsxSingleQuote": false,
 | 
			
		||||
    "printWidth": 120,
 | 
			
		||||
    "proseWrap": "preserve",
 | 
			
		||||
    "quoteProps": "consistent",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
    "@emotion/server": "^11.11.0",
 | 
			
		||||
    "@emotion/styled": "^11.13.0",
 | 
			
		||||
    "@mui/icons-material": "^5.16.6",
 | 
			
		||||
    "@mui/lab": "^5.0.0-alpha.173",
 | 
			
		||||
    "@mui/material": "^5.16.6",
 | 
			
		||||
    "@tauri-apps/api": "^1.6.0",
 | 
			
		||||
    "jotai": "^2.9.1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,9 +12,8 @@ interface FloatingDialog {
 | 
			
		|||
  openButton: ReactNode;
 | 
			
		||||
  openState: boolean;
 | 
			
		||||
  setMaximisedState: (state: boolean) => void;
 | 
			
		||||
  sx?: any;
 | 
			
		||||
  title: string;
 | 
			
		||||
  toggleOpen: () => void;
 | 
			
		||||
  sx?: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const FloatingDialog: FC<FloatingDialog> = ({
 | 
			
		||||
| 
						 | 
				
			
			@ -26,9 +25,8 @@ export const FloatingDialog: FC<FloatingDialog> = ({
 | 
			
		|||
  openButton,
 | 
			
		||||
  openState,
 | 
			
		||||
  setMaximisedState,
 | 
			
		||||
  sx,
 | 
			
		||||
  title,
 | 
			
		||||
  toggleOpen,
 | 
			
		||||
  sx,
 | 
			
		||||
}) => {
 | 
			
		||||
  const { settings } = useSettings();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,18 +34,17 @@ export const FloatingDialog: FC<FloatingDialog> = ({
 | 
			
		|||
    <>
 | 
			
		||||
      {openButton}
 | 
			
		||||
 | 
			
		||||
      <Modal onClose={close} open={openState}>
 | 
			
		||||
      <Modal
 | 
			
		||||
        onClose={close}
 | 
			
		||||
        open={openState}
 | 
			
		||||
      >
 | 
			
		||||
        <Box
 | 
			
		||||
          sx={{
 | 
			
		||||
            bgcolor: "background.paper",
 | 
			
		||||
            borderRadius: maximisedState
 | 
			
		||||
              ? "0px"
 | 
			
		||||
              : settings.display.radius + "px",
 | 
			
		||||
            borderRadius: maximisedState ? "0px" : settings.display.radius + "px",
 | 
			
		||||
            display: "flex",
 | 
			
		||||
            flexDirection: "column",
 | 
			
		||||
            height: maximisedState
 | 
			
		||||
              ? "100%"
 | 
			
		||||
              : settings.display.window_height + "%",
 | 
			
		||||
            height: maximisedState ? "100%" : settings.display.window_height + "%",
 | 
			
		||||
            left: "50%",
 | 
			
		||||
            maxHeight: maximisedState ? "100vh" : "96vh",
 | 
			
		||||
            maxWidth: maximisedState ? "100vw" : "96vw",
 | 
			
		||||
| 
						 | 
				
			
			@ -57,9 +54,7 @@ export const FloatingDialog: FC<FloatingDialog> = ({
 | 
			
		|||
            transform: "translate(-50%, -50%)",
 | 
			
		||||
            transition: "all ease-in-out",
 | 
			
		||||
            transitionDuration: settings.display.transition_duration + "ms",
 | 
			
		||||
            width: maximisedState
 | 
			
		||||
              ? "100vw"
 | 
			
		||||
              : settings.display.window_width + "px",
 | 
			
		||||
            width: maximisedState ? "100vw" : settings.display.window_width + "px",
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Box
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
import { Box, Button, IconButton, Typography } from "@mui/material";
 | 
			
		||||
import { WindowButtons } from "./WindowButtons";
 | 
			
		||||
import { BugReport } from "@mui/icons-material";
 | 
			
		||||
import { BugReport, BugReportOutlined } from "@mui/icons-material";
 | 
			
		||||
import { useRouter } from "next/router";
 | 
			
		||||
import { Settings } from "./Settings/Settings";
 | 
			
		||||
 | 
			
		||||
export const HeaderBar = () => {
 | 
			
		||||
  const router = useRouter();
 | 
			
		||||
| 
						 | 
				
			
			@ -46,8 +47,9 @@ export const HeaderBar = () => {
 | 
			
		|||
            router.push("/testing");
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <BugReport />
 | 
			
		||||
          <BugReportOutlined />
 | 
			
		||||
        </IconButton>
 | 
			
		||||
        <Settings />
 | 
			
		||||
        <WindowButtons />
 | 
			
		||||
      </Box>
 | 
			
		||||
    </Box>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,119 @@
 | 
			
		|||
// import { IconButton, Typography, useTheme } from "@mui/material";
 | 
			
		||||
// import { FloatingDialog } from "../../Generic/FloatingDialog";
 | 
			
		||||
// import { SettingsCell, SettingsOutlined } from "@mui/icons-material";
 | 
			
		||||
import { SettingsOutlined } from "@mui/icons-material";
 | 
			
		||||
import { LoadingButton } from "@mui/lab";
 | 
			
		||||
import { Box, Button, IconButton, Typography, useTheme } from "@mui/material";
 | 
			
		||||
import { useAtom } from "jotai";
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
import { useSettings } from "../../../contexts/SettingsContext";
 | 
			
		||||
import { settingsAtom } from "../../../lib/store/jotai/settings";
 | 
			
		||||
import { FloatingDialog } from "../../Generic/FloatingDialog";
 | 
			
		||||
 | 
			
		||||
// export const Settings = () => {
 | 
			
		||||
//   // contexts
 | 
			
		||||
//   const theme = useTheme();
 | 
			
		||||
//   const { settings, updateSettingsLocal } = useSettings();
 | 
			
		||||
export const Settings = () => {
 | 
			
		||||
  // contexts
 | 
			
		||||
  const theme = useTheme();
 | 
			
		||||
  const { settings, updateSettings, resetSettings } = useSettings();
 | 
			
		||||
 | 
			
		||||
//   return (
 | 
			
		||||
//     <FloatingDialog
 | 
			
		||||
//       body={<Typography>Settings</Typography>}
 | 
			
		||||
//       openButton={
 | 
			
		||||
//         <IconButton>
 | 
			
		||||
//           <SettingsOutlined />
 | 
			
		||||
//         </IconButton>
 | 
			
		||||
//       }
 | 
			
		||||
//     />
 | 
			
		||||
//   );
 | 
			
		||||
// };
 | 
			
		||||
  // atoms
 | 
			
		||||
  const [stagedSettings, setStagedSettings] = useAtom(settingsAtom);
 | 
			
		||||
 | 
			
		||||
  // states
 | 
			
		||||
  const [settingsOpenState, setSettingsOpenState] = useState<boolean>(false);
 | 
			
		||||
  const [settingsMaximisedState, setSettingsMaximisedState] = useState<boolean>(false);
 | 
			
		||||
  const [subTabValue, setSubTabValue] = useState("display");
 | 
			
		||||
  const [applyLoading, setApplyLoading] = useState<boolean>(false);
 | 
			
		||||
  const [saveLoading, setSaveLoading] = useState<boolean>(false);
 | 
			
		||||
 | 
			
		||||
  const toggleSettings = () => {
 | 
			
		||||
    // reset the settings maximised state
 | 
			
		||||
    setSettingsMaximisedState(false);
 | 
			
		||||
    setSettingsOpenState((prevState) => !prevState);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const closeSettings = () => {
 | 
			
		||||
    setSettingsOpenState(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // logic for switching tabs
 | 
			
		||||
  const subTabChangeEvent = (newTabValue: string) => {
 | 
			
		||||
    setSubTabValue(newTabValue);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const applyClickEvent = () => {
 | 
			
		||||
    setApplyLoading(true);
 | 
			
		||||
 | 
			
		||||
    updateSettings(stagedSettings);
 | 
			
		||||
 | 
			
		||||
    setApplyLoading(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const saveClickEvent = () => {
 | 
			
		||||
    setSaveLoading(true);
 | 
			
		||||
 | 
			
		||||
    updateSettings(stagedSettings);
 | 
			
		||||
 | 
			
		||||
    setSaveLoading(false);
 | 
			
		||||
    closeSettings();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setStagedSettings(settings);
 | 
			
		||||
  }, [setStagedSettings, settings]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <FloatingDialog
 | 
			
		||||
      body={<Typography>Settings</Typography>}
 | 
			
		||||
      bottomBar={
 | 
			
		||||
        <Box
 | 
			
		||||
          sx={{
 | 
			
		||||
            display: "flex",
 | 
			
		||||
            justifyContent: "flex-end",
 | 
			
		||||
            px: 0,
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Button
 | 
			
		||||
            onClick={() => setSettingsOpenState(false)}
 | 
			
		||||
            size="small"
 | 
			
		||||
            sx={{
 | 
			
		||||
              mr: 1,
 | 
			
		||||
            }}
 | 
			
		||||
            variant="outlined"
 | 
			
		||||
          >
 | 
			
		||||
            Cancel
 | 
			
		||||
          </Button>
 | 
			
		||||
 | 
			
		||||
          <LoadingButton
 | 
			
		||||
            loading={applyLoading}
 | 
			
		||||
            onClick={applyClickEvent}
 | 
			
		||||
            size="small"
 | 
			
		||||
            sx={{
 | 
			
		||||
              mr: 1,
 | 
			
		||||
            }}
 | 
			
		||||
            variant="outlined"
 | 
			
		||||
          >
 | 
			
		||||
            Apply
 | 
			
		||||
          </LoadingButton>
 | 
			
		||||
          <LoadingButton
 | 
			
		||||
            loading={saveLoading}
 | 
			
		||||
            onClick={saveClickEvent}
 | 
			
		||||
            size="small"
 | 
			
		||||
            variant="contained"
 | 
			
		||||
          >
 | 
			
		||||
            Save
 | 
			
		||||
          </LoadingButton>
 | 
			
		||||
        </Box>
 | 
			
		||||
      }
 | 
			
		||||
      close={closeSettings}
 | 
			
		||||
      maximisedState={settingsMaximisedState}
 | 
			
		||||
      openButton={
 | 
			
		||||
        <IconButton
 | 
			
		||||
          onClick={toggleSettings}
 | 
			
		||||
          size="small"
 | 
			
		||||
        >
 | 
			
		||||
          <SettingsOutlined />
 | 
			
		||||
        </IconButton>
 | 
			
		||||
      }
 | 
			
		||||
      openState={settingsOpenState}
 | 
			
		||||
      setMaximisedState={setSettingsMaximisedState}
 | 
			
		||||
      title="Settings"
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,16 @@
 | 
			
		|||
import { Close, CloseFullscreen, Minimize } from "@mui/icons-material";
 | 
			
		||||
import { Box, Button, ButtonGroup, Stack, useTheme } from "@mui/material";
 | 
			
		||||
import { Box, Button, ButtonGroup, IconButton, Stack, useTheme } from "@mui/material";
 | 
			
		||||
import { WebviewWindow } from "@tauri-apps/api/window";
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
import { useSettings } from "../../contexts/SettingsContext";
 | 
			
		||||
import { exit } from "@tauri-apps/api/process";
 | 
			
		||||
 | 
			
		||||
export const WindowButtons = () => {
 | 
			
		||||
  // contexts
 | 
			
		||||
  const userTheme = useTheme();
 | 
			
		||||
  const { settings } = useSettings();
 | 
			
		||||
 | 
			
		||||
  // states
 | 
			
		||||
  const [appWindow, setAppWindow] = useState<WebviewWindow>();
 | 
			
		||||
 | 
			
		||||
  // explanation:
 | 
			
		||||
| 
						 | 
				
			
			@ -27,8 +32,8 @@ export const WindowButtons = () => {
 | 
			
		|||
    appWindow?.toggleMaximize();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const close = () => {
 | 
			
		||||
    appWindow?.close();
 | 
			
		||||
  const close = async () => {
 | 
			
		||||
    await exit(1);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,10 +42,14 @@ export const WindowButtons = () => {
 | 
			
		|||
 | 
			
		||||
  return (
 | 
			
		||||
    <Box>
 | 
			
		||||
      <Stack direction="row" spacing={1}>
 | 
			
		||||
        <ButtonGroup>
 | 
			
		||||
          <Button
 | 
			
		||||
      <Stack
 | 
			
		||||
        direction="row"
 | 
			
		||||
        spacing={1}
 | 
			
		||||
      >
 | 
			
		||||
        {settings.window.minimize_button && (
 | 
			
		||||
          <IconButton
 | 
			
		||||
            onClick={minimize}
 | 
			
		||||
            size="small"
 | 
			
		||||
            sx={{
 | 
			
		||||
              backgroundColor: userTheme.palette.grey[800],
 | 
			
		||||
            }}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,24 +60,28 @@ export const WindowButtons = () => {
 | 
			
		|||
                backgroundColor: userTheme.palette.grey[800],
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
          </IconButton>
 | 
			
		||||
        )}
 | 
			
		||||
        {settings.window.maximize_button && (
 | 
			
		||||
          <IconButton
 | 
			
		||||
            onClick={maximize}
 | 
			
		||||
            size="small"
 | 
			
		||||
            sx={{
 | 
			
		||||
              backgroundColor: userTheme.palette.grey[800],
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <CloseFullscreen fontSize="inherit" />
 | 
			
		||||
          </Button>
 | 
			
		||||
          <Button
 | 
			
		||||
            onClick={close}
 | 
			
		||||
            sx={{
 | 
			
		||||
              backgroundColor: userTheme.palette.grey[800],
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <Close fontSize="inherit" />
 | 
			
		||||
          </Button>
 | 
			
		||||
        </ButtonGroup>
 | 
			
		||||
          </IconButton>
 | 
			
		||||
        )}
 | 
			
		||||
        <IconButton
 | 
			
		||||
          onClick={close}
 | 
			
		||||
          size="small"
 | 
			
		||||
          sx={{
 | 
			
		||||
            backgroundColor: userTheme.palette.grey[800],
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Close fontSize="inherit" />
 | 
			
		||||
        </IconButton>
 | 
			
		||||
      </Stack>
 | 
			
		||||
    </Box>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,10 @@ export const defaultSettings = {
 | 
			
		|||
    font_family: "monospace" as string,
 | 
			
		||||
    font_scaling: 100,
 | 
			
		||||
  },
 | 
			
		||||
  window: {
 | 
			
		||||
    minimize_button: false as boolean,
 | 
			
		||||
    maximize_button: false as boolean,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type SettingsType = typeof defaultSettings;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								src/lib/store/jotai/settings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/lib/store/jotai/settings.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
import { atom } from "jotai";
 | 
			
		||||
import { defaultSettings } from "../../settings";
 | 
			
		||||
 | 
			
		||||
export const settingsAtom = atom(defaultSettings);
 | 
			
		||||
| 
						 | 
				
			
			@ -29,24 +29,7 @@ export default function Testing() {
 | 
			
		|||
      >
 | 
			
		||||
        reset settings
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Button
 | 
			
		||||
        onClick={() => {
 | 
			
		||||
          updateSettings({
 | 
			
		||||
            display: {
 | 
			
		||||
              dark_mode: false as boolean,
 | 
			
		||||
              accent_color: "#8ab4f8" as string,
 | 
			
		||||
              transition_duration: 200 as number,
 | 
			
		||||
              radius: 8 as number,
 | 
			
		||||
              window_height: 60 as number,
 | 
			
		||||
              window_width: 400 as number,
 | 
			
		||||
              font_family: "monospace" as string,
 | 
			
		||||
              font_scaling: 100,
 | 
			
		||||
            },
 | 
			
		||||
          });
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        update settings
 | 
			
		||||
      </Button>
 | 
			
		||||
      <Button onClick={() => {}}>update settings</Button>
 | 
			
		||||
      <Button
 | 
			
		||||
        onClick={() => {
 | 
			
		||||
          console.log(settings);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue