From b8878c4fb8d814a85abcf9f4753a825fc3fe72cf Mon Sep 17 00:00:00 2001 From: Kentai Radiquum Date: Fri, 19 Apr 2024 22:58:45 +0500 Subject: [PATCH] frontend: add color theme & theme switcher --- frontend/app/App.jsx | 21 +++++ .../NavigationRail}/NavigationRail.js | 31 +++++-- frontend/app/globals.css | 83 +++++++++++++++++++ frontend/app/layout.js | 15 ++-- frontend/app/store/theme-store.js | 20 +++++ frontend/package-lock.json | 38 ++++++++- frontend/package.json | 3 +- 7 files changed, 192 insertions(+), 19 deletions(-) create mode 100644 frontend/app/App.jsx rename frontend/{components => app/components/NavigationRail}/NavigationRail.js (51%) create mode 100644 frontend/app/store/theme-store.js diff --git a/frontend/app/App.jsx b/frontend/app/App.jsx new file mode 100644 index 0000000..4683b99 --- /dev/null +++ b/frontend/app/App.jsx @@ -0,0 +1,21 @@ +"use client"; + +import { NavigationRail } from "@/app/components/NavigationRail/NavigationRail"; +import { useThemeStore } from "./store/theme-store"; +import { useEffect } from "react"; +// import { useStore } from "./store/app-store"; + +export const App = (props) => { + const themeStore = useThemeStore(); + + useEffect(() => { + themeStore.checkTheme(); + }, []); + + return ( + + +
{props.children}
+ + ); +}; diff --git a/frontend/components/NavigationRail.js b/frontend/app/components/NavigationRail/NavigationRail.js similarity index 51% rename from frontend/components/NavigationRail.js rename to frontend/app/components/NavigationRail/NavigationRail.js index 414250c..6c79f01 100644 --- a/frontend/components/NavigationRail.js +++ b/frontend/app/components/NavigationRail/NavigationRail.js @@ -1,10 +1,13 @@ "use client"; import { usePathname } from "next/navigation"; +import { useThemeStore } from "@/app/store/theme-store"; import Link from "next/link"; export const NavigationRail = () => { const pathname = usePathname(); + const themeStore = useThemeStore(); + return ( ); }; diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 7ffc567..3160a44 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -11,3 +11,86 @@ body { text-wrap: balance; } } + +body, nav.left{ + transition: background .2s; + transform-origin: left; +} + +body.light.light { + --primary: #bc004b; + --on-primary: #ffffff; + --primary-container: #ffd9de; + --on-primary-container: #400014; + --secondary: #75565b; + --on-secondary: #ffffff; + --secondary-container: #ffd9de; + --on-secondary-container: #2c1519; + --tertiary: #795831; + --on-tertiary: #ffffff; + --tertiary-container: #ffddba; + --on-tertiary-container: #2b1700; + --error: #ba1a1a; + --on-error: #ffffff; + --error-container: #ffdad6; + --on-error-container: #410002; + --background: #fffbff; + --on-background: #201a1b; + --surface: #fff8f7; + --on-surface: #201a1b; + --surface-variant: #f3dddf; + --on-surface-variant: #524345; + --outline: #847375; + --outline-variant: #d6c2c3; + --shadow: #000000; + --scrim: #000000; + --inverse-surface: #362f2f; + --inverse-on-surface: #fbeeee; + --inverse-primary: #ffb2be; + --surface-dim: #e3d7d8; + --surface-bright: #fff8f7; + --surface-container-lowest: #ffffff; + --surface-container-low: #fdf1f1; + --surface-container: #f8ebeb; + --surface-container-high: #f2e5e6; + --surface-container-highest: #ece0e0; +} + +body.dark.dark { + --primary: #ffb2be; + --on-primary: #660025; + --primary-container: #900038; + --on-primary-container: #ffd9de; + --secondary: #e5bdc2; + --on-secondary: #43292d; + --secondary-container: #5c3f43; + --on-secondary-container: #ffd9de; + --tertiary: #ebbf90; + --on-tertiary: #452b08; + --tertiary-container: #5f411c; + --on-tertiary-container: #ffddba; + --error: #ffb4ab; + --on-error: #690005; + --error-container: #93000a; + --on-error-container: #ffb4ab; + --background: #201a1b; + --on-background: #ece0e0; + --surface: #181213; + --on-surface: #ece0e0; + --surface-variant: #524345; + --on-surface-variant: #d6c2c3; + --outline: #9f8c8e; + --outline-variant: #524345; + --shadow: #000000; + --scrim: #000000; + --inverse-surface: #ece0e0; + --inverse-on-surface: #362f2f; + --inverse-primary: #bc004b; + --surface-dim: #181213; + --surface-bright: #3f3738; + --surface-container-lowest: #120d0d; + --surface-container-low: #201a1b; + --surface-container: #241e1f; + --surface-container-high: #2f2829; + --surface-container-highest: #3a3334; +} \ No newline at end of file diff --git a/frontend/app/layout.js b/frontend/app/layout.js index 3656b24..bf915f1 100644 --- a/frontend/app/layout.js +++ b/frontend/app/layout.js @@ -1,21 +1,16 @@ import "./globals.css"; import "beercss"; -import "material-dynamic-colors"; - -import { NavigationRail } from "@/components/NavigationRail"; +import {App} from "@/app/App" export const metadata = { title: "AniX", - description: "Unofficial web app for anixart", + description: "Неофициальное веб приложение для anixart", }; -export default function RootLayout({ children }) { +export default async function RootLayout({ children }) { return ( - - - -
{children}
- + + {children} ); } diff --git a/frontend/app/store/theme-store.js b/frontend/app/store/theme-store.js new file mode 100644 index 0000000..3903029 --- /dev/null +++ b/frontend/app/store/theme-store.js @@ -0,0 +1,20 @@ +"use client"; +import { create } from "zustand"; + +export function setTheme(theme) { + localStorage.setItem("theme", theme); +} +export function getTheme() { + return localStorage.getItem("theme"); +} + +export const useThemeStore = create((set) => ({ + theme: "light", + changeTheme: (theme) => { + set({ theme: theme }); + setTheme(theme); + }, + checkTheme: () => { + set({ theme: getTheme() || "light" }); + } +})); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 73ce7a3..d998560 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,8 @@ "material-dynamic-colors": "^1.1.0", "next": "14.2.2", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "zustand": "^4.5.2" }, "devDependencies": { "postcss": "^8", @@ -1764,6 +1765,14 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1907,6 +1916,33 @@ "engines": { "node": ">= 14" } + }, + "node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/frontend/package.json b/frontend/package.json index 70d9c06..d815725 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,8 @@ "material-dynamic-colors": "^1.1.0", "next": "14.2.2", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "zustand": "^4.5.2" }, "devDependencies": { "postcss": "^8",