@brandon_m_behring/book-scaffold-astro 4.0.0 → 4.1.2
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 +23 -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/scripts/build-labels.mjs +11 -2
- package/scripts/validate.mjs +6 -2
- package/scripts/walk-mdx.mjs +68 -2
- 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,23 @@
|
|
|
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 = 'tutorial' | 'how-to' | 'tldr' | 'part-summary' | 'cheat-sheet';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
kind: PocLayoutKind;
|
|
18
|
+
}
|
|
19
|
+
const { kind } = Astro.props;
|
|
20
|
+
---
|
|
21
|
+
<div class={`poc-layout poc-layout-${kind}`}>
|
|
22
|
+
<slot />
|
|
23
|
+
</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.2",
|
|
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/scripts/build-labels.mjs
CHANGED
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
* Designed to run in <2 s on a medium book.
|
|
35
35
|
*/
|
|
36
36
|
import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';
|
|
37
|
-
import { resolve, join, basename, dirname } from 'node:path';
|
|
37
|
+
import { resolve, relative, join, basename, dirname } from 'node:path';
|
|
38
|
+
import { readChaptersBase } from './walk-mdx.mjs';
|
|
38
39
|
|
|
39
40
|
// --help / -h: non-mutating (closes #14).
|
|
40
41
|
const USAGE = `Usage: book-scaffold build-labels
|
|
@@ -56,7 +57,15 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
|
56
57
|
process.exit(0);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
// v4.1.1 (closes #63): readChaptersBase honors BOOK_CHAPTERS_DIR env (when set)
|
|
61
|
+
// then parses the consumer's content.config.{ts,mjs,js} for a `chapters`
|
|
62
|
+
// collection `loader.base` override. Multi-guide consumers use
|
|
63
|
+
// `src/content/<guide-slug>/` rather than the Astro 5 default.
|
|
64
|
+
const CHAPTERS_DIR_ABS = await readChaptersBase(process.cwd());
|
|
65
|
+
// build-labels uses CHAPTERS_DIR as a path relative to cwd elsewhere in the
|
|
66
|
+
// script (joined with `walkMdx`). Convert the absolute path back to relative
|
|
67
|
+
// for compatibility with the existing call sites.
|
|
68
|
+
const CHAPTERS_DIR = relative(process.cwd(), CHAPTERS_DIR_ABS) || 'src/content/chapters';
|
|
60
69
|
const OUTPUT_PATH = process.env.BOOK_LABELS_OUT ?? 'src/data/labels.json';
|
|
61
70
|
|
|
62
71
|
/** Component names that participate in cross-referencing. */
|
package/scripts/validate.mjs
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
import { readFile, access } from 'node:fs/promises';
|
|
29
29
|
import { existsSync, readFileSync } from 'node:fs';
|
|
30
30
|
import { resolve, dirname, join } from 'node:path';
|
|
31
|
-
import { walkMdx } from './walk-mdx.mjs';
|
|
31
|
+
import { walkMdx, readChaptersBase } from './walk-mdx.mjs';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Best-effort .env reader. Mirrors `readEnvFile` in src/types.ts; kept inline
|
|
@@ -95,7 +95,11 @@ const presetFromFlag = presetFlagIdx >= 0 ? argv[presetFlagIdx + 1] : undefined;
|
|
|
95
95
|
// Resolves issue #8 — three reference consumers reported "0 chapter(s) checked"
|
|
96
96
|
// because ROOT was the package directory inside node_modules.
|
|
97
97
|
const ROOT = process.cwd();
|
|
98
|
-
|
|
98
|
+
// v4.1.1 (closes #63): read the consumer's content.config.{ts,mjs,js} to
|
|
99
|
+
// honor `loader.base` overrides (multi-guide pattern uses
|
|
100
|
+
// `src/content/<guide-slug>/` instead of the Astro 5 default).
|
|
101
|
+
// Falls back to `src/content/chapters` when no override / no config file.
|
|
102
|
+
const CHAPTERS_DIR = await readChaptersBase(ROOT);
|
|
99
103
|
const PUBLIC_DIR = resolve(ROOT, 'public');
|
|
100
104
|
const DATA_DIR = resolve(ROOT, 'src/data');
|
|
101
105
|
|
package/scripts/walk-mdx.mjs
CHANGED
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* Output: relative paths in POSIX form ("subdir/file.mdx"), matching what
|
|
13
13
|
* the previous `glob('**\/*.{md,mdx}', { cwd })` produced.
|
|
14
14
|
*/
|
|
15
|
-
import { readdir } from 'node:fs/promises';
|
|
16
|
-
import {
|
|
15
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
16
|
+
import { existsSync } from 'node:fs';
|
|
17
|
+
import { join, relative, resolve } from 'node:path';
|
|
17
18
|
|
|
18
19
|
export async function* walkMdx(dir, baseDir = dir) {
|
|
19
20
|
let entries;
|
|
@@ -32,3 +33,68 @@ export async function* walkMdx(dir, baseDir = dir) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Read the consumer's `content.config.ts` (or `.mjs` / `.js`) and extract
|
|
39
|
+
* the `loader.base` path for the `chapters` content collection.
|
|
40
|
+
*
|
|
41
|
+
* v4.1.1 (closes #63): consumers in the multi-guide / multi-book pattern
|
|
42
|
+
* override the chapters dir to `src/content/<guide-slug>` rather than the
|
|
43
|
+
* Astro 5 default `src/content/chapters/`. Without this helper,
|
|
44
|
+
* `book-scaffold validate` + `book-scaffold build-labels` silently report
|
|
45
|
+
* 0 chapters because they walk the default path. This helper parses the
|
|
46
|
+
* consumer's config file and returns the actual base path so both scripts
|
|
47
|
+
* discover the consumer's chapter files.
|
|
48
|
+
*
|
|
49
|
+
* Strategy: regex-parse the source file (avoid runtime import; the file
|
|
50
|
+
* imports from `astro:content` / `astro/loaders` which don't resolve in
|
|
51
|
+
* plain Node). Matches both single- and double-quoted string literals;
|
|
52
|
+
* matches paths with or without the `./` prefix.
|
|
53
|
+
*
|
|
54
|
+
* Returns the resolved absolute path. Falls back to
|
|
55
|
+
* `${projectRoot}/src/content/chapters` when:
|
|
56
|
+
* - content.config.{ts,mjs,js} doesn't exist
|
|
57
|
+
* - the file exists but no `chapters` collection or `loader.base` found
|
|
58
|
+
* - the matched base path uses dynamic forms (variables, template literals)
|
|
59
|
+
* instead of a string literal
|
|
60
|
+
*
|
|
61
|
+
* Honors env override: BOOK_CHAPTERS_DIR (when set) wins over config parse.
|
|
62
|
+
*/
|
|
63
|
+
export async function readChaptersBase(projectRoot) {
|
|
64
|
+
const envOverride = process.env.BOOK_CHAPTERS_DIR;
|
|
65
|
+
if (envOverride) {
|
|
66
|
+
return resolve(projectRoot, envOverride);
|
|
67
|
+
}
|
|
68
|
+
const DEFAULT_BASE = resolve(projectRoot, 'src/content/chapters');
|
|
69
|
+
for (const ext of ['ts', 'mjs', 'js']) {
|
|
70
|
+
const configPath = join(projectRoot, `src/content.config.${ext}`);
|
|
71
|
+
if (!existsSync(configPath)) continue;
|
|
72
|
+
let source;
|
|
73
|
+
try {
|
|
74
|
+
source = await readFile(configPath, 'utf8');
|
|
75
|
+
} catch {
|
|
76
|
+
return DEFAULT_BASE;
|
|
77
|
+
}
|
|
78
|
+
// Look for a `chapters` collection's `loader.base` string. Permissive
|
|
79
|
+
// form: match the `chapters` identifier, then within the next 500
|
|
80
|
+
// chars find `base: 'string'` or `base: "string"`. NOT template
|
|
81
|
+
// literals (which use backticks and may contain ${} interpolation —
|
|
82
|
+
// those fall back to the default since the value is dynamic).
|
|
83
|
+
//
|
|
84
|
+
// Forms matched:
|
|
85
|
+
// - `const chapters = defineCollection({ loader: glob({ base: './foo' }) })`
|
|
86
|
+
// - `export const collections = { chapters: defineCollection({ loader: glob({ base: './foo' }) }) }`
|
|
87
|
+
// - any indentation / line break style
|
|
88
|
+
const re = /\bchapters\b[\s\S]{0,500}?\bbase\s*:\s*'([^']+)'|\bchapters\b[\s\S]{0,500}?\bbase\s*:\s*"([^"]+)"/;
|
|
89
|
+
const m = source.match(re);
|
|
90
|
+
const captured = m && (m[1] || m[2]);
|
|
91
|
+
if (captured) {
|
|
92
|
+
return resolve(projectRoot, captured);
|
|
93
|
+
}
|
|
94
|
+
// File exists but no override found — assume the consumer uses the
|
|
95
|
+
// scaffold's defineBookSchemas() default.
|
|
96
|
+
return DEFAULT_BASE;
|
|
97
|
+
}
|
|
98
|
+
// No content.config.{ts,mjs,js} at all — return the Astro 5 default.
|
|
99
|
+
return DEFAULT_BASE;
|
|
100
|
+
}
|
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;
|