improved settings page

This commit is contained in:
Fedor Katurov 2023-04-27 16:58:02 +06:00
parent 70f6dcd495
commit 06d56d1800
19 changed files with 228 additions and 69 deletions

View file

@ -6,5 +6,8 @@
"Background": "Background",
"Text": "Text",
"Links": "Links",
"Colors": "Colors"
"Colors": "Colors",
"Inline code": "Inline code",
"Ok": "Ok",
"Settings": "Settings"
}

View file

@ -6,5 +6,8 @@
"Background": "Фон",
"Text": "Текст",
"Links": "Ссылки",
"Colors": "Цвета"
"Colors": "Цвета",
"Inline code": "Код в строке",
"Ok": "Ok",
"Settings": "Настройки"
}

View file

@ -6,6 +6,10 @@
cursor: pointer;
transition: all 0.25s;
&.size-normal {
padding: 4px 20px;
}
&.size-small {
padding: 2px 16px;
font-size: 0.8rem;

View file

@ -0,0 +1,18 @@
import { FC, ReactNode } from "react";
import styles from "./styles.module.scss";
interface RowGroupProps {
children: ReactNode[];
}
const RowGroup: FC<RowGroupProps> = ({ children }) => (
<div className={styles.group}>
{children.map((item, key) => (
<div key={key} className={styles.row}>
{item}
</div>
))}
</div>
);
export { RowGroup };

View file

@ -0,0 +1,12 @@
.group {
display: flex;
flex-direction: column;
border-radius: 6px;
box-shadow: var(--color-border) 0 0 0 1px;
}
.row {
&:not(:last-child) {
box-shadow: var(--color-border) 0 1px;
}
}

View file

@ -0,0 +1,15 @@
import { FC, PropsWithChildren } from "react";
import styles from "./styles.module.scss";
type SettingsRowProps = PropsWithChildren & {
title: string;
};
const SettingsRow: FC<SettingsRowProps> = ({ title, children }) => (
<div className={styles.row}>
<div className={styles.title}>{title}</div>
<div className={styles.item}>{children}</div>
</div>
);
export { SettingsRow };

View file

@ -0,0 +1,11 @@
.row {
display: flex;
flex-direction: row;
padding: 10px;
align-items: center;
gap: 20px;
}
.title {
flex: 1;
}

View file

@ -1,6 +1,5 @@
.editor {
position: relative;
height: 100%;
min-height: 100%;
box-sizing: border-box;
}
@ -17,7 +16,7 @@
}
&:hover {
opacity: 1;
opacity: 1 !important;
}
}

View file

@ -1,12 +1,25 @@
import { FC, PropsWithChildren } from "react";
import styles from "./styles.module.scss";
import { IconButton } from "~/components/buttons/IconButton";
interface ModalPageProps extends PropsWithChildren {
title?: string;
onClose: () => void;
}
const ModalPage: FC<ModalPageProps> = ({ children }) => (
<div className={styles.page}>{children}</div>
const ModalPage: FC<ModalPageProps> = ({ children, title, onClose }) => (
<div className={styles.page}>
<div className={styles.header}>
<div className={styles.title}>{title}</div>
<div className={styles.close}>
<IconButton onClick={onClose} role="button">
x
</IconButton>
</div>
</div>
{children}
</div>
);
export { ModalPage };

View file

@ -2,4 +2,16 @@
background: var(--color-background);
padding: 16px;
border-radius: 10px;
box-shadow: var(--color-border) 0 0 0 1px;
}
.header {
display: flex;
flex-direction: row;
padding: 0 0 20px 0;
}
.title {
flex: 1;
font-size: 1.4em;
}

View file

@ -0,0 +1,70 @@
import { ChangeEvent, FC, useCallback } from "react";
import { useTranslation } from "react-i18next";
import { RowGroup } from "~/components/containers/RowGroup";
import { SettingsRow } from "~/components/containers/SettingsRow";
import {
SettingsValue,
useSettings,
} from "~/modules/settings/context/SettingsContext";
const ColorSettings: FC = () => {
const { update, settings } = useSettings();
const { t } = useTranslation();
const setString = useCallback(
(field: keyof SettingsValue) => (event: ChangeEvent<HTMLInputElement>) => {
update({ [field]: event.target.value });
},
[update]
);
return (
<RowGroup>
<label htmlFor="color">
<SettingsRow title={t("Background")}>
<input
type="color"
id="color"
onChange={setString("backgroundColor")}
value={settings.backgroundColor}
/>
</SettingsRow>
</label>
<label htmlFor="color">
<SettingsRow title={t("Text")}>
<input
type="color"
id="color"
onChange={setString("textColor")}
value={settings.textColor}
/>
</SettingsRow>
</label>
<label htmlFor="color">
<SettingsRow title={t("Links")}>
<input
type="color"
id="color"
onChange={setString("linkColor")}
value={settings.linkColor}
/>
</SettingsRow>
</label>
<label htmlFor="color">
<SettingsRow title={t("Inline code")}>
<input
type="color"
id="color"
onChange={setString("codeColor")}
value={settings.codeColor}
/>
</SettingsRow>
</label>
</RowGroup>
);
};
export { ColorSettings };

View file

@ -1,66 +1,11 @@
import { ChangeEvent, FC, useCallback } from "react";
import { useSettings } from "../../context/SettingsContext";
import { useTranslation } from "react-i18next";
import { FC } from "react";
import { ColorSettings } from "../ColorSettings";
import styles from "./styles.module.scss";
const SettingsContainer: FC = () => {
const { update, settings } = useSettings();
const { t } = useTranslation();
const updateBackgroundColor = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
update({ backgroundColor: event.target.value });
},
[update]
);
const updateTextColor = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
update({ textColor: event.target.value });
},
[update]
);
const updateLinkColor = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
update({ linkColor: event.target.value });
},
[update]
);
return (
<div>
<h2>{t("Colors")}</h2>
<label htmlFor="color">
{t("Background")}
<input
type="color"
id="color"
onChange={updateBackgroundColor}
value={settings.backgroundColor}
/>
</label>
<label htmlFor="color">
{t("Text")}
<input
type="color"
id="color"
onChange={updateTextColor}
value={settings.textColor}
/>
</label>
<label htmlFor="color">
{t("Links")}
<input
type="color"
id="color"
onChange={updateLinkColor}
value={settings.linkColor}
/>
</label>
<div className={styles.container}>
<ColorSettings />
</div>
);
};

View file

@ -0,0 +1,3 @@
.container {
width: min(100vw, 400px);
}

View file

@ -4,6 +4,7 @@ export interface ColorSettings {
backgroundColor: string;
textColor: string;
linkColor: string;
codeColor: string;
}
export type SettingsValue = ColorSettings & {
@ -15,6 +16,7 @@ export const defaultSettings: SettingsValue = {
backgroundColor: "",
textColor: "",
linkColor: "",
codeColor: "",
};
export const SettingsContext = createContext({

View file

@ -13,8 +13,12 @@ import {
defaultDarkTheme,
defaultLightTheme,
} from "~/modules/theme/constants/theme";
import { Button } from "~/components/buttons/Button";
import { useTranslation } from "react-i18next";
import styles from "./styles.module.scss";
const SettingsProvider: FC<PropsWithChildren> = ({ children }) => {
const { t } = useTranslation();
const theme = useDetectTheme();
const defaultColors =
theme === Theme.Dark ? defaultDarkTheme : defaultLightTheme;
@ -36,8 +40,14 @@ const SettingsProvider: FC<PropsWithChildren> = ({ children }) => {
<SettingsContext.Provider value={{ settings, update, show, hide }}>
{settingsModalVisible && (
<Modal onClose={hide}>
<ModalPage onClose={hide}>
<ModalPage onClose={hide} title={t("Settings")}>
<SettingsContainer />
<div className={styles.buttons}>
<div className={styles.filler} />
<Button onClick={hide}>{t("Ok")}</Button>
<div className={styles.filler} />
</div>
</ModalPage>
</Modal>
)}

View file

@ -0,0 +1,9 @@
.buttons {
padding-top: 20px;
display: flex;
flex-direction: row;
}
.filler {
flex: 1;
}

View file

@ -9,10 +9,12 @@ export const defaultDarkTheme: ColorSettings = {
backgroundColor: "#2e2e2e",
textColor: "#eeeeee",
linkColor: "#25bfe6",
codeColor: "#ff3344",
};
export const defaultLightTheme: ColorSettings = {
backgroundColor: "#eeeeee",
textColor: "#2e2e2e",
linkColor: "#25bfe6",
codeColor: "#ff3344",
};

View file

@ -9,11 +9,22 @@ export const useThemeColors = (settings: ColorSettings) => {
const border = isDark
? background.mix(Color("white"), 0.1)
: background.mix(Color("black"), 0.1);
: background.mix(Color("black"), 0.2);
const code = new Color(settings.codeColor);
document.body.style.setProperty("--color-background", background.hex());
document.body.style.setProperty("--color-code", code.hex());
document.body.style.setProperty(
"--color-code-background",
code.fade(isDark ? 0.9 : 0.7).toString()
);
document.body.style.setProperty("--color-text", settings.textColor);
document.body.style.setProperty("--color-link", settings.linkColor);
document.body.style.setProperty("--color-border", border.hex());
document.body.style.setProperty(
"--color-pre-background",
isDark ? background.lighten(0.2).hex() : background.darken(0.2).hex()
);
}, [settings]);
};

View file

@ -54,3 +54,20 @@ pre {
color: inherit;
}
}
blockquote {
background: var(--color-pre-background);
margin-left: 0;
padding: 5px 10px;
border-radius: 4px;
font-size: 0.9em;
border-left: var(--color-border) 4px solid;
p {
margin: 5px 0;
}
}
img {
max-width: 100%;
}