Files
commitea/docs/design/ui_kits/app/RunwayScreen.js.txt
Christian LeDoux 7a5cacc54c 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>
2026-07-07 20:42:46 -04:00

74 lines
3.8 KiB
Plaintext

// Runway — capacity vs milestone dates; ranges, never points
function RunwayScreen({ onOpenCalibration, onOpenMilestone }) {
const DS = window.CommiTeaDesignSystem_20e63b;
const { Card, Badge, Tag, Icon } = DS;
const d = window.CT_DATA;
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<header style={{ borderBottom: 'var(--rule-double)', paddingBottom: 14 }}>
<h1 style={{ font: 'var(--text-display)', color: 'var(--ink-1)', margin: 0 }}>Runway</h1>
<p style={{ font: 'var(--text-data)', color: 'var(--ink-3)', margin: '6px 0 0' }}>capacity vs milestone dates · calibrated on 27 closed issues</p>
</header>
<Card overline="Milestones" flush>
<div>
{d.runway.map((m, i) => (
<div key={m.name} onClick={onOpenMilestone} style={{
display: 'grid', gridTemplateColumns: '160px 1fr 150px 90px', gap: 16, alignItems: 'center', cursor: 'pointer',
padding: '14px 20px', borderTop: i === 0 ? 'none' : '1px solid var(--line-1)',
}}
onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--paper-2)'; }}
onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}>
<div>
<div style={{ font: 'var(--text-body-strong)', color: 'var(--ink-1)', display: 'flex', alignItems: 'center', gap: 7 }}>
<Icon name="milestone" size={14} style={{ color: 'var(--ink-3)' }} />{m.name}
</div>
<div style={{ font: '400 11.5px var(--font-mono)', color: 'var(--ink-3)', marginTop: 3 }}>
due {m.due}{m.hard ? ' ' : ''}
</div>
{m.hard ? <Tag label="deadline/hard" style={{ marginTop: 5 }} /> : null}
</div>
<window.RunwayBar m={m} />
<span style={{ font: '400 12px var(--font-mono)', color: 'var(--ink-2)' }}>80% {m.p80}</span>
<Badge tone={m.tone} dot>{m.note}</Badge>
</div>
))}
</div>
</Card>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, alignItems: 'start' }}>
<Card overline="Capacity" flush>
<div>
{d.capacity.map((p, i) => (
<div key={p.who} style={{
display: 'flex', alignItems: 'center', gap: 12, padding: '12px 20px',
borderTop: i === 0 ? 'none' : '1px solid var(--line-1)',
}}>
<span style={{
width: 26, height: 26, borderRadius: '50%', background: 'var(--spruce-2)', color: 'var(--accent-text)',
font: '600 10px/26px var(--font-sans)', textAlign: 'center', flexShrink: 0,
}}>{p.who.split(' ').map(w => w[0]).join('')}</span>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ font: 'var(--text-body-strong)' }}>{p.who}</div>
<div style={{ font: '400 11.5px var(--font-mono)', color: 'var(--ink-3)', marginTop: 2 }}>{p.slices}</div>
</div>
<span style={{ font: '400 12px var(--font-mono)', color: 'var(--ink-2)' }}>{p.hours}</span>
</div>
))}
</div>
</Card>
<Card overline="Calibration" actions={<DS.IconButton icon="arrow-up-right" label="Full report" size="sm" onClick={onOpenCalibration} />}>
<p style={{ font: 'var(--text-body)', margin: '0 0 8px' }}>
Your estimates run <strong>18% optimistic</strong> on <code>est/3d</code> and above. Smaller tickets are honest.
</p>
<p style={{ font: 'var(--text-agent)', color: 'var(--ink-2)', margin: 0 }}>
I widen the cone accordingly. No judgement — it's the most common shape of hope.
</p>
</Card>
</div>
</div>
);
}
Object.assign(window, { RunwayScreen });