From 7da5b99f0c79d2b5b2b45eb5484bd9632fa1f4b7 Mon Sep 17 00:00:00 2001 From: Martin Berka Date: Mon, 26 Oct 2026 08:40:51 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20nov=C3=BD=20vzhled=20Gudetama?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/index.html | 2 +- client/src/App.tsx | 1 + client/src/components/EaterBadge.scss | 11 + client/src/components/EaterBadge.tsx | 9 +- client/src/components/WheelConfetti.scss | 75 +++ client/src/components/WheelConfetti.tsx | 18 +- .../src/components/modals/SpinWheelModal.scss | 260 +++++++++ client/src/context/settings.tsx | 5 +- client/src/games/themeIcons.ts | 2 + client/src/themes/gudetama.scss | 539 ++++++++++++++++++ 10 files changed, 917 insertions(+), 5 deletions(-) create mode 100644 client/src/themes/gudetama.scss diff --git a/client/index.html b/client/index.html index 411bd21..2a8ff22 100644 --- a/client/index.html +++ b/client/index.html @@ -28,7 +28,7 @@ } document.documentElement.setAttribute('data-bs-theme', theme); var style = localStorage.getItem('style_theme'); - var styles = ['umamusume', 'mlp', 'hellgirl', 'kon', 'bocchi', 'evangelion', 'yurucamp', 'spyfamily', 'apothecary', 'frieren', 'mlpg5', 'aggretsuko', 'sumikko']; + var styles = ['umamusume', 'mlp', 'hellgirl', 'kon', 'bocchi', 'evangelion', 'yurucamp', 'spyfamily', 'apothecary', 'frieren', 'mlpg5', 'aggretsuko', 'sumikko', 'gudetama']; document.documentElement.setAttribute('data-luncher-theme', styles.indexOf(style) >= 0 ? style : 'simple'); } catch (e) { // Fallback pokud localStorage není dostupný diff --git a/client/src/App.tsx b/client/src/App.tsx index aaa787b..30991be 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -23,6 +23,7 @@ import './themes/frieren.scss'; import './themes/mlpg5.scss'; import './themes/aggretsuko.scss'; import './themes/sumikko.scss'; +import './themes/gudetama.scss'; import { faCircleCheck, faNoteSticky, faTrashCan, faComment } from '@fortawesome/free-regular-svg-icons'; import { useSettings } from './context/settings'; import Footer from './components/Footer'; diff --git a/client/src/components/EaterBadge.scss b/client/src/components/EaterBadge.scss index 1e0fb3e..e8221c7 100644 --- a/client/src/components/EaterBadge.scss +++ b/client/src/components/EaterBadge.scss @@ -164,6 +164,17 @@ outline-offset: -5px; } +// Styl Gudetama: emoji na bílku se žloutkovým lemem +.eater-badge-gudetama { + display: inline-grid; + place-items: center; + font-size: 15px; + line-height: 1; + border-color: #fffdf5; + background: radial-gradient(circle at 40% 35%, #fffdf5, #fff3c4); + box-shadow: 0 0 0 2px #f5b301; +} + // Odznak a jméno drží na jednom řádku (úzký sloupec „Člen" na stránce objednávek) .user-info:has(.eater-badge) { display: inline-flex; diff --git a/client/src/components/EaterBadge.tsx b/client/src/components/EaterBadge.tsx index d1dedb9..f6fc3a7 100644 --- a/client/src/components/EaterBadge.tsx +++ b/client/src/components/EaterBadge.tsx @@ -85,6 +85,12 @@ const SK_LEVELS = [ { minItems: 2, emoji: '🥒', title: 'Úroveň Penguin? — k obědu ještě okurka, aby se cítil jako kappa' }, ]; +/** Úrovně ve stylu Gudetama — emoji na bílku se žloutkovým lemem. Seřazeno od nejvyšší úrovně. */ +const GT_LEVELS = [ + { minItems: 3, emoji: '🍳', title: 'Úroveň Nisetama-san — sní to všechno sám, Gudetamovi se jíst nechce' }, + { minItems: 2, emoji: '🥓', title: 'Úroveň slaniny — k obědu ještě plátek slaniny… ale jen jako deka' }, +]; + /** Úrovně podle stylu pro odznaky s emoji. */ const EMOJI_LEVELS: Partial> = { mlp: MLP_LEVELS, @@ -99,6 +105,7 @@ const EMOJI_LEVELS: Partial> = { mlpg5: G5_LEVELS, aggretsuko: AGG_LEVELS, sumikko: SK_LEVELS, + gudetama: GT_LEVELS, }; type Props = { @@ -106,7 +113,7 @@ type Props = { items: number, }; -/** Odznak s postavou u strávníků s více jídly — jen ve stylech Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family, Apothecary Diaries, Frieren, My Little Pony G5, Aggretsuko a Sumikko Gurashi. */ +/** Odznak s postavou u strávníků s více jídly — jen ve stylech Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family, Apothecary Diaries, Frieren, My Little Pony G5, Aggretsuko, Sumikko Gurashi a Gudetama. */ export default function EaterBadge({ items }: Readonly) { const styleTheme = useSettings()?.styleTheme; const isUma = styleTheme === 'umamusume'; diff --git a/client/src/components/WheelConfetti.scss b/client/src/components/WheelConfetti.scss index c1ccac3..a66e217 100644 --- a/client/src/components/WheelConfetti.scss +++ b/client/src/components/WheelConfetti.scss @@ -1116,3 +1116,78 @@ } } } + +// ============================================ +// Konfety ve stylu Gudetama +// ============================================ +.confetti-gt { + filter: drop-shadow(0 3px 2px rgb(74 53 32 / 0.25)); +} + +// Štítky jako líně rozteklé bubliny +.confetti-gt-badge { + padding: 4px 16px; + border-radius: 999px 999px 999px 999px / 60% 60% 40% 40%; + border: 2px solid #fffdf5; + color: #fffdf5; + font-family: 'Fredoka', 'Nunito', sans-serif; + font-weight: 600; + font-size: 1.15rem; + white-space: nowrap; + text-shadow: 0 1px 0 rgb(74 53 32 / 0.3); +} + +// Nápis „ぐでたま…" — bílek se žloutkem, dopadne na pánev a líně se rozteče +.confetti-gt-banner { + position: absolute; + top: 38%; + left: 50%; + transform: translate(-50%, -50%); + padding: 14px 48px 16px; + font-family: 'Fredoka', 'Nunito', sans-serif; + font-weight: 600; + font-size: clamp(1.8rem, 7vw, 4rem); + white-space: nowrap; + color: #4a3520; + background: + radial-gradient(circle at 50% 50%, rgb(255 210 63 / 0.35) 0 30%, transparent 60%), + #fffdf5; + border-radius: 58% 42% 55% 45% / 60% 55% 45% 40%; + box-shadow: 0 6px 0 #efe3c4, 0 18px 34px rgb(0 0 0 / 0.25); + transform-origin: 50% 100%; + animation: gt-banner 2.8s ease both; +} + +@keyframes gt-banner { + 0% { transform: translate(-50%, -160%) scale(0.8); opacity: 0; } + 14% { transform: translate(-50%, -50%) scale(1); opacity: 1; animation-timing-function: ease-out; } + 20% { transform: translate(-50%, -50%) scale(1.12, 0.82); } + 30% { transform: translate(-50%, -50%) scale(1, 1); } + // Gude~ — pomalé rozteklé usazení + 55%, 82% { transform: translate(-50%, -48%) scale(1.06, 0.92); opacity: 1; } + 100% { transform: translate(-50%, -40%) scale(1.25, 0.6); opacity: 0; } +} + +// Postava s hláškou — žloutek na bílku a bublina jako bílek +.confetti-gudetama-voice { + .confetti-mlp-avatar { + border: 4px solid #fffdf5; + background: radial-gradient(circle at 34% 30%, #fff6c8 0 6px, #ffd23f 10px, #f5b301 100%); + box-shadow: 0 0 0 3px var(--mlp-speaker, #f5b301), 0 6px 12px rgb(0 0 0 / 0.25); + } + + .confetti-mlp-bubble { + background: #fffdf5; + color: #4a3520; + border: 2px solid var(--mlp-speaker, #f5b301); + border-radius: 58% 42% 55% 45% / 40% 45% 55% 60%; + padding: 14px 22px; + box-shadow: 0 4px 0 #efe3c4; + font-family: 'Fredoka', 'Nunito', sans-serif; + + p { + font-weight: 500; + font-size: 1.05rem; + } + } +} diff --git a/client/src/components/WheelConfetti.tsx b/client/src/components/WheelConfetti.tsx index 78f2c2c..4c81423 100644 --- a/client/src/components/WheelConfetti.tsx +++ b/client/src/components/WheelConfetti.tsx @@ -196,6 +196,21 @@ const SK_SPEAKERS = [ { name: 'Zassou', emoji: '🌱', color: '#9cc06f', quote: 'Jednou ze mě bude krásná kytice. Do té doby si dám oběd.' }, { name: 'Tapioka', emoji: '🧋', color: '#e8a0b8', quote: 'Nás perliček zbylo na dně hodně… tak jdeme na to!' }, ]; +const GT_EMOJI = ['🍳', '🥚', '🥓', '🍞', '🧂', '🥢', '🍚', '😪', '💤', '🍜', '🧈', '🍣', '🫠', '🥄']; +// Hlášky Gudetamy (gude~, meh…, nechce se mi, slanina jako deka...) +const GT_BADGES = ['ぐでたま', 'Gude~', 'Meh…', 'Nechce se mi…', 'Ještě 5 minut', 'Slanina = deka', 'Na měkko', 'Volské oko', 'Tamagoyaki', 'Zítra…']; +const GT_BADGE_COLORS = ['#f5b301', '#e08a00', '#c8553d', '#6b4a2e', '#d9a066', '#8a7a64']; +/** Gudetama ve všech podobách a jeho okolí s „hláškou" po finálním výsledku. */ +const GT_SPEAKERS = [ + { name: 'Gudetama', emoji: '🍳', color: '#f5b301', quote: 'Oběd…? Meh… přineste mi ho sem… nechce se mi…' }, + { name: 'Nisetama-san', emoji: '🥚', color: '#c9a227', quote: 'Gudetamo, vstávej! Jde se na oběd! …No tak, aspoň se převal!' }, + { name: 'Shakipiyo', emoji: '🐣', color: '#f2a03a', quote: 'Píp! Já tam doběhnu první! Gudetamo, dělej!' }, + { name: 'Gudetama na měkko', emoji: '🥚', color: '#e8c06a', quote: 'Jsem na měkko… a takhle i zůstanu. Gude~' }, + { name: 'Tamagoyaki Gudetama', emoji: '🍱', color: '#e0a830', quote: 'Jsem srolovaný do omelety… jako do peřiny. Dobrou.' }, + { name: 'Slanina', emoji: '🥓', color: '#c8553d', quote: '(přikryje Gudetamu jako deka a usne s ním)' }, + { name: 'Gudetama v ramenu', emoji: '🍜', color: '#d9a066', quote: 'Plavu si tu v ramenu… vývar je teplý, nechce se mi ven.' }, + { name: 'Gudetama na rýži', emoji: '🍚', color: '#a3927c', quote: 'Na rýži se leží nejlíp… itadakimasu… zítra.' }, +]; /** Styly, jejichž konfety tvoří emoji a samolepky s hláškami (a po finále promluví postava s emoji). */ const EMOJI_CONFETTI: Partial big && emojiConfetti ? pick(emojiConfetti.speakers) : undefined, diff --git a/client/src/components/modals/SpinWheelModal.scss b/client/src/components/modals/SpinWheelModal.scss index 81039bd..73006ff 100644 --- a/client/src/components/modals/SpinWheelModal.scss +++ b/client/src/components/modals/SpinWheelModal.scss @@ -3654,6 +3654,266 @@ } } +// ============================================ +// STYL GUDETAMA kola štěstí (dle stylu zvoleného v nastavení). +// Kolo leží na litinové pánvi: výseče v barvách snídaně (žloutek, bílek, +// slanina, toust, sójová omáčka, nori), střed jako žloutek. +// ============================================ +.spin-wheel-modal.spin-theme-gudetama { + --gt-font: 'Nunito', sans-serif; + --gt-display: 'Fredoka', 'Nunito', sans-serif; + --gt-yolk: #ffd23f; + --gt-yolk-shadow: #d99a00; + --gt-ink: #4a3520; + --gt-line: #efe3c4; + --gt-panel: #ffffff; + --wheel-c0: #ffd23f; + --wheel-c1: #f5e6b8; + --wheel-c2: #f2a7a0; + --wheel-c3: #e8c08a; + --wheel-c4: #c9a07a; + --wheel-c5: #b8d48f; + --wheel-label: #4a3520; + --wheel-rim: #2b2725; + --wheel-hub: #ffd23f; + + font-family: var(--gt-font); + + .modal-content { + border: 2px solid var(--gt-line); + border-radius: 24px; + overflow: hidden; + background: + linear-gradient(rgb(74 53 32 / 0.05) 1.5px, transparent 1.5px) 0 0 / 46px 46px, + linear-gradient(90deg, rgb(74 53 32 / 0.05) 1.5px, transparent 1.5px) 0 0 / 46px 46px, + #fbf8f1; + color: var(--gt-ink); + } + + .modal-header { + background: + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='10'%3E%3Cpath d='M0 3Q12 0 24 3T48 3V7Q36 10 24 7T0 7Z' fill='%23f2a7a0'/%3E%3Cpath d='M0 5Q12 2 24 5T48 5' stroke='%23c8553d' stroke-width='1.5' fill='none'/%3E%3C/svg%3E") left bottom / 48px 10px repeat-x, + linear-gradient(180deg, #ffdc5c, var(--gt-yolk)); + border-bottom: none; + padding-bottom: calc(var(--bs-modal-header-padding-y, 1rem) + 8px); + + h2 { + color: var(--gt-ink); + font-family: var(--gt-display); + font-weight: 600; + } + } + + .modal-footer { + border-top: 2px solid var(--gt-line); + } + + .spin-steps span { + font-family: var(--gt-display); + font-weight: 600; + background: #f5ecd6; + color: #a3927c; + border-radius: 999px; + padding: 2px 16px; + + // Text na žloutku je vždy tmavý (i v tmavém režimu) + &.active { + background: var(--gt-yolk); + color: #4a3520; + box-shadow: 0 3px 0 var(--gt-yolk-shadow); + } + + &.done { + background: #fffdf5; + color: #a8650a; + box-shadow: inset 0 0 0 2px var(--gt-yolk); + } + } + + .btn { + font-family: var(--gt-font); + font-weight: 800; + border-radius: 999px; + transition: transform 0.5s ease, box-shadow 0.5s ease, background 0.5s ease; + } + + .btn-primary { + background: var(--gt-yolk); + border: none; + color: #4a3520; + box-shadow: 0 4px 0 var(--gt-yolk-shadow); + + &:hover:not(:disabled) { + background: #ffdc5c; + color: #4a3520; + } + + &:disabled { + background: #efe6cf; + color: #a3927c; + box-shadow: none; + } + } + + // Tlačítko roztočení — „…tak jo, no" + .spin-button { + font-family: var(--gt-display); + font-weight: 600; + font-size: 1.3rem; + padding: 8px 40px; + } + + .btn-outline-primary { + background: var(--gt-panel); + border: 2px solid #f5b301; + color: #a8650a; + + &:hover { + background: #fff3c4; + color: #a8650a; + } + } + + .btn-secondary { + background: #6b4a2e; + border: none; + color: #fffdf5; + box-shadow: 0 4px 0 #4a3220; + } + + .spin-source { + background: #f5ecd6; + + > .btn-primary { + box-shadow: none !important; + } + + > .btn-outline-primary { + background: transparent; + color: var(--gt-ink); + + &:hover { + background: var(--gt-panel); + } + } + } + + .spin-result { + font-weight: 800; + + strong { + color: #a8650a; + } + } + + .spin-options { + background: var(--gt-panel); + border: 2px solid var(--gt-line); + border-radius: 18px; + + li:hover { + background: #fff8dc; + } + } + + .spin-options-header { + border-bottom: 2px solid #f5dc8a; + color: #a8650a; + font-family: var(--gt-display); + } + + .spin-empty { + border-color: var(--gt-line); + } + + .spin-wheel-pointer { + border-top-color: #c8553d; + } + + .spin-wheel-hub { + stroke: #fffdf5; + } + + .spin-seg { + stroke: #2b2725; + stroke-width: 1.5; + } + + .spin-seg-label { + font-family: var(--gt-display); + font-weight: 600; + } +} + +// Tmavý režim — litinová pánev +[data-bs-theme="dark"] .spin-wheel-modal.spin-theme-gudetama { + --gt-ink: #f5ead2; + --gt-line: #3a332e; + --gt-panel: #211d1a; + --wheel-rim: #3a3430; + + .modal-content { + background: + radial-gradient(circle at 50% 50%, rgb(255 210 63 / 0.08) 0 120px, transparent 300px), + #141210; + } + + .modal-header { + background: + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='10'%3E%3Cpath d='M0 3Q12 0 24 3T48 3V7Q36 10 24 7T0 7Z' fill='%23f2a7a0'/%3E%3Cpath d='M0 5Q12 2 24 5T48 5' stroke='%23c8553d' stroke-width='1.5' fill='none'/%3E%3C/svg%3E") left bottom / 48px 10px repeat-x, + #0e0d0c; + + h2 { + color: #ffd23f; + } + + .btn-close { + filter: invert(1) grayscale(1) brightness(2); + } + } + + .spin-steps span:not(.active):not(.done) { + background: #2b2622; + color: #968a7a; + } + + .spin-steps span.done { + background: #2b2622; + color: #ffd23f; + } + + .btn-primary:disabled { + background: #3a332e; + color: #968a7a; + } + + .btn-outline-primary { + color: #ffd23f; + + &:hover { + background: #3a3018; + color: #ffe17a; + } + } + + .spin-source { + background: #2b2622; + } + + .spin-options li:hover { + background: #2b2622; + } + + .spin-options-header { + color: #ffd23f; + border-bottom-color: #4a3d1c; + } + + .spin-result strong { + color: #ffd23f; + } +} + // Ikona kola se při najetí pootočí .spin-wheel-icon { transition: transform 0.4s ease !important; diff --git a/client/src/context/settings.tsx b/client/src/context/settings.tsx index aa32937..554890b 100644 --- a/client/src/context/settings.tsx +++ b/client/src/context/settings.tsx @@ -13,7 +13,7 @@ const AUTO_ORDER_CHOICE_KEY = 'auto_order_choice'; export type ThemePreference = 'system' | 'light' | 'dark'; /** Vizuální styl aplikace (nezávislý na světlém/tmavém režimu). */ -export type StyleTheme = 'simple' | 'umamusume' | 'mlp' | 'hellgirl' | 'kon' | 'bocchi' | 'evangelion' | 'yurucamp' | 'spyfamily' | 'apothecary' | 'frieren' | 'mlpg5' | 'aggretsuko' | 'sumikko'; +export type StyleTheme = 'simple' | 'umamusume' | 'mlp' | 'hellgirl' | 'kon' | 'bocchi' | 'evangelion' | 'yurucamp' | 'spyfamily' | 'apothecary' | 'frieren' | 'mlpg5' | 'aggretsuko' | 'sumikko' | 'gudetama'; export const STYLE_THEMES: { value: StyleTheme, label: string }[] = [ { value: 'simple', label: 'Jednoduchý' }, @@ -30,6 +30,7 @@ export const STYLE_THEMES: { value: StyleTheme, label: string }[] = [ { value: 'frieren', label: 'Frieren' }, { value: 'aggretsuko', label: 'Aggretsuko' }, { value: 'sumikko', label: 'Sumikko Gurashi' }, + { value: 'gudetama', label: 'Gudetama' }, ]; export type SettingsContextProps = { @@ -261,7 +262,7 @@ function useProvideSettings(): SettingsContextProps { }, [autoOrderChoice]); // Aplikuje accent barvy při změně hue nebo přepnutí světlý/tmavý. - // Tematické styly (Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family, Apothecary Diaries, Frieren, My Little Pony G5, Aggretsuko, Sumikko Gurashi) mají vlastní pevnou paletu, accent barvu proto uplatňuje jen jednoduchý styl. + // Tematické styly (Umamusume, My Little Pony, Hell Girl, K-ON!, Bocchi the Rock!, Evangelion, Yuru Camp△, Spy × Family, Apothecary Diaries, Frieren, My Little Pony G5, Aggretsuko, Sumikko Gurashi, Gudetama) mají vlastní pevnou paletu, accent barvu proto uplatňuje jen jednoduchý styl. useEffect(() => { localStorage.setItem(ACCENT_HUE_KEY, String(accentHue)); if (styleTheme === 'simple') { diff --git a/client/src/games/themeIcons.ts b/client/src/games/themeIcons.ts index cc9cf85..1ee17f5 100644 --- a/client/src/games/themeIcons.ts +++ b/client/src/games/themeIcons.ts @@ -31,6 +31,8 @@ const ICONS: Record> = { aggretsuko: { drawing: '🖊️' }, // Tužka, kterou se kreslí postavičky ze San-X sumikko: { drawing: '✏️' }, + // Vajíčko — kreslit se mu ale stejně nechce + gudetama: { drawing: '🥚' }, }; /** Styl z — pro místa mimo React kontext nastavení. */ diff --git a/client/src/themes/gudetama.scss b/client/src/themes/gudetama.scss new file mode 100644 index 0000000..656a4dc --- /dev/null +++ b/client/src/themes/gudetama.scss @@ -0,0 +1,539 @@ +// ============================================ +// STYL "GUDETAMA" (volitelný, výchozí je jednoduchý styl) +// Inspirováno líným vajíčkem Gudetama (ぐでたま) od Sanria. +// Kuchyň s bílými kachličkami, žloutkově žlutá, bílek, proužek slaniny +// (Gudetamova oblíbená deka) a titulek dne jako volské oko, které se +// občas líně „rozteče". Všechno je trochu líné — i přechody tlačítek. +// Tmavý režim = litinová pánev, ve které svítí žloutek. +// Aktivní, pokud má atribut data-luncher-theme="gudetama". +// ============================================ + +$gt: 'html[data-luncher-theme="gudetama"]'; + +// Proužek slaniny — vlnitý růžový pruh s tmavší žilkou, opakuje se vodorovně +$gt-bacon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='10'%3E%3Cpath d='M0 3Q12 0 24 3T48 3V7Q36 10 24 7T0 7Z' fill='%23f2a7a0'/%3E%3Cpath d='M0 5Q12 2 24 5T48 5' stroke='%23c8553d' stroke-width='1.5' fill='none'/%3E%3C/svg%3E"); + +#{$gt} { + --gt-font: 'Nunito', -apple-system, sans-serif; + --gt-display: 'Fredoka', 'Nunito', sans-serif; + --gt-yolk: #ffd23f; // žloutek + --gt-yolk-deep: #f5b301; + --gt-yolk-shadow: #d99a00; + --gt-white: #fffdf5; // bílek + --gt-bacon: #c8553d; + --gt-soy: #6b4a2e; // sójová omáčka + --gt-ink: #4a3520; + --gt-grout: rgb(74 53 32 / 0.06); + --gt-line: #efe3c4; + + --luncher-primary: #a8650a; + --luncher-primary-hover: #8a5208; + --luncher-primary-light: #fff3c4; + --luncher-bg: #fbf8f1; + --luncher-bg-card: #ffffff; + --luncher-bg-hover: #fff8dc; + --luncher-text: var(--gt-ink); + --luncher-text-secondary: #6e5a44; + --luncher-text-muted: #a3927c; + --luncher-border: var(--gt-line); + --luncher-border-light: #f5ecd6; + --luncher-navbar-bg: var(--gt-yolk); + --luncher-navbar-text: var(--gt-ink); + --luncher-action-icon: #a8650a; + --luncher-buyer-icon: var(--gt-bacon); + --luncher-success: #5a9a4a; + --luncher-warning: #e08a00; + --luncher-danger: var(--gt-bacon); + --luncher-radius-sm: 12px; + --luncher-radius: 16px; + --luncher-radius-lg: 20px; + --luncher-radius-xl: 24px; + --luncher-shadow: 0 4px 0 rgb(217 154 0 / 0.12), 0 8px 18px rgb(74 53 32 / 0.08); + --luncher-shadow-lg: 0 6px 0 rgb(217 154 0 / 0.18), 0 14px 28px rgb(74 53 32 / 0.14); + + &[data-bs-theme="dark"] { + // Litinová pánev — žloutek svítí ve tmě + --gt-white: #2a2522; + --gt-ink: #f5ead2; + --gt-line: #3a332e; + + --luncher-primary: #ffd23f; + --luncher-primary-hover: #ffe17a; + --luncher-primary-light: #3a3018; + --luncher-bg: #141210; + --luncher-bg-card: #211d1a; + --luncher-bg-hover: #2b2622; + --luncher-text: var(--gt-ink); + --luncher-text-secondary: #d3c6ae; + --luncher-text-muted: #968a7a; + --luncher-border-light: #2a2522; + --luncher-navbar-bg: #0e0d0c; + --luncher-navbar-text: #ffd23f; + --luncher-action-icon: #ffd23f; + --luncher-buyer-icon: #f2a7a0; + --luncher-success: #9ccf86; + --luncher-warning: #ffc04d; + --luncher-danger: #f08a7a; + --luncher-shadow: 0 4px 14px rgb(0 0 0 / 0.4); + --luncher-shadow-lg: 0 10px 28px rgb(255 210 63 / 0.14); + } + + body { + font-family: var(--gt-font); + background-color: var(--luncher-bg); + // Kuchyňské kachličky se spárami, nahoře teplé světlo + background-image: + linear-gradient(var(--gt-grout) 1.5px, transparent 1.5px), + linear-gradient(90deg, var(--gt-grout) 1.5px, transparent 1.5px), + linear-gradient(180deg, #fff6d6 0, var(--luncher-bg) 360px); + background-size: 46px 46px, 46px 46px, 100% 100%; + background-attachment: fixed; + } + + &[data-bs-theme="dark"] body { + // Dno litinové pánve s okrajem a teplou září žloutku + background-image: + radial-gradient(circle at 50% 45%, rgb(255 210 63 / 0.07) 0 160px, transparent 360px), + radial-gradient(circle at 50% 45%, #1d1a17 0 min(46vw, 560px), #2e2925 calc(min(46vw, 560px) + 1px) calc(min(46vw, 560px) + 14px), transparent calc(min(46vw, 560px) + 15px)); + } + + .app-container { + background: transparent; + } + + h1, h2, h3, h4, .navbar-brand { + font-family: var(--gt-display); + font-weight: 600; + } + + .btn { + font-family: var(--gt-font); + } + + // ---------- Navbar: žloutek s proužkem slaniny ---------- + .navbar { + background: + #{$gt-bacon} left bottom / 48px 10px repeat-x, + linear-gradient(180deg, #ffdc5c, var(--luncher-navbar-bg)) !important; + padding-bottom: calc(var(--bs-navbar-padding-y, 0.5rem) + 10px); + border-bottom: none; + + .navbar-brand { + // Vajíčko na pánvi + &::after { + content: '🍳'; + display: inline-block; + margin-left: 6px; + margin-right: 0.6em; + font-size: 0.75em; + } + } + + // Navbar je ve variantě „dark" — ikonu hamburgeru na žlutém pozadí ztmavíme + .navbar-toggler { + border-color: rgb(74 53 32 / 0.35); + } + + .navbar-toggler-icon { + filter: invert(1) brightness(0.3); + } + + .dropdown-menu { + border: 2px solid var(--gt-line); + border-radius: var(--luncher-radius); + box-shadow: var(--luncher-shadow-lg); + } + } + + &[data-bs-theme="dark"] .navbar { + background: + #{$gt-bacon} left bottom / 48px 10px repeat-x, + var(--luncher-navbar-bg) !important; + + .navbar-toggler { + border-color: rgb(255 210 63 / 0.4); + } + + .navbar-toggler-icon { + filter: none; + } + } + + // ---------- Titulek dne: volské oko — bílek, vedle žloutek, občas se rozteče ---------- + .day-navigator .title { + position: relative; + display: inline-block; + padding: 10px 34px 12px 70px; + font-family: var(--gt-display); + font-weight: 600; + font-size: 1.65rem; + color: #4a3520 !important; + background: #fffdf5; + // Nepravidelný tvar bílku + border-radius: 58% 42% 55% 45% / 60% 55% 45% 40%; + box-shadow: 0 4px 0 #efe3c4, 0 10px 22px rgb(74 53 32 / 0.14); + transform-origin: 50% 100%; + animation: gt-gude 7s ease-in-out infinite; + + // Žloutek (Gudetama) s odleskem + &::before { + content: ''; + position: absolute; + left: 20px; + top: 50%; + width: 38px; + height: 32px; + margin-top: -15px; + border-radius: 50% 50% 46% 46% / 58% 58% 42% 42%; + background: radial-gradient(circle at 34% 30%, #fff6c8 0 4px, #ffd23f 6px, #f5b301 100%); + box-shadow: 0 2px 3px rgb(217 154 0 / 0.5); + } + + // Líné „zzz" + &::after { + content: '💤'; + position: absolute; + left: 46px; + top: -12px; + font-size: 0.55em; + opacity: 0.85; + } + + &.text-muted { + color: #8a7a64 !important; + background: #f3efe6; + animation: none; + + // Jiný den — vystydlé vajíčko + &::before { + background: radial-gradient(circle at 34% 30%, #fbf3d8 0 4px, #e8d8a0 6px, #d9c27a 100%); + box-shadow: none; + } + + &::after { + display: none; + } + } + } + + &[data-bs-theme="dark"] .day-navigator .title { + box-shadow: 0 4px 0 #d9ccb0, 0 0 30px rgb(255 210 63 / 0.18); + + &.text-muted { + background: #d9d2c2; + box-shadow: none; + } + } + + // ---------- Karty podniků: žloutková hlavička, při najetí se líně prohne ---------- + .restaurant-card { + border: 2px solid var(--gt-line); + border-radius: var(--luncher-radius-lg); + box-shadow: var(--luncher-shadow); + overflow: hidden; + + &:hover { + transform: translateY(-2px); + border-color: var(--gt-line); + box-shadow: var(--luncher-shadow-lg); + } + + .restaurant-header { + // Lesklý žloutek + background: + radial-gradient(ellipse 40% 60% at 12% 20%, rgb(255 255 255 / 0.45), transparent 70%), + linear-gradient(180deg, #ffdc5c, var(--gt-yolk-deep)); + border-bottom: 3px solid var(--gt-yolk-shadow); + border-radius: 0 0 26px 26px / 0 0 10px 10px; + transform-origin: 50% 0; + transition: transform 0.8s ease, border-radius 0.8s ease, background 0.6s ease; + + // Gude~ — hlavička se líně prohne a „rozteče" + &:hover { + background: + radial-gradient(ellipse 40% 60% at 12% 20%, rgb(255 255 255 / 0.45), transparent 70%), + linear-gradient(180deg, #ffd23f, #eba300); + border-radius: 0 0 60% 40% / 0 0 22px 14px; + transform: scaleY(1.04); + } + + h3 { + color: #4a3520; + } + + small { + color: rgb(74 53 32 / 0.7); + } + + .restaurant-warning { + color: var(--gt-bacon); + } + } + } + + .food-table tbody tr:hover > td { + background: #fff8dc; + } + + &[data-bs-theme="dark"] .food-table tbody tr:hover > td { + background: #2b2622; + } + + .food-price { + color: #a8650a; + font-weight: 800; + } + + &[data-bs-theme="dark"] .food-price { + color: var(--gt-yolk); + } + + // ---------- Panely a tabulka voleb ---------- + .choice-section, + .choices-table, + .pizza-section, + .no-votes { + border: 2px solid var(--gt-line); + border-radius: var(--luncher-radius-lg); + box-shadow: var(--luncher-shadow); + } + + .choices-table { + border-collapse: separate; + border-spacing: 0; + } + + // Sloupec s podnikem: světlý žloutek + .choices-table > tbody > tr > td:first-child { + background: #fff3c4; + color: #4a3520; + font-family: var(--gt-display); + font-weight: 600; + border-right: 2px solid #f5dc8a; + } + + &[data-bs-theme="dark"] .choices-table > tbody > tr > td:first-child { + background: #3a3018; + color: var(--gt-yolk); + border-right-color: #4a3d1c; + } + + // Bootstrap karty (skupinové objednávky apod.) a seznamy + .card { + border: 2px solid var(--gt-line); + border-radius: var(--luncher-radius-lg); + box-shadow: var(--luncher-shadow); + overflow: hidden; + background: var(--luncher-bg-card); + + // Rozbalovací výběr z nabídky nesmí karta oříznout + &:has(.select-search-container) { + overflow: visible; + } + + > .card-header { + background: var(--luncher-primary-light); + border-bottom: 2px solid #f5dc8a; + font-weight: 700; + + &:first-child { + border-radius: calc(var(--luncher-radius-lg) - 2px) calc(var(--luncher-radius-lg) - 2px) 0 0; + } + } + + .table { + --bs-table-bg: transparent; + margin-bottom: 0; + + > :last-child > tr:last-child > * { + border-bottom-width: 0; + } + } + } + + .list-group { + border-radius: var(--luncher-radius); + overflow: hidden; + border: 2px solid var(--gt-line); + + > .list-group-item { + border-left: none; + border-right: none; + + &:first-child { + border-top: none; + } + + &:last-child { + border-bottom: none; + } + } + } + + .form-select, .form-control, + input[type="text"], input[type="email"], input[type="password"] { + border-radius: var(--luncher-radius-sm); + border: 2px solid var(--gt-line); + + &:focus { + border-color: var(--gt-yolk-deep); + box-shadow: 0 0 0 4px rgb(255 210 63 / 0.3); + } + } + + // ---------- Tlačítka: žloutková a buclatá, s líným přechodem ---------- + .btn { + border-radius: 999px; + font-weight: 800; + transition: transform 0.5s ease, box-shadow 0.5s ease, background 0.5s ease; + } + + .btn-primary { + background: var(--gt-yolk); + border: none; + color: #4a3520; + box-shadow: 0 4px 0 var(--gt-yolk-shadow); + + &:hover { + background: #ffdc5c; + color: #4a3520; + box-shadow: 0 4px 0 var(--gt-yolk-shadow), 0 0 0 4px rgb(255 210 63 / 0.3); + } + + &:active { + transform: translateY(3px) scaleY(0.94) !important; + box-shadow: 0 1px 0 var(--gt-yolk-shadow) !important; + } + + &:disabled { + background: #efe6cf; + color: #a3927c; + box-shadow: none; + } + } + + &[data-bs-theme="dark"] .btn-primary:disabled { + background: #3a332e; + color: #968a7a; + } + + .btn-outline-primary { + background: var(--luncher-bg-card); + border: 2px solid var(--gt-yolk-deep); + color: var(--luncher-primary); + + &:hover { + background: var(--luncher-primary-light); + border-color: var(--gt-yolk-deep); + color: var(--luncher-primary); + } + } + + // Sekundární — sójová omáčka + .btn-secondary { + background: var(--gt-soy); + border: none; + color: #fffdf5; + box-shadow: 0 4px 0 #4a3220; + + &:hover { + background: #7d5a3a; + color: #fffdf5; + } + } + + .btn-danger { + background: var(--gt-bacon); + border: none; + box-shadow: 0 4px 0 #9a3a28; + } + + .action-icon:hover { + background: var(--luncher-primary-light); + color: var(--luncher-primary); + } + + // ---------- Modaly: žloutek nahoře, proužek slaniny ---------- + .modal-content { + border: 2px solid var(--gt-line); + border-radius: var(--luncher-radius-xl); + box-shadow: 0 16px 40px rgb(74 53 32 / 0.25); + overflow: hidden; + } + + .modal-header { + background: + #{$gt-bacon} left bottom / 48px 10px repeat-x, + linear-gradient(180deg, #ffdc5c, var(--gt-yolk)); + border-bottom: none; + padding-bottom: calc(var(--bs-modal-header-padding-y, 1rem) + 8px); + + .modal-title, .modal-title h2 { + color: #4a3520; + font-family: var(--gt-display); + font-weight: 600; + } + } + + &[data-bs-theme="dark"] .modal-header { + background: + #{$gt-bacon} left bottom / 48px 10px repeat-x, + #0e0d0c; + + .modal-title, .modal-title h2 { + color: var(--gt-yolk); + } + + .btn-close { + filter: invert(1) grayscale(1) brightness(2); + } + } + + .footer { + border-top: none; + background-image: $gt-bacon; + background-size: 48px 10px; + background-repeat: repeat-x; + background-position: top; + + a { + color: #8a3a28; + } + } + + &[data-bs-theme="dark"] .footer a { + color: #f2a7a0; + } +} + +// Gude~ — vajíčko se občas líně „rozteče" a zase se sebere +@keyframes gt-gude { + 0%, 78%, 100% { transform: scale(1, 1); } + 84% { transform: scale(1.04, 0.92); } + 90% { transform: scale(1.06, 0.9); } + 95% { transform: scale(1.01, 0.98); } +} + +@media (max-width: 575.98px) { + #{$gt} .day-navigator .title { + font-size: 1.3rem; + padding: 8px 22px 10px 56px; + + &::before { + left: 14px; + width: 30px; + height: 26px; + margin-top: -12px; + } + + &::after { + left: 36px; + } + } +} + +@media (prefers-reduced-motion: reduce) { + #{$gt} .day-navigator .title { + animation: none; + } +}