style improvements

This commit is contained in:
Vomitblood 2024-08-10 02:43:41 +08:00
parent 72f9121593
commit e48611b11c
9 changed files with 151 additions and 44 deletions

View file

@ -1,7 +1,8 @@
import { Close, UnfoldLess, UnfoldMore } from "@mui/icons-material"; import { Close, UnfoldLess, UnfoldMore } from "@mui/icons-material";
import { Box, IconButton, Modal, Tooltip, Typography } from "@mui/material"; import { Box, IconButton, Modal, Tooltip, Typography, useTheme } from "@mui/material";
import { FC, ReactNode } from "react"; import { FC, ReactNode } from "react";
import { useSettings } from "../../contexts/SettingsContext"; import { useSettings } from "../../contexts/SettingsContext";
import { hexToRgba } from "../../lib/utils/color";
interface FloatingDialog { interface FloatingDialog {
actionButtons?: ReactNode; actionButtons?: ReactNode;
@ -28,7 +29,11 @@ export const FloatingDialog: FC<FloatingDialog> = ({
title, title,
sx, sx,
}) => { }) => {
// contexts
const { settings } = useSettings(); const { settings } = useSettings();
const theme = useTheme();
const { r, g, b, a } = hexToRgba(theme.palette.background.paper);
return ( return (
<> <>
@ -40,7 +45,8 @@ export const FloatingDialog: FC<FloatingDialog> = ({
> >
<Box <Box
sx={{ sx={{
bgcolor: "background.paper", backdropFilter: `blur(${settings.style.blur_radius}px)`,
backgroundColor: `rgba(${r}, ${g}, ${b}, ${settings.style.opacity})`,
borderRadius: maximisedState ? "0px" : settings.style.radius + "px", borderRadius: maximisedState ? "0px" : settings.style.radius + "px",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",

View file

@ -1,4 +1,4 @@
import { Box, Button } from "@mui/material"; import { Box, Button, useTheme } from "@mui/material";
import { convertFileSrc } from "@tauri-apps/api/tauri"; import { convertFileSrc } from "@tauri-apps/api/tauri";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useSettings } from "../../contexts/SettingsContext"; import { useSettings } from "../../contexts/SettingsContext";
@ -6,7 +6,9 @@ import { FooterBar } from "../FooterBar/FooterBar";
import { HeaderBar } from "../HeaderBar/HeaderBar"; import { HeaderBar } from "../HeaderBar/HeaderBar";
export const Layout = () => { export const Layout = () => {
// contexts
const { settings } = useSettings(); const { settings } = useSettings();
const theme = useTheme();
const [imageUrl, setImageUrl] = useState<string | null>(null); const [imageUrl, setImageUrl] = useState<string | null>(null);
@ -23,7 +25,7 @@ export const Layout = () => {
<Box <Box
sx={{ sx={{
// Use the URL function for background images // Use the URL function for background images
backgroundColor: settings.background.background_color, backgroundColor: theme.palette.background.default,
backgroundImage: settings.background.background_image_path ? `url(${imageUrl})` : "", backgroundImage: settings.background.background_image_path ? `url(${imageUrl})` : "",
backgroundSize: "cover", backgroundSize: "cover",
backgroundPosition: "center", backgroundPosition: "center",

View file

@ -7,9 +7,9 @@ import { useEffect, useState } from "react";
import { useSettings } from "../../../contexts/SettingsContext"; import { useSettings } from "../../../contexts/SettingsContext";
import { stagedSettingsAtom } from "../../../lib/store/jotai/settings"; import { stagedSettingsAtom } from "../../../lib/store/jotai/settings";
import { FloatingDialog } from "../../Generic/FloatingDialog"; import { FloatingDialog } from "../../Generic/FloatingDialog";
import { SettingsTabBackground } from "./SettingsTabs/SettingsTabBackground"; import { Background } from "./SettingsTabs/Background";
import { SettingsTabStyle } from "./SettingsTabs/SettingsTabStyle"; import { Style } from "./SettingsTabs/Style";
import { SettingsTabWindow } from "./SettingsTabs/SettingsTabWindow"; import { Window } from "./SettingsTabs/Window";
export const Settings = () => { export const Settings = () => {
// contexts // contexts
@ -127,19 +127,19 @@ export const Settings = () => {
sx={{ p: 2 }} sx={{ p: 2 }}
value="style" value="style"
> >
<SettingsTabStyle /> <Style />
</TabPanel> </TabPanel>
<TabPanel <TabPanel
sx={{ p: 2 }} sx={{ p: 2 }}
value="background" value="background"
> >
<SettingsTabBackground /> <Background />
</TabPanel> </TabPanel>
<TabPanel <TabPanel
sx={{ p: 2 }} sx={{ p: 2 }}
value="window" value="window"
> >
<SettingsTabWindow /> <Window />
</TabPanel> </TabPanel>
</Box> </Box>
</TabContext> </TabContext>

View file

@ -1,21 +1,22 @@
import { DeleteOutline, FileOpenOutlined } from "@mui/icons-material"; import { DeleteOutline, FileOpenOutlined } from "@mui/icons-material";
import { Box, Button, Stack, TextField } from "@mui/material"; import { Box, Button, Stack, TextField } from "@mui/material";
import { open } from "@tauri-apps/api/dialog"; import { open } from "@tauri-apps/api/dialog";
import { convertFileSrc, invoke } from "@tauri-apps/api/tauri"; import { readBinaryFile } from "@tauri-apps/api/fs";
import { invoke } from "@tauri-apps/api/tauri";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import Image from "next/image"; import Image from "next/image";
import { FC, useEffect, useState } from "react"; import { FC, useEffect, useState } from "react";
import { useSettings } from "../../../../contexts/SettingsContext"; import { useSettings } from "../../../../contexts/SettingsContext";
import { defaultSettings } from "../../../../lib/settings";
import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings"; import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings";
import { CategoryTitle } from "../CategoryTitle"; import { CategoryTitle } from "../CategoryTitle";
import { SettingsItem } from "../SettingsItem"; import { SettingsItem } from "../SettingsItem";
import { readBinaryFile } from "@tauri-apps/api/fs";
interface SettingsTabBackgroundProps { interface BackgroundProps {
sx?: any; sx?: any;
} }
export const SettingsTabBackground: FC<SettingsTabBackgroundProps> = ({ sx }) => { export const Background: FC<BackgroundProps> = ({ sx }) => {
// contexts // contexts
const { settings, updateSettings } = useSettings(); const { settings, updateSettings } = useSettings();
@ -195,7 +196,7 @@ export const SettingsTabBackground: FC<SettingsTabBackgroundProps> = ({ sx }) =>
</Box> </Box>
<CategoryTitle title="Colors" /> <CategoryTitle title="Colors" />
<SettingsItem <SettingsItem
defaultText="#202124" defaultText={defaultSettings.background.background_color}
description="Background color" description="Background color"
input={ input={
<TextField <TextField
@ -213,13 +214,25 @@ export const SettingsTabBackground: FC<SettingsTabBackgroundProps> = ({ sx }) =>
/> />
} }
/> />
<button <SettingsItem
onClick={() => { defaultText={defaultSettings.background.background_color_popup}
updateSettings(stagedSettings); description="Popup background color"
input={
<TextField
name="background_color_popup"
onChange={(e) => {
handleSettingsBackgroundValueChange(e.target.name, e.target.value);
}} }}
> sx={{
apply width: "100%",
</button> }}
size="small"
type="color"
value={stagedSettings.background.background_color_popup}
variant="standard"
/>
}
/>
</Box> </Box>
); );
}; };

View file

@ -1,17 +1,18 @@
import { Box, InputAdornment, MenuItem, Slider, Switch, TextField, Typography } from "@mui/material"; import { Box, InputAdornment, MenuItem, Slider, Switch, TextField } from "@mui/material";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { FC } from "react"; import { FC } from "react";
import { defaultSettings } from "../../../../lib/settings";
import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings"; import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings";
import { BetaChip } from "../BetaChip"; import { BetaChip } from "../BetaChip";
import { CategoryTitle } from "../CategoryTitle"; import { CategoryTitle } from "../CategoryTitle";
import { DevChip } from "../DevChip"; import { DevChip } from "../DevChip";
import { SettingsItem } from "../SettingsItem"; import { SettingsItem } from "../SettingsItem";
interface SettingsTabStyleProps { interface StyleProps {
sx?: any; sx?: any;
} }
export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => { export const Style: FC<StyleProps> = ({ sx }) => {
// atoms // atoms
const [stagedSettings, setStagedSettings] = useAtom(stagedSettingsAtom); const [stagedSettings, setStagedSettings] = useAtom(stagedSettingsAtom);
@ -32,7 +33,7 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
<Box sx={{ sx }}> <Box sx={{ sx }}>
<CategoryTitle title="Basic styles" /> <CategoryTitle title="Basic styles" />
<SettingsItem <SettingsItem
defaultText="On" defaultText={defaultSettings.style.dark_mode ? "On" : "Off"}
description={ description={
<> <>
<BetaChip /> <BetaChip />
@ -50,7 +51,7 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="#8ab4f8" defaultText={defaultSettings.style.accent_color}
description="Accent color" description="Accent color"
input={ input={
<TextField <TextField
@ -69,7 +70,7 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="Monospace" defaultText={defaultSettings.style.font_family}
description="Font family" description="Font family"
inputLong={ inputLong={
<TextField <TextField
@ -94,7 +95,7 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="100%" defaultText={defaultSettings.style.font_scaling + "%"}
description="Font scaling" description="Font scaling"
inputBottom={ inputBottom={
<Slider <Slider
@ -134,20 +135,20 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
/> />
<CategoryTitle title="Advanced settings" /> <CategoryTitle title="Advanced settings" />
<SettingsItem <SettingsItem
defaultText="200ms" defaultText={defaultSettings.style.blur_radius + "px"}
description={ description={
<> <>
<DevChip /> <DevChip />
Transition duration Blur radius
</> </>
} }
input={ input={
<TextField <TextField
InputProps={{ InputProps={{
endAdornment: <InputAdornment position="end">ms</InputAdornment>, endAdornment: <InputAdornment position="end">px</InputAdornment>,
inputProps: { min: 0, max: 100, step: 1 }, inputProps: { min: 0, max: 100, step: 1 },
}} }}
name="transition_duration" name="blur_radius"
onChange={(e) => { onChange={(e) => {
handleSettingsStyleValueChange(e.target.name, parseFloat(e.target.value)); handleSettingsStyleValueChange(e.target.name, parseFloat(e.target.value));
}} }}
@ -156,13 +157,13 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
}} }}
size="small" size="small"
type="number" type="number"
value={stagedSettings.style.transition_duration} value={stagedSettings.style.blur_radius}
variant="standard" variant="standard"
/> />
} }
/> />
<SettingsItem <SettingsItem
defaultText="8px" defaultText={defaultSettings.style.radius + "px"}
description={ description={
<> <>
<DevChip /> <DevChip />
@ -190,7 +191,62 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="60%" defaultText={defaultSettings.style.opacity.toString()}
description={
<>
<DevChip />
Opacity
</>
}
input={
<TextField
InputProps={{
inputProps: { min: 0, max: 1, step: 0.01 },
}}
name="opacity"
onChange={(e) => {
handleSettingsStyleValueChange(e.target.name, parseFloat(e.target.value));
}}
sx={{
width: "100%",
}}
size="small"
type="number"
value={stagedSettings.style.opacity}
variant="standard"
/>
}
/>
<SettingsItem
defaultText={defaultSettings.style.transition_duration.toString()}
description={
<>
<DevChip />
Transition duration
</>
}
input={
<TextField
InputProps={{
endAdornment: <InputAdornment position="end">ms</InputAdornment>,
inputProps: { min: 0, max: 100, step: 1 },
}}
name="transition_duration"
onChange={(e) => {
handleSettingsStyleValueChange(e.target.name, parseFloat(e.target.value));
}}
sx={{
width: "100%",
}}
size="small"
type="number"
value={stagedSettings.style.transition_duration}
variant="standard"
/>
}
/>
<SettingsItem
defaultText={defaultSettings.style.window_height + "%"}
description={ description={
<> <>
<DevChip /> <DevChip />
@ -218,7 +274,7 @@ export const SettingsTabStyle: FC<SettingsTabStyleProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="400px" defaultText={defaultSettings.style.window_width + "px"}
description={ description={
<> <>
<DevChip /> <DevChip />

View file

@ -4,12 +4,13 @@ import { FC } from "react";
import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings"; import { stagedSettingsAtom } from "../../../../lib/store/jotai/settings";
import { CategoryTitle } from "../CategoryTitle"; import { CategoryTitle } from "../CategoryTitle";
import { SettingsItem } from "../SettingsItem"; import { SettingsItem } from "../SettingsItem";
import { defaultSettings } from "../../../../lib/settings";
interface SettingsTabWindowProps { interface WindowProps {
sx?: any; sx?: any;
} }
export const SettingsTabWindow: FC<SettingsTabWindowProps> = ({ sx }) => { export const Window: FC<WindowProps> = ({ sx }) => {
// atoms // atoms
const [stagedSettings, setStagedSettings] = useAtom(stagedSettingsAtom); const [stagedSettings, setStagedSettings] = useAtom(stagedSettingsAtom);
@ -30,7 +31,7 @@ export const SettingsTabWindow: FC<SettingsTabWindowProps> = ({ sx }) => {
<Box sx={{ sx }}> <Box sx={{ sx }}>
<CategoryTitle title="Fullscreen" /> <CategoryTitle title="Fullscreen" />
<SettingsItem <SettingsItem
defaultText="On" defaultText={defaultSettings.window.start_fullscreen ? "On" : "Off"}
description="Fullscreen on startup" description="Fullscreen on startup"
input={ input={
<Switch <Switch
@ -44,7 +45,7 @@ export const SettingsTabWindow: FC<SettingsTabWindowProps> = ({ sx }) => {
/> />
<CategoryTitle title="Titlebar Buttons" /> <CategoryTitle title="Titlebar Buttons" />
<SettingsItem <SettingsItem
defaultText="Off" defaultText={defaultSettings.window.minimize_button ? "On" : "Off"}
description="Minimize button" description="Minimize button"
input={ input={
<Switch <Switch
@ -57,7 +58,7 @@ export const SettingsTabWindow: FC<SettingsTabWindowProps> = ({ sx }) => {
} }
/> />
<SettingsItem <SettingsItem
defaultText="Off" defaultText={defaultSettings.window.maximize_button ? "On" : "Off"}
description="Maximize button" description="Maximize button"
input={ input={
<Switch <Switch

View file

@ -60,8 +60,8 @@ export const UserThemeProvider: FC<UserThemeProviderProps> = ({ children }) => {
A700: "#616161", A700: "#616161",
}, },
background: { background: {
paper: settings.style.dark_mode ? "#303134" : "#fff", paper: settings.style.dark_mode ? settings.background.background_color_popup : "#fff",
default: settings.style.dark_mode ? "#202124" : "#fff", default: settings.style.dark_mode ? settings.background.background_color : "#fff",
}, },
}; };

View file

@ -4,13 +4,16 @@ import { readTomlFile, writeTomlFile } from "./utils/toml";
export const defaultSettings = { export const defaultSettings = {
background: { background: {
background_color: "#202124" as string, background_color: "#202124" as string,
background_color_popup: "#303134" as string,
background_image_path: "" as string, background_image_path: "" as string,
}, },
style: { style: {
accent_color: "#8ab4f8" as string, accent_color: "#8ab4f8" as string,
blur_radius: 10 as number,
dark_mode: true as boolean, dark_mode: true as boolean,
font_family: "monospace" as string, font_family: "monospace" as string,
font_scaling: 100, font_scaling: 100,
opacity: 0.8 as number,
radius: 8 as number, radius: 8 as number,
transition_duration: 200 as number, transition_duration: 200 as number,
window_height: 80 as number, window_height: 80 as number,

26
src/lib/utils/color.ts Normal file
View file

@ -0,0 +1,26 @@
export const hexToRgba = (hex: string): { r: number; g: number; b: number; a: number } => {
// remove the hash at the start if it is there
hex = hex.replace("#", "");
let r, g, b, a;
if (hex.length === 8) {
// hex have alpha (rrggbbaa)
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
// convert alpha (from 0-255) to decimal (from 0-1)
a = parseInt(hex.substring(6, 8), 16) / 255;
} else if (hex.length === 6) {
// hex no have alpha
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
// default alpha is 1
a = 1;
} else {
throw new Error("Invalid hex color format. Must be #rrggbbaa or #rrggbb.");
}
return { r, g, b, a };
};