diff --git a/client/src/components/LoginModal.tsx b/client/src/components/LoginModal.tsx index 830cfb9..9c02489 100644 --- a/client/src/components/LoginModal.tsx +++ b/client/src/components/LoginModal.tsx @@ -68,7 +68,14 @@ export default function LoginModal({ isOpen, onClose }: LoginModalProps) { - 로그인 + + Login to + SAPIENS +
diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 1f600e6..4a2655e 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -1,23 +1,66 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useAuth } from "@/hooks/useAuth"; -import { Search, Settings, User, LogOut } from "lucide-react"; -import { useState } from "react"; +import { Search, Settings, User, LogOut, Sun, Moon, Monitor, Globe } from "lucide-react"; +import { useState, useEffect } from "react"; import MainContent from "@/components/MainContent"; import LoginModal from "@/components/LoginModal"; import SearchModal from "@/components/SearchModal"; -import SettingsModal from "@/components/SettingsModal"; import { useToast } from "@/hooks/use-toast"; import { queryClient } from "@/lib/queryClient"; import { useLocation } from "wouter"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; export default function Home() { const { user, isAuthenticated } = useAuth(); const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); - const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); const { toast } = useToast(); const [, setLocation] = useLocation(); + + const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light'); + const [language, setLanguage] = useState(() => localStorage.getItem('language') || 'en'); + + useEffect(() => { + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + localStorage.setItem('theme', theme); + }, [theme]); + + useEffect(() => { + localStorage.setItem('language', language); + }, [language]); + + const handleThemeChange = (newTheme: string) => { + setTheme(newTheme); + }; + + const handleLanguageChange = (newLanguage: string) => { + setLanguage(newLanguage); + }; + + const languages = [ + { code: 'en', name: 'English' }, + { code: 'fr', name: 'Français' }, + { code: 'de', name: 'Deutsch' }, + { code: 'it', name: 'Italiano' }, + { code: 'hi', name: 'हिन्दी' }, + { code: 'ar', name: 'العربية' }, + { code: 'ja', name: '日本語' }, + { code: 'ko', name: '한국어' }, + { code: 'zh-TW', name: '繁體中文' }, + { code: 'zh-CN', name: '简体中文' }, + ]; const handleLogout = async () => { try { @@ -128,14 +171,59 @@ export default function Home() { )} - + + + + + + Theme + handleThemeChange('light')} + className="cursor-pointer" + data-testid="theme-light" + > + + Light + + handleThemeChange('dark')} + className="cursor-pointer" + data-testid="theme-dark" + > + + Dark + + handleThemeChange('system')} + className="cursor-pointer" + data-testid="theme-system" + > + + System + + + + + Language + {languages.map((lang) => ( + handleLanguageChange(lang.code)} + className="cursor-pointer" + data-testid={`language-${lang.code}`} + > + + {lang.name} + + ))} + +
@@ -155,12 +243,6 @@ export default function Home() { isOpen={isSearchModalOpen} onClose={() => setIsSearchModalOpen(false)} /> - - {/* Settings Modal */} - setIsSettingsModalOpen(false)} - /> ); } \ No newline at end of file diff --git a/client/src/pages/Landing.tsx b/client/src/pages/Landing.tsx index 397442a..6b11c40 100644 --- a/client/src/pages/Landing.tsx +++ b/client/src/pages/Landing.tsx @@ -1,18 +1,24 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useMutation } from "@tanstack/react-query"; -import { Search, Settings, User } from "lucide-react"; +import { Search, Settings, User, Sun, Moon, Monitor, Globe } from "lucide-react"; import MainContent from "@/components/MainContent"; -import SettingsModal from "@/components/SettingsModal"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; export default function Landing() { const [showLoginModal, setShowLoginModal] = useState(false); const [showRequestModal, setShowRequestModal] = useState(false); - const [showSettingsModal, setShowSettingsModal] = useState(false); const [loginForm, setLoginForm] = useState({ username: "", password: "" }); const [requestForm, setRequestForm] = useState({ name: "", @@ -20,6 +26,43 @@ export default function Landing() { description: "" }); const { toast } = useToast(); + + const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light'); + const [language, setLanguage] = useState(() => localStorage.getItem('language') || 'en'); + + useEffect(() => { + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + localStorage.setItem('theme', theme); + }, [theme]); + + useEffect(() => { + localStorage.setItem('language', language); + }, [language]); + + const handleThemeChange = (newTheme: string) => { + setTheme(newTheme); + }; + + const handleLanguageChange = (newLanguage: string) => { + setLanguage(newLanguage); + }; + + const languages = [ + { code: 'en', name: 'English' }, + { code: 'fr', name: 'Français' }, + { code: 'de', name: 'Deutsch' }, + { code: 'it', name: 'Italiano' }, + { code: 'hi', name: 'हिन्दी' }, + { code: 'ar', name: 'العربية' }, + { code: 'ja', name: '日本語' }, + { code: 'ko', name: '한국어' }, + { code: 'zh-TW', name: '繁體中文' }, + { code: 'zh-CN', name: '简体中文' }, + ]; const loginMutation = useMutation({ mutationFn: async (credentials: { username: string; password: string }) => { @@ -107,14 +150,59 @@ export default function Landing() { /> - + + + + + + Theme + handleThemeChange('light')} + className="cursor-pointer" + data-testid="theme-light" + > + + Light + + handleThemeChange('dark')} + className="cursor-pointer" + data-testid="theme-dark" + > + + Dark + + handleThemeChange('system')} + className="cursor-pointer" + data-testid="theme-system" + > + + System + + + + + Language + {languages.map((lang) => ( + handleLanguageChange(lang.code)} + className="cursor-pointer" + data-testid={`language-${lang.code}`} + > + + {lang.name} + + ))} + +
- - {/* Settings Modal */} - setShowSettingsModal(false)} - /> ); }