From b87b7516dcd1ba758f8bdfa6b4eccdc5fc7a1441 Mon Sep 17 00:00:00 2001 From: pat Date: Mon, 31 Aug 2026 07:33:23 +0000 Subject: [PATCH] feat(reader): add full nested workflow block --- .../components/reader/WorkflowBlock.jsx | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 marketing-site/components/reader/WorkflowBlock.jsx diff --git a/marketing-site/components/reader/WorkflowBlock.jsx b/marketing-site/components/reader/WorkflowBlock.jsx new file mode 100644 index 0000000..08b5a3e --- /dev/null +++ b/marketing-site/components/reader/WorkflowBlock.jsx @@ -0,0 +1,232 @@ +import { useState } from "react"; +import Link from "next/link"; +import TermOutput from "./TermOutput"; + +function ShieldCheck() { + return ( + + ); +} + +function CheckMark() { + return ( + + ); +} + +async function copyText(text) { + try { + await navigator.clipboard.writeText(text); + return true; + } catch { + try { + const el = document.createElement("textarea"); + el.value = text; + el.setAttribute("readonly", ""); + el.style.position = "fixed"; + el.style.left = "-9999px"; + document.body.appendChild(el); + el.select(); + const ok = document.execCommand("copy"); + el.remove(); + return ok; + } catch { + return false; + } + } +} + +export default function WorkflowBlock({ + recipe, + complete = false, + onToggleComplete, + focused = false, +}) { + const [copied, setCopied] = useState(false); + + const onShare = async () => { + const ok = await copyText(recipe.shareBlurb); + if (!ok) return; + setCopied(true); + window.setTimeout(() => setCopied(false), 1800); + }; + + return ( +
+
+ + recipe {recipe.id} · v{recipe.version} · {recipe.time} · {recipe.cost} + + {recipe.vertical} +
+ +
+

+ {recipe.title} +

+ +
+
Problem
+
+ {recipe.problem}{" "} + {recipe.problemJob} +
+
+ +
+
Actors
+
+
    + {recipe.actors.map((line) => ( +
  • {line}
  • + ))} +
+
+
+ +
+
Setup
+
+
    + {recipe.setup.map((line) => ( +
  • {line}
  • + ))} +
+
+
+ +
+
Safeguards
+
+ {recipe.safeguards.map((line) => ( +
+ + {line} +
+ ))} +
+
+ +
+
Method
+
+
    + {recipe.method.map((step, i) => ( +
  1. +
    + {step.text} + {step.term ? : null} +
    +
  2. + ))} +
+
+
+ +
+
Evidence
+
+ {recipe.evidence.map((line) => ( +

+ {line} +

+ ))} +
+
+ +
+
Try it
+
+

+ About {recipe.tryit.minutes} minutes. {recipe.tryit.sample}{" "} + {recipe.tryit.produce} +

+

+ {recipe.tryit.done}{" "} + + {recipe.tryit.hrefLabel} + +

+

+ ◷ {recipe.tryit.chip} +

+ {onToggleComplete ? ( +
+ +
+ ) : null} +
+
+ +
+
Share
+
+

+ Copy a short result line. Share the outcome, not the recipe text. +

+
+ +
+
+
+ +
+
Record
+
+ Author: {recipe.author} + Sources: {recipe.sources} + Last updated: {recipe.lastUpdated} + {focused ? ( + + + Back to the chapter + + + ) : ( + + Open on paper + + )} +
+
+
+
+ ); +}