fix(ui): polish the light palette, center the stage bloom (#108)
* fix(ui): make the light theme a real light theme The web shell hardcoded dark surfaces (panel hex, white/black alphas, white text), so switching to light left the sidebar, chat, composer and side panel dark with ink text on top. Shell surfaces now use the shared tokens: light gets a warm paper frame with white panels, hairline borders and short soft shadows; dark keeps its look via dark: variants. - Light palette: visible borders (border was equal to muted), white primary-foreground, lighter user bubble, readable warning/success. - Selected sidebar row lives in one place (roster-row-style). - Markdown, inline code, code blocks, quotes and scrollbars follow tokens. - cn() now knows the text-ui-* scale is a font size; tailwind-merge treated it as a color and dropped labels' color on resized buttons (sign-up submit rendered ink on ink). - Stage bloom was offset left by a double translateX. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016or6oqCqP8wbNafvhnbLQT * refactor(ui-web): leave the cn() fix to #115 #115 fixes the same tailwind-merge bug more completely (text, control, icon and spacing scales, guarded against styles.css) and adds the same two files, so this branch drops its narrower copy to avoid the overlap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016or6oqCqP8wbNafvhnbLQT --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4ba7d843b1
commit
c4c5ce3c2d
@ -67,6 +67,9 @@ test("account settings appearance control switches to light mode", async ({ page
|
||||
await settings.getByRole("button", { name: "Close user settings" }).click();
|
||||
await expect(settings).toBeHidden();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "light");
|
||||
// Light surfaces stay light: no dark panel or white-on-paper text survives the switch.
|
||||
await expect(page.locator("main").first()).toHaveCSS("background-color", "rgb(255, 255, 255)");
|
||||
await expect(page.locator("aside").first()).toHaveCSS("background-color", "rgb(245, 245, 242)");
|
||||
await captureScreenshot(page, testInfo, "ui-appearance-light-shell");
|
||||
await captureSidebarSearchSelected(page, testInfo, "sidebar-search-selected-light");
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
const meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute("content", theme === "light" ? "#fafaf8" : "#07080a");
|
||||
if (meta) meta.setAttribute("content", theme === "light" ? "#ffffff" : "#07080a");
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
|
||||
@ -134,7 +134,7 @@ export function OnboardingScanProgress({
|
||||
>
|
||||
<div className="flex-shrink-0">
|
||||
{isDone ? (
|
||||
<span className="grid size-6 items-center justify-center rounded-full bg-emerald-500/20 text-emerald-500 text-sm">
|
||||
<span className="grid size-6 items-center justify-center rounded-full bg-emerald-500/20 text-emerald-700 text-sm dark:text-emerald-500">
|
||||
✓
|
||||
</span>
|
||||
) : isActive ? (
|
||||
@ -174,7 +174,7 @@ export function OnboardingScanProgress({
|
||||
<div className="mt-8 text-center">
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-xl bg-primary px-6 py-3 text-sm font-medium text-white"
|
||||
className="rounded-xl bg-primary px-6 py-3 text-sm font-medium text-primary-foreground"
|
||||
onClick={onComplete}
|
||||
>
|
||||
Continue to your workspace →
|
||||
|
||||
@ -55,22 +55,22 @@ export function StageHero({
|
||||
) : null}
|
||||
|
||||
<div
|
||||
className={`relative flex ${orbSize} items-center justify-center rounded-full border border-border bg-muted/45 shadow-[0_16px_48px_rgba(0,0,0,0.45),inset_0_1px_0_rgba(255,255,255,0.12)] backdrop-blur-xl`}
|
||||
style={
|
||||
reducedMotion
|
||||
? undefined
|
||||
: {
|
||||
boxShadow: `0 16px 48px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.12), 0 0 ${Math.round(18 + energy * 32)}px ${glowRgb}`,
|
||||
}
|
||||
}
|
||||
className={`relative flex ${orbSize} items-center justify-center rounded-full border border-border bg-muted/45 shadow-[0_12px_32px_-12px_rgba(24,24,22,0.18)] backdrop-blur-xl dark:shadow-[0_16px_48px_rgba(0,0,0,0.45),inset_0_1px_0_rgba(255,255,255,0.12)]`}
|
||||
>
|
||||
{reducedMotion ? null : (
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute inset-0 rounded-full"
|
||||
style={{ boxShadow: `0 0 ${Math.round(18 + energy * 32)}px ${glowRgb}` }}
|
||||
/>
|
||||
)}
|
||||
<BotAvatar
|
||||
color={botColor}
|
||||
identity={botId}
|
||||
status={botStatus}
|
||||
pose={pose}
|
||||
size={avatarSize}
|
||||
className="drop-shadow-[0_6px_24px_rgba(0,0,0,0.4)]"
|
||||
className="drop-shadow-[0_6px_16px_rgba(0,0,0,0.12)] dark:drop-shadow-[0_6px_24px_rgba(0,0,0,0.4)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ export function TextStageCanvas({
|
||||
style={{
|
||||
background: `radial-gradient(circle, ${phaseTint} 0%, ${personaTint} 42%, transparent 72%)`,
|
||||
opacity: 0.55 + energy * 0.2,
|
||||
transform: `translateX(-50%) scale(${bloomScale})`,
|
||||
transform: `scale(${bloomScale})`,
|
||||
transition: reducedMotion
|
||||
? undefined
|
||||
: "transform 140ms ease-out, opacity 140ms ease-out",
|
||||
|
||||
@ -84,17 +84,17 @@ export function ChoiceCard({
|
||||
aria-label={option.label}
|
||||
disabled={Boolean(block.answerId) || pending}
|
||||
onClick={() => void choose(option.id)}
|
||||
className={`tactile-press flex w-full items-start gap-3.5 rounded-[18px] border border-white/5 p-3.5 text-start text-foreground disabled:opacity-60 transition-all ${
|
||||
className={`tactile-press flex w-full items-start gap-3.5 rounded-[18px] border border-foreground/5 p-3.5 text-start text-foreground disabled:opacity-60 transition-all ${
|
||||
block.answerId === option.id
|
||||
? "bg-blue-500/20 border-blue-500/40 shadow-sm"
|
||||
: "bg-white/[0.04] hover:bg-white/[0.08] hover:border-white/10"
|
||||
: "bg-foreground/[0.04] hover:bg-foreground/[0.08] hover:border-foreground/10"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`mt-0.5 grid h-6 w-6 shrink-0 place-items-center rounded-[8px] text-ui-body-sm font-semibold ${
|
||||
block.answerId === option.id
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-white/10 text-foreground/80"
|
||||
: "bg-foreground/10 text-foreground/80"
|
||||
}`}
|
||||
>
|
||||
{option.letter}
|
||||
@ -105,7 +105,7 @@ export function ChoiceCard({
|
||||
{option.label}
|
||||
</span>
|
||||
{block.answerId === option.id ? (
|
||||
<span className="mt-0.5 text-blue-400 font-bold">✓</span>
|
||||
<span className="mt-0.5 text-blue-700 dark:text-blue-400 font-bold">✓</span>
|
||||
) : null}
|
||||
</button>
|
||||
))}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
export function rosterRowClass(selected: boolean): string {
|
||||
return `flex w-full items-center gap-3 rounded-2xl border px-3 py-3 mb-[2px] text-start transition-all duration-150 cursor-pointer min-h-[52px] ${
|
||||
selected
|
||||
? "border-sidebar-border bg-sidebar-accent shadow-[inset_0_1px_0_rgba(255,255,255,0.14),0_4px_16px_rgba(0,0,0,0.4)]"
|
||||
? "border-sidebar-border bg-sidebar-accent shadow-xs dark:shadow-[inset_0_1px_0_rgba(255,255,255,0.14),0_4px_16px_rgba(0,0,0,0.4)]"
|
||||
: "border-transparent hover:bg-sidebar-accent/50"
|
||||
}`;
|
||||
}
|
||||
|
||||
@ -82,38 +82,38 @@ export const darkTokens = {
|
||||
} as const satisfies ColorTokens;
|
||||
|
||||
export const lightTokens = {
|
||||
background: "#FAFAF8",
|
||||
background: "#FFFFFF",
|
||||
foreground: "#1A1A1A",
|
||||
card: "#FFFFFF",
|
||||
cardForeground: "#1A1A1A",
|
||||
popover: "#FFFFFF",
|
||||
popoverForeground: "#1A1A1A",
|
||||
primary: "#1A1A1A",
|
||||
primaryForeground: "#F1F1EF",
|
||||
secondary: "#F0F0ED",
|
||||
primaryForeground: "#FFFFFF",
|
||||
secondary: "#F4F4F1",
|
||||
secondaryForeground: "#1A1A1A",
|
||||
chatUser: "#E2E2DC",
|
||||
chatUser: "#EFEFEB",
|
||||
chatUserForeground: "#1A1A1A",
|
||||
muted: "#F0F0ED",
|
||||
mutedForeground: "#6C6C70",
|
||||
accent: "#EAEAE6",
|
||||
muted: "#F4F4F1",
|
||||
mutedForeground: "#67676C",
|
||||
accent: "#ECECE8",
|
||||
accentForeground: "#1A1A1A",
|
||||
destructive: "#DC2626",
|
||||
destructiveForeground: "#FFFFFF",
|
||||
border: "#F0F0ED",
|
||||
input: "#EAEAE6",
|
||||
ring: "#6C6C70",
|
||||
sidebar: "#ECECE9",
|
||||
border: "#E5E5E0",
|
||||
input: "#DADAD4",
|
||||
ring: "#9C9C97",
|
||||
sidebar: "#F5F5F2",
|
||||
sidebarForeground: "#1A1A1A",
|
||||
sidebarBorder: "#E8E8E4",
|
||||
sidebarBorder: "#E8E8E3",
|
||||
sidebarAccent: "#FFFFFF",
|
||||
sidebarAccentForeground: "#1A1A1A",
|
||||
link: "#2563EB",
|
||||
success: "#228B3B",
|
||||
warning: "#B7791F",
|
||||
overlay: "rgba(20, 20, 22, 0.45)",
|
||||
scrollbar: "#C8C8C4",
|
||||
scrollbarHover: "#A8A8A4",
|
||||
success: "#1E7F37",
|
||||
warning: "#A16207",
|
||||
overlay: "rgba(24, 24, 22, 0.28)",
|
||||
scrollbar: "#D3D3CD",
|
||||
scrollbarHover: "#B3B3AC",
|
||||
} as const satisfies ColorTokens;
|
||||
|
||||
/** Dark palette. Prefer `tokensForAppearance` when theme-aware. */
|
||||
|
||||
@ -65,38 +65,38 @@
|
||||
|
||||
[data-theme="light"] {
|
||||
color-scheme: light;
|
||||
--background: #fafaf8;
|
||||
--background: #ffffff;
|
||||
--foreground: #1a1a1a;
|
||||
--card: #ffffff;
|
||||
--card-foreground: #1a1a1a;
|
||||
--popover: #ffffff;
|
||||
--popover-foreground: #1a1a1a;
|
||||
--primary: #1a1a1a;
|
||||
--primary-foreground: #f1f1ef;
|
||||
--secondary: #f0f0ed;
|
||||
--primary-foreground: #ffffff;
|
||||
--secondary: #f4f4f1;
|
||||
--secondary-foreground: #1a1a1a;
|
||||
--chat-user: #e2e2dc;
|
||||
--chat-user: #efefeb;
|
||||
--chat-user-foreground: #1a1a1a;
|
||||
--muted: #f0f0ed;
|
||||
--muted-foreground: #6c6c70;
|
||||
--accent: #eaeae6;
|
||||
--muted: #f4f4f1;
|
||||
--muted-foreground: #67676c;
|
||||
--accent: #ecece8;
|
||||
--accent-foreground: #1a1a1a;
|
||||
--destructive: #dc2626;
|
||||
--destructive-foreground: #ffffff;
|
||||
--border: #f0f0ed;
|
||||
--input: #eaeae6;
|
||||
--ring: #6c6c70;
|
||||
--sidebar: #ecece9;
|
||||
--border: #e5e5e0;
|
||||
--input: #dadad4;
|
||||
--ring: #9c9c97;
|
||||
--sidebar: #f5f5f2;
|
||||
--sidebar-foreground: #1a1a1a;
|
||||
--sidebar-border: #e8e8e4;
|
||||
--sidebar-border: #e8e8e3;
|
||||
--sidebar-accent: #ffffff;
|
||||
--sidebar-accent-foreground: #1a1a1a;
|
||||
--link: #2563eb;
|
||||
--success: #228b3b;
|
||||
--warning: #b7791f;
|
||||
--overlay: rgba(20, 20, 22, 0.45);
|
||||
--scrollbar: #c8c8c4;
|
||||
--scrollbar-hover: #a8a8a4;
|
||||
--success: #1e7f37;
|
||||
--warning: #a16207;
|
||||
--overlay: rgba(24, 24, 22, 0.28);
|
||||
--scrollbar: #d3d3cd;
|
||||
--scrollbar-hover: #b3b3ac;
|
||||
--radius: 0.75rem;
|
||||
--font-size-caption: 0.75rem;
|
||||
--font-size-label: 0.84375rem;
|
||||
|
||||
@ -459,8 +459,8 @@ export function GrokShapePreview({
|
||||
className={cn(
|
||||
"relative flex size-11 items-center justify-center rounded-xl transition-transform hover:scale-105 active:scale-95 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover",
|
||||
selected
|
||||
? "ring-2 ring-primary ring-offset-2 ring-offset-popover bg-white/10"
|
||||
: "hover:bg-white/5",
|
||||
? "ring-2 ring-primary ring-offset-2 ring-offset-popover bg-foreground/10"
|
||||
: "hover:bg-foreground/5",
|
||||
)}
|
||||
>
|
||||
<EvooMascot pose="idle" size={32} trackPointer="none" />
|
||||
|
||||
@ -295,7 +295,7 @@ export const EvooMascot = memo(function EvooMascot({
|
||||
style={{ height: size * 0.86, paddingBottom: size * 0.23 }}
|
||||
>
|
||||
<span
|
||||
className="font-['EvOo_Display',sans-serif] font-bold tracking-tight text-emerald-400 leading-none inline-flex items-baseline select-none"
|
||||
className="font-['EvOo_Display',sans-serif] font-bold tracking-tight text-emerald-500 leading-none dark:text-emerald-400 inline-flex items-baseline select-none"
|
||||
style={{ fontSize: size * 0.65 }}
|
||||
>
|
||||
<span className="tracking-[-0.03em]">e</span>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user