Author the design language once in the canonical React designbook and project it
one-way onto each stack: React -> designbook/ -> ir/ -> adapters/<stack>/.
Phase 0 — contracts & governance (T01-T03):
- ir/SCHEMA.md + ir/schema/{component,tokens}.schema.json — neutral IR contract
(W3C DTCG tokens; React prop -> HTML attribute mapping; non-portable props flagged).
- adapters/ADAPTER_CONTRACT.md — inputs, drift-report + parity-result shapes,
idempotency rules, CI exit codes (0 ok / 2 usage / 3 drift / 4 parity / 5 internal).
- .claude/rules/designbook-propagation.md + DesignSystemIntroduction.md §5.1 —
one-way directionality + drift-resolution workflow.
T04 — canonical React designbook + the missing pull tool:
- The bundled /design-sync skill only PUSHES repo->cloud; it cannot populate
designbook/. Added scripts/designbook_pull.py + `make designbook-pull`, which drives
the local claude binary headless (acceptEdits) so DesignSync fetch+write runs in a
subprocess (contents never hit the orchestrator's context). Pulled 44 files;
excludes the _whynot-design-seed/ self-copy. Corrected the docs that wrongly called
/design-sync the pull.
T05 — IR extractor (scripts/ir-extract.mjs + `make ir`):
- ir/tokens.json (80 tokens, DTCG, var() -> {ref} alias resolution); ir/components/*.json
(10 contracts parsed from .jsx signatures: enum/boolean/number inference, prop->attr
map, style/callback marked non-portable); ir/exemplars/*.
T06 — Lit token adapter (adapters/lit/ + `make adapt-lit`):
- Full-gen tokens into src/styles/colors_and_type.css :root (marker-bounded, idempotent
no-op on re-run; hand-authored type CSS preserved).
NOTE: token regen synced Lit to canonical React — fonts IBM Plex -> system stacks and 8
status tokens added. This is a VISUAL change: review and run `pnpm test:visual:update`
before merge. Remaining: T07 scaffold+drift, T08 parity, T09 runbook, T10 2nd-adapter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1397 lines
41 KiB
JavaScript
1397 lines
41 KiB
JavaScript
/* @ds-bundle: {"format":3,"namespace":"WhyNotDesignSystem_fb2eef","components":[],"sourceHashes":{"ui_kits/whynot-control/Atoms.jsx":"79a33f57ef80","ui_kits/whynot-control/Chrome.jsx":"31e0ba69d22d","ui_kits/whynot-control/DocView.jsx":"636cbc6e3422","ui_kits/whynot-control/Screens.jsx":"c21f0206c6c7","ui_kits/whynot-control/data.jsx":"16b3caf0bced"},"inlinedExternals":[],"unexposedExports":[]} */
|
||
|
||
(() => {
|
||
|
||
const __ds_ns = (window.WhyNotDesignSystem_fb2eef = window.WhyNotDesignSystem_fb2eef || {});
|
||
|
||
const __ds_scope = {};
|
||
|
||
(__ds_ns.__errors = __ds_ns.__errors || []);
|
||
|
||
// ui_kits/whynot-control/Atoms.jsx
|
||
try { (() => {
|
||
// =============================================================
|
||
// Atoms — Eyebrow, Tag, Button, StageDot, Stamp, IconBtn
|
||
// =============================================================
|
||
|
||
function Eyebrow({
|
||
children,
|
||
style
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 11px/1.2 var(--ff-mono)',
|
||
letterSpacing: '0.08em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)',
|
||
...style
|
||
}
|
||
}, children);
|
||
}
|
||
function Tag({
|
||
children,
|
||
active,
|
||
draft,
|
||
style
|
||
}) {
|
||
const base = {
|
||
font: '500 10px/1 var(--ff-mono)',
|
||
letterSpacing: '0.1em',
|
||
textTransform: 'uppercase',
|
||
padding: '5px 10px',
|
||
borderRadius: 'var(--r-pill)',
|
||
border: '1px solid var(--border)',
|
||
color: 'var(--fg-2)',
|
||
background: 'var(--paper)',
|
||
display: 'inline-block'
|
||
};
|
||
if (active) Object.assign(base, {
|
||
background: 'var(--ink)',
|
||
color: 'var(--paper)',
|
||
borderColor: 'var(--ink)'
|
||
});
|
||
if (draft) Object.assign(base, {
|
||
background: 'var(--hi)',
|
||
color: 'var(--hi-ink)',
|
||
borderColor: 'transparent'
|
||
});
|
||
return /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
...base,
|
||
...style
|
||
}
|
||
}, children);
|
||
}
|
||
function Button({
|
||
children,
|
||
variant = 'secondary',
|
||
onClick,
|
||
style,
|
||
icon
|
||
}) {
|
||
const base = {
|
||
font: '500 13px var(--ff-sans)',
|
||
letterSpacing: '-0.005em',
|
||
padding: '9px 14px',
|
||
borderRadius: 'var(--r-2)',
|
||
border: '1px solid var(--border)',
|
||
background: 'var(--paper)',
|
||
color: 'var(--ink)',
|
||
cursor: 'pointer',
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
gap: 8,
|
||
whiteSpace: 'nowrap',
|
||
transition: 'background 120ms ease, border-color 120ms ease'
|
||
};
|
||
if (variant === 'primary') Object.assign(base, {
|
||
background: 'var(--ink)',
|
||
color: 'var(--paper)',
|
||
borderColor: 'var(--ink)'
|
||
});
|
||
if (variant === 'ghost') Object.assign(base, {
|
||
background: 'transparent',
|
||
borderColor: 'transparent',
|
||
padding: '7px 10px'
|
||
});
|
||
return /*#__PURE__*/React.createElement("button", {
|
||
onClick: onClick,
|
||
style: {
|
||
...base,
|
||
...style
|
||
}
|
||
}, icon && /*#__PURE__*/React.createElement("i", {
|
||
"data-lucide": icon,
|
||
style: {
|
||
width: 14,
|
||
height: 14,
|
||
strokeWidth: 1.5
|
||
}
|
||
}), children);
|
||
}
|
||
const STAGE_COLORS = {
|
||
S0: '#B5B5B3',
|
||
S1: '#8A8A8A',
|
||
S2: '#5C5C5C',
|
||
S3: '#0A0A0A',
|
||
S4: '#FFD400'
|
||
};
|
||
function StageDot({
|
||
level = 'S2',
|
||
label,
|
||
style
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 10px/1 var(--ff-mono)',
|
||
letterSpacing: '0.1em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-2)',
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
gap: 6,
|
||
...style
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
width: 8,
|
||
height: 8,
|
||
borderRadius: 999,
|
||
background: STAGE_COLORS[level]
|
||
}
|
||
}), label || level);
|
||
}
|
||
function Stamp({
|
||
children,
|
||
style
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
display: 'inline-block',
|
||
background: 'var(--hi)',
|
||
color: 'var(--hi-ink)',
|
||
padding: '5px 10px 3px',
|
||
font: '500 10px/1 var(--ff-mono)',
|
||
letterSpacing: '0.12em',
|
||
textTransform: 'uppercase',
|
||
transform: 'rotate(-1.5deg)',
|
||
...style
|
||
}
|
||
}, children);
|
||
}
|
||
function Icon({
|
||
name,
|
||
size = 16,
|
||
style
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("i", {
|
||
"data-lucide": name,
|
||
style: {
|
||
width: size,
|
||
height: size,
|
||
strokeWidth: 1.5,
|
||
...style
|
||
}
|
||
});
|
||
}
|
||
Object.assign(window, {
|
||
Eyebrow,
|
||
Tag,
|
||
Button,
|
||
StageDot,
|
||
Stamp,
|
||
Icon,
|
||
STAGE_COLORS
|
||
});
|
||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/whynot-control/Atoms.jsx", error: String((e && e.message) || e) }); }
|
||
|
||
// ui_kits/whynot-control/Chrome.jsx
|
||
try { (() => {
|
||
// =============================================================
|
||
// Chrome — TopNav, Sidebar, PageHeader, PipelineStrip
|
||
// =============================================================
|
||
|
||
function TopNav({
|
||
onNew
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("nav", {
|
||
style: {
|
||
height: 56,
|
||
background: 'rgba(255,255,255,0.92)',
|
||
borderBottom: '1px solid var(--border)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 28,
|
||
padding: '0 24px',
|
||
position: 'sticky',
|
||
top: 0,
|
||
zIndex: 10
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 10
|
||
}
|
||
}, /*#__PURE__*/React.createElement("img", {
|
||
src: "../../assets/whynot-logo.png",
|
||
alt: "",
|
||
style: {
|
||
width: 22,
|
||
height: 22
|
||
}
|
||
}), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 14px var(--ff-sans)'
|
||
}
|
||
}, "whynot"), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 12px var(--ff-mono)',
|
||
color: 'var(--fg-3)',
|
||
letterSpacing: '0.04em'
|
||
}
|
||
}, "/ control")), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
marginLeft: 'auto',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 12
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
font: '400 12px var(--ff-mono)',
|
||
color: 'var(--fg-3)',
|
||
border: '1px solid var(--border)',
|
||
padding: '6px 10px',
|
||
borderRadius: 'var(--r-1)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 10,
|
||
minWidth: 240
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Icon, {
|
||
name: "search",
|
||
size: 14
|
||
}), /*#__PURE__*/React.createElement("span", null, "Search ideas, prototypes, signals…"), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
marginLeft: 'auto',
|
||
padding: '1px 5px',
|
||
border: '1px solid var(--border)',
|
||
borderRadius: 2,
|
||
fontSize: 10
|
||
}
|
||
}, "⌘ K")), /*#__PURE__*/React.createElement(Button, {
|
||
variant: "primary",
|
||
icon: "plus",
|
||
onClick: onNew
|
||
}, "New idea")));
|
||
}
|
||
const NAV_ITEMS = [{
|
||
key: 'inbox',
|
||
label: 'Inbox',
|
||
icon: 'inbox',
|
||
count: 7
|
||
}, {
|
||
key: 'prototypes',
|
||
label: 'Prototypes',
|
||
icon: 'flask-conical',
|
||
count: 4
|
||
}, {
|
||
key: 'signals',
|
||
label: 'Signals',
|
||
icon: 'activity',
|
||
count: 12
|
||
}, {
|
||
key: 'betas',
|
||
label: 'Betas',
|
||
icon: 'users',
|
||
count: 1
|
||
}, {
|
||
key: 'decisions',
|
||
label: 'Decisions',
|
||
icon: 'check-square',
|
||
count: 3
|
||
}];
|
||
const DOC_ITEMS = [{
|
||
key: 'intent',
|
||
label: 'INTENT.md'
|
||
}, {
|
||
key: 'scope',
|
||
label: 'SCOPE.md'
|
||
}, {
|
||
key: 'operating',
|
||
label: 'OPERATING_MODEL.md'
|
||
}, {
|
||
key: 'pipeline',
|
||
label: 'PROTOTYPE_PIPELINE.md'
|
||
}, {
|
||
key: 'agent',
|
||
label: 'AGENT_RULES.md'
|
||
}];
|
||
function Sidebar({
|
||
current,
|
||
onNav
|
||
}) {
|
||
const itemStyle = active => ({
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 10,
|
||
padding: '6px 10px',
|
||
color: active ? 'var(--fg-1)' : 'var(--fg-3)',
|
||
background: 'transparent',
|
||
borderLeft: active ? '2px solid var(--ink)' : '2px solid transparent',
|
||
paddingLeft: active ? 10 : 12,
|
||
font: active ? '500 13px var(--ff-sans)' : '400 13px var(--ff-sans)',
|
||
cursor: 'pointer',
|
||
textDecoration: 'none',
|
||
transition: 'color 120ms ease, border-color 120ms ease'
|
||
});
|
||
return /*#__PURE__*/React.createElement("aside", {
|
||
style: {
|
||
width: 200,
|
||
flex: 'none',
|
||
background: 'transparent',
|
||
borderRight: 'none',
|
||
padding: '32px 0 32px 8px',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 32,
|
||
height: 'calc(100vh - 56px)',
|
||
position: 'sticky',
|
||
top: 56,
|
||
overflowY: 'auto'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Eyebrow, {
|
||
style: {
|
||
paddingLeft: 12,
|
||
marginBottom: 10,
|
||
display: 'block',
|
||
opacity: 0.7
|
||
}
|
||
}, "Work"), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 1
|
||
}
|
||
}, NAV_ITEMS.map(item => /*#__PURE__*/React.createElement("a", {
|
||
key: item.key,
|
||
onClick: () => onNav(item.key),
|
||
style: itemStyle(current === item.key)
|
||
}, /*#__PURE__*/React.createElement("span", null, item.label), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
marginLeft: 'auto',
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--ink-5)'
|
||
}
|
||
}, item.count))))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Eyebrow, {
|
||
style: {
|
||
paddingLeft: 12,
|
||
marginBottom: 10,
|
||
display: 'block',
|
||
opacity: 0.7
|
||
}
|
||
}, "Control docs"), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 1
|
||
}
|
||
}, DOC_ITEMS.map(item => /*#__PURE__*/React.createElement("a", {
|
||
key: item.key,
|
||
onClick: () => onNav('doc:' + item.key),
|
||
style: {
|
||
...itemStyle(current === 'doc:' + item.key),
|
||
font: current === 'doc:' + item.key ? '500 12px var(--ff-mono)' : '400 12px var(--ff-mono)'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", null, item.label))))), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
marginTop: 'auto',
|
||
padding: '0 12px'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 8
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
width: 5,
|
||
height: 5,
|
||
borderRadius: 999,
|
||
background: 'var(--ink-4)'
|
||
}
|
||
}), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 11px var(--ff-mono)',
|
||
letterSpacing: '0.06em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, "A1 \xB7 Incubating"))));
|
||
}
|
||
function PageHeader({
|
||
eyebrow,
|
||
title,
|
||
lede,
|
||
actions
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("header", {
|
||
style: {
|
||
marginBottom: 48,
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 10
|
||
}
|
||
}, eyebrow && /*#__PURE__*/React.createElement(Eyebrow, null, eyebrow), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
alignItems: 'flex-end',
|
||
gap: 24
|
||
}
|
||
}, /*#__PURE__*/React.createElement("h1", {
|
||
style: {
|
||
font: '400 36px/1.1 var(--ff-sans)',
|
||
letterSpacing: '-0.02em',
|
||
margin: 0,
|
||
flex: 1
|
||
}
|
||
}, title), actions && /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
gap: 8
|
||
}
|
||
}, actions)), lede && /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
font: '400 16px/1.6 var(--ff-sans)',
|
||
color: 'var(--fg-2)',
|
||
margin: '4px 0 0',
|
||
maxWidth: '56ch'
|
||
}
|
||
}, lede));
|
||
}
|
||
function PipelineStrip({
|
||
activeIdx = 3
|
||
}) {
|
||
const stages = [{
|
||
num: 'Stage 0',
|
||
name: 'Raw idea',
|
||
meta: 'inbox/'
|
||
}, {
|
||
num: 'Stage 1',
|
||
name: 'Triage',
|
||
meta: '2026-02-12'
|
||
}, {
|
||
num: 'Stage 2',
|
||
name: 'Prototype card',
|
||
meta: 'prototypes/'
|
||
}, {
|
||
num: 'Stage 3',
|
||
name: 'Experiment',
|
||
meta: 'ends 2026-04-01'
|
||
}, {
|
||
num: 'Stage 4',
|
||
name: 'Signal review',
|
||
meta: '— pending'
|
||
}];
|
||
return /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: 'repeat(5, 1fr)',
|
||
gap: 0,
|
||
position: 'relative',
|
||
margin: '0 0 32px'
|
||
}
|
||
}, stages.map((s, i) => {
|
||
const state = i < activeIdx ? 'done' : i === activeIdx ? 'active' : 'pending';
|
||
const topColor = state === 'done' ? 'var(--ink)' : state === 'active' ? 'var(--hi-2)' : 'var(--border)';
|
||
return /*#__PURE__*/React.createElement("div", {
|
||
key: i,
|
||
style: {
|
||
padding: '10px 12px 14px',
|
||
borderTop: `2px solid ${topColor}`,
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 4,
|
||
position: 'relative'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 10px/1 var(--ff-mono)',
|
||
letterSpacing: '0.1em',
|
||
textTransform: 'uppercase',
|
||
color: state === 'pending' ? 'var(--fg-3)' : 'var(--fg-1)'
|
||
}
|
||
}, s.num), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 14px/1.25 var(--ff-sans)',
|
||
color: state === 'pending' ? 'var(--fg-3)' : 'var(--fg-1)'
|
||
}
|
||
}, s.name), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 11px/1.35 var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, s.meta), i > 0 && /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
position: 'absolute',
|
||
top: -8,
|
||
right: -7,
|
||
font: '400 14px var(--ff-mono)',
|
||
color: state === 'pending' ? 'var(--ink-5)' : 'var(--ink)'
|
||
}
|
||
}, "→"));
|
||
}));
|
||
}
|
||
Object.assign(window, {
|
||
TopNav,
|
||
Sidebar,
|
||
PageHeader,
|
||
PipelineStrip,
|
||
NAV_ITEMS,
|
||
DOC_ITEMS
|
||
});
|
||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/whynot-control/Chrome.jsx", error: String((e && e.message) || e) }); }
|
||
|
||
// ui_kits/whynot-control/DocView.jsx
|
||
try { (() => {
|
||
// =============================================================
|
||
// Document viewer — renders one of the control docs
|
||
// =============================================================
|
||
|
||
const DOC_CONTENT = {
|
||
intent: {
|
||
title: 'INTENT.md',
|
||
eyebrow: 'whynot-control · control document',
|
||
sections: [{
|
||
h: 'Purpose',
|
||
p: 'whynot-control exists to serve as the control repository for the whynot organisation: a prototype, feedback, and market-signal space for discovering the weird and the useful.'
|
||
}, {
|
||
h: 'Primary utility',
|
||
list: ['capture unusual but potentially useful ideas;', 'distinguish curiosity from commitment;', 'shape rough ideas into testable prototypes;', 'collect early feedback and market signals;', 'run closed beta concepts in a controlled way;', 'identify which ideas should move toward Helix, Coulomb, Sloppers, Plenitude, Binky, or Tegwick;', 'prevent premature productisation.']
|
||
}, {
|
||
h: 'Operating principle',
|
||
quote: 'A prototype is a question made tangible. The purpose of a prototype is not to prove that an idea is brilliant. The purpose is to learn what is actually useful, desirable, feasible, or irrelevant.'
|
||
}]
|
||
},
|
||
scope: {
|
||
title: 'SCOPE.md',
|
||
eyebrow: 'whynot-control · control document',
|
||
sections: [{
|
||
h: 'Current reality',
|
||
p: 'whynot-control is the control repository for organising prototype exploration and early market-signal capture.'
|
||
}, {
|
||
h: 'In scope',
|
||
list: ['Prototype idea capture.', 'Prototype classification.', 'Early user feedback notes.', 'Market-signal tracking.', 'Closed beta planning.', 'Experiment records.', 'Promotion recommendations.', 'Agent-assisted drafting and analysis.']
|
||
}, {
|
||
h: 'Out of scope',
|
||
list: ['Production implementation.', 'Long-term product maintenance.', 'Payment processing.', 'Legal investment documentation.', 'Public launch operations.', 'Binding financial, legal, or tax conclusions.']
|
||
}, {
|
||
h: 'Scope guardrail',
|
||
quote: 'whynot-control explores and validates. It does not absorb all product development.'
|
||
}]
|
||
},
|
||
operating: {
|
||
title: 'OPERATING_MODEL.md',
|
||
eyebrow: 'whynot-control · control document',
|
||
sections: [{
|
||
h: 'Core rules',
|
||
list: ['Prototypes are questions. Each prototype should express a question about usefulness, desirability, feasibility, or willingness to pay.', 'Signal beats enthusiasm. An idea should not be promoted only because it is exciting.', 'Low-cost learning first. Prefer sketches, mockups, demos, landing pages, conversations.', 'Closed beta before broad launch.', 'Promotion requires criteria.']
|
||
}, {
|
||
h: 'Burnout guardrail',
|
||
quote: 'A prototype can be interesting and still be parked. whynot exists to reduce uncertainty, not to create more obligations.'
|
||
}]
|
||
},
|
||
pipeline: {
|
||
title: 'PROTOTYPE_PIPELINE.md',
|
||
eyebrow: 'whynot-control · control document',
|
||
sections: [{
|
||
h: 'Stage 0 — Raw capture',
|
||
p: 'Capture ideas without judging them immediately. Located in inbox/. Done when the idea is saved and no longer needs to be held in memory.'
|
||
}, {
|
||
h: 'Stage 1 — Triage',
|
||
p: 'Decide whether an idea deserves a prototype card. Outcomes: create card, park, merge, reject.'
|
||
}, {
|
||
h: 'Stage 2 — Prototype card',
|
||
p: 'Turn the idea into a structured prototype candidate. Located in prototypes/.'
|
||
}, {
|
||
h: 'Stage 3 — Experiment',
|
||
p: 'Test the idea with minimal cost: concept note, landing page, clickable mockup, CLI/demo script, Wizard-of-Oz, manual concierge test, closed conversation, private beta.'
|
||
}, {
|
||
h: 'Stage 4 — Signal review',
|
||
p: 'Evaluate what was learned. Interest, usefulness, retention, referral, payment, contribution, strategic fit.'
|
||
}, {
|
||
h: 'Stage 5 — Decision',
|
||
p: 'Park, iterate, promote, reject, or merge. Promotion requires an explicit record in DECISIONS.md.'
|
||
}]
|
||
},
|
||
agent: {
|
||
title: 'AGENT_RULES.md',
|
||
eyebrow: 'whynot-control · control document',
|
||
sections: [{
|
||
h: 'General principle',
|
||
p: 'Agents may help clarify, structure, draft, compare, and analyse prototype ideas. They must not silently turn experiments into product commitments.'
|
||
}, {
|
||
h: 'Allowed',
|
||
list: ['draft prototype cards', 'classify ideas by lifecycle stage', 'propose smallest useful tests', 'summarise feedback', 'compare prototype candidates', 'improve wording and structure']
|
||
}, {
|
||
h: 'Forbidden',
|
||
list: ['create artificial urgency', 'treat all prototype ideas as products', 'infer willingness to pay without evidence', 'present weak signals as strong validation', 'create legal, financial, or investment commitments']
|
||
}, {
|
||
h: 'Preferred output style',
|
||
quote: 'Agent outputs should be concise, evidence-oriented, explicit about uncertainty, and careful to separate idea, hypothesis, signal, and decision.'
|
||
}]
|
||
}
|
||
};
|
||
function DocView({
|
||
docKey
|
||
}) {
|
||
const doc = DOC_CONTENT[docKey];
|
||
if (!doc) return /*#__PURE__*/React.createElement("div", null, "Doc not found.");
|
||
return /*#__PURE__*/React.createElement("article", {
|
||
style: {
|
||
maxWidth: 680
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, null, doc.eyebrow), /*#__PURE__*/React.createElement("h1", {
|
||
style: {
|
||
font: '600 36px/1.1 var(--ff-mono)',
|
||
letterSpacing: '-0.01em',
|
||
margin: '12px 0 28px'
|
||
}
|
||
}, doc.title), doc.sections.map((s, i) => /*#__PURE__*/React.createElement("section", {
|
||
key: i,
|
||
style: {
|
||
marginBottom: 36
|
||
}
|
||
}, /*#__PURE__*/React.createElement("h2", {
|
||
style: {
|
||
font: '500 22px/1.25 var(--ff-sans)',
|
||
letterSpacing: '-0.005em',
|
||
margin: '0 0 14px'
|
||
}
|
||
}, s.h), s.p && /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
margin: 0,
|
||
font: '400 15px/1.65 var(--ff-sans)',
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}, s.p), s.list && /*#__PURE__*/React.createElement("ul", {
|
||
style: {
|
||
margin: 0,
|
||
paddingLeft: 18,
|
||
color: 'var(--fg-1)',
|
||
font: '400 15px/1.7 var(--ff-sans)'
|
||
}
|
||
}, s.list.map((li, j) => /*#__PURE__*/React.createElement("li", {
|
||
key: j,
|
||
style: {
|
||
marginBottom: 6
|
||
}
|
||
}, li))), s.quote && /*#__PURE__*/React.createElement("blockquote", {
|
||
style: {
|
||
margin: 0,
|
||
paddingLeft: 16,
|
||
borderLeft: '1px solid var(--border-strong)'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
margin: 0,
|
||
font: '400 italic 17px/1.55 var(--ff-serif)',
|
||
color: 'var(--fg-2)'
|
||
}
|
||
}, s.quote)))), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
marginTop: 48,
|
||
padding: '14px 0',
|
||
borderTop: '1px solid var(--border)',
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", null, "whynot-control / ", doc.title), /*#__PURE__*/React.createElement("span", null, "A1 \xB7 Incubating \xB7 2026")));
|
||
}
|
||
Object.assign(window, {
|
||
DocView,
|
||
DOC_CONTENT
|
||
});
|
||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/whynot-control/DocView.jsx", error: String((e && e.message) || e) }); }
|
||
|
||
// ui_kits/whynot-control/Screens.jsx
|
||
try { (() => {
|
||
// =============================================================
|
||
// Screens — Inbox, PrototypesIndex, PrototypeDetail, SignalsIndex, DocView, BetasIndex, DecisionsIndex
|
||
// =============================================================
|
||
|
||
function Inbox({
|
||
onCapture
|
||
}) {
|
||
const [draft, setDraft] = React.useState('');
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: "whynot-control / inbox",
|
||
title: "Inbox",
|
||
lede: "Temporary capture for rough ideas, weird observations, user comments, market hints, and product fragments. Capture is not commitment."
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
border: '1px solid var(--border)',
|
||
borderRadius: 'var(--r-2)',
|
||
padding: 16,
|
||
background: 'var(--paper)',
|
||
marginBottom: 28,
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 10
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "Capture"), /*#__PURE__*/React.createElement("textarea", {
|
||
value: draft,
|
||
onChange: e => setDraft(e.target.value),
|
||
placeholder: "An idea, an observation, a fragment. No filter, no judgement, no commitment.",
|
||
style: {
|
||
font: '400 14px/1.5 var(--ff-sans)',
|
||
border: 'none',
|
||
outline: 'none',
|
||
resize: 'none',
|
||
minHeight: 64,
|
||
padding: 0,
|
||
background: 'transparent',
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 8
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)',
|
||
marginRight: 'auto'
|
||
}
|
||
}, "⌘ ↵ to capture \xB7 stored in ", /*#__PURE__*/React.createElement("code", {
|
||
className: "mono"
|
||
}, "inbox/")), /*#__PURE__*/React.createElement(Button, {
|
||
variant: "ghost",
|
||
onClick: () => setDraft('')
|
||
}, "Discard"), /*#__PURE__*/React.createElement(Button, {
|
||
variant: "primary",
|
||
icon: "inbox",
|
||
onClick: () => {
|
||
onCapture && onCapture(draft);
|
||
setDraft('');
|
||
}
|
||
}, "Capture"))), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 12,
|
||
marginBottom: 14
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "Recent \xB7 7"), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
flex: 1,
|
||
borderTop: '1px solid var(--border-soft)'
|
||
}
|
||
}), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, "↓ newest first")), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column'
|
||
}
|
||
}, INBOX.map(item => /*#__PURE__*/React.createElement("div", {
|
||
key: item.id,
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: '120px 1fr',
|
||
gap: '4px 24px',
|
||
padding: '20px 0',
|
||
borderBottom: '1px solid var(--border-soft)',
|
||
alignItems: 'baseline'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, item.ts), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 10px/1 var(--ff-mono)',
|
||
letterSpacing: '0.08em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, item.from), /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
gridColumn: '1 / -1',
|
||
margin: '4px 0 0',
|
||
font: '400 15px/1.6 var(--ff-sans)',
|
||
color: 'var(--fg-1)',
|
||
maxWidth: '60ch'
|
||
}
|
||
}, item.text)))));
|
||
}
|
||
function PrototypeListCard({
|
||
p,
|
||
onOpen
|
||
}) {
|
||
const [hover, setHover] = React.useState(false);
|
||
return /*#__PURE__*/React.createElement("article", {
|
||
onClick: () => onOpen(p.id),
|
||
onMouseEnter: () => setHover(true),
|
||
onMouseLeave: () => setHover(false),
|
||
style: {
|
||
background: 'var(--paper)',
|
||
borderTop: '1px solid var(--border-soft)',
|
||
padding: '24px 0 28px',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 12,
|
||
position: 'relative',
|
||
cursor: 'pointer',
|
||
transition: 'background 120ms ease'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'baseline'
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, {
|
||
style: {
|
||
color: hover ? 'var(--fg-1)' : 'var(--fg-3)'
|
||
}
|
||
}, p.id, " \xB7 Prototype"), /*#__PURE__*/React.createElement(StageDot, {
|
||
level: p.signal,
|
||
label: p.stageLabel
|
||
})), /*#__PURE__*/React.createElement("h3", {
|
||
style: {
|
||
font: '400 22px/1.3 var(--ff-sans)',
|
||
letterSpacing: '-0.01em',
|
||
margin: '2px 0 8px',
|
||
color: 'var(--fg-1)',
|
||
maxWidth: '52ch'
|
||
}
|
||
}, p.pitch), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: '140px 1fr',
|
||
gap: '10px 16px',
|
||
fontSize: 14,
|
||
color: 'var(--fg-2)',
|
||
maxWidth: '60ch'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 11px/1.7 var(--ff-mono)',
|
||
letterSpacing: '0.06em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, "Learning q."), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
lineHeight: 1.55
|
||
}
|
||
}, p.learning), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 11px/1.7 var(--ff-mono)',
|
||
letterSpacing: '0.06em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, "Smallest test"), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
lineHeight: 1.55
|
||
}
|
||
}, p.test)), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
gap: 24,
|
||
marginTop: 4,
|
||
font: '500 11px var(--ff-mono)',
|
||
letterSpacing: '0.06em',
|
||
textTransform: 'uppercase',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", null, "→ ", p.target), /*#__PURE__*/React.createElement("span", null, p.signal, " signal"), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
marginLeft: 'auto',
|
||
color: hover ? 'var(--fg-1)' : 'var(--fg-3)'
|
||
}
|
||
}, "Open →")));
|
||
}
|
||
function PrototypesIndex({
|
||
onOpen
|
||
}) {
|
||
const [filter, setFilter] = React.useState('All');
|
||
const filters = ['All', 'Experiment', 'Signal review', 'Parked'];
|
||
const list = filter === 'All' ? PROTOTYPES : PROTOTYPES.filter(p => p.stageLabel === filter);
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: "whynot-control / prototypes",
|
||
title: "Prototypes",
|
||
lede: "Structured prototype cards. A prototype card defines a learning question and the smallest useful test.",
|
||
actions: /*#__PURE__*/React.createElement(Button, {
|
||
variant: "primary",
|
||
icon: "plus"
|
||
}, "New prototype")
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
gap: 10,
|
||
marginBottom: 8,
|
||
alignItems: 'center'
|
||
}
|
||
}, filters.map(f => /*#__PURE__*/React.createElement(Tag, {
|
||
key: f,
|
||
active: filter === f,
|
||
style: {
|
||
cursor: 'pointer'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("span", {
|
||
onClick: () => setFilter(f)
|
||
}, f))), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
marginLeft: 'auto',
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, list.length, " of ", PROTOTYPES.length)), /*#__PURE__*/React.createElement("div", null, list.map(p => /*#__PURE__*/React.createElement(PrototypeListCard, {
|
||
key: p.id,
|
||
p: p,
|
||
onOpen: onOpen
|
||
}))));
|
||
}
|
||
function PrototypeDetail({
|
||
id,
|
||
onBack
|
||
}) {
|
||
const p = PROTOTYPES.find(p => p.id === id) || PROTOTYPES[0];
|
||
const stageIdx = {
|
||
'parked': 0,
|
||
'experiment': 3,
|
||
'signal': 4,
|
||
'experiment-active': 3
|
||
}[p.stage] ?? 3;
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("a", {
|
||
onClick: onBack,
|
||
style: {
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
gap: 6,
|
||
font: '400 12px var(--ff-mono)',
|
||
color: 'var(--fg-2)',
|
||
textDecoration: 'none',
|
||
marginBottom: 18,
|
||
cursor: 'pointer'
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Icon, {
|
||
name: "arrow-left",
|
||
size: 14
|
||
}), " Back to prototypes"), /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: `${p.id} · Prototype`,
|
||
title: p.pitch,
|
||
actions: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
||
variant: "secondary",
|
||
icon: "archive"
|
||
}, "Park"), /*#__PURE__*/React.createElement(Button, {
|
||
variant: "primary",
|
||
icon: "arrow-right"
|
||
}, "Promote → ", p.target))
|
||
}), /*#__PURE__*/React.createElement(PipelineStrip, {
|
||
activeIdx: stageIdx
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: '1.4fr 1fr',
|
||
gap: 32
|
||
}
|
||
}, /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 22
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Field, {
|
||
label: "Learning question",
|
||
value: p.learning
|
||
}), /*#__PURE__*/React.createElement(Field, {
|
||
label: "Smallest useful test",
|
||
value: p.test
|
||
}), /*#__PURE__*/React.createElement(Field, {
|
||
label: "Expected signal",
|
||
value: "At least one person asks for a concrete next step, gives specific use-case feedback, or identifies a realistic context where the idea would matter."
|
||
}), /*#__PURE__*/React.createElement(Field, {
|
||
label: "Risks",
|
||
value: p.risks
|
||
})), /*#__PURE__*/React.createElement("aside", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 18
|
||
}
|
||
}, /*#__PURE__*/React.createElement(SidebarField, {
|
||
label: "Stage",
|
||
value: /*#__PURE__*/React.createElement(Tag, {
|
||
active: true
|
||
}, p.stageLabel)
|
||
}), /*#__PURE__*/React.createElement(SidebarField, {
|
||
label: "Signal",
|
||
value: /*#__PURE__*/React.createElement(StageDot, {
|
||
level: p.signal
|
||
})
|
||
}), /*#__PURE__*/React.createElement(SidebarField, {
|
||
label: "Target",
|
||
value: /*#__PURE__*/React.createElement("code", {
|
||
className: "mono"
|
||
}, "→ ", p.target)
|
||
}), /*#__PURE__*/React.createElement(SidebarField, {
|
||
label: "Audience",
|
||
value: "Potential early users, collaborators, or customers."
|
||
}), /*#__PURE__*/React.createElement(SidebarField, {
|
||
label: "Agentic suitability",
|
||
value: "Agents may help turn rough notes into a sharper prototype card."
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
marginTop: 6,
|
||
border: '1px dashed var(--border-strong)',
|
||
borderRadius: 4,
|
||
padding: 14
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, {
|
||
style: {
|
||
display: 'block',
|
||
marginBottom: 8
|
||
}
|
||
}, "Caveat"), /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
margin: 0,
|
||
font: '400 13px/1.55 var(--ff-sans)',
|
||
color: 'var(--fg-2)'
|
||
}
|
||
}, "A prototype can be interesting and still be parked. ", /*#__PURE__*/React.createElement("code", {
|
||
className: "mono"
|
||
}, "whynot"), " exists to reduce uncertainty, not create more obligations.")))));
|
||
}
|
||
function Field({
|
||
label,
|
||
value
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 6
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, null, label), /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
margin: 0,
|
||
font: '400 15px/1.55 var(--ff-sans)',
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}, value));
|
||
}
|
||
function SidebarField({
|
||
label,
|
||
value
|
||
}) {
|
||
return /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 6
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Eyebrow, null, label), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
font: '400 13px/1.5 var(--ff-sans)',
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}, value));
|
||
}
|
||
function SignalsIndex() {
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: "whynot-control / signals",
|
||
title: "Signals",
|
||
lede: "Market-signal and feedback records. A signal is evidence. Record what happened, who did it, and how strong the evidence is.",
|
||
actions: /*#__PURE__*/React.createElement(Button, {
|
||
variant: "primary",
|
||
icon: "plus"
|
||
}, "Record signal")
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column'
|
||
}
|
||
}, SIGNALS.map(s => /*#__PURE__*/React.createElement("div", {
|
||
key: s.id,
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: '90px 90px 1fr',
|
||
gap: '6px 24px',
|
||
padding: '20px 0',
|
||
borderBottom: '1px solid var(--border-soft)',
|
||
alignItems: 'baseline'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("code", {
|
||
className: "mono",
|
||
style: {
|
||
background: 'none',
|
||
padding: 0,
|
||
color: 'var(--fg-3)',
|
||
font: '400 11px var(--ff-mono)'
|
||
}
|
||
}, s.id), /*#__PURE__*/React.createElement("code", {
|
||
className: "mono",
|
||
style: {
|
||
background: 'none',
|
||
padding: 0,
|
||
color: 'var(--fg-2)',
|
||
font: '400 11px var(--ff-mono)'
|
||
}
|
||
}, s.proto), /*#__PURE__*/React.createElement(StageDot, {
|
||
level: s.level
|
||
}), /*#__PURE__*/React.createElement("p", {
|
||
style: {
|
||
gridColumn: '1 / -1',
|
||
margin: '4px 0 0',
|
||
font: '400 14px/1.55 var(--ff-sans)',
|
||
color: 'var(--fg-1)',
|
||
maxWidth: '60ch'
|
||
}
|
||
}, s.what), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
gridColumn: '1 / -1',
|
||
font: '400 11px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, s.source, " \xB7 ", s.date)))));
|
||
}
|
||
function BetasIndex() {
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: "whynot-control / betas",
|
||
title: "Betas",
|
||
lede: "Closed beta plans and beta review notes. A beta should have a clear learning question, entry criteria, and exit outcome."
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
border: '1px dashed var(--border-strong)',
|
||
padding: 32,
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
alignItems: 'center',
|
||
gap: 8,
|
||
textAlign: 'center',
|
||
color: 'var(--fg-3)',
|
||
borderRadius: 4
|
||
}
|
||
}, /*#__PURE__*/React.createElement(Icon, {
|
||
name: "users",
|
||
size: 20
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
font: '500 14px var(--ff-sans)',
|
||
color: 'var(--fg-2)'
|
||
}
|
||
}, "One beta plan in draft."), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
font: '400 12px var(--ff-mono)',
|
||
color: 'var(--fg-3)'
|
||
}
|
||
}, "WNO-021 \xB7 Concierge triage \xB7 pending Binky approval"), /*#__PURE__*/React.createElement("a", {
|
||
href: "#",
|
||
style: {
|
||
font: '500 12px var(--ff-mono)',
|
||
color: 'var(--fg-1)',
|
||
marginTop: 4
|
||
}
|
||
}, "Open draft →")));
|
||
}
|
||
function DecisionsIndex() {
|
||
const decisions = [{
|
||
id: 'DEC-001',
|
||
title: 'Shorten organisation name from whywhynot to whynot.',
|
||
status: 'Accepted',
|
||
date: '2026-01-08'
|
||
}, {
|
||
id: 'DEC-002',
|
||
title: 'Maintain A1 Incubating until first prototype candidates review.',
|
||
status: 'Open',
|
||
date: '—'
|
||
}, {
|
||
id: 'DEC-003',
|
||
title: 'Initial promotion targets: Helix, Coulomb, Sloppers, Plenitude, Binky, Tegwick.',
|
||
status: 'Open',
|
||
date: '—'
|
||
}];
|
||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PageHeader, {
|
||
eyebrow: "whynot-control / decisions",
|
||
title: "Decisions",
|
||
lede: "A promotion record is required before any prototype moves to Helix, Coulomb, Sloppers, Plenitude, Binky, or Tegwick."
|
||
}), /*#__PURE__*/React.createElement("div", {
|
||
style: {
|
||
display: 'flex',
|
||
flexDirection: 'column'
|
||
}
|
||
}, decisions.map(d => /*#__PURE__*/React.createElement("div", {
|
||
key: d.id,
|
||
style: {
|
||
display: 'grid',
|
||
gridTemplateColumns: '90px 1fr 130px 100px',
|
||
gap: 20,
|
||
alignItems: 'baseline',
|
||
padding: '16px 4px',
|
||
borderBottom: '1px solid var(--border-soft)'
|
||
}
|
||
}, /*#__PURE__*/React.createElement("code", {
|
||
className: "mono",
|
||
style: {
|
||
background: 'none',
|
||
padding: 0,
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}, d.id), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '500 15px var(--ff-sans)',
|
||
color: 'var(--fg-1)'
|
||
}
|
||
}, d.title), /*#__PURE__*/React.createElement(Tag, {
|
||
active: d.status === 'Accepted',
|
||
draft: d.status === 'Open'
|
||
}, d.status), /*#__PURE__*/React.createElement("span", {
|
||
style: {
|
||
font: '400 12px var(--ff-mono)',
|
||
color: 'var(--fg-3)',
|
||
textAlign: 'right'
|
||
}
|
||
}, d.date)))));
|
||
}
|
||
Object.assign(window, {
|
||
Inbox,
|
||
PrototypesIndex,
|
||
PrototypeDetail,
|
||
SignalsIndex,
|
||
BetasIndex,
|
||
DecisionsIndex,
|
||
Field,
|
||
SidebarField,
|
||
PrototypeListCard
|
||
});
|
||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/whynot-control/Screens.jsx", error: String((e && e.message) || e) }); }
|
||
|
||
// ui_kits/whynot-control/data.jsx
|
||
try { (() => {
|
||
// =============================================================
|
||
// Sample data — prototypes, signals, inbox items
|
||
// =============================================================
|
||
|
||
const PROTOTYPES = [{
|
||
id: 'WNO-014',
|
||
pitch: 'A field-notebook for catching weird ideas before they evaporate.',
|
||
learning: 'Do people return to capture more than once?',
|
||
test: 'One-page landing + email capture, 14 days.',
|
||
target: 'Coulomb',
|
||
stage: 'experiment',
|
||
stageLabel: 'Experiment',
|
||
signal: 'S1',
|
||
risks: 'Confused with note-taking apps.'
|
||
}, {
|
||
id: 'WNO-017',
|
||
pitch: 'A LEGO-brick mood board for engineers who don’t think in mood boards.',
|
||
learning: 'Will engineers attach metaphors to their tickets?',
|
||
test: 'Slack bot, three teams, two weeks.',
|
||
target: 'Helix',
|
||
stage: 'signal',
|
||
stageLabel: 'Signal review',
|
||
signal: 'S3',
|
||
risks: 'Cute but unused after a week.'
|
||
}, {
|
||
id: 'WNO-021',
|
||
pitch: 'Concierge-style “prototype triage” for indie hackers.',
|
||
learning: 'Will three founders pay for a one-hour triage call?',
|
||
test: 'Offer beta · 3 calls · listed price.',
|
||
target: 'Plenitude',
|
||
stage: 'experiment',
|
||
stageLabel: 'Experiment',
|
||
signal: 'S2',
|
||
risks: 'Time-cost outruns signal value.'
|
||
}, {
|
||
id: 'WNO-024',
|
||
pitch: 'A relevant-#CoronaPolitics timeline, re-released with one editor.',
|
||
learning: 'Is there residual demand five years on?',
|
||
test: 'Static preview page, 30 days, count returns.',
|
||
target: 'None yet',
|
||
stage: 'parked',
|
||
stageLabel: 'Parked',
|
||
signal: 'S0',
|
||
risks: 'Topical relevance has clearly faded.'
|
||
}];
|
||
const INBOX = [{
|
||
id: 1,
|
||
ts: '2026-03-02 14:21',
|
||
text: 'Idea: “subway map” view of the prototype pipeline. People understand transit maps; they don’t understand kanban boards.',
|
||
from: 'Tegwick'
|
||
}, {
|
||
id: 2,
|
||
ts: '2026-03-01 09:08',
|
||
text: 'Weird observation from yesterday’s call: three founders independently asked for “something to capture the half-formed stuff”.',
|
||
from: 'note-to-self'
|
||
}, {
|
||
id: 3,
|
||
ts: '2026-02-28 23:55',
|
||
text: 'Could the LEGO-brick metaphor extend to a public “build log” format? One brick = one decision.',
|
||
from: 'Tegwick'
|
||
}, {
|
||
id: 4,
|
||
ts: '2026-02-27 11:34',
|
||
text: 'Park idea: realtime sentiment dashboard for prototype landing pages. Probably worse than reading the comments.',
|
||
from: 'note-to-self'
|
||
}, {
|
||
id: 5,
|
||
ts: '2026-02-26 17:02',
|
||
text: 'Conversation with R. about closed-beta etiquette. Useful: pre-write the exit email before the beta opens.',
|
||
from: 'note-to-self'
|
||
}, {
|
||
id: 6,
|
||
ts: '2026-02-25 08:12',
|
||
text: 'fuerindifferenz shirts: residual interest from old whywhynot.de page. Could a yearly drop work?',
|
||
from: 'Tegwick'
|
||
}, {
|
||
id: 7,
|
||
ts: '2026-02-24 15:40',
|
||
text: 'Tiny idea: a “reject log” that publishes the ideas you said no to, with one-sentence reasons.',
|
||
from: 'note-to-self'
|
||
}];
|
||
const SIGNALS = [{
|
||
id: 'SIG-031',
|
||
proto: 'WNO-017',
|
||
level: 'S3',
|
||
what: 'Two teams shipped public README sections labelled “brick: scope” after using the bot for a week.',
|
||
source: 'usage log',
|
||
date: '2026-03-04'
|
||
}, {
|
||
id: 'SIG-030',
|
||
proto: 'WNO-017',
|
||
level: 'S2',
|
||
what: 'Three engineers DM’d asking for an export-to-Notion option.',
|
||
source: 'Slack',
|
||
date: '2026-03-03'
|
||
}, {
|
||
id: 'SIG-029',
|
||
proto: 'WNO-014',
|
||
level: 'S1',
|
||
what: 'Landing page: 34 visits, 7 emails, 0 returns in week 1.',
|
||
source: 'Plausible',
|
||
date: '2026-03-01'
|
||
}, {
|
||
id: 'SIG-028',
|
||
proto: 'WNO-021',
|
||
level: 'S2',
|
||
what: 'First triage call booked at listed price; second declined on price.',
|
||
source: 'Stripe / email',
|
||
date: '2026-02-28'
|
||
}, {
|
||
id: 'SIG-027',
|
||
proto: 'WNO-021',
|
||
level: 'S1',
|
||
what: '“Interesting but I’d want a free first one” ×2.',
|
||
source: 'interview',
|
||
date: '2026-02-26'
|
||
}, {
|
||
id: 'SIG-026',
|
||
proto: 'WNO-024',
|
||
level: 'S0',
|
||
what: 'Static preview: 12 visits in 30 days, 0 returns.',
|
||
source: 'Plausible',
|
||
date: '2026-02-24'
|
||
}];
|
||
Object.assign(window, {
|
||
PROTOTYPES,
|
||
INBOX,
|
||
SIGNALS
|
||
});
|
||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/whynot-control/data.jsx", error: String((e && e.message) || e) }); }
|
||
|
||
})();
|