Label nested workflows and add in-recipe jump links

This commit is contained in:
pat
2026-09-01 03:44:05 +00:00
parent d7c6a239c1
commit 8937061c49
@@ -2,6 +2,16 @@ import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import TermOutput from "./TermOutput"; import TermOutput from "./TermOutput";
const JUMP = [
{ id: "problem", label: "Problem" },
{ id: "actors", label: "Actors" },
{ id: "setup", label: "Setup" },
{ id: "safeguards", label: "Safeguards" },
{ id: "method", label: "Method" },
{ id: "evidence", label: "Evidence" },
{ id: "tryit", label: "Try-it" },
];
function ShieldCheck() { function ShieldCheck() {
return ( return (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
@@ -59,13 +69,25 @@ async function copyText(text) {
} }
} }
function Field({ anchor, name, label, children }) {
return (
<div className="row" id={`${anchor}-${name}`}>
<h4 className="k">{label}</h4>
<div className="v">{children}</div>
</div>
);
}
export default function WorkflowBlock({ export default function WorkflowBlock({
recipe, recipe,
complete = false, complete = false,
onToggleComplete, onToggleComplete,
focused = false, focused = false,
index = 1,
total = 1,
}) { }) {
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const a = recipe.anchor;
const onShare = async () => { const onShare = async () => {
const ok = await copyText(recipe.shareBlurb); const ok = await copyText(recipe.shareBlurb);
@@ -76,67 +98,60 @@ export default function WorkflowBlock({
return ( return (
<article <article
id={recipe.anchor} id={a}
className={`recipe recipe-nested${focused ? " recipe-focus" : ""}`} className={`recipe recipe-nested${focused ? " recipe-focus" : ""}`}
aria-labelledby={`${recipe.anchor}-title`} aria-labelledby={`${a}-title`}
> >
<div className="recipe-top"> <div className="recipe-top">
<span className="recipe-id"> <span className="recipe-id">
recipe <b>{recipe.id}</b> · v{recipe.version} · {recipe.time} · {recipe.cost} Workflow {index} of {total} · <b>{recipe.id}</b> · v{recipe.version} · {recipe.time} · {recipe.cost}
</span> </span>
<span className="recipe-vert">{recipe.vertical}</span> <span className="recipe-vert">{recipe.vertical}</span>
</div> </div>
<div className="recipe-body"> <div className="recipe-body">
<h3 className="recipe-title" id={`${recipe.anchor}-title`}> <h3 className="recipe-title" id={`${a}-title`}>
{recipe.title} {recipe.title}
</h3> </h3>
<div className="row"> <nav className="recipe-jump" aria-label="In this workflow">
<div className="k">Problem</div> {JUMP.map((j) => (
<div className="v"> <a key={j.id} href={`#${a}-${j.id}`}>
{recipe.problem}{" "} {j.label}
<span className="sub">{recipe.problemJob}</span> </a>
</div> ))}
</div> </nav>
<div className="row"> <Field anchor={a} name="problem" label="Problem">
<div className="k">Actors</div> {recipe.problem} <span className="sub">{recipe.problemJob}</span>
<div className="v"> </Field>
<Field anchor={a} name="actors" label="Actors">
<ul className="plain-list"> <ul className="plain-list">
{recipe.actors.map((line) => ( {recipe.actors.map((line) => (
<li key={line}>{line}</li> <li key={line}>{line}</li>
))} ))}
</ul> </ul>
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="setup" label="Setup">
<div className="k">Setup</div>
<div className="v">
<ul className="plain-list"> <ul className="plain-list">
{recipe.setup.map((line) => ( {recipe.setup.map((line) => (
<li key={line}>{line}</li> <li key={line}>{line}</li>
))} ))}
</ul> </ul>
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="safeguards" label="Safeguards">
<div className="k">Safeguards</div>
<div className="v">
{recipe.safeguards.map((line) => ( {recipe.safeguards.map((line) => (
<div className="guard" key={line}> <div className="guard" key={line}>
<ShieldCheck /> <ShieldCheck />
<span>{line}</span> <span>{line}</span>
</div> </div>
))} ))}
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="method" label="Method">
<div className="k">Method</div>
<div className="v">
<ol className="steps"> <ol className="steps">
{recipe.method.map((step, i) => ( {recipe.method.map((step, i) => (
<li key={i}> <li key={i}>
@@ -147,23 +162,17 @@ export default function WorkflowBlock({
</li> </li>
))} ))}
</ol> </ol>
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="evidence" label="Evidence">
<div className="k">Evidence</div>
<div className="v">
{recipe.evidence.map((line) => ( {recipe.evidence.map((line) => (
<p key={line} className="evidence-p"> <p key={line} className="evidence-p">
{line} {line}
</p> </p>
))} ))}
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="tryit" label="Try-it">
<div className="k">Try it</div>
<div className="v">
<p> <p>
About {recipe.tryit.minutes} minutes. {recipe.tryit.sample}{" "} About {recipe.tryit.minutes} minutes. {recipe.tryit.sample}{" "}
{recipe.tryit.produce} {recipe.tryit.produce}
@@ -190,26 +199,19 @@ export default function WorkflowBlock({
</button> </button>
</div> </div>
) : null} ) : null}
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="share" label="Share">
<div className="k">Share</div> <p>Copy a short result line. Share the outcome, not the recipe text.</p>
<div className="v">
<p>
Copy a short result line. Share the outcome, not the recipe text.
</p>
<div className="tryit-actions"> <div className="tryit-actions">
<button type="button" className="btn btn-ghost" onClick={onShare}> <button type="button" className="btn btn-ghost" onClick={onShare}>
{copied ? "Copied" : "Copy result line"} {copied ? "Copied" : "Copy result line"}
</button> </button>
</div> </div>
</div> </Field>
</div>
<div className="row"> <Field anchor={a} name="record" label="Record">
<div className="k">Record</div> <div className="recipe-record">
<div className="v recipe-record">
<span>Author: {recipe.author}</span> <span>Author: {recipe.author}</span>
<span>Sources: {recipe.sources}</span> <span>Sources: {recipe.sources}</span>
<span>Last updated: {recipe.lastUpdated}</span> <span>Last updated: {recipe.lastUpdated}</span>
@@ -225,7 +227,7 @@ export default function WorkflowBlock({
</span> </span>
)} )}
</div> </div>
</div> </Field>
</div> </div>
</article> </article>
); );