@brandon_m_behring/book-scaffold-astro 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -1
- package/components/Pitfall.astro +17 -0
- package/components/PocLayout.astro +28 -0
- package/components/WorkedExample.astro +29 -0
- package/components/YouWillLearn.astro +24 -0
- package/dist/schemas.mjs +11 -2
- package/package.json +6 -1
- package/styles/callouts.css +48 -0
- package/styles/poc-layouts.css +57 -0
- package/styles/tokens.css +5 -0
package/CLAUDE.md
CHANGED
|
@@ -66,7 +66,9 @@ Two callout families coexist. Authors import what they need.
|
|
|
66
66
|
|
|
67
67
|
**Academic family** (`src/components/callouts/`, 10 components): `NoteBox`, `ExampleBox`, `DynConnect`, `InsightBox`, `WarnBox`, `CounterBox`, `TipBox`, `OpenQuestion`, `PaperBox`, `ResultBox`. Plus `Theorem` (unified for theorem/proposition/lemma/corollary/definition/example/exercise/remark/proof).
|
|
68
68
|
|
|
69
|
-
**
|
|
69
|
+
**Pedagogy family** (v4.1.0+, any profile, 3 components): `Pitfall` (rose; "common mistake" — distinct from `WarnBox`'s preemptive warning), `WorkedExample` (plum; collapsible `<details>` block with `#worked-example-{id}` anchor for deep links), `YouWillLearn` (gold; chapter-opener with optional `prerequisites` prop). Slot bullets/code freely; render at any preset.
|
|
70
|
+
|
|
71
|
+
**Utility components** (`src/components/`, any profile): `Cite`, `XRef`, `Figure`, `MarginNote`, `Sidenote`, `WeekRef`, `CodeRef`, `CodeBlock`, `Tag`, `StatusBadge`, `PocLayout` (v4.1.0+; wraps slot in a per-`kind` layout shell — 5 closed-union kinds; see `recipes/15-defining-styles.md`).
|
|
70
72
|
|
|
71
73
|
Full reference in `recipes/04-component-library.md`.
|
|
72
74
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Pitfall — distinct from generic <WarnBox>.
|
|
4
|
+
* Retrospective "this often goes wrong" callout (vs WarnBox's preemptive
|
|
5
|
+
* "this could go wrong"). React.dev "Pitfall" vocabulary. Closes #58.
|
|
6
|
+
*
|
|
7
|
+
* Family: crimson (--callout-pitfall, deeper than warn-rose).
|
|
8
|
+
*/
|
|
9
|
+
interface Props {
|
|
10
|
+
title?: string;
|
|
11
|
+
}
|
|
12
|
+
const { title = 'Common mistake' } = Astro.props;
|
|
13
|
+
---
|
|
14
|
+
<aside class="callout callout-pitfall" role="note">
|
|
15
|
+
<strong class="callout-title">{title}</strong>
|
|
16
|
+
<div class="callout-body"><slot /></div>
|
|
17
|
+
</aside>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* PocLayout — per-PoC-kind layout selector (closes #56).
|
|
4
|
+
*
|
|
5
|
+
* Wraps slotted content in a <div> that swaps 3 CSS variables per kind
|
|
6
|
+
* (line-length, vertical rhythm, heading emphasis). 5 closed-union kinds.
|
|
7
|
+
*
|
|
8
|
+
* CSS variable surface defined in package/styles/poc-layouts.css. Authors
|
|
9
|
+
* can override per-kind in their own stylesheets via `:where(.poc-layout-X)`.
|
|
10
|
+
*
|
|
11
|
+
* Closed `kind` union: discriminated literal type. To add a 6th kind in
|
|
12
|
+
* a future release, expand the union + add a CSS block in poc-layouts.css.
|
|
13
|
+
*/
|
|
14
|
+
export type PocLayoutKind =
|
|
15
|
+
| 'tutorial'
|
|
16
|
+
| 'how-to'
|
|
17
|
+
| 'tldr'
|
|
18
|
+
| 'part-summary'
|
|
19
|
+
| 'cheat-sheet';
|
|
20
|
+
|
|
21
|
+
interface Props {
|
|
22
|
+
kind: PocLayoutKind;
|
|
23
|
+
}
|
|
24
|
+
const { kind } = Astro.props;
|
|
25
|
+
---
|
|
26
|
+
<div class={`poc-layout poc-layout-${kind}`}>
|
|
27
|
+
<slot />
|
|
28
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* WorkedExample — collapsible demonstration block (closes #57).
|
|
4
|
+
*
|
|
5
|
+
* Pedagogical worked-example-effect treatment (Sweller/Cooper). Uses
|
|
6
|
+
* native <details>; collapsed by default unless `expanded` prop set.
|
|
7
|
+
* The outer aside carries `id="worked-example-{id}"` for deep links
|
|
8
|
+
* from TL;DRs or cheat-sheets. Prefix avoids collision with author
|
|
9
|
+
* heading anchors.
|
|
10
|
+
*
|
|
11
|
+
* Family: plum (--callout-worked, reuses --callout-official authority hue).
|
|
12
|
+
*/
|
|
13
|
+
interface Props {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
expanded?: boolean;
|
|
17
|
+
}
|
|
18
|
+
const { id, title, expanded = false } = Astro.props;
|
|
19
|
+
const anchorId = `worked-example-${id}`;
|
|
20
|
+
---
|
|
21
|
+
<aside class="callout callout-worked" id={anchorId} role="note">
|
|
22
|
+
<details open={expanded}>
|
|
23
|
+
<summary>
|
|
24
|
+
<strong class="callout-title">{title}</strong>
|
|
25
|
+
<span class="callout-chip">Worked example</span>
|
|
26
|
+
</summary>
|
|
27
|
+
<div class="callout-body"><slot /></div>
|
|
28
|
+
</details>
|
|
29
|
+
</aside>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* YouWillLearn — chapter-opener "what this chapter delivers" callout
|
|
4
|
+
* (closes #59). React.dev pedagogy vocabulary; Bloom's-taxonomy framing.
|
|
5
|
+
*
|
|
6
|
+
* Slotted body — author writes markdown bullets directly.
|
|
7
|
+
* Optional `prerequisites` prop renders a small "Before you start" sub-block.
|
|
8
|
+
*
|
|
9
|
+
* Family: gold (--callout-learn, reuses --callout-insight to signal importance).
|
|
10
|
+
*/
|
|
11
|
+
interface Props {
|
|
12
|
+
prerequisites?: string;
|
|
13
|
+
}
|
|
14
|
+
const { prerequisites } = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
<aside class="callout callout-learn" role="note">
|
|
17
|
+
{prerequisites && (
|
|
18
|
+
<div class="callout-prereq">
|
|
19
|
+
<strong class="callout-prereq-label">Before you start:</strong> {prerequisites}
|
|
20
|
+
</div>
|
|
21
|
+
)}
|
|
22
|
+
<strong class="callout-title">You will learn</strong>
|
|
23
|
+
<div class="callout-body"><slot /></div>
|
|
24
|
+
</aside>
|
package/dist/schemas.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/schemas-entry.ts
|
|
2
|
-
import { existsSync as existsSync2 } from "fs";
|
|
2
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
3
3
|
import { defineCollection } from "astro:content";
|
|
4
4
|
import { glob, file } from "astro/loaders";
|
|
5
5
|
|
|
@@ -565,6 +565,15 @@ function resolvePreset(explicitPreset, explicitProfile) {
|
|
|
565
565
|
}
|
|
566
566
|
|
|
567
567
|
// src/schemas-entry.ts
|
|
568
|
+
function isYamlEmpty(path) {
|
|
569
|
+
try {
|
|
570
|
+
const raw = readFileSync2(path, "utf8");
|
|
571
|
+
const stripped = raw.split(/\r?\n/).map((line) => line.replace(/#.*$/, "").trim()).filter((line) => line.length > 0).join("");
|
|
572
|
+
return stripped === "" || stripped === "[]";
|
|
573
|
+
} catch {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
568
577
|
function frontmatterCollection(schema, base = "./src/content/frontmatter") {
|
|
569
578
|
return defineCollection({
|
|
570
579
|
loader: glob({
|
|
@@ -589,7 +598,7 @@ function defineBookSchemas(opts = {}) {
|
|
|
589
598
|
const collections = {
|
|
590
599
|
chapters
|
|
591
600
|
};
|
|
592
|
-
if (existsSync2("./sources/manifest.yaml")) {
|
|
601
|
+
if (existsSync2("./sources/manifest.yaml") && !isYamlEmpty("./sources/manifest.yaml")) {
|
|
593
602
|
collections.sources = defineCollection({
|
|
594
603
|
loader: file("sources/manifest.yaml"),
|
|
595
604
|
schema: sourcesSchema
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brandon_m_behring/book-scaffold-astro",
|
|
3
3
|
"description": "Astro 6 + MDX toolkit for long-form technical books. Profile-aware (academic / tools / minimal); ships Tufte typography, KaTeX, BibTeX citations, Pagefind, Cloudflare Workers deploy. See PACKAGE_DESIGN.md for the API contract.",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Brandon Behring",
|
|
@@ -65,6 +65,8 @@
|
|
|
65
65
|
"./components/OpenQuestion.astro": "./components/OpenQuestion.astro",
|
|
66
66
|
"./components/PaperBox.astro": "./components/PaperBox.astro",
|
|
67
67
|
"./components/PatternTimeline.astro": "./components/PatternTimeline.astro",
|
|
68
|
+
"./components/Pitfall.astro": "./components/Pitfall.astro",
|
|
69
|
+
"./components/PocLayout.astro": "./components/PocLayout.astro",
|
|
68
70
|
"./components/PolicyRef.astro": "./components/PolicyRef.astro",
|
|
69
71
|
"./components/PreReleaseBanner.astro": "./components/PreReleaseBanner.astro",
|
|
70
72
|
"./components/Recovery.astro": "./components/Recovery.astro",
|
|
@@ -88,7 +90,9 @@
|
|
|
88
90
|
},
|
|
89
91
|
"./components/WarnBox.astro": "./components/WarnBox.astro",
|
|
90
92
|
"./components/WeekRef.astro": "./components/WeekRef.astro",
|
|
93
|
+
"./components/WorkedExample.astro": "./components/WorkedExample.astro",
|
|
91
94
|
"./components/XRef.astro": "./components/XRef.astro",
|
|
95
|
+
"./components/YouWillLearn.astro": "./components/YouWillLearn.astro",
|
|
92
96
|
"./styles/tokens.css": "./styles/tokens.css",
|
|
93
97
|
"./styles/layout.css": "./styles/layout.css",
|
|
94
98
|
"./styles/callouts.css": "./styles/callouts.css",
|
|
@@ -96,6 +100,7 @@
|
|
|
96
100
|
"./styles/typography.css": "./styles/typography.css",
|
|
97
101
|
"./styles/print.css": "./styles/print.css",
|
|
98
102
|
"./styles/convergence.css": "./styles/convergence.css",
|
|
103
|
+
"./styles/poc-layouts.css": "./styles/poc-layouts.css",
|
|
99
104
|
"./styles/tool-filter.css": "./styles/tool-filter.css",
|
|
100
105
|
"./layouts/Base.astro": "./layouts/Base.astro",
|
|
101
106
|
"./layouts/Chapter.astro": "./layouts/Chapter.astro",
|
package/styles/callouts.css
CHANGED
|
@@ -162,6 +162,54 @@
|
|
|
162
162
|
background: var(--color-bg-subtle);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
/* Crimson — Pitfall (v4.1.0, #58). Distinct from warn-rose: deeper, more
|
|
166
|
+
* saturated. Used for "common mistake" / retrospective error patterns. */
|
|
167
|
+
.callout-pitfall {
|
|
168
|
+
border-left-color: var(--callout-pitfall);
|
|
169
|
+
background: var(--warm-crimson-tint);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Plum-dashed — WorkedExample (v4.1.0, #57). Reuses callout-official
|
|
173
|
+
* (plum) bar; <details>/<summary> chrome is plain — no extra structure. */
|
|
174
|
+
.callout-worked {
|
|
175
|
+
border-left-color: var(--callout-worked);
|
|
176
|
+
background: var(--warm-plum-tint);
|
|
177
|
+
}
|
|
178
|
+
.callout-worked summary {
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
list-style: none;
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: baseline;
|
|
183
|
+
gap: var(--space-3);
|
|
184
|
+
}
|
|
185
|
+
.callout-worked summary::-webkit-details-marker {
|
|
186
|
+
display: none;
|
|
187
|
+
}
|
|
188
|
+
.callout-worked .callout-chip {
|
|
189
|
+
font-size: var(--text-xs);
|
|
190
|
+
text-transform: uppercase;
|
|
191
|
+
letter-spacing: 0.05em;
|
|
192
|
+
padding: 0 var(--space-2);
|
|
193
|
+
border: 1px solid var(--callout-worked);
|
|
194
|
+
border-radius: var(--radius-sm);
|
|
195
|
+
color: var(--callout-worked);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Gold — YouWillLearn (v4.1.0, #59). Reuses callout-insight (gold) hue;
|
|
199
|
+
* "Before you start" prereq sub-block sits above the title in muted style. */
|
|
200
|
+
.callout-learn {
|
|
201
|
+
border-left-color: var(--callout-learn);
|
|
202
|
+
background: var(--warm-gold-tint);
|
|
203
|
+
}
|
|
204
|
+
.callout-learn .callout-prereq {
|
|
205
|
+
font-size: var(--text-sm);
|
|
206
|
+
color: var(--color-text-muted);
|
|
207
|
+
margin-bottom: var(--space-2);
|
|
208
|
+
}
|
|
209
|
+
.callout-learn .callout-prereq-label {
|
|
210
|
+
color: var(--color-text);
|
|
211
|
+
}
|
|
212
|
+
|
|
165
213
|
/* ===== Theorem family (Theorem.astro) =====
|
|
166
214
|
* Plain (theorem/proposition/lemma/corollary): italic body
|
|
167
215
|
* Definition family (definition/example/exercise/remark/proof): upright body
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* poc-layouts.css — per-PoC-kind layout variables (v4.1.0, closes #56).
|
|
2
|
+
*
|
|
3
|
+
* Each kind swaps 3 CSS variables that downstream stylesheets (chapter.css,
|
|
4
|
+
* layout.css) can read. Consumers can override per-kind in their own
|
|
5
|
+
* stylesheets via `:where(.poc-layout-X) { --bs-content-line-length: ... }`.
|
|
6
|
+
*
|
|
7
|
+
* Variable surface (intentionally narrow):
|
|
8
|
+
* --bs-content-line-length — main column max line length (ch)
|
|
9
|
+
* --bs-content-vertical-rhythm — body line-height multiplier
|
|
10
|
+
* --bs-heading-emphasis — heading font-weight (400-900)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
:where(.poc-layout-tutorial) {
|
|
14
|
+
--bs-content-line-length: 70ch;
|
|
15
|
+
--bs-content-vertical-rhythm: 1.6;
|
|
16
|
+
--bs-heading-emphasis: 600;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
:where(.poc-layout-how-to) {
|
|
20
|
+
--bs-content-line-length: 68ch;
|
|
21
|
+
--bs-content-vertical-rhythm: 1.5;
|
|
22
|
+
--bs-heading-emphasis: 700;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:where(.poc-layout-tldr) {
|
|
26
|
+
--bs-content-line-length: 65ch;
|
|
27
|
+
--bs-content-vertical-rhythm: 1.4;
|
|
28
|
+
--bs-heading-emphasis: 500;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:where(.poc-layout-part-summary) {
|
|
32
|
+
--bs-content-line-length: 90ch;
|
|
33
|
+
--bs-content-vertical-rhythm: 1.5;
|
|
34
|
+
--bs-heading-emphasis: 600;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:where(.poc-layout-cheat-sheet) {
|
|
38
|
+
--bs-content-line-length: 55ch;
|
|
39
|
+
--bs-content-vertical-rhythm: 1.3;
|
|
40
|
+
--bs-heading-emphasis: 600;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* All kinds: apply the variables to the wrapper itself.
|
|
44
|
+
* Authors can read these vars from descendants for tighter control. */
|
|
45
|
+
.poc-layout {
|
|
46
|
+
max-width: var(--bs-content-line-length, 70ch);
|
|
47
|
+
line-height: var(--bs-content-vertical-rhythm, 1.6);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.poc-layout :is(h1, h2, h3, h4, h5, h6) {
|
|
51
|
+
font-weight: var(--bs-heading-emphasis, 600);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Cheat-sheet: tables should fill the available width since the column is narrower. */
|
|
55
|
+
.poc-layout-cheat-sheet table {
|
|
56
|
+
width: 100%;
|
|
57
|
+
}
|
package/styles/tokens.css
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
--warm-green: #4A7E3F; /* positive: tips, practitioner */
|
|
15
15
|
--warm-plum: #8A4E82; /* authority: official, exercises */
|
|
16
16
|
--warm-gold: #C09840; /* insight: convergence, reasoning */
|
|
17
|
+
--warm-crimson:#A03838; /* pitfall: deeper red distinct from warm-rose */
|
|
17
18
|
|
|
18
19
|
/* Warm neutrals (Anthropic-derived) */
|
|
19
20
|
--paper: #FDFCF9; /* page background — slightly off-white */
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
--warm-green-tint: color-mix(in srgb, var(--warm-green) 6%, var(--paper));
|
|
28
29
|
--warm-plum-tint: color-mix(in srgb, var(--warm-plum) 6%, var(--paper));
|
|
29
30
|
--warm-gold-tint: color-mix(in srgb, var(--warm-gold) 6%, var(--paper));
|
|
31
|
+
--warm-crimson-tint:color-mix(in srgb, var(--warm-crimson) 6%, var(--paper));
|
|
30
32
|
|
|
31
33
|
/* ===== Layer 2: Semantic roles (light mode) ===== */
|
|
32
34
|
--color-bg: var(--paper);
|
|
@@ -45,6 +47,9 @@
|
|
|
45
47
|
--callout-tip: var(--warm-green);
|
|
46
48
|
--callout-official: var(--warm-plum);
|
|
47
49
|
--callout-insight: var(--warm-gold);
|
|
50
|
+
--callout-pitfall: var(--warm-crimson);
|
|
51
|
+
--callout-worked: var(--warm-plum);
|
|
52
|
+
--callout-learn: var(--warm-gold);
|
|
48
53
|
|
|
49
54
|
/* ===== Typography scale ===== */
|
|
50
55
|
--font-body: 'Roboto Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|