Add Motion: the go-to-market operating system on top of the ledger
The ledger answers which contracted capacity is sold, to whom, at what margin. It says nothing about the motion — the repeatable practice that turns a customer conversation into a scoped deployment, and turns that deployment into something the next one reuses. Motion is deliberately not a parallel entity tree. DEMAND_STAGES already is the motion, so Motion binds reusable artefacts to the stages of a demand deal that already exists: an engagement hangs off one deal, cascade deleted, one per deal by unique constraint. Nine closed kinds, each declaring which stages it serves, and a starter library of twelve templates covering all eight open stages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Source with a copy button — the fence chrome, in one place.
|
||||
*
|
||||
* Reference architectures arrive as `mermaid`, both in a template's structured
|
||||
* `fields` and inside the markdown body a promoted artefact brings with it, and
|
||||
* neither is rendered as a picture. Bundling mermaid means roughly two
|
||||
* megabytes and evaluating author-supplied text, and the proxy allows exactly
|
||||
* one inline script by hash (AGENTS.md §5), so it would drag a CSP change onto
|
||||
* the deployment host too. Source with a copy button gets the reader into their
|
||||
* own diagram tool in two clicks; the picture is tracked as follow-up in
|
||||
* `docs/motion.md`.
|
||||
*
|
||||
* The copy button is here rather than in each caller because a diagram in a
|
||||
* body and a diagram in a field are the same thing to the person reading it,
|
||||
* and one of the two silently lacking the button is the sort of difference
|
||||
* nobody reports.
|
||||
*/
|
||||
import { useState } from 'react';
|
||||
import { Check, Copy } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui';
|
||||
|
||||
export function CodeBlock({
|
||||
source,
|
||||
language,
|
||||
label,
|
||||
}: {
|
||||
source: string;
|
||||
/** The fence's language, shown as the block's caption. Absent for a bare fence. */
|
||||
language?: string | null;
|
||||
/** What the copy button says it copies, for a screen reader. */
|
||||
label?: string;
|
||||
}) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const copy = async () => {
|
||||
// `navigator.clipboard` is absent outside a secure context, which the LAN
|
||||
// dev server is — so this branch is reached routinely, not exceptionally.
|
||||
if (!navigator.clipboard) {
|
||||
toast.error('The browser refused clipboard access. Select the source and copy it by hand.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(source);
|
||||
setCopied(true);
|
||||
toast.success('Source copied.');
|
||||
window.setTimeout(() => setCopied(false), 2000);
|
||||
} catch {
|
||||
toast.error('The browser refused clipboard access. Select the source and copy it by hand.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-w-0 overflow-hidden rounded-lg border border-border bg-surface-2">
|
||||
<div className="flex min-w-0 items-center justify-between gap-2 border-b border-border pl-3">
|
||||
<span className="min-w-0 truncate font-mono text-[11px] lowercase text-muted">
|
||||
{language ?? 'source'}
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => void copy()}
|
||||
aria-label={label ? `Copy the ${label} source` : 'Copy the source'}
|
||||
>
|
||||
{copied ? <Check className="size-4" aria-hidden /> : <Copy className="size-4" aria-hidden />}
|
||||
{copied ? 'Copied' : 'Copy'}
|
||||
</Button>
|
||||
</div>
|
||||
<pre className="scroll-x p-3 text-xs leading-5">
|
||||
<code className="font-mono">{source}</code>
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user