Baking Recipe
The Bluefish gallery brownie example: a recipe table built from padded cells, groups of refs as row/column guides, and span relations drawing the cell borders
import { Graphic } from "@modular-svg/react";
import * as React from "react";
// The span relation's JSX tag collides with HTML <span> in TypeScript's
// eyes, so it goes through createElement (the reconciler sees the same tag)
function Span(props: { axis: "x" | "y"; children?: React.ReactNode }) {
return React.createElement("span", props);
}
const FONT = 14;
// A padded cell: a transparent background wrapping its content
function Pad({ id, children }: { id: string; children: React.ReactNode }) {
return (
<background key={id} padding={5} fill="transparent" stroke-width={0}>
{children}
</background>
);
}
// A table cell border: a rect spanning a horizontal and a vertical guide
function CellBorder({
id,
horizontal,
vertical,
}: {
id: string;
horizontal: string;
vertical: string;
}) {
return (
<group>
<rect key={id} fill="transparent" stroke="#40A03F" stroke-width={1} />
<Span axis="x">
<ref target={horizontal} />
<ref target={id} />
</Span>
<Span axis="y">
<ref target={vertical} />
<ref target={id} />
</Span>
</group>
);
}
function Label({ children }: { children: string }) {
return <text font-size={FONT}>{children}</text>;
}
const rows = [0, 1, 2, 3, 4, 5].map((i) => `col0-row${i}`);
export function BakingRecipe() {
return (
<Graphic
style={{
border: "1px solid #ddd",
borderRadius: "8px",
display: "inline-block",
maxWidth: "100%",
overflow: "auto",
}}
margin={10}
>
<group>
<background
key="outer"
padding={50}
fill="#7CD4AC"
opacity={0.3}
stroke-width={0}
>
<background
key="recipeTable"
padding={0}
stroke="#40A03F"
fill="#FFFFFF"
stroke-width={3}
>
<Pad id="title">
<Label>
Preheat oven to 325°F (160°C) and butter a 9x13-in. baking pan
</Label>
</Pad>
<Pad id="col0-row0">
<Label>6 oz. (170 g) 70% cacao chocolate</Label>
</Pad>
<Pad id="col0-row1">
<Label>6 oz. (170 g) butter</Label>
</Pad>
<Pad id="col0-row2">
<Label>1-1/2 cup (300 g) granulated sugar </Label>
</Pad>
<Pad id="col0-row3">
<stackV>
<Label>3 large eggs</Label>
</stackV>
</Pad>
<Pad id="col0-row4">
<Label>1 tsp. (5 mL) vanilla extract</Label>
</Pad>
<Pad id="col0-row5">
<Label>1 cup (125 g) all-purpose flour</Label>
</Pad>
<Pad id="col1-row0_1">
<Label>melt in double boiler</Label>
</Pad>
<Pad id="col1_2-row0_2">
<Label>stir in</Label>
</Pad>
<Pad id="col1_2-row3_4">
<Label>lightly beat</Label>
</Pad>
<Pad id="col3-row0_5">
<Label>stir in</Label>
</Pad>
<Pad id="col4-row0_5">
<Label>stir in</Label>
</Pad>
<Pad id="col5-row0_5">
<Label>bake 325°F (160°C) for 35 min.</Label>
</Pad>
<stackV alignment="left" spacing={0}>
<ref target="title" />
{rows.map((r) => (
<ref key={`stack-${r}`} target={r} />
))}
</stackV>
<group key="col0">
{rows.map((r) => (
<ref key={`col0-${r}`} target={r} />
))}
</group>
<distribute axis="x" spacing={0}>
<ref target="col0" />
<ref target="col1-row0_1" />
</distribute>
<align alignment="centerY">
<group>
<ref target="col0-row0" />
<ref target="col0-row1" />
</group>
<ref target="col1-row0_1" />
</align>
<distribute axis="x" spacing={0}>
<ref target="col1-row0_1" />
<ref target="col1_2-row0_2" />
</distribute>
<align alignment="centerY">
<group>
<ref target="col0-row0" />
<ref target="col0-row1" />
<ref target="col0-row2" />
</group>
<ref target="col1_2-row0_2" />
</align>
<align alignment="centerY">
<group>
<ref target="col0-row3" />
<ref target="col0-row4" />
</group>
<ref target="col1_2-row3_4" />
</align>
<align alignment="left">
<group>
<ref target="col1-row0_1" />
<ref target="col1_2-row0_2" />
</group>
<ref target="col1_2-row3_4" />
</align>
<distribute axis="x" spacing={0}>
<group>
<ref target="col1-row0_1" />
<ref target="col1_2-row0_2" />
<ref target="col1_2-row3_4" />
</group>
<ref target="col3-row0_5" />
</distribute>
<align alignment="centerY">
<group>
<ref target="col0-row0" />
<ref target="col0-row4" />
</group>
<ref target="col3-row0_5" />
</align>
<distribute axis="x" spacing={0}>
<group>
<ref target="col3-row0_5" />
</group>
<ref target="col4-row0_5" />
</distribute>
<align alignment="centerY">
<group>
<ref target="col0-row0" />
<ref target="col0-row5" />
</group>
<ref target="col4-row0_5" />
</align>
<distribute axis="x" spacing={0}>
<group>
<ref target="col4-row0_5" />
</group>
<ref target="col5-row0_5" />
</distribute>
<align alignment="centerY">
<group>
<ref target="col0-row0" />
<ref target="col0-row5" />
</group>
<ref target="col5-row0_5" />
</align>
{rows.map((r, i) => (
<CellBorder
key={`cb-${r}`}
id={`cb${i + 1}`}
horizontal="col0"
vertical={r}
/>
))}
<group key="col1_2">
<ref target="col1-row0_1" />
<ref target="col1_2-row0_2" />
<ref target="col1_2-row3_4" />
</group>
<group key="col1_3">
<ref target="col1_2" />
<ref target="col3-row0_5" />
</group>
<group key="row0_1">
<ref target="col0-row0" />
<ref target="col0-row1" />
</group>
<group key="row0_2">
<ref target="col0-row0" />
<ref target="col0-row2" />
</group>
<group key="row3_4">
<ref target="col0-row3" />
<ref target="col0-row4" />
</group>
<group key="row0_5">
<ref target="col0-row0" />
<ref target="col0-row5" />
</group>
<group key="row0_4">
<ref target="col0-row0" />
<ref target="col0-row4" />
</group>
<CellBorder id="cb7" horizontal="col1-row0_1" vertical="row0_1" />
<CellBorder id="cb8" horizontal="col1_2" vertical="row0_2" />
<CellBorder id="cb9" horizontal="col1_2" vertical="row3_4" />
<CellBorder id="cb10" horizontal="col1_3" vertical="row0_4" />
<CellBorder id="cb11" horizontal="col5-row0_5" vertical="row0_5" />
<group key="col0_5">
<ref target="col0-row0" />
<ref target="col5-row0_5" />
</group>
<CellBorder id="cb12" horizontal="col0_5" vertical="title" />
</background>
</background>
<text key="recipeName" font-size={FONT}>
Dark Chocolate Brownies (makes 24 squares)
</text>
<stackV spacing={10} alignment="left">
<ref target="recipeName" />
<ref target="recipeTable" />
</stackV>
</group>
</Graphic>
);
}