concept-atlas-dense-explain 0.8.0 → 0.9.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/bin/cli.mjs +4 -2
- package/package.json +1 -1
- package/skill/SKILL.md +2 -1
- package/template/guides/atlas-guide.mdx +12 -3
- package/template/guides/scroll-guide.mdx +8 -0
- package/template/src/components/MDXComponents.jsx +32 -0
- package/template/src/model/validate-content.js +2 -0
- package/template/src/styles/core.css +60 -0
package/bin/cli.mjs
CHANGED
|
@@ -156,12 +156,13 @@ if (command === 'create' || command === 'new') {
|
|
|
156
156
|
<Children><ConceptRef id="first-branch" /><ConceptRef id="second-branch" /></Children>
|
|
157
157
|
</ConceptNode>
|
|
158
158
|
|
|
159
|
-
<ConceptNode id="first-branch" title="第一条关键分支" level="L1" parent="root-node">
|
|
159
|
+
<ConceptNode id="first-branch" title="第一条关键分支" level="L1" parent="root-node" summary="第一条关键分支解决什么问题,以及它为什么值得先理解。">
|
|
160
160
|
<Overview>解释第一个重要组成部分。</Overview>
|
|
161
161
|
<Example title="典型例子">填写一个具体例子,帮助读者验证理解。</Example>
|
|
162
|
+
<CodeBlock language="bash" title="验证方式" code="npm run validate" lineNumbers />
|
|
162
163
|
</ConceptNode>
|
|
163
164
|
|
|
164
|
-
<ConceptNode id="second-branch" title="第二条关键分支" level="L1" parent="root-node">
|
|
165
|
+
<ConceptNode id="second-branch" title="第二条关键分支" level="L1" parent="root-node" summary="第二条关键分支解决什么问题,以及它和第一条分支如何配合。">
|
|
165
166
|
<Overview>解释第二个重要组成部分。</Overview>
|
|
166
167
|
<Boundary>填写它的边界、代价或常见误区。</Boundary>
|
|
167
168
|
</ConceptNode>
|
|
@@ -182,6 +183,7 @@ if (command === 'create' || command === 'new') {
|
|
|
182
183
|
<ScrollSection title="解释关键机制">
|
|
183
184
|
<ScrollProse>按输入、步骤、输出的顺序解释过程,不要只罗列名词。</ScrollProse>
|
|
184
185
|
<Flow title="处理流程" steps={[{title:'输入',description:'原始条件或数据'},{title:'处理',description:'关键变化或判断'},{title:'输出',description:'结果与可观察证据'}]} />
|
|
186
|
+
<CodeBlock language="bash" title="实践命令" code="npm run validate" caption="通用代码块可以放在任意章节;需要逐行讲解时加 lineNumbers。" />
|
|
185
187
|
</ScrollSection>
|
|
186
188
|
|
|
187
189
|
<ScrollSection title="边界与实践">
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -38,7 +38,7 @@ Drive everything through the `concept-atlas-dense-explain` npm CLI. This skill i
|
|
|
38
38
|
|
|
39
39
|
## Component families
|
|
40
40
|
|
|
41
|
-
- Node semantics: `Overview`, `Definition`, `Mechanism`, `Implementation`, `Boundary`, `Example`, `Counterexample`, `Prerequisite`, `Input`, `Output`, `Glossary`
|
|
41
|
+
- Node semantics: `Overview`, `Definition`, `Mechanism`, `Implementation`, `CodeBlock`, `Boundary`, `Example`, `Counterexample`, `Prerequisite`, `Input`, `Output`, `Glossary`
|
|
42
42
|
- Argument and evidence: `Evidence`, `Invariant`, `FailureMode`, `Tradeoff`, `LearningObjectives`, `KeyQuestion`
|
|
43
43
|
- Information models: `Flow`, `Timeline`, `Compare`, `DecisionMatrix`, `FrameworkModel`, `MatrixModel`, `FormulaModel`, `PyramidModel`, `FunnelModel`
|
|
44
44
|
- Reading and layout: `Insight`, `Callout`, `Details`, `NoteGrid`, `Tabs`, `Columns`, `Stack`, `Grid`, `Split`, `ScrollGrid`, `ScrollPair`, `ScrollToc`
|
|
@@ -52,6 +52,7 @@ Drive everything through the `concept-atlas-dense-explain` npm CLI. This skill i
|
|
|
52
52
|
- Array props are arrays of objects: `Flow steps={[{title, description}]}`, `Timeline events={[{label, content}]}`, `MatrixModel cells={[{title, description, tone}]}`, `DecisionMatrix headers={[...]} rows={[[...]]}`, `Chart data={[{label, value}]}`, `References items={[{id, authors, year, title, url, source}]}`. The validator warns (`PROP_EXPECTS_ARRAY`) when an array prop gets a string or non-array.
|
|
53
53
|
- `Relation type` must be one of `prerequisite`, `causes`, `produces`, `uses`, `implements`, `contrasts`, `depends-on`, `exception-of`, `precedes`, and each `Relation` needs a `label`. Parent/child hierarchy is implicit (via `parent` and `Children`/`ConceptRef`) — do not express it with a `Relation`.
|
|
54
54
|
- **Math**: MDX parses `{ ... }` in children as expressions, so pass LaTeX with braces or backslashes through `formula`: `<Math formula="r_{\text{ann}} = (1 + r)^{12} - 1" />`, `<MathBlock formula="I(x) = -\log_2 p(x)" variables={[{symbol, description}]} />`. Brace-free children such as `<Math>\log_2 N</Math>` are fine. The validator warns (`MATH_CHILDREN_BRACES`).
|
|
55
|
+
- **CodeBlock**: a general code block usable anywhere; `Implementation` is the node-bound variant. Pass the code as a string via `code` (or as children) wrapped in a template literal so MDX does not read it as expressions: `<CodeBlock language="bash" title="..." lineNumbers>{`npm run validate`}</CodeBlock>`. `language` adds the badge, `title`/`caption` add labels, `lineNumbers` and `wrap` are booleans.
|
|
55
56
|
- **Chart**: `type` is `bar` | `line` | `pie`; use `data` for bar/pie and `labels` + `series={[{name, values}]}` for line. Charts follow theme colors.
|
|
56
57
|
- **Figure**: a relative `src` (`./assets/diagram.png`) is inlined as base64 at build time so the HTML stays standalone; `http(s)` URLs stay links. Always set `alt`; add `label` and `caption` for a numbered caption. A missing relative file warns (`ASSET_MISSING`) and shows a placeholder. Readers can click a figure to open it full-screen (zoom, drag, `Esc`) — mention it for diagram-heavy pages.
|
|
57
58
|
- **Figure size & cost**: inlining images is what makes a screenshot-heavy page large; a page with no heavy renderers otherwise lands near 250KB. When the user cares, compile with `--link-assets` to keep images as relative links (measured 1.51MB → 270KB); the output must then sit beside the MDX's `assets/`, and the CLI warns if `-o` points elsewhere — tell the user that trade-off instead of choosing silently.
|
|
@@ -114,9 +114,9 @@
|
|
|
114
114
|
<RelationMap title="可视化摘要" items={[{from:'MDX',type:'produces',to:'Graph',note:'生成关系图'},{from:'Node',type:'uses',to:'Mermaid',note:'展示局部流程'}]} />
|
|
115
115
|
</ConceptNode>
|
|
116
116
|
|
|
117
|
-
<ConceptNode id="extension-family" title="
|
|
118
|
-
<Definition>扩展组件把文本之外的证据接进页面:Math/MathBlock 渲染数学、Chart 绘制数据、Figure 承载配图、Cite/References 保留出处。</Definition>
|
|
119
|
-
<Children><ConceptRef id="math-demo" /><ConceptRef id="chart-demo" /><ConceptRef id="figure-demo" /><ConceptRef id="citation-demo" /></Children>
|
|
117
|
+
<ConceptNode id="extension-family" title="扩展能力:公式、图表、图片、代码与引用" level="L1" parent="showroom" summary="数学公式、数据图表、配图题注、代码块和参考文献五项能力,让讲解可以带上推导、数据、实现与出处。">
|
|
118
|
+
<Definition>扩展组件把文本之外的证据接进页面:Math/MathBlock 渲染数学、Chart 绘制数据、Figure 承载配图、CodeBlock 展示代码或命令、Cite/References 保留出处。</Definition>
|
|
119
|
+
<Children><ConceptRef id="math-demo" /><ConceptRef id="chart-demo" /><ConceptRef id="figure-demo" /><ConceptRef id="code-demo" /><ConceptRef id="citation-demo" /></Children>
|
|
120
120
|
</ConceptNode>
|
|
121
121
|
|
|
122
122
|
<ConceptNode id="math-demo" title="Math 与 MathBlock:把推导写进正文" level="L2" parent="extension-family" summary="Math 用于行内符号,MathBlock 用于独立公式并支持变量说明。">
|
|
@@ -138,6 +138,15 @@
|
|
|
138
138
|
<Boundary>大图会显著增大单文件 HTML;截图类内容建议控制尺寸。</Boundary>
|
|
139
139
|
</ConceptNode>
|
|
140
140
|
|
|
141
|
+
<ConceptNode id="code-demo" title="CodeBlock:把命令、配置或伪代码放进正文" level="L2" parent="extension-family" summary="与绑定节点的 Implementation 不同,CodeBlock 可以出现在任何位置,并支持标题、题注、换行和行号。">
|
|
142
|
+
<Definition>CodeBlock 通过 code(或子内容)接收字符串,language 决定语言标记,title 与 caption 提供说明,lineNumbers 和 wrap 控制逐行讲解与长行折行。</Definition>
|
|
143
|
+
<CodeBlock language="bash" title="校验与构建" caption="命令行、伪代码或配置都可以用它承载,不依附于某个概念节点。" lineNumbers>{`npm run validate
|
|
144
|
+
npm run sync
|
|
145
|
+
npm run build`}</CodeBlock>
|
|
146
|
+
<CodeBlock language="javascript" title="语义优先" wrap>{`const explain = concept => concept.mechanism ?? concept.definition ?? concept.overview;`}</CodeBlock>
|
|
147
|
+
<Boundary>代码里的反引号、花括号请放在模板字符串中传入,避免被 MDX 当作表达式解析。</Boundary>
|
|
148
|
+
</ConceptNode>
|
|
149
|
+
|
|
141
150
|
<ConceptNode id="citation-demo" title="Cite 与 References:让结论可以追溯" level="L2" parent="extension-family" summary="行内用 Cite 标记引用,文末用 References 列出完整出处,编号自动对应。">
|
|
142
151
|
<Definition>Cite 的 id 与 References 条目的 id 对应,渲染时显示条目在列表中的序号,并链接到该条目。</Definition>
|
|
143
152
|
<Overview>信息密度的价值在于可验证性<Cite id="shannon1948" />,而可验证性依赖清晰的出处<Cite id="tufte1983" />。</Overview>
|
|
@@ -42,6 +42,14 @@
|
|
|
42
42
|
<Chart title="四周留存趋势" type="line" labels={['第1周','第2周','第3周','第4周']} series={[{name:'留存率',values:[100,72,58,49]},{name:'活跃度',values:[100,64,52,40]}]} />
|
|
43
43
|
</ScrollSection>
|
|
44
44
|
|
|
45
|
+
<ScrollSection title="把命令与代码放进正文">
|
|
46
|
+
<ScrollProse>CodeBlock 承载命令行、配置或伪代码。它不依附于某个概念节点,可以出现在任何章节;需要逐行讲解时打开行号,长行过多时可以折行。</ScrollProse>
|
|
47
|
+
<CodeBlock language="bash" title="本地校验与预览" caption="CodeBlock 复用模板的代码表面,因此自动跟随当前皮肤与组件风格。" lineNumbers>{`npm run validate
|
|
48
|
+
npm run sync
|
|
49
|
+
npm run dev`}</CodeBlock>
|
|
50
|
+
<CodeBlock language="javascript" title="语义优先" wrap>{`const explain = concept => concept.mechanism ?? concept.definition ?? concept.overview;`}</CodeBlock>
|
|
51
|
+
</ScrollSection>
|
|
52
|
+
|
|
45
53
|
<ScrollSection title="组织证据,再收敛到行动">
|
|
46
54
|
<ScrollGrid columns="3">
|
|
47
55
|
<PyramidModel title="论证层级" levels={[{title:'结论',description:'读者需要带走的判断'},{title:'理由',description:'支撑判断的关键分组'},{title:'证据',description:'事实、数据与案例'}]} />
|
|
@@ -180,6 +180,38 @@ export function Implementation({ language = 'text', title = '实现代码', chil
|
|
|
180
180
|
}
|
|
181
181
|
Implementation.displayName = 'Implementation';
|
|
182
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Generic code block for any carrier. `Implementation` is bound to a node's
|
|
185
|
+
* implementation section; `CodeBlock` is meant for shell commands, config,
|
|
186
|
+
* output, prompts and pseudocode that live anywhere in a document.
|
|
187
|
+
* Pass the code as a string through `code` (or as children) so MDX parsing and
|
|
188
|
+
* the validator never confuse code with markup.
|
|
189
|
+
*/
|
|
190
|
+
export function CodeBlock({ code, language = 'text', title, caption, lineNumbers = false, wrap = false, children }) {
|
|
191
|
+
const raw = typeof code === 'string' ? code : childrenToText(children);
|
|
192
|
+
const text = typeof raw === 'string' ? raw.replace(/^\n+|\s+$/g, '') : '';
|
|
193
|
+
if (!text) return null;
|
|
194
|
+
const showLanguage = Boolean(language) && language !== 'text';
|
|
195
|
+
const showHead = Boolean(title) || showLanguage;
|
|
196
|
+
return (
|
|
197
|
+
<figure className="semantic-code" data-language={language}>
|
|
198
|
+
{showHead && (
|
|
199
|
+
<div className="semantic-code-head">
|
|
200
|
+
{title && <span className="semantic-code-title">{title}</span>}
|
|
201
|
+
{showLanguage && <span className="lang-badge">{language}</span>}
|
|
202
|
+
</div>
|
|
203
|
+
)}
|
|
204
|
+
<pre className={`code-block${lineNumbers ? ' code-block-numbered' : ''}${wrap ? ' code-block-wrap' : ''}`}>
|
|
205
|
+
{lineNumbers
|
|
206
|
+
? <code>{text.split('\n').map((line, index) => <span className="code-line" key={index}>{line}</span>)}</code>
|
|
207
|
+
: <code>{text}</code>}
|
|
208
|
+
</pre>
|
|
209
|
+
{caption && <figcaption className="semantic-code-caption">{caption}</figcaption>}
|
|
210
|
+
</figure>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
CodeBlock.displayName = 'CodeBlock';
|
|
214
|
+
|
|
183
215
|
export function Boundary({ title = '边界与约束', children }) {
|
|
184
216
|
return (
|
|
185
217
|
<div className="semantic-boundary">
|
|
@@ -27,6 +27,7 @@ export const KNOWN_COMPONENTS = [
|
|
|
27
27
|
'Definition',
|
|
28
28
|
'Mechanism',
|
|
29
29
|
'Implementation',
|
|
30
|
+
'CodeBlock',
|
|
30
31
|
'Boundary',
|
|
31
32
|
'Example',
|
|
32
33
|
'Counterexample',
|
|
@@ -110,6 +111,7 @@ const CORE_CONTENT_COMPONENTS = new Set([
|
|
|
110
111
|
'Definition',
|
|
111
112
|
'Mechanism',
|
|
112
113
|
'Implementation',
|
|
114
|
+
'CodeBlock',
|
|
113
115
|
'Boundary',
|
|
114
116
|
'Example',
|
|
115
117
|
'Counterexample',
|
|
@@ -1033,6 +1033,66 @@ button.flow-box {
|
|
|
1033
1033
|
box-shadow: var(--shadow-inset);
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
|
+
/* Generic CodeBlock. It reuses `.code-block` so every skin and style pack
|
|
1037
|
+
keeps one code surface, and only adds an optional title bar, wrap and
|
|
1038
|
+
line numbers on top. */
|
|
1039
|
+
.semantic-code {
|
|
1040
|
+
margin: 0;
|
|
1041
|
+
display: flex;
|
|
1042
|
+
flex-direction: column;
|
|
1043
|
+
gap: 8px;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
.semantic-code-head {
|
|
1047
|
+
display: flex;
|
|
1048
|
+
align-items: center;
|
|
1049
|
+
justify-content: space-between;
|
|
1050
|
+
gap: 10px;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.semantic-code-title {
|
|
1054
|
+
font-family: var(--font-heading);
|
|
1055
|
+
font-weight: 700;
|
|
1056
|
+
font-size: 13px;
|
|
1057
|
+
color: var(--text-secondary);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.semantic-code-caption {
|
|
1061
|
+
font-size: 12px;
|
|
1062
|
+
color: var(--text-muted);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.code-block-wrap {
|
|
1066
|
+
white-space: pre-wrap;
|
|
1067
|
+
overflow-wrap: anywhere;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.code-block-numbered {
|
|
1071
|
+
counter-reset: code-line;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.code-block-numbered code {
|
|
1075
|
+
display: block;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.code-block-numbered .code-line {
|
|
1079
|
+
position: relative;
|
|
1080
|
+
display: block;
|
|
1081
|
+
min-height: 1.6em;
|
|
1082
|
+
padding-left: 3em;
|
|
1083
|
+
counter-increment: code-line;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.code-block-numbered .code-line::before {
|
|
1087
|
+
content: counter(code-line);
|
|
1088
|
+
position: absolute;
|
|
1089
|
+
left: 0;
|
|
1090
|
+
width: 2em;
|
|
1091
|
+
text-align: right;
|
|
1092
|
+
color: rgba(148, 163, 184, 0.55);
|
|
1093
|
+
user-select: none;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1036
1096
|
.example-item, .counterexample-item {
|
|
1037
1097
|
margin-top: 12px;
|
|
1038
1098
|
padding: 14px 18px;
|