feat: podpora themes
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 21s
CI / Build server (push) Successful in 24s
CI / Build client (push) Successful in 33s
CI / Playwright E2E tests (push) Successful in 1m16s
CI / Build and push Docker image (push) Successful in 42s
CI / Notify (push) Successful in 1s
CI / Generate TypeScript types (push) Successful in 10s
CI / Server unit tests (push) Successful in 21s
CI / Build server (push) Successful in 24s
CI / Build client (push) Successful in 33s
CI / Playwright E2E tests (push) Successful in 1m16s
CI / Build and push Docker image (push) Successful in 42s
CI / Notify (push) Successful in 1s
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
<FontAwesomeIcon icon={effectiveTheme === 'dark' ? faSun : faMoon} />
|
||||
</button>
|
||||
<NavDropdown
|
||||
align="end"
|
||||
title={<FontAwesomeIcon icon={faPalette} />}
|
||||
id="color-theme-dropdown"
|
||||
className="theme-toggle"
|
||||
>
|
||||
<NavDropdown.Item active={settings?.colorTheme === 'green'} onClick={() => settings?.setColorTheme('green' as ColorTheme)}>🟢 Zelený</NavDropdown.Item>
|
||||
<NavDropdown.Item active={settings?.colorTheme === 'blue'} onClick={() => settings?.setColorTheme('blue' as ColorTheme)}>🔵 Modrý</NavDropdown.Item>
|
||||
<NavDropdown.Item active={settings?.colorTheme === 'purple'} onClick={() => settings?.setColorTheme('purple' as ColorTheme)}>🟣 Fialový</NavDropdown.Item>
|
||||
</NavDropdown>
|
||||
<NavDropdown align="end" title={auth?.login} id="basic-nav-dropdown">
|
||||
<NavDropdown.Item onClick={() => setSettingsModalOpen(true)}>Nastavení</NavDropdown.Item>
|
||||
<NavDropdown.Item onClick={() => setRefreshMenuModalOpen(true)}>Přenačtení menu</NavDropdown.Item>
|
||||
|
||||
@@ -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<string | undefined>();
|
||||
const [holderName, setHolderName] = useState<string | undefined>();
|
||||
const [hideSoups, setHideSoups] = useState<boolean | undefined>();
|
||||
const [themePreference, setTheme] = useState<ThemePreference>(getInitialTheme);
|
||||
const [colorTheme, setColor] = useState<ColorTheme>(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,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user