- apps/desktop: electron-vite + React + Tailwind mapped onto design tokens (preflight off; tokens/base.css owns the reset); boots to a Reginald placeholder proving fonts/tokens/core wiring - packages/core: pure TS; gitea label schema (est/*, p/*, deadline/hard) with pessimistic conflict resolution + 15 unit tests - docs/design: full design handoff (tokens, 16 component contracts, interactive 14-screen prototype, Reginald voice rules) - docs/PLAN.md: product plan (purity rule, pm-state repo, deterministic scheduler + Monte Carlo, directive log) - Deliberate deviation from novelpad stack: no ElectricSQL/PGlite — local store is a rebuildable cache over gitea REST/webhooks (better-sqlite3 in main process, arriving in P1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
53 lines
2.6 KiB
Plaintext
53 lines
2.6 KiB
Plaintext
// Morning service — focus screen
|
||
function FocusScreen({ onOpenIssue }) {
|
||
const DS = window.CommiTeaDesignSystem_20e63b;
|
||
const { Card, Tag, Badge, Button, IconButton } = DS;
|
||
const d = window.CT_DATA;
|
||
|
||
const FocusRow = ({ slot, issue, jade }) => (
|
||
<Card overline={slot} jade={jade}
|
||
title={<a href="#" onClick={(e) => { e.preventDefault(); onOpenIssue(issue); }}
|
||
style={{ color: 'inherit', border: 'none' }}>{issue.title}</a>}
|
||
actions={<IconButton icon="ellipsis" label="More" size="sm" />}
|
||
footer={jade ? <>
|
||
<Button size="sm">Start</Button>
|
||
<Button size="sm" variant="ghost">Defer</Button>
|
||
<span style={{ marginLeft: 'auto', font: 'var(--text-caption)', color: 'var(--ink-3)' }}>scheduler pick · critical path</span>
|
||
</> : null}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, flexWrap: 'wrap' }}>
|
||
<span style={{ font: 'var(--text-data)', color: 'var(--ink-3)' }}>#{issue.id}</span>
|
||
{issue.labels.map((l) => <Tag key={l} label={l} />)}
|
||
{issue.steeping ? <Badge tone="warn" dot>steeping {issue.steeping}</Badge> : null}
|
||
</div>
|
||
<p style={{ font: 'var(--text-agent)', color: 'var(--ink-2)', margin: 0 }}>{issue.rationale}</p>
|
||
</Card>
|
||
);
|
||
|
||
return (
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||
<header style={{ borderBottom: 'var(--rule-double)', paddingBottom: 14, display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
|
||
<div>
|
||
<h1 style={{ font: 'var(--text-display)', color: 'var(--ink-1)', margin: 0 }}>Morning service</h1>
|
||
<p style={{ font: 'var(--text-data)', color: 'var(--ink-3)', margin: '6px 0 0', whiteSpace: 'nowrap' }}>{d.today} · reconcile 3.2s</p>
|
||
</div>
|
||
<Badge tone="ok" dot>ahead of forecast</Badge>
|
||
</header>
|
||
|
||
<div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr 1fr', gap: 14, alignItems: 'start' }}>
|
||
<FocusRow slot="Now" issue={d.focus.now} jade />
|
||
<FocusRow slot="Next" issue={d.focus.next} />
|
||
<FocusRow slot="Later" issue={d.focus.later} />
|
||
</div>
|
||
|
||
<Card overline="Milestone · Beta" title={<>80% this lands <span style={{ whiteSpace: 'nowrap' }}>Mar 3–12</span></>}
|
||
actions={<IconButton icon="chart-line" label="Open runway" size="sm" />}>
|
||
<window.BurnUpCone />
|
||
<p style={{ font: 'var(--text-agent)', color: 'var(--ink-2)', margin: '10px 0 0' }}>
|
||
The cone has narrowed since Friday. I'm quietly pleased.
|
||
</p>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
Object.assign(window, { FocusScreen });
|