caro5 / client /src /theme.ts
Pedro de Carvalho
Update client
9c34cd3
Raw
History Blame Contribute Delete
7.97 kB
import { useEffect, useState } from 'react'
export type ThemeMode = 'midnight' | 'garden' | 'forest' | 'arctic'
export interface ThemeColors {
bg: number
bgStr: string
bgPanel: string
border: string
text: string
textMuted: string
player1: number
player1Str: string
player2: number
player2Str: string
gridMinor: number
gridMajor: number
gridBorder: number
win: string
draw: string
waiting: string
playing: string
error: string
errorBg: string
hoverFill: number
hoverFillAlpha: number
hoverStroke: number
hoverStrokeAlpha: number
rematchBg: string
rematchBgHover: string
effectGlow: number
effectSpark: number
effectGold: number
winLineColor: number
particleGold: number
particleSpark: number
screenFlash: number
cellFill: number
cellFillAlt: number
}
export interface ThemeInfo {
label: string
emoji: string
colors: ThemeColors
backgroundImage: string | null
}
const midnight: ThemeColors = {
bg: 0x0d1117,
bgStr: '#0d1117',
bgPanel: 'rgba(22,27,34,0.92)',
border: '#21262d',
text: '#e6edf3',
textMuted: '#8b949e',
player1: 0x58a6ff,
player1Str: '#58a6ff',
player2: 0xf0883e,
player2Str: '#f0883e',
gridMinor: 0x1c2128,
gridMajor: 0x2d333b,
gridBorder: 0x444c5e,
win: '#3fb950',
draw: '#d29922',
waiting: '#8b949e',
playing: '#58a6ff',
error: '#f85149',
errorBg: 'rgba(35,10,10,0.92)',
hoverFill: 0x58a6ff,
hoverFillAlpha: 0.10,
hoverStroke: 0x58a6ff,
hoverStrokeAlpha: 0.25,
rematchBg: '#238636',
rematchBgHover: '#2ea043',
effectGlow: 0x58a6ff,
effectSpark: 0x58a6ff,
effectGold: 0xffd700,
winLineColor: 0x3fb950,
particleGold: 0xffd700,
particleSpark: 0xffffff,
screenFlash: 0xffffff,
cellFill: 0x0d1117,
cellFillAlt: 0x0f141c,
}
const garden: ThemeColors = {
bg: 0xf5f0e8,
bgStr: '#f5f0e8',
bgPanel: 'rgba(245,240,232,0.92)',
border: '#e0d8c8',
text: '#3a3a2e',
textMuted: '#9a9a82',
player1: 0x6a9e6a,
player1Str: '#6a9e6a',
player2: 0xd4869a,
player2Str: '#d4869a',
gridMinor: 0xd8d0ba,
gridMajor: 0xc8c0aa,
gridBorder: 0xb8b098,
win: '#6a9e6a',
draw: '#c9a84c',
waiting: '#9a9a82',
playing: '#6a9e6a',
error: '#d47878',
errorBg: 'rgba(200,80,80,0.12)',
hoverFill: 0x6a9e6a,
hoverFillAlpha: 0.10,
hoverStroke: 0x6a9e6a,
hoverStrokeAlpha: 0.25,
rematchBg: '#6a9e6a',
rematchBgHover: '#7ab07a',
effectGlow: 0x6a9e6a,
effectSpark: 0x6a9e6a,
effectGold: 0xffd700,
winLineColor: 0x6a9e6a,
particleGold: 0xffd700,
particleSpark: 0xd4869a,
screenFlash: 0xffffff,
cellFill: 0xf5f0e8,
cellFillAlt: 0xf2ece0,
}
const forest: ThemeColors = {
bg: 0x0a1f0d,
bgStr: '#0a1f0d',
bgPanel: 'rgba(10,31,13,0.92)',
border: '#1a3d1f',
text: '#d4edda',
textMuted: '#8bb99a',
player1: 0x8bde6d,
player1Str: '#8bde6d',
player2: 0xd4a54d,
player2Str: '#d4a54d',
gridMinor: 0x122a16,
gridMajor: 0x1a3d1f,
gridBorder: 0x2d5234,
win: '#fbbf24',
draw: '#f59e0b',
waiting: '#8bb99a',
playing: '#8bde6d',
error: '#f87171',
errorBg: 'rgba(35,10,10,0.92)',
hoverFill: 0x8bde6d,
hoverFillAlpha: 0.15,
hoverStroke: 0x8bde6d,
hoverStrokeAlpha: 0.30,
rematchBg: '#2d7d3a',
rematchBgHover: '#3a9c4a',
effectGlow: 0x8bde6d,
effectSpark: 0x8bde6d,
effectGold: 0xffd700,
winLineColor: 0xfbbf24,
particleGold: 0xffd700,
particleSpark: 0xd4a54d,
screenFlash: 0xffffff,
cellFill: 0x2a1c0c,
cellFillAlt: 0x26190a,
}
const arctic: ThemeColors = {
bg: 0x0b1620,
bgStr: '#0b1620',
bgPanel: 'rgba(11,22,32,0.92)',
border: '#1a3348',
text: '#deeaf5',
textMuted: '#8aaac4',
player1: 0x7ec8e3,
player1Str: '#7ec8e3',
player2: 0xe8d5b7,
player2Str: '#e8d5b7',
gridMinor: 0x102838,
gridMajor: 0x1a3348,
gridBorder: 0x2a4a62,
win: '#a3d9ff',
draw: '#d4a574',
waiting: '#8aaac4',
playing: '#7ec8e3',
error: '#f87171',
errorBg: 'rgba(35,10,10,0.92)',
hoverFill: 0x7ec8e3,
hoverFillAlpha: 0.15,
hoverStroke: 0x7ec8e3,
hoverStrokeAlpha: 0.30,
rematchBg: '#2a7a9a',
rematchBgHover: '#3a8aaa',
effectGlow: 0x7ec8e3,
effectSpark: 0x7ec8e3,
effectGold: 0xffd700,
winLineColor: 0xa3d9ff,
particleGold: 0xffd700,
particleSpark: 0xe8d5b7,
screenFlash: 0xffffff,
cellFill: 0x0c1e2c,
cellFillAlt: 0x0e2232,
}
export const THEMES: Record<ThemeMode, ThemeInfo> = {
midnight: { label: 'Midnight', emoji: '🌙', colors: midnight, backgroundImage: 'bg/night-bg.jpg?v=3' },
garden: { label: 'Garden', emoji: '🌷', colors: garden, backgroundImage: null },
forest: { label: 'Forest', emoji: '🌲', colors: forest, backgroundImage: 'bg/forest_bg.jpg?v=3' },
arctic: { label: 'Arctic', emoji: '🧊', colors: arctic, backgroundImage: null },
}
const listeners = new Set<() => void>()
const stored: string | null = null
let currentMode: ThemeMode = stored !== null && stored in THEMES ? stored as ThemeMode : 'forest'
let currentTheme: ThemeColors = THEMES[currentMode].colors
export const theme = new Proxy<ThemeColors>({} as ThemeColors, {
get(_, prop) {
return currentTheme[prop as keyof ThemeColors]
},
ownKeys() {
return Reflect.ownKeys(currentTheme) as (keyof ThemeColors)[]
},
getOwnPropertyDescriptor() {
return { configurable: true, enumerable: true }
},
})
export function setThemeMode(mode: ThemeMode): void {
if (mode === currentMode) return
currentMode = mode
currentTheme = THEMES[mode].colors
document.body.style.background = currentTheme.bgStr
document.body.style.color = currentTheme.text
listeners.forEach((fn) => fn())
}
export function getThemeMode(): ThemeMode {
return currentMode
}
export function getThemeBackgroundImage(mode: ThemeMode = currentMode): string | null {
return THEMES[mode].backgroundImage
}
export function onThemeChange(fn: () => void): () => void {
listeners.add(fn)
return () => listeners.delete(fn)
}
export function useThemeMode(): [ThemeMode, (mode: ThemeMode) => void] {
const [mode, setMode] = useState<ThemeMode>(getThemeMode)
useEffect(() => {
return onThemeChange(() => setMode(getThemeMode()))
}, [])
return [mode, setThemeMode]
}
document.body.style.background = currentTheme.bgStr
document.body.style.color = currentTheme.text
let _playerName: string | null = null
let _player2Name: string | null = null
let _playerSymbol: string = 'X'
let _player2Symbol: string = 'O'
let _playerColor: string | null = null
let _player2Color: string | null = null
let _playerDrawTower: boolean = true
let _player2DrawTower: boolean = true
export function setPlayerName(name: string): void {
_playerName = name
}
export function getPlayerName(): string {
return _playerName || 'Caro 1'
}
export function setPlayer2Name(name: string): void {
_player2Name = name
}
export function getPlayer2Name(): string {
return _player2Name || 'Caro 2'
}
export function setPlayerSymbol(symbol: string): void {
_playerSymbol = symbol
}
export function getPlayerSymbol(): string {
return _playerSymbol
}
export function setPlayer1Symbol(symbol: string): void {
setPlayerSymbol(symbol)
}
export function getPlayer1Symbol(): string {
return getPlayerSymbol()
}
export function setPlayer2Symbol(symbol: string): void {
_player2Symbol = symbol
}
export function getPlayer2Symbol(): string {
return _player2Symbol
}
export function setPlayerColor(color: string): void {
_playerColor = color
}
export function getPlayerColor(): string | null {
return _playerColor
}
export function setPlayer2Color(color: string): void {
_player2Color = color
}
export function getPlayer2Color(): string | null {
return _player2Color
}
export function setPlayerDrawTower(draw: boolean): void {
_playerDrawTower = draw
}
export function getPlayerDrawTower(): boolean {
return _playerDrawTower
}
export function setPlayer2DrawTower(draw: boolean): void {
_player2DrawTower = draw
}
export function getPlayer2DrawTower(): boolean {
return _player2DrawTower
}