[aidan] ui/workflows: three-tone surface depth so the window lifts off the canvas in both themes

This commit is contained in:
abccodes
2026-06-23 03:03:47 -07:00
parent fa0b0760eb
commit d7f30f98fd
6 changed files with 23 additions and 15 deletions
@@ -99,7 +99,7 @@ const CalendarView: React.FC<{ nav: AppNav }> = ({ nav }) => {
const selectFromPop = (id: string) => { setDayPop(null); nav.selectWorkflow(id); };
return (
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.paper }}>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.page }}>
<div style={{ flex: 'none', padding: '14px 26px', borderBottom: `1px solid ${WC.line}`, display: 'flex', alignItems: 'center', gap: 14 }}>
<button onClick={() => nav.setRefDate(new Date())} style={{ background: WC.paper, border: `1px solid rgba(${WC.inkRGB},0.14)`, borderRadius: 8, padding: '6px 14px', fontSize: 13, fontWeight: 600, color: WC.ink, cursor: 'pointer' }}>Today</button>
<div style={{ display: 'flex', gap: 4 }}>
@@ -39,7 +39,7 @@ const DetailView: React.FC<{ workflowId: string; nav: AppNav }> = ({ workflowId
if (workflow) dispatch(setWorkflowsRunContext(runContextChip(workflow, r)));
}, [detailRuns, workflowId, dispatch, workflow]);
if (!workflow) return <div style={{ flex: 1, background: WC.paper }} />;
if (!workflow) return <div style={{ flex: 1, background: WC.page }} />;
const running = isRunning(workflow, active);
const enabled = isScheduleActive(workflow.schedule);
@@ -59,7 +59,7 @@ const DetailView: React.FC<{ workflowId: string; nav: AppNav }> = ({ workflowId
return (
<>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.paper }}>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.page }}>
<div style={{ flex: 'none', padding: '20px 28px 16px', borderBottom: `1px solid rgba(${WC.inkRGB},0.06)` }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 13 }}>
<ColorSwatch value={colorForWorkflow(workflow)} onChange={(hex) => patch(workflow, { color: hex })} size={14} />
@@ -87,7 +87,7 @@ const HomeView: React.FC<{ nav: AppNav }> = ({ nav }) => {
const reRunAll = () => { if (missed.length) dispatch(runMissedRuns(missed.map((m) => m.id))); };
return (
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.paper }}>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', background: WC.page }}>
<div style={{ flex: 'none', padding: '22px 30px 14px', borderBottom: `1px solid rgba(${WC.inkRGB},0.06)` }}>
<div style={{ fontFamily: "'JetBrains Mono',monospace", fontSize: 11, letterSpacing: '0.06em', textTransform: 'uppercase', color: WC.muted2 }}>{todayLabel}</div>
</div>
@@ -201,7 +201,7 @@ const WorkflowsAppCard: React.FC<Props> = ({
contain: 'layout style',
willChange: 'transform',
left: dx, top: dy, width: dw, height: dh,
background: WC.paper,
background: WC.page,
border,
borderRadius: WC.radius.lg,
boxShadow: (isDragging || isResizing) ? WC.shadow.lg : WC.shadow.md,
@@ -58,7 +58,7 @@ const WorkflowsAppContent: React.FC = () => {
}), [mode, selectedId, calView, refDate, dashboardId, dispatch]);
return (
<div style={{ flex: 1, display: 'flex', minHeight: 0, fontFamily: FONT_SANS, color: WC.ink, background: WC.paper }}>
<div style={{ flex: 1, display: 'flex', minHeight: 0, fontFamily: FONT_SANS, color: WC.ink, background: WC.page }}>
<LeftRail nav={nav} />
{mode === 'home' && <HomeView nav={nav} />}
{mode === 'calendar' && <CalendarView nav={nav} />}
+17 -9
View File
@@ -10,6 +10,7 @@ import type { ClaudeTokens } from '@/shared/styles/claudeTokens';
export interface WCPalette {
accent: string;
paper: string;
page: string;
panel: string;
rail: string;
inset: string;
@@ -43,7 +44,7 @@ export interface WCPalette {
// The identity half of the palette: accent, text, status, hairlines. The neutral
// surfaces + structural primitives are blended in from claudeTokens by useWC(),
// so the window is the same material as every other card.
type WCColors = Omit<WCPalette, 'shadow' | 'radius' | 'border' | 'paper' | 'panel' | 'rail' | 'inset' | 'raised'>;
type WCColors = Omit<WCPalette, 'shadow' | 'radius' | 'border' | 'paper' | 'page' | 'panel' | 'rail' | 'inset' | 'raised'>;
export const WC_LIGHT: WCColors = {
accent: '#C25A36',
@@ -97,15 +98,22 @@ export function useWC(): WCPalette {
const base = mode === 'dark' ? WC_DARK : WC_LIGHT;
return {
...base,
// Surfaces straight from the app tokens, so the window is the same material
// as every other card in both themes (the warmth lives in accent + text).
// Title bar + sidebar stay on bg.surface (not a darker fill) so the whole
// window reads as one card like the chat card; borders separate the regions.
paper: c.bg.surface,
panel: c.bg.surface,
rail: c.bg.surface,
// Three-tone depth from the app tokens (matches the Claude design): the
// content area sits on `page`, cards/title bar pop on `surface` above it,
// and the sidebar/right rail recede on `secondary`. surface > page in BOTH
// themes, so cards always pop (no light/dark inversion).
// Light's palette inverts (elevated is lighter than surface in light, darker
// in dark), so the mid content tone must flip per mode: in light it steps UP
// to bg.elevated so the window stands apart from the bg.page canvas behind it
// and cards still pop on bg.surface above; in dark bg.page is already darker
// than the cards, so it stays. Rows mirror it (surface in light, elevated in
// dark) so they always sit above the content.
paper: c.bg.surface, // cards, title bar, popovers
page: mode === 'dark' ? c.bg.secondary : c.bg.elevated, // content area: one step above the canvas in both modes
panel: c.bg.surface, // title bar
rail: mode === 'dark' ? c.bg.page : c.bg.secondary, // sidebar / right rail: the recessed darkest column
inset: c.bg.page,
raised: c.bg.elevated,
raised: mode === 'dark' ? c.bg.elevated : c.bg.surface, // extra-raised rows / dropdowns
shadow: c.shadow,
radius: c.radius,
border: c.border,