Scaffold CommiTea: yarn workspaces, Electron shell, core label schema, design system
- 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>
This commit is contained in:
98
docs/design/ui_kits/app/MilestoneScreen.js.txt
Normal file
98
docs/design/ui_kits/app/MilestoneScreen.js.txt
Normal file
@@ -0,0 +1,98 @@
|
||||
// Milestone detail — scope, cone, issues; forecasts stay ranges
|
||||
function MilestoneScreen({ onBack, onOpenIssue }) {
|
||||
const DS = window.CommiTeaDesignSystem_20e63b;
|
||||
const { Card, Tag, Badge, Button, Icon } = DS;
|
||||
const cols = window.CT_DATA.columns;
|
||||
const byState = (ids) => cols.flatMap((c) => c.issues.map((i) => ({ ...i, col: c.label }))).filter((i) => ids.includes(i.id));
|
||||
|
||||
const groups = [
|
||||
{ label: 'Steeping', issues: byState([87, 84]) },
|
||||
{ label: 'In review', issues: byState([92]) },
|
||||
{ label: 'Queued', issues: byState([102, 103, 99, 96, 78]) },
|
||||
{ label: 'Done', issues: byState([71, 69, 65]), muted: true },
|
||||
];
|
||||
|
||||
const Stat = ({ label, value, tone }) => (
|
||||
<div style={{ flex: 1, padding: '12px 18px', borderRight: '1px solid var(--line-1)' }}>
|
||||
<div style={{ font: 'var(--text-overline)', letterSpacing: 'var(--letter-spacing-wide)', textTransform: 'uppercase', color: 'var(--ink-3)', marginBottom: 5 }}>{label}</div>
|
||||
<div style={{ font: `500 14px var(--font-mono)`, color: tone || 'var(--ink-1)', whiteSpace: 'nowrap' }}>{value}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<button type="button" onClick={onBack} style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 6, background: 'none', border: 'none',
|
||||
font: '500 12.5px var(--font-sans)', color: 'var(--ink-2)', cursor: 'pointer', padding: '2px 0', marginBottom: 10,
|
||||
}}>
|
||||
<Icon name="arrow-left" size={14} /> Runway
|
||||
</button>
|
||||
<header style={{ borderBottom: 'var(--rule-double)', paddingBottom: 14, display: 'flex', alignItems: 'flex-start', gap: 16 }}>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<p style={{ font: '400 12px var(--font-mono)', color: 'var(--ink-3)', margin: '0 0 6px', display: 'inline-flex', alignItems: 'center', gap: 6 }}>
|
||||
<Icon name="milestone" size={13} /> milestone · due Mar 15 · soft — scope may flex
|
||||
</p>
|
||||
<h1 style={{ font: 'var(--text-display)', color: 'var(--ink-1)', margin: 0 }}>Beta</h1>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10 }}>
|
||||
<Badge tone="ok" dot>ahead of forecast</Badge>
|
||||
<span style={{ font: '400 12px var(--font-mono)', color: 'var(--ink-2)', whiteSpace: 'nowrap' }}>80% Mar 3–12</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button variant="secondary" icon="arrow-up-right">Open in Gitea</Button>
|
||||
</header>
|
||||
</div>
|
||||
|
||||
{/* stats strip */}
|
||||
<Card flush>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<Stat label="Scope" value="42 issues · est 61d" />
|
||||
<Stat label="Done" value="24 · 57%" />
|
||||
<Stat label="Forecast" value="80% Mar 3–12" />
|
||||
<div style={{ flex: 1, padding: '12px 18px' }}>
|
||||
<div style={{ font: 'var(--text-overline)', letterSpacing: 'var(--letter-spacing-wide)', textTransform: 'uppercase', color: 'var(--ink-3)', marginBottom: 5 }}>Drift · 7d</div>
|
||||
<div style={{ font: '500 14px var(--font-mono)', color: 'var(--ok)', whiteSpace: 'nowrap' }}>−2d · cone narrowed</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 14, alignItems: 'start' }}>
|
||||
<Card overline="Burn-up" title={<>80% this lands <span style={{ whiteSpace: 'nowrap' }}>Mar 3–12</span></>} jade>
|
||||
<window.BurnUpCone />
|
||||
<p style={{ font: 'var(--text-agent)', color: 'var(--ink-2)', margin: '10px 0 0' }}>
|
||||
Comfortably ahead. Beta needs #87 more than it needs my commentary.
|
||||
</p>
|
||||
</Card>
|
||||
|
||||
<Card overline="Issues" flush>
|
||||
<div>
|
||||
{groups.map((g) => (
|
||||
<div key={g.label}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '10px 20px 6px' }}>
|
||||
<span style={{ font: 'var(--text-overline)', letterSpacing: 'var(--letter-spacing-wide)', textTransform: 'uppercase', color: 'var(--ink-3)' }}>{g.label}</span>
|
||||
<span style={{ font: '400 11px var(--font-mono)', color: 'var(--ink-3)' }}>{g.issues.length}</span>
|
||||
</div>
|
||||
{g.issues.map((i) => (
|
||||
<div key={i.id}
|
||||
onClick={() => onOpenIssue({ id: i.id, title: i.title, labels: i.labels, days: i.days })}
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: 8, padding: '7px 20px', cursor: 'pointer',
|
||||
opacity: g.muted ? 0.6 : 1,
|
||||
}}
|
||||
onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--paper-2)'; }}
|
||||
onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
|
||||
>
|
||||
<span style={{ font: '400 11px var(--font-mono)', color: 'var(--ink-3)', width: 34, flexShrink: 0 }}>#{i.id}</span>
|
||||
<span style={{ font: 'var(--text-small)', color: 'var(--ink-1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: 1 }}>{i.title}</span>
|
||||
{(i.labels || []).filter((l) => l.startsWith('est/')).map((l) => <Tag key={l} label={l} />)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Object.assign(window, { MilestoneScreen });
|
||||
Reference in New Issue
Block a user