Restructure the chapter shell around a visible outline

This commit is contained in:
pat
2026-09-01 03:44:06 +00:00
parent 8937061c49
commit b645d1bec2
+82 -35
View File
@@ -1,16 +1,18 @@
import { useEffect } from "react";
import { useEffect, useMemo } from "react";
import Head from "next/head";
import ReaderNav from "../../components/reader/ReaderNav";
import ReaderFooter from "../../components/reader/ReaderFooter";
import WorkflowBlock from "../../components/reader/WorkflowBlock";
import ChapterOutline from "../../components/reader/ChapterOutline";
import useActivation from "../../components/reader/useActivation";
import { CHAPTER, RECIPES } from "../../data/sample-chapter";
import { CHAPTER, RECIPES, buildOutline } from "../../data/sample-chapter";
const RECIPE_IDS = RECIPES.map((r) => r.id);
const ESSAY_KEYS = ["stakes", "constraints", "practice"];
function Essay({ heading, paragraphs }) {
function Essay({ id, heading, paragraphs }) {
return (
<section className="essay">
<section className="essay" id={id}>
<h2>{heading}</h2>
{paragraphs.map((p) => (
<p key={p}>{p}</p>
@@ -22,6 +24,9 @@ function Essay({ heading, paragraphs }) {
export default function RealEstateChapter() {
const { complete, toggle, count, total } = useActivation(RECIPE_IDS);
const [first, second] = RECIPES;
const outline = useMemo(() => buildOutline(CHAPTER, RECIPES), []);
const essayGroup = outline.find((g) => g.label === "Essay");
const workflowGroup = outline.find((g) => g.label === "Workflows");
useEffect(() => {
const hash = window.location.hash;
@@ -33,32 +38,23 @@ export default function RealEstateChapter() {
return (
<>
<Head>
<title>{CHAPTER.title} — AIBook.fun reading demo</title>
<title>{CHAPTER.title} · AIBook.fun reading demo</title>
<meta name="description" content={CHAPTER.promise} />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<ReaderNav chapterName={CHAPTER.vertical} />
<div className="chapter-progress" role="status" aria-live="polite">
<div className="wrap chapter-progress-in">
<span>
{count}/{total} Try-its complete
</span>
<span className="chapter-progress-links">
{RECIPES.map((r) => (
<a key={r.id} href={`#${r.anchor}`}>
{r.id}
{complete[r.id] ? " · done" : ""}
</a>
))}
</span>
</div>
</div>
<main>
<article className="chapter-page">
<div className="wrap">
<div className="wrap chapter-shell">
<ChapterOutline
groups={outline}
complete={complete}
count={count}
total={total}
/>
<div className="chapter-col">
<span className="spec demo-chip">Reading demo · not the live book</span>
<p className="spec chapter-kicker">
@@ -67,40 +63,90 @@ export default function RealEstateChapter() {
<h1 className="chapter-title">{CHAPTER.title}</h1>
<p className="chapter-by">{CHAPTER.authors}</p>
<ChapterOutline
variant="mobile"
groups={outline}
complete={complete}
count={count}
total={total}
/>
<p className="chapter-promise">{CHAPTER.promise}</p>
<section className="chapter-map" aria-label="What's in this chapter">
<h2 className="chapter-map-title">What's in this chapter</h2>
<div className="chapter-map-block">
<p className="spec">Essay</p>
<ul>
{essayGroup.items.map((item) => (
<li key={item.id}>
<a href={`#${item.id}`}>{item.label}</a>
</li>
))}
</ul>
</div>
<div className="chapter-map-block">
<p className="spec">Workflows</p>
<ul>
{workflowGroup.items.map((item) => (
<li key={item.id}>
<a href={`#${item.id}`}>
{item.recipeId} · {item.shortTitle} · {item.time}
</a>
</li>
))}
</ul>
</div>
</section>
<div className="skip-row">
<span className="skip-label">Skip to a Try-it</span>
{CHAPTER.skip.map((s) => (
<a key={s.id} className="skip-chip" href={s.href}>
{s.id}
<span className="skip-chip-job">{s.title}</span>
{RECIPES.map((r) => (
<a key={r.id} className="skip-chip" href={`#${r.anchor}`}>
{r.id}
<span className="skip-chip-job">{r.shortTitle}</span>
</a>
))}
</div>
<Essay heading={CHAPTER.stakes.heading} paragraphs={CHAPTER.stakes.paragraphs} />
<Essay
heading={CHAPTER.constraints.heading}
paragraphs={CHAPTER.constraints.paragraphs}
/>
<Essay heading={CHAPTER.practice.heading} paragraphs={CHAPTER.practice.paragraphs} />
{ESSAY_KEYS.map((key) => (
<Essay
key={key}
id={CHAPTER[key].id}
heading={CHAPTER[key].heading}
paragraphs={CHAPTER[key].paragraphs}
/>
))}
<p className="spec workflow-kicker">
Workflow 1 of {RECIPES.length} in this chapter
</p>
<WorkflowBlock
recipe={first}
index={1}
total={RECIPES.length}
complete={!!complete[first.id]}
onToggleComplete={toggle}
/>
<Essay heading={CHAPTER.between.heading} paragraphs={CHAPTER.between.paragraphs} />
<Essay
id={CHAPTER.between.id}
heading={CHAPTER.between.heading}
paragraphs={CHAPTER.between.paragraphs}
/>
<p className="spec workflow-kicker">
Workflow 2 of {RECIPES.length} in this chapter
</p>
<WorkflowBlock
recipe={second}
index={2}
total={RECIPES.length}
complete={!!complete[second.id]}
onToggleComplete={toggle}
/>
<section className="end-matter">
<section className="end-matter" id="further">
<h2>Further workflows in this vertical</h2>
<ul className="further-list">
{CHAPTER.further.map((item) => (
@@ -125,14 +171,15 @@ export default function RealEstateChapter() {
</li>
))}
</ul>
</section>
<section className="end-sources" id="sources">
<h2>Sources</h2>
<ul className="further-list">
{CHAPTER.sources.map((s) => (
<li key={s}>{s}</li>
))}
</ul>
<p className="chapter-updated">Last updated: {CHAPTER.lastUpdated}</p>
</section>
</div>