feat: futuristic theme ladder + stacked landing banner

Add three opt-in dark themes (BooCode+, BooCode Classic, BooCode
Override) plus an in-place Ember polish, on a class-scoped effects
engine: matrix rain, a neon grid field, and frosted glass, all gated
by a localStorage "Animated background" toggle and prefers-reduced-
motion. Extend the server theme_id whitelist so the new ids persist,
and replace the Home landing wordmark with the stacked mascot +
wordmark banner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 14:16:59 +00:00
parent d10d79399b
commit fc4fbb0b7e
21 changed files with 1822 additions and 30 deletions

View File

@@ -13,6 +13,7 @@ import { useTheme } from '@/lib/theme';
import { SidebarDrawerProvider, useSidebarDrawer } from '@/hooks/useSidebarDrawer';
import { RightRailDrawerProvider, useRightRailDrawer } from '@/hooks/useRightRailDrawer';
import { useViewport } from '@/hooks/useViewport';
import { ThemeFx } from '@/components/fx/ThemeFx';
function SessionRightRail() {
const { id } = useParams<{ id: string }>();
@@ -73,24 +74,32 @@ function AppShell() {
// descendant — including the terminal pane — measures itself against a
// height that extends behind the URL bar, and xterm allocates extra rows
// that scroll out of reach on iPhone.
//
// ThemeFx: canvas-based animated backgrounds (Classic rain, Override neon
// field) rendered at z-0 behind the content wrapper. ThemeFx also manages
// the bc-anim-on gate class on <html>. Content wrapper at z-10 ensures all
// UI sits above any fixed canvas regardless of theme.
return (
<div className="h-dvh flex bg-background text-foreground">
<ProjectSidebar />
<MobileBackdrop />
<main className="flex-1 flex flex-col min-w-0">
<>
<ThemeFx />
<div className="h-dvh flex bg-background text-foreground relative z-10">
<ProjectSidebar />
<MobileBackdrop />
<main className="flex-1 flex flex-col min-w-0">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/project/:id" element={<Project />} />
<Route path="/session/:id" element={<Session />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</main>
<MobileRightRailBackdrop />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/project/:id" element={<Project />} />
<Route path="/session/:id" element={<Session />} />
<Route path="/settings" element={<Settings />} />
<Route path="/session/:id" element={<SessionRightRail />} />
</Routes>
</main>
<MobileRightRailBackdrop />
<Routes>
<Route path="/session/:id" element={<SessionRightRail />} />
</Routes>
<Toaster position="bottom-right" />
</div>
<Toaster position="bottom-right" />
</div>
</>
);
}