mirror of
https://github.com/usememos/memos.git
synced 2024-12-27 15:42:51 +08:00
feat: dark mode support for auth page (#569)
* feat: dark mode support for auth page * chore: update
This commit is contained in:
parent
2d5d734da4
commit
90c85103c3
8 changed files with 111 additions and 8 deletions
53
web/src/components/ApperanceDropdownMenu.tsx
Normal file
53
web/src/components/ApperanceDropdownMenu.tsx
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { Option, Select } from "@mui/joy";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Icon from "./Icon";
|
||||
import { APPERANCE_OPTIONS } from "../helpers/consts";
|
||||
import useApperance, { Apperance } from "../hooks/useApperance";
|
||||
|
||||
const ApperanceDropdownMenu = () => {
|
||||
const [apperance, setApperance] = useApperance();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const apperanceOptionItems = [
|
||||
[
|
||||
APPERANCE_OPTIONS[0],
|
||||
<>
|
||||
<Icon.Feather className="w-4 h-4" />
|
||||
<p>{t("setting.apperance-option.follow-system")}</p>
|
||||
</>,
|
||||
],
|
||||
[
|
||||
APPERANCE_OPTIONS[1],
|
||||
<>
|
||||
<Icon.Sun className="w-4 h-4" />
|
||||
<p>{t("setting.apperance-option.always-light")}</p>
|
||||
</>,
|
||||
],
|
||||
[
|
||||
APPERANCE_OPTIONS[2],
|
||||
<>
|
||||
<Icon.Moon className="w-4 h-4" />
|
||||
<p>{t("setting.apperance-option.always-dark")}</p>
|
||||
</>,
|
||||
],
|
||||
] as const;
|
||||
|
||||
return (
|
||||
<Select
|
||||
className="w-56 text-sm"
|
||||
value={apperance}
|
||||
onChange={(_, value) => {
|
||||
setApperance(value as Apperance);
|
||||
}}
|
||||
>
|
||||
{apperanceOptionItems.map((item) => (
|
||||
<Option key={item[0]} value={item[0]}>
|
||||
<span className="flex items-center gap-2">{item[1]}</span>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
export default ApperanceDropdownMenu;
|
|
@ -22,3 +22,6 @@ export const IS_FOLDING_ENABLED_DEFAULT_VALUE = true;
|
|||
export const SETTING_IS_FOLDING_ENABLED_KEY = "setting_IS_FOLDING_ENABLED";
|
||||
|
||||
export const TAB_SPACE_WIDTH = 2;
|
||||
|
||||
export const APPERANCE_OPTIONS = ["auto", "light", "dark"] as const;
|
||||
export const APPERANCE_OPTIONS_STORAGE_KEY = "setting_APPERANCE_OPTIONS";
|
||||
|
|
28
web/src/hooks/useApperance.ts
Normal file
28
web/src/hooks/useApperance.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { useEffect } from "react";
|
||||
import { useColorScheme } from "@mui/joy/styles";
|
||||
|
||||
import { APPERANCE_OPTIONS, APPERANCE_OPTIONS_STORAGE_KEY } from "../helpers/consts";
|
||||
import useLocalStorage from "./useLocalStorage";
|
||||
|
||||
export type Apperance = typeof APPERANCE_OPTIONS[number];
|
||||
|
||||
const useApperance = () => {
|
||||
const [apperance, setApperance] = useLocalStorage<Apperance>(APPERANCE_OPTIONS_STORAGE_KEY, APPERANCE_OPTIONS[0]);
|
||||
|
||||
const { setMode } = useColorScheme();
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (apperance === "dark" || (apperance === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
|
||||
root.classList.add("dark");
|
||||
setMode("dark");
|
||||
} else {
|
||||
root.classList.remove("dark");
|
||||
setMode("light");
|
||||
}
|
||||
}, [apperance]);
|
||||
|
||||
return [apperance, setApperance] as const;
|
||||
};
|
||||
|
||||
export default useApperance;
|
|
@ -1,5 +1,5 @@
|
|||
.page-wrapper.auth {
|
||||
@apply flex flex-row justify-center items-center w-full h-screen bg-white;
|
||||
@apply flex flex-row justify-center items-center w-full h-screen bg-white dark:bg-zinc-900;
|
||||
|
||||
> .page-container {
|
||||
@apply w-80 max-w-full h-full py-4 flex flex-col justify-start items-center;
|
||||
|
@ -11,15 +11,19 @@
|
|||
@apply flex flex-col justify-start items-start w-full mb-4;
|
||||
|
||||
> .title-container {
|
||||
@apply w-full flex flex-row justify-between items-center;
|
||||
@apply w-full flex flex-row justify-start items-center;
|
||||
|
||||
> .logo-img {
|
||||
@apply h-20 w-auto;
|
||||
}
|
||||
|
||||
> .logo-text {
|
||||
@apply text-4xl tracking-wide text-black dark:text-white;
|
||||
}
|
||||
}
|
||||
|
||||
> .slogan-text {
|
||||
@apply text-sm text-gray-700;
|
||||
@apply text-sm text-gray-700 dark:text-gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +37,7 @@
|
|||
@apply absolute top-3 left-3 px-1 leading-10 flex-shrink-0 text-base cursor-text text-gray-400 bg-transparent transition-all select-none;
|
||||
|
||||
&.not-null {
|
||||
@apply text-sm top-0 z-10 leading-4 bg-white rounded;
|
||||
@apply text-sm top-0 z-10 leading-4 bg-white dark:bg-zinc-800 rounded;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +45,7 @@
|
|||
@apply py-2;
|
||||
|
||||
> input {
|
||||
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400 hover:opacity-80;
|
||||
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400 hover:opacity-80 dark:bg-zinc-800 dark:text-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +62,7 @@
|
|||
@apply flex flex-row justify-center items-center px-1 py-2 text-sm rounded hover:opacity-80;
|
||||
|
||||
&.signup-btn {
|
||||
@apply px-3;
|
||||
@apply px-3 dark:text-white dark:opacity-70;
|
||||
}
|
||||
|
||||
&.signin-btn {
|
||||
|
|
|
@ -160,6 +160,11 @@
|
|||
"additional-script": "Additional script",
|
||||
"additional-style-placeholder": "Additional CSS codes",
|
||||
"additional-script-placeholder": "Additional JavaScript codes"
|
||||
},
|
||||
"apperance-option": {
|
||||
"follow-system": "Follow system",
|
||||
"always-light": "Always light",
|
||||
"always-dark": "Always dark"
|
||||
}
|
||||
},
|
||||
"amount-text": {
|
||||
|
|
|
@ -160,6 +160,11 @@
|
|||
"additional-script": "自定义脚本",
|
||||
"additional-style-placeholder": "自定义 CSS 代码",
|
||||
"additional-script-placeholder": "自定义 JavaScript 代码"
|
||||
},
|
||||
"apperance-option": {
|
||||
"follow-system": "跟随系统",
|
||||
"always-light": "总是浅色",
|
||||
"always-dark": "总是深色"
|
||||
}
|
||||
},
|
||||
"amount-text": {
|
||||
|
|
|
@ -9,6 +9,7 @@ import useLoading from "../hooks/useLoading";
|
|||
import { globalService, userService } from "../services";
|
||||
import Icon from "../components/Icon";
|
||||
import toastHelper from "../components/Toast";
|
||||
import ApperanceDropdownMenu from "../components/ApperanceDropdownMenu";
|
||||
import "../less/auth.less";
|
||||
|
||||
const validateConfig: ValidatorConfig = {
|
||||
|
@ -113,7 +114,8 @@ const Auth = () => {
|
|||
<div className="auth-form-wrapper">
|
||||
<div className="page-header-container">
|
||||
<div className="title-container">
|
||||
<img className="logo-img" src="/logo-full.webp" alt="" />
|
||||
<img className="logo-img" src="/logo.webp" alt="" />
|
||||
<p className="logo-text">memos</p>
|
||||
</div>
|
||||
<p className="slogan-text">{t("slogan")}</p>
|
||||
</div>
|
||||
|
@ -160,7 +162,7 @@ const Auth = () => {
|
|||
{!systemStatus?.host && <p className="tip-text">{t("auth.host-tip")}</p>}
|
||||
</div>
|
||||
<div className="footer-container">
|
||||
<div className="w-full flex flex-row justify-center items-center">
|
||||
<div className="w-full flex flex-row justify-center items-center gap-2">
|
||||
<Select
|
||||
className="w-40 text-sm"
|
||||
startDecorator={<Icon.Globe className="w-4 h-auto" />}
|
||||
|
@ -172,6 +174,7 @@ const Auth = () => {
|
|||
<Option value="vi">Tiếng Việt</Option>
|
||||
<Option value="fr">French</Option>
|
||||
</Select>
|
||||
<ApperanceDropdownMenu />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* eslint-disable no-undef */
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,tsx}"],
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
fontSize: {
|
||||
xs: ".75rem",
|
||||
|
|
Loading…
Reference in a new issue