From 28fc3ab0fb2b29954a120f3f7302ce9c69dcf973 Mon Sep 17 00:00:00 2001 From: DIKER0K Date: Sun, 14 Dec 2025 22:25:01 +0500 Subject: [PATCH 1/2] add theme provider --- src/renderer/index.tsx | 11 ++- src/theme/themes.ts | 173 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/theme/themes.ts diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 8864218..e18b0c2 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -1,9 +1,18 @@ import { createRoot } from 'react-dom/client'; import App from './App'; +import { ThemeProvider, CssBaseline } from '@mui/material'; +import { defaultTheme } from '../theme/themes'; // <-- поправь путь, если themes.ts лежит в другом месте + const container = document.getElementById('root') as HTMLElement; const root = createRoot(container); -root.render(); + +root.render( + + + + , +); // calling IPC exposed from preload script window.electron?.ipcRenderer.once('ipc-example', (arg) => { diff --git a/src/theme/themes.ts b/src/theme/themes.ts new file mode 100644 index 0000000..f64a55a --- /dev/null +++ b/src/theme/themes.ts @@ -0,0 +1,173 @@ +import { createTheme, SxProps, Theme } from '@mui/material/styles'; + +declare module '@mui/material/styles' { + interface Theme { + launcher: { + fonts: { + default: string; + }; + + topbar: { + firstBox: { + background: string; + backdropFilter: string; + boxShadow: string; + }; + backButton: { + transition: string; + '&:hover': { + transform: string; + }; + }; + tabsBox: { + borderColor: string; + }; + tabs: SxProps; + tabBase: SxProps; + tabActive: SxProps; + menuPaper: SxProps; + menuDivider: SxProps; + menuItem: SxProps; + menuUsername: SxProps; + logoutButton: SxProps; + windowControlIcon: { + color: string; + }; + windowControlButton: SxProps; + }; + }; + } + + interface ThemeOptions { + launcher?: Theme['launcher']; + } +} + +export const defaultTheme = createTheme({ + palette: { + mode: 'dark', + primary: { main: '#F27121' }, + secondary: { main: '#E940CD' }, + text: { + primary: '#FFFFFF', + secondary: 'rgba(255,255,255,0.7)', + }, + }, + + launcher: { + fonts: { + default: 'Benzin-Bold', + }, + + topbar: { + firstBox: { + background: + 'linear-gradient(71deg, rgba(242,113,33,0.18) 0%, rgba(233,64,205,0.14) 70%, rgba(138,35,135,0.16) 100%)', + backdropFilter: 'blur(10px)', + boxShadow: '0 8px 30px rgba(0,0,0,0.35)', + }, + backButton: { + transition: 'transform 0.3s ease', + '&:hover': { + transform: 'scale(1.2)', + }, + }, + tabsBox: { + borderColor: 'transparent', + }, + tabs: { + // один градиент на весь Tabs + '--tabs-grad': + 'linear-gradient(90deg, #F27121 0%, #E940CD 50%, #8A2387 100%)', + + // активный текст показывает “срез” общего градиента + '& .MuiTab-root.Mui-selected': { + color: 'transparent', + backgroundImage: 'var(--tabs-grad)', + backgroundRepeat: 'no-repeat', + backgroundSize: 'var(--tabs-w) 100%', + backgroundPosition: 'calc(-1 * var(--active-x)) 0', + WebkitBackgroundClip: 'text', + backgroundClip: 'text', + }, + + // подчёркивание тоже из того же “единого” градиента + '& .MuiTabs-indicator': { + height: '2px', + backgroundImage: 'var(--tabs-grad)', + backgroundRepeat: 'no-repeat', + backgroundSize: 'var(--tabs-w) 100%', + backgroundPosition: 'calc(-1 * var(--active-x)) 0', + }, + }, + tabBase: (theme: Theme) => ({ + color: 'white', + fontFamily: theme.launcher.fonts.default, + transition: 'all 0.3s ease', + '&:hover': { + color: 'rgb(170, 170, 170)', + }, + }), + tabActive: { + color: 'transparent', + WebkitTextFillColor: 'transparent', + backgroundImage: 'var(--tabs-grad)', + backgroundRepeat: 'no-repeat', + backgroundSize: 'var(--tabs-w) 100%', + backgroundPosition: 'calc(-1 * var(--active-x)) 0', + WebkitBackgroundClip: 'text', + backgroundClip: 'text', + }, + menuPaper: { + color: 'white', + bgcolor: 'rgba(0,0,0,0.82)', + backdropFilter: 'blur(10px)', + border: '1px solid rgba(233,64,205,0.25)', + boxShadow: '0 18px 40px rgba(0,0,0,0.55)', + }, + + menuDivider: { + borderColor: 'rgba(255,255,255,0.08)', + }, + + menuItem: (theme: Theme) => ({ + fontFamily: theme.launcher.fonts.default, + '&:hover': { + bgcolor: 'rgba(255,77,77,0.15)', + }, + }), + + menuUsername: (theme: Theme) => ({ + fontFamily: theme.launcher.fonts.default, + color: theme.palette.text.primary, + }), + + logoutButton: (theme: Theme) => ({ + fontFamily: theme.launcher.fonts.default, + background: + 'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)', + color: theme.palette.text.primary, + border: 'none', + transition: 'transform 0.3s ease', + '&:hover': { + background: + 'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)', + transform: 'scale(1.01)', + boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)', + }, + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)', + }), + + windowControlIcon: { + color: 'white', + }, + + windowControlButton: { + // тут только “визуал”, размеры оставим в TopBar + '&:hover': { + bgcolor: 'rgba(255,255,255,0.06)', + }, + }, + }, + }, +}); From ff87c9d4a5cfffc40259e79d36cd434452aca5ab Mon Sep 17 00:00:00 2001 From: DIKER0K Date: Sun, 14 Dec 2025 23:49:32 +0500 Subject: [PATCH 2/2] rework style TobBar in themes.ts --- src/renderer/components/TopBar.tsx | 242 ++++++++++------------------- src/theme/themes.ts | 39 ++--- 2 files changed, 103 insertions(+), 178 deletions(-) diff --git a/src/renderer/components/TopBar.tsx b/src/renderer/components/TopBar.tsx index 8524874..4807efc 100644 --- a/src/renderer/components/TopBar.tsx +++ b/src/renderer/components/TopBar.tsx @@ -20,6 +20,7 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; import PersonIcon from '@mui/icons-material/Person'; import SettingsIcon from '@mui/icons-material/Settings'; +import { useTheme } from '@mui/material/styles'; declare global { interface Window { electron: { @@ -48,6 +49,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { const navigate = useNavigate(); const tabsWrapperRef = useRef(null); const tabsRootRef = useRef(null); + const theme = useTheme(); const updateGradientVars = useCallback(() => { const root = tabsRootRef.current; @@ -71,7 +73,8 @@ export default function TopBar({ onRegister, username }: TopBarProps) { ); const path = location.pathname || ''; - const isAuthPage = path.startsWith('/login') || path.startsWith('/registration'); + const isAuthPage = + path.startsWith('/login') || path.startsWith('/registration'); const TAB_ROUTES: Array<{ value: number; @@ -198,26 +201,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { // Функция для получения количества монет - const tabBaseSx = { - color: 'white', - fontFamily: 'Benzin-Bold', - fontSize: '0.7em', - transition: 'all 0.3s ease', - '&:hover': { - color: 'rgb(170, 170, 170)', - }, - }; - - const activeTabSx = { - color: 'transparent', - WebkitTextFillColor: 'transparent', - backgroundImage: 'var(--tabs-grad)', - backgroundRepeat: 'no-repeat', - backgroundSize: 'var(--tabs-w) 100%', - backgroundPosition: 'calc(-1 * var(--active-x)) 0', - WebkitBackgroundClip: 'text', - backgroundClip: 'text', - }; + const tabBaseSx = [{ fontSize: '0.7em' }, theme.launcher.topbar.tabBase]; const logout = () => { localStorage.removeItem('launcher_config'); @@ -230,7 +214,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { return; } - const savedConfig = localStorage.getItem('launcher_config'); + const savedConfig = localStorage.getItem('launcher_config'); if (!savedConfig) return; let cfg: any = null; @@ -263,33 +247,29 @@ export default function TopBar({ onRegister, username }: TopBarProps) { }; window.addEventListener('skin-updated', handler as EventListener); - return () => window.removeEventListener('skin-updated', handler as EventListener); + return () => + window.removeEventListener('skin-updated', handler as EventListener); }, [loadSkin]); return ( {/* Левая часть */} handleLaunchPage()} - sx={{ - width: '3em', - height: '3em', - borderRadius: '50%', - border: 'unset', - color: 'white', - minWidth: 'unset', - minHeight: 'unset', - transition: 'transform 0.3s ease', - '&:hover': { - transform: 'scale(1.2)', + sx={[ + { + width: '3em', + height: '3em', + borderRadius: '50%', + minWidth: 'unset', + minHeight: 'unset', }, - }} + theme.launcher.topbar.backButton, + ]} > @@ -329,7 +306,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { // старый вариант sx={{ borderBottom: 1, - borderColor: 'transparent', + ...theme.launcher.topbar.tabsBox, // '& .MuiTabs-indicator': { // backgroundColor: 'rgba(255, 77, 77, 1)', // }, @@ -371,61 +348,40 @@ export default function TopBar({ onRegister, username }: TopBarProps) { scrollButtons={false} disableRipple={true} sx={{ - // один градиент на весь Tabs - '--tabs-grad': 'linear-gradient(90deg, #F27121 0%, #E940CD 50%, #8A2387 100%)', - - // активный текст показывает “срез” общего градиента - '& .MuiTab-root.Mui-selected': { - color: 'transparent', - backgroundImage: 'var(--tabs-grad)', - backgroundRepeat: 'no-repeat', - backgroundSize: 'var(--tabs-w) 100%', - backgroundPosition: 'calc(-1 * var(--active-x)) 0', - WebkitBackgroundClip: 'text', - backgroundClip: 'text', - }, - - // подчёркивание тоже из того же “единого” градиента - '& .MuiTabs-indicator': { - height: '2px', - backgroundImage: 'var(--tabs-grad)', - backgroundRepeat: 'no-repeat', - backgroundSize: 'var(--tabs-w) 100%', - backgroundPosition: 'calc(-1 * var(--active-x)) 0', - }, + ...theme.launcher.topbar.tabs, }} > @@ -497,6 +453,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { width: '3em', height: '3em', borderRadius: '50%', + ...theme.launcher.topbar.windowControlButton, }} > @@ -521,9 +478,12 @@ export default function TopBar({ onRegister, username }: TopBarProps) { width: '3em', height: '3em', borderRadius: '50%', + ...theme.launcher.topbar.windowControlButton, }} > - + @@ -571,10 +527,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) { {username || 'Игрок'} @@ -593,22 +546,17 @@ export default function TopBar({ onRegister, username }: TopBarProps) { - + { handleAvatarMenuClose(); navigate('/profile'); }} - sx={{ - fontFamily: 'Benzin-Bold', - fontSize: '1.5vw', - gap: '0.5vw', - py: '0.7vw', - '&:hover': { - bgcolor: 'rgba(255,77,77,0.15)', - }, - }} + sx={[ + { fontSize: '1.5vw', gap: '0.5vw', py: '0.7vw' }, + theme.launcher.topbar.menuItem, + ]} > Профиль @@ -619,15 +567,10 @@ export default function TopBar({ onRegister, username }: TopBarProps) { handleAvatarMenuClose(); navigate('/dailyquests'); }} - sx={{ - fontFamily: 'Benzin-Bold', - fontSize: '1.5vw', - gap: '0.5vw', - py: '0.7vw', - '&:hover': { - bgcolor: 'rgba(255,77,77,0.15)', - }, - }} + sx={[ + { fontSize: '1.5vw', gap: '0.5vw', py: '0.7vw' }, + theme.launcher.topbar.menuItem, + ]} > Ежедневные задания @@ -638,15 +581,10 @@ export default function TopBar({ onRegister, username }: TopBarProps) { handleAvatarMenuClose(); navigate('/daily'); }} - sx={{ - fontFamily: 'Benzin-Bold', - fontSize: '1.5vw', - gap: '0.5vw', - py: '0.7vw', - '&:hover': { - bgcolor: 'rgba(255,77,77,0.15)', - }, - }} + sx={[ + { fontSize: '1.5vw', gap: '0.5vw', py: '0.7vw' }, + theme.launcher.topbar.menuItem, + ]} > Ежедневная награда @@ -656,20 +594,15 @@ export default function TopBar({ onRegister, username }: TopBarProps) { handleAvatarMenuClose(); navigate('/settings'); }} - sx={{ - fontFamily: 'Benzin-Bold', - fontSize: '1.5vw', - gap: '0.5vw', - py: '0.7vw', - '&:hover': { - bgcolor: 'rgba(255,77,77,0.15)', - }, - }} + sx={[ + { fontSize: '1.5vw', gap: '0.5vw', py: '0.7vw' }, + theme.launcher.topbar.menuItem, + ]} > Настройки - + {!isLoginPage && !isRegistrationPage && username && ( diff --git a/src/theme/themes.ts b/src/theme/themes.ts index f64a55a..c81b645 100644 --- a/src/theme/themes.ts +++ b/src/theme/themes.ts @@ -7,18 +7,14 @@ declare module '@mui/material/styles' { default: string; }; + gradients: { + accent: string; + tabs: string; + }; + topbar: { - firstBox: { - background: string; - backdropFilter: string; - boxShadow: string; - }; - backButton: { - transition: string; - '&:hover': { - transform: string; - }; - }; + firstBox: SxProps; + backButton: SxProps; tabsBox: { borderColor: string; }; @@ -59,19 +55,25 @@ export const defaultTheme = createTheme({ default: 'Benzin-Bold', }, + gradients: { + accent: '#F27121 0%, #E940CD 50%, #8A2387 100%', + tabs: 'linear-gradient(71deg, rgba(242,113,33,0.18) 0%, rgba(233,64,205,0.14) 70%, rgba(138,35,135,0.16) 100%)', + }, + topbar: { - firstBox: { - background: - 'linear-gradient(71deg, rgba(242,113,33,0.18) 0%, rgba(233,64,205,0.14) 70%, rgba(138,35,135,0.16) 100%)', + firstBox: (theme: Theme) => ({ + background: theme.launcher.gradients.tabs, backdropFilter: 'blur(10px)', boxShadow: '0 8px 30px rgba(0,0,0,0.35)', - }, - backButton: { + }), + backButton: (theme: Theme) => ({ + color: theme.palette.text.primary, transition: 'transform 0.3s ease', '&:hover': { transform: 'scale(1.2)', }, - }, + border: 'unset', + }), tabsBox: { borderColor: 'transparent', }, @@ -144,9 +146,10 @@ export const defaultTheme = createTheme({ logoutButton: (theme: Theme) => ({ fontFamily: theme.launcher.fonts.default, + borderRadius: '2.5vw', background: 'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)', - color: theme.palette.text.primary, + color: 'white', border: 'none', transition: 'transform 0.3s ease', '&:hover': {