diff --git a/frontend/.qwen/settings.json b/frontend/.qwen/settings.json new file mode 100644 index 0000000..eed251d --- /dev/null +++ b/frontend/.qwen/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(yarn *)" + ] + } +} \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 8556a28..c240c26 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,9 +1,12 @@ import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router"; +import { ThemeInitialProvider } from "./modules/theme-changer"; import App from "./app/App"; createRoot(document.getElementById("root")!).render( - + + + , ); diff --git a/frontend/src/modules/theme-bw/stores/theme.store.ts b/frontend/src/modules/theme-bw/stores/theme.store.ts index 10cffdc..befdb4b 100644 --- a/frontend/src/modules/theme-bw/stores/theme.store.ts +++ b/frontend/src/modules/theme-bw/stores/theme.store.ts @@ -1,6 +1,7 @@ import type { Theme } from "@/modules/auth/types/auth.types"; import { create } from "zustand"; import { persist } from "zustand/middleware"; +import { applyTheme, getSavedTheme, getCurrentTheme } from "@/modules/theme-changer/utils/apply.theme"; interface ThemeState { theme: Theme; @@ -10,26 +11,20 @@ interface ThemeState { export const useThemeStore = create()( persist( - (set) => ({ - theme: "dark", + (set, get) => ({ + theme: "dark" as Theme, toggleTheme: () => { - set((state) => { - const newTheme = state.theme === "dark" ? "light" : "dark"; - // Применяем класс к documentElement - if (newTheme === "dark") { - document.documentElement.classList.add("dark"); - } else { - document.documentElement.classList.remove("dark"); - } - return { theme: newTheme }; - }); + const currentTheme = getCurrentTheme(); + const newThemeType = currentTheme === "dark" || currentTheme === "nightowl" || currentTheme === "sunset" || currentTheme === "forest" || currentTheme === "ocean" || currentTheme === "coffee" + ? "light" + : "dark"; + // Переключаемся между light и dark базовыми темами + const newTheme = newThemeType === "dark" ? "dark" : "light"; + applyTheme(newTheme); + set({ theme: newTheme as Theme }); }, setTheme: (theme: Theme) => { - if (theme === "dark") { - document.documentElement.classList.add("dark"); - } else { - document.documentElement.classList.remove("dark"); - } + applyTheme(theme); set({ theme }); }, }), @@ -38,17 +33,3 @@ export const useThemeStore = create()( }, ), ); - -// Инициализация темы при загрузке -if (typeof window !== "undefined") { - const storedTheme = localStorage.getItem("theme-storage"); - if (storedTheme) { - const { state } = JSON.parse(storedTheme); - if (state.theme === "dark") { - document.documentElement.classList.add("dark"); - } - } else { - // По умолчанию dark - document.documentElement.classList.add("dark"); - } -} diff --git a/frontend/src/modules/theme-bw/ui/ThemeToggle.tsx b/frontend/src/modules/theme-bw/ui/ThemeToggle.tsx index 75019a6..f3fccf4 100644 --- a/frontend/src/modules/theme-bw/ui/ThemeToggle.tsx +++ b/frontend/src/modules/theme-bw/ui/ThemeToggle.tsx @@ -1,20 +1,56 @@ -import React from "react"; -import { useThemeStore } from "../stores/theme.store"; +import React, { useState, useEffect } from "react"; import { FiSun, FiMoon } from "react-icons/fi"; +import { getCurrentTheme, toggleDarkLight, getSavedTheme } from "../../theme-changer/utils/apply.theme"; +import { themes } from "../../theme-changer/config/theme.config"; export const ThemeToggle: React.FC = () => { - const { theme, toggleTheme } = useThemeStore(); + const [currentTheme, setCurrentTheme] = useState(() => getSavedTheme()); + + const currentThemeData = themes.find((t) => t.id === currentTheme); + const isDark = currentThemeData?.type === "dark"; + + const handleClick = () => { + const newTheme = toggleDarkLight(); + setCurrentTheme(newTheme); + }; + + // Инициализация при монтировании + useEffect(() => { + const saved = getSavedTheme(); + const current = getCurrentTheme() || saved; + setCurrentTheme(current); + }, []); + + // Слушаем изменения темы из других компонентов + useEffect(() => { + const handleThemeChange = (e: Event) => { + const event = e as CustomEvent; + setCurrentTheme(event.detail.theme); + }; + window.addEventListener("themechange", handleThemeChange); + return () => window.removeEventListener("themechange", handleThemeChange); + }, []); return ( ); diff --git a/frontend/src/pages/auth.page.tsx b/frontend/src/pages/auth.page.tsx index d9f5cb6..a20c8ad 100644 --- a/frontend/src/pages/auth.page.tsx +++ b/frontend/src/pages/auth.page.tsx @@ -13,7 +13,7 @@ export const AuthPage: React.FC = () => { useEffect(() => { if (token) { - navigate("/dashboard"); + navigate("/"); } }, [token, navigate]); @@ -21,7 +21,7 @@ export const AuthPage: React.FC = () => { e.preventDefault(); try { await login(formData); - navigate("/dashboard"); + navigate("/"); } catch (err) { // Error is handled by store } @@ -36,23 +36,49 @@ export const AuthPage: React.FC = () => { }; return ( -
-
+
+
{/* Card */} -
+
{/* Header */}
-

- Welcome Back +
+ +
+

+ С возвращением!

-

- Sign in to your account +

+ Войдите в свой аккаунт

{/* Error Message */} {error && ( -
+
{error}
)} @@ -60,37 +86,75 @@ export const AuthPage: React.FC = () => { {/* Form */}
-
-
@@ -98,14 +162,29 @@ export const AuthPage: React.FC = () => { @@ -113,13 +192,20 @@ export const AuthPage: React.FC = () => { {/* Footer */}
-

- Don't have an account?{" "} +

+ Нет аккаунта?{" "} { + e.currentTarget.style.color = "var(--link-hover)"; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = "var(--link)"; + }} > - Sign up + Зарегистрироваться

diff --git a/frontend/src/pages/register.page.tsx b/frontend/src/pages/register.page.tsx index b2b77a4..98d8843 100644 --- a/frontend/src/pages/register.page.tsx +++ b/frontend/src/pages/register.page.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import { useNavigate, Link } from "react-router-dom"; -import { FiUser, FiLock, FiUserPlus, FiMail } from "react-icons/fi"; +import { FiUser, FiLock, FiUserPlus } from "react-icons/fi"; import { useAuthStore } from "@/modules/auth/store/useAuthStore"; export const RegisterPage: React.FC = () => { @@ -17,7 +17,7 @@ export const RegisterPage: React.FC = () => { useEffect(() => { if (token) { - navigate("/dashboard"); + navigate("/"); } }, [token, navigate]); @@ -25,7 +25,7 @@ export const RegisterPage: React.FC = () => { e.preventDefault(); if (formData.password !== formData.confirmPassword) { - setPasswordError("Passwords do not match"); + setPasswordError("Пароли не совпадают"); return; } @@ -38,7 +38,7 @@ export const RegisterPage: React.FC = () => { firstName: formData.firstName, lastName: formData.lastName, }); - navigate("/dashboard"); + navigate("/"); } catch (err) { // Error is handled by store } @@ -53,34 +53,72 @@ export const RegisterPage: React.FC = () => { if (passwordError) setPasswordError(null); }; + const inputStyles = ` + w-full pl-10 pr-3 py-2.5 rounded-lg border focus:outline-none focus:ring-2 transition-all + `; + + const simpleInputStyles = ` + w-full px-3 py-2.5 rounded-lg border focus:outline-none focus:ring-2 transition-all + `; + return ( -
-
+
+
{/* Card */} -
+
{/* Header */}
-

- Create Account +
+ +
+

+ Создать аккаунт

-

- Sign up to get started +

+ Зарегистрируйтесь, чтобы начать

{/* Error Message */} {error && ( -
+
{error}
)} {/* Form */} + {/* Name Fields */}
-
-
+ {/* Login */}
-
+ {/* Password */}
-
+ {/* Confirm Password */}
-