feat(frontend): default site theme to Amber instead of Classic

New visitors (no saved lv_theme) now get the Amber accent; reconciled the
static CSS accent, demo scene colors and console greeting to match so there
is no blue/emerald flash before the theme provider applies. Updated the
default-theme assertions in the theme tests.
This commit is contained in:
loki5512344 2026-09-29 10:55:18 +02:00
parent 8a758754dd
commit 3f679b83f6
Signed by: boba
GPG key ID: 253067914055423B
8 changed files with 16 additions and 12 deletions

View file

@ -36,6 +36,7 @@ test('a theme card inside the preview loads that preset into the draft, not the
await user.click(within(gui).getByRole('option', { name: 'Тема Nitro' }))
expect(screen.getByDisplayValue('Nitro')).toBeInTheDocument()
expect(within(gui).getByRole('option', { name: 'Тема Nitro' })).toHaveAttribute('aria-selected', 'true')
expect(screen.getByRole('status', { name: 'site theme' })).toHaveTextContent(PRESETS[0].id)
// The site keeps its default theme (amber) even though the draft loaded Classic.
expect(screen.getByRole('status', { name: 'site theme' })).toHaveTextContent('amber')
expect(window.localStorage.getItem('lv_theme')).toBeNull()
})

View file

@ -21,7 +21,7 @@ afterEach(() => {
test('a user pick persists to lv_theme, re-accents the page and locks out demo switches', () => {
render(<ActiveThemeProvider><Probe /></ActiveThemeProvider>)
expect(screen.getByTestId('id')).toHaveTextContent('classic')
expect(screen.getByTestId('id')).toHaveTextContent('amber')
act(() => screen.getByText('demo').click())
expect(screen.getByTestId('id')).toHaveTextContent('sunset')
expect(window.localStorage.getItem('lv_theme')).toBeNull()
@ -47,7 +47,7 @@ test('restores the stored theme and survives blocked storage', () => {
throw new Error('blocked')
})
render(<ActiveThemeProvider><Probe /></ActiveThemeProvider>)
expect(screen.getByTestId('id')).toHaveTextContent('classic')
expect(screen.getByTestId('id')).toHaveTextContent('amber')
act(() => screen.getByText('user').click())
expect(screen.getByTestId('id')).toHaveTextContent('nitro')
vi.restoreAllMocks()

View file

@ -3,7 +3,9 @@ import { PRESETS } from './presets.generated'
import { parseArgb, type ThemeEntry, withAlpha } from './types'
const STORAGE_KEY = 'lv_theme'
const FALLBACK = PRESETS[0]
// Amber is the site default for visitors who never picked a theme; Classic stays at PRESETS[0]
// (mirroring the mod's own default) and is only reached if the amber preset ever goes missing.
const FALLBACK = PRESETS.find((p) => p.id === 'amber') ?? PRESETS[0]
type ActiveTheme = {
theme: ThemeEntry
@ -66,7 +68,7 @@ export function ActiveThemeProvider({ children, applyToPage = true }: { children
return createElement(ActiveThemeContext.Provider, { value }, children)
}
/** The active ClickGui theme. Outside a provider it falls back to Classic with a no-op setter. */
/** The active ClickGui theme. Outside a provider it falls back to the default with a no-op setter. */
export function useActiveTheme(): ActiveTheme {
return useContext(ActiveThemeContext) ?? { theme: FALLBACK, userPicked: false, setTheme: () => {} }
}

View file

@ -9,8 +9,9 @@
--color-shoal: #1f3238;
--color-frost: #9fb3b0;
--color-snow: #eef5f3;
--color-ice: #34d399;
--color-ember: #e8835a;
/* Matches the Amber preset (#FFE69A43) so first paint agrees with the default theme. */
--color-ice: #e69a43;
--font-display: "Unbounded Variable", system-ui, sans-serif;
--font-sans: "Onest Variable", system-ui, sans-serif;
@ -29,12 +30,12 @@
@property --color-ice {
syntax: "<color>";
inherits: true;
initial-value: #34d399;
initial-value: #e69a43;
}
@property --page-accent-glow {
syntax: "<color>";
inherits: true;
initial-value: rgb(52 211 153 / 0.35);
initial-value: rgb(230 154 67 / 0.35);
}
@layer base {

View file

@ -4,7 +4,7 @@ import { VoxelScene } from '@features/landing/effects/VoxelScene'
import { SlotGrid } from '@features/configs/components/SlotGrid'
import { PageTitle } from '@shared/layout/PageTitle'
const ACCENT = 'rgb(52, 211, 153)'
const ACCENT = 'rgb(230, 154, 67)'
export default function ConfigsPage() {
const { t } = useTranslation('configs')

View file

@ -3,7 +3,7 @@ import { ParticleField } from '@features/landing/effects/ParticleField'
import { VoxelScene } from '@features/landing/effects/VoxelScene'
import { ListingDetail } from '@features/showcase/components/ListingDetail'
const ACCENT = 'rgb(52, 211, 153)'
const ACCENT = 'rgb(230, 154, 67)'
export default function ListingPage() {
const { id } = useParams<{ id: string }>()

View file

@ -4,7 +4,7 @@ import { VoxelScene } from '@features/landing/effects/VoxelScene'
import { ListingList } from '@features/showcase/components/ListingList'
import { PageTitle } from '@shared/layout/PageTitle'
const ACCENT = 'rgb(52, 211, 153)'
const ACCENT = 'rgb(230, 154, 67)'
export default function ShowcasePage() {
const { t } = useTranslation('showcase')

View file

@ -2,7 +2,7 @@ import { LOGO_ART } from './art.generated'
export function printConsoleGreeting(lang: string): void {
const ru = lang.startsWith('ru')
console.log(`%c${LOGO_ART}`, 'color:#34d399;font-family:monospace;font-weight:bold')
console.log(`%c${LOGO_ART}`, 'color:#e69a43;font-family:monospace;font-weight:bold')
console.log(
`%c${ru ? 'Открыл DevTools? Значит, тебе тут рады.' : 'Opened DevTools? You are welcome here.'}`,
'color:#eef5f3;font-size:13px',