diff --git a/client/src/App.scss b/client/src/App.scss index 1a940d8..a0d7f1f 100644 --- a/client/src/App.scss +++ b/client/src/App.scss @@ -87,6 +87,42 @@ --luncher-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.5), 0 4px 6px -4px rgb(0 0 0 / 0.4); } +// Modrý motiv – světlý +[data-luncher-color="blue"][data-bs-theme="light"] { + --luncher-primary: #2563eb; + --luncher-primary-hover: #1d4ed8; + --luncher-primary-light: #dbeafe; + --luncher-action-icon: #2563eb; + --luncher-success: #2563eb; +} + +// Modrý motiv – tmavý +[data-luncher-color="blue"][data-bs-theme="dark"] { + --luncher-primary: #3b82f6; + --luncher-primary-hover: #60a5fa; + --luncher-primary-light: #172554; + --luncher-action-icon: #3b82f6; + --luncher-success: #3b82f6; +} + +// Fialový motiv – světlý +[data-luncher-color="purple"][data-bs-theme="light"] { + --luncher-primary: #7c3aed; + --luncher-primary-hover: #6d28d9; + --luncher-primary-light: #ede9fe; + --luncher-action-icon: #7c3aed; + --luncher-success: #7c3aed; +} + +// Fialový motiv – tmavý +[data-luncher-color="purple"][data-bs-theme="dark"] { + --luncher-primary: #a78bfa; + --luncher-primary-hover: #c4b5fd; + --luncher-primary-light: #2e1065; + --luncher-action-icon: #a78bfa; + --luncher-success: #a78bfa; +} + // ============================================ // BASE STYLES // ============================================ @@ -226,6 +262,33 @@ body { &:hover svg { transform: rotate(15deg); } + + // Přizpůsobení pro NavDropdown (palette ikona) + &.nav-item.dropdown { + .dropdown-toggle { + background: transparent; + border: none; + color: var(--luncher-navbar-text); + padding: 8px 12px; + font-size: 1.1rem; + display: flex; + align-items: center; + + &::after { + display: none; + } + + &:hover { + background: rgba(255, 255, 255, 0.1); + transform: scale(1.1); + } + + &:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3); + } + } + } } // ============================================ diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx index 9bcecf3..7e9a3e9 100644 --- a/client/src/components/Header.tsx +++ b/client/src/components/Header.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { Navbar, Nav, NavDropdown, Modal, Button } from "react-bootstrap"; import { useAuth } from "../context/auth"; import SettingsModal from "./modals/SettingsModal"; -import { useSettings, ThemePreference } from "../context/settings"; +import { useSettings, ThemePreference, ColorTheme } from "../context/settings"; import FeaturesVotingModal from "./modals/FeaturesVotingModal"; import PizzaCalculatorModal from "./modals/PizzaCalculatorModal"; import RefreshMenuModal from "./modals/RefreshMenuModal"; @@ -13,7 +13,7 @@ import { useNavigate } from "react-router"; import { STATS_URL, OBJEDNANI_URL } from "../AppRoutes"; import { FeatureRequest, getVotes, updateVote, LunchChoices, getChangelogs } from "../../../types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faSun, faMoon } from "@fortawesome/free-solid-svg-icons"; +import { faSun, faMoon, faPalette } from "@fortawesome/free-solid-svg-icons"; import { formatDateString } from "../Utils"; const LAST_SEEN_CHANGELOG_KEY = "lastChangelogDate"; @@ -196,10 +196,20 @@ export default function Header({ choices, dayIndex }: Props) { className="theme-toggle" onClick={toggleTheme} title={effectiveTheme === 'dark' ? 'Přepnout na světlý režim' : 'Přepnout na tmavý režim'} - aria-label="Přepnout barevný motiv" + aria-label="Přepnout světlý/tmavý režim" > + } + id="color-theme-dropdown" + className="theme-toggle" + > + settings?.setColorTheme('green' as ColorTheme)}>🟢 Zelený + settings?.setColorTheme('blue' as ColorTheme)}>🔵 Modrý + settings?.setColorTheme('purple' as ColorTheme)}>🟣 Fialový + setSettingsModalOpen(true)}>Nastavení setRefreshMenuModalOpen(true)}>Přenačtení menu diff --git a/client/src/context/settings.tsx b/client/src/context/settings.tsx index 1775c79..ea3796f 100644 --- a/client/src/context/settings.tsx +++ b/client/src/context/settings.tsx @@ -4,18 +4,22 @@ const BANK_ACCOUNT_NUMBER_KEY = 'bank_account_number'; const BANK_ACCOUNT_HOLDER_KEY = 'bank_account_holder_name'; const HIDE_SOUPS_KEY = 'hide_soups'; const THEME_KEY = 'theme_preference'; +const COLOR_THEME_KEY = 'color_theme'; export type ThemePreference = 'system' | 'light' | 'dark'; +export type ColorTheme = 'green' | 'blue' | 'purple'; export type SettingsContextProps = { bankAccount?: string, holderName?: string, hideSoups?: boolean, themePreference: ThemePreference, + colorTheme: ColorTheme, setBankAccountNumber: (accountNumber?: string) => void, setBankAccountHolderName: (holderName?: string) => void, setHideSoupsOption: (hideSoups?: boolean) => void, setThemePreference: (theme: ThemePreference) => void, + setColorTheme: (color: ColorTheme) => void, } type ContextProps = { @@ -45,11 +49,24 @@ function getInitialTheme(): ThemePreference { return 'system'; } +function getInitialColorTheme(): ColorTheme { + try { + const saved = localStorage.getItem(COLOR_THEME_KEY) as ColorTheme | null; + if (saved && ['green', 'blue', 'purple'].includes(saved)) { + return saved; + } + } catch (e) { + // localStorage nedostupný + } + return 'green'; +} + function useProvideSettings(): SettingsContextProps { const [bankAccount, setBankAccount] = useState(); const [holderName, setHolderName] = useState(); const [hideSoups, setHideSoups] = useState(); const [themePreference, setTheme] = useState(getInitialTheme); + const [colorTheme, setColor] = useState(getInitialColorTheme); useEffect(() => { const accountNumber = localStorage.getItem(BANK_ACCOUNT_NUMBER_KEY); @@ -94,6 +111,11 @@ function useProvideSettings(): SettingsContextProps { localStorage.setItem(THEME_KEY, themePreference); }, [themePreference]); + useEffect(() => { + localStorage.setItem(COLOR_THEME_KEY, colorTheme); + document.documentElement.setAttribute('data-luncher-color', colorTheme); + }, [colorTheme]); + useEffect(() => { const applyTheme = (theme: 'light' | 'dark') => { document.documentElement.setAttribute('data-bs-theme', theme); @@ -129,14 +151,20 @@ function useProvideSettings(): SettingsContextProps { setTheme(theme); } + function setColorTheme(color: ColorTheme) { + setColor(color); + } + return { bankAccount, holderName, hideSoups, themePreference, + colorTheme, setBankAccountNumber, setBankAccountHolderName, setHideSoupsOption, setThemePreference, + setColorTheme, } }