concept-atlas-dense-explain 2.0.0 → 3.0.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.
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import { useEffect, useRef, useState } from 'react';
2
2
  import { Check, Palette } from 'lucide-react';
3
3
  import { SKINS, COMPONENT_STYLES } from '../model/skins.js';
4
4
 
@@ -24,10 +24,10 @@ export function SkinPicker({ skin, style, onSkinChange, onStyleChange }) {
24
24
 
25
25
  useEffect(() => {
26
26
  if (!open) return undefined;
27
- const handlePointer = (event) => {
27
+ const handlePointer = event => {
28
28
  if (!rootRef.current?.contains(event.target)) setOpen(false);
29
29
  };
30
- const handleKey = (event) => {
30
+ const handleKey = event => {
31
31
  if (event.key !== 'Escape') return;
32
32
  setOpen(false);
33
33
  // Stop Escape from also reaching the window-level handler in App.jsx,
@@ -63,11 +63,16 @@ export function SkinPicker({ skin, style, onSkinChange, onStyleChange }) {
63
63
  key={item.id}
64
64
  selected={item.id === skin}
65
65
  label={`配色 ${item.label}`}
66
- onClick={() => { onSkinChange(item.id); setOpen(false); }}
66
+ onClick={() => {
67
+ onSkinChange(item.id);
68
+ setOpen(false);
69
+ }}
67
70
  >
68
71
  <span
69
72
  className="skin-swatch"
70
- style={{ background: `linear-gradient(135deg, ${item.swatch.dark} 0 42%, ${item.swatch.accent} 42% 58%, ${item.swatch.light} 58% 100%)` }}
73
+ style={{
74
+ background: `linear-gradient(135deg, ${item.swatch.dark} 0 42%, ${item.swatch.accent} 42% 58%, ${item.swatch.light} 58% 100%)`
75
+ }}
71
76
  aria-hidden="true"
72
77
  />
73
78
  <span className="skin-option-label">{item.label}</span>
@@ -79,7 +84,10 @@ export function SkinPicker({ skin, style, onSkinChange, onStyleChange }) {
79
84
  key={item.id}
80
85
  selected={item.id === style}
81
86
  label={`组件风格 ${item.label}`}
82
- onClick={() => { onStyleChange(item.id); setOpen(false); }}
87
+ onClick={() => {
88
+ onStyleChange(item.id);
89
+ setOpen(false);
90
+ }}
83
91
  >
84
92
  <span className={`style-glyph style-glyph-${item.id}`} aria-hidden="true" />
85
93
  <span className="skin-option-label">{item.label}</span>
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { RELATION_TYPES, LEVEL_DEFS } from './relation-types.js';
3
2
  import { NODE_KIND_SET, normalizeKind } from './node-kinds.js';
4
3
 
@@ -14,7 +13,7 @@ export function createConceptGraphState() {
14
13
  rootId: ''
15
14
  },
16
15
  nodes: new Map(), // id -> NodeObject
17
- relations: [], // Array<{ from, to, type, label, description }>
16
+ relations: [] // Array<{ from, to, type, label, description }>
18
17
  };
19
18
  }
20
19
 
@@ -30,7 +29,7 @@ export function normalizeNode(raw) {
30
29
  kind: normalizeKind(raw.kind),
31
30
  parent: raw.parent || null,
32
31
  children: Array.isArray(raw.children) ? raw.children : [],
33
-
32
+
34
33
  // Semantic Content Sections
35
34
  summary: raw.summary || '',
36
35
  overview: raw.overview || null,
@@ -54,7 +53,7 @@ export function normalizeNode(raw) {
54
53
  evidence: Array.isArray(raw.evidence) ? raw.evidence : [],
55
54
  invariants: Array.isArray(raw.invariants) ? raw.invariants : [],
56
55
  failureModes: Array.isArray(raw.failureModes) ? raw.failureModes : [],
57
- tradeoffs: Array.isArray(raw.tradeoffs) ? raw.tradeoffs : [],
56
+ tradeoffs: Array.isArray(raw.tradeoffs) ? raw.tradeoffs : []
58
57
  };
59
58
  }
60
59
 
@@ -73,7 +72,8 @@ export function buildGraphModel(rawGraph) {
73
72
  if (n.kind && !NODE_KIND_SET.has(n.kind)) {
74
73
  diagnostics.push({ level: 'warning', code: 'UNKNOWN_KIND', nodeId: node.id, kind: n.kind });
75
74
  }
76
- if (nodes.has(node.id)) diagnostics.push({ level: 'error', code: 'DUPLICATE_NODE_ID', nodeId: node.id });
75
+ if (nodes.has(node.id))
76
+ diagnostics.push({ level: 'error', code: 'DUPLICATE_NODE_ID', nodeId: node.id });
77
77
  nodes.set(node.id, node);
78
78
  });
79
79
 
@@ -95,11 +95,28 @@ export function buildGraphModel(rawGraph) {
95
95
  if (!childNode.parent) {
96
96
  childNode.parent = node.id;
97
97
  }
98
- }
99
- else diagnostics.push({ level: 'warning', code: 'MISSING_CHILD', nodeId: node.id, targetId: childId });
98
+ } else
99
+ diagnostics.push({
100
+ level: 'warning',
101
+ code: 'MISSING_CHILD',
102
+ nodeId: node.id,
103
+ targetId: childId
104
+ });
100
105
  });
101
- if (node.parent && !nodes.has(node.parent)) diagnostics.push({ level: 'warning', code: 'ORPHAN_NODE', nodeId: node.id, targetId: node.parent });
102
- if (!LEVEL_DEFS[node.level]) diagnostics.push({ level: 'warning', code: 'UNKNOWN_LEVEL', nodeId: node.id, level: node.level });
106
+ if (node.parent && !nodes.has(node.parent))
107
+ diagnostics.push({
108
+ level: 'warning',
109
+ code: 'ORPHAN_NODE',
110
+ nodeId: node.id,
111
+ targetId: node.parent
112
+ });
113
+ if (!LEVEL_DEFS[node.level])
114
+ diagnostics.push({
115
+ level: 'warning',
116
+ code: 'UNKNOWN_LEVEL',
117
+ nodeId: node.id,
118
+ nodeLevel: node.level
119
+ });
103
120
  });
104
121
 
105
122
  // Filter valid relations
@@ -169,9 +186,7 @@ export function getSiblingNodes(nodes, nodeId) {
169
186
  }
170
187
  const parent = nodes.get(current.parent);
171
188
  if (!parent) return [];
172
- return parent.children
173
- .filter(id => id !== nodeId && nodes.has(id))
174
- .map(id => nodes.get(id));
189
+ return parent.children.filter(id => id !== nodeId && nodes.has(id)).map(id => nodes.get(id));
175
190
  }
176
191
 
177
192
  /**
@@ -15,43 +15,43 @@ export const NODE_KINDS = {
15
15
  system: {
16
16
  label: '系统',
17
17
  description: '整体系统、产品或问题域的全貌',
18
- tone: 'var(--kind-system)',
18
+ tone: 'var(--kind-system)'
19
19
  },
20
20
  stage: {
21
21
  label: '阶段',
22
22
  description: '生命周期阶段、处理步骤或子系统',
23
- tone: 'var(--kind-stage)',
23
+ tone: 'var(--kind-stage)'
24
24
  },
25
25
  mechanism: {
26
26
  label: '机制',
27
27
  description: '可解释、可验证的工作机制',
28
- tone: 'var(--kind-mechanism)',
28
+ tone: 'var(--kind-mechanism)'
29
29
  },
30
30
  artifact: {
31
31
  label: '产物',
32
32
  description: '阶段产出的实体、数据或文件',
33
- tone: 'var(--kind-artifact)',
33
+ tone: 'var(--kind-artifact)'
34
34
  },
35
35
  failure: {
36
36
  label: '故障',
37
37
  description: '失败模式、异常与边界情况',
38
- tone: 'var(--kind-failure)',
38
+ tone: 'var(--kind-failure)'
39
39
  },
40
40
  tool: {
41
41
  label: '工具',
42
42
  description: '使用的工具、库或外部依赖',
43
- tone: 'var(--kind-tool)',
43
+ tone: 'var(--kind-tool)'
44
44
  },
45
45
  boundary: {
46
46
  label: '边界',
47
47
  description: '约束、前提、限制与非目标',
48
- tone: 'var(--kind-boundary)',
48
+ tone: 'var(--kind-boundary)'
49
49
  },
50
50
  decision: {
51
51
  label: '决策',
52
52
  description: '设计取舍与选择点',
53
- tone: 'var(--kind-decision)',
54
- },
53
+ tone: 'var(--kind-decision)'
54
+ }
55
55
  };
56
56
 
57
57
  export const NODE_KIND_NAMES = Object.keys(NODE_KINDS);
@@ -1,4 +1,4 @@
1
- import React, { Children, isValidElement } from 'react';
1
+ import { Children, isValidElement } from 'react';
2
2
  import { KNOWN_COMPONENT_SET } from './validate-content.js';
3
3
 
4
4
  /**
@@ -16,7 +16,7 @@ export function extractConceptData(explainPageElement) {
16
16
  summary: explainPageElement.props.summary || '',
17
17
  rootId: null,
18
18
  layout: explainPageElement.props.layout || 'editorial',
19
- density: explainPageElement.props.density || 'reading',
19
+ density: explainPageElement.props.density || 'reading'
20
20
  },
21
21
  nodes: [],
22
22
  relations: []
@@ -124,7 +124,7 @@ function parseConceptNode(nodeElement) {
124
124
  evidence: [],
125
125
  invariants: [],
126
126
  failureModes: [],
127
- tradeoffs: [],
127
+ tradeoffs: []
128
128
  };
129
129
 
130
130
  Children.forEach(props.children, child => {
@@ -207,7 +207,7 @@ function parseConceptNode(nodeElement) {
207
207
  // original element in customSections so existing rendering is unchanged.
208
208
  case 'LearningObjectives':
209
209
  node.learningObjectives.push(
210
- ...(Array.isArray(child.props.items) ? child.props.items.filter(Boolean) : []),
210
+ ...(Array.isArray(child.props.items) ? child.props.items.filter(Boolean) : [])
211
211
  );
212
212
  node.customSections.push(child);
213
213
  break;
@@ -219,14 +219,14 @@ function parseConceptNode(nodeElement) {
219
219
  node.evidence.push({
220
220
  command: child.props.command || '',
221
221
  observes: child.props.observes || '',
222
- content: child.props.children,
222
+ content: child.props.children
223
223
  });
224
224
  node.customSections.push(child);
225
225
  break;
226
226
  case 'Invariant':
227
227
  node.invariants.push({
228
228
  title: child.props.title || '不变量',
229
- content: child.props.children,
229
+ content: child.props.children
230
230
  });
231
231
  node.customSections.push(child);
232
232
  break;
@@ -236,14 +236,14 @@ function parseConceptNode(nodeElement) {
236
236
  cause: child.props.cause || '',
237
237
  evidence: child.props.evidence || '',
238
238
  remedy: child.props.remedy || '',
239
- content: child.props.children,
239
+ content: child.props.children
240
240
  });
241
241
  node.customSections.push(child);
242
242
  break;
243
243
  case 'Tradeoff':
244
244
  node.tradeoffs.push({
245
245
  title: child.props.title || '工程权衡',
246
- options: Array.isArray(child.props.options) ? child.props.options : [],
246
+ options: Array.isArray(child.props.options) ? child.props.options : []
247
247
  });
248
248
  node.customSections.push(child);
249
249
  break;
@@ -7,7 +7,7 @@ export const RELATION_TYPES = {
7
7
  hasArrow: true,
8
8
  isTree: true
9
9
  },
10
- 'prerequisite': {
10
+ prerequisite: {
11
11
  label: '前置知识',
12
12
  description: '理解当前概念所需的前置基础',
13
13
  color: 'var(--rel-prerequisite)',
@@ -15,7 +15,7 @@ export const RELATION_TYPES = {
15
15
  hasArrow: true,
16
16
  isTree: false
17
17
  },
18
- 'causes': {
18
+ causes: {
19
19
  label: '因果推动',
20
20
  description: '引起或触发后续状态变化',
21
21
  color: 'var(--rel-causes)',
@@ -23,7 +23,7 @@ export const RELATION_TYPES = {
23
23
  hasArrow: true,
24
24
  isTree: false
25
25
  },
26
- 'produces': {
26
+ produces: {
27
27
  label: '产出生成',
28
28
  description: '阶段处理后产出的产物或实体',
29
29
  color: 'var(--rel-produces)',
@@ -31,7 +31,7 @@ export const RELATION_TYPES = {
31
31
  hasArrow: true,
32
32
  isTree: false
33
33
  },
34
- 'uses': {
34
+ uses: {
35
35
  label: '消费使用',
36
36
  description: '调用或引用其他概念与数据',
37
37
  color: 'var(--rel-uses)',
@@ -39,7 +39,7 @@ export const RELATION_TYPES = {
39
39
  hasArrow: true,
40
40
  isTree: false
41
41
  },
42
- 'implements': {
42
+ implements: {
43
43
  label: '实现关系',
44
44
  description: '具体机制或代码实现特定抽象',
45
45
  color: 'var(--rel-implements)',
@@ -47,7 +47,7 @@ export const RELATION_TYPES = {
47
47
  hasArrow: true,
48
48
  isTree: false
49
49
  },
50
- 'contrasts': {
50
+ contrasts: {
51
51
  label: '对比关系',
52
52
  description: '概念间的异同对照或对立维度',
53
53
  color: 'var(--rel-contrasts)',
@@ -71,7 +71,7 @@ export const RELATION_TYPES = {
71
71
  hasArrow: true,
72
72
  isTree: false
73
73
  },
74
- 'precedes': {
74
+ precedes: {
75
75
  label: '时序先后',
76
76
  description: '时间或处理流水线的前后相继',
77
77
  color: 'var(--rel-precedes)',
@@ -82,9 +82,34 @@ export const RELATION_TYPES = {
82
82
  };
83
83
 
84
84
  export const LEVEL_DEFS = {
85
- L0: { name: '全局概览', tag: 'L0 · 全局概览', desc: '系统全貌与全局定位', color: 'var(--level-l0)' },
86
- L1: { name: '主要阶段 / 子系统', tag: 'L1 · 子系统', desc: '主要生命周期阶段或子系统划分', color: 'var(--level-l1)' },
87
- L2: { name: '局部机制', tag: 'L2 · 局部机制', desc: '具体工作机制与逻辑流动', color: 'var(--level-l2)' },
88
- L3: { name: '实现细节', tag: 'L3 · 实现细节', desc: '算法、数据结构或代码实现', color: 'var(--level-l3)' },
89
- L4: { name: '边界与反例', tag: 'L4 · 边界反例', desc: '边界情况、异常分支与典型反例', color: 'var(--level-l4)' }
85
+ L0: {
86
+ name: '全局概览',
87
+ tag: 'L0 · 全局概览',
88
+ desc: '系统全貌与全局定位',
89
+ color: 'var(--level-l0)'
90
+ },
91
+ L1: {
92
+ name: '主要阶段 / 子系统',
93
+ tag: 'L1 · 子系统',
94
+ desc: '主要生命周期阶段或子系统划分',
95
+ color: 'var(--level-l1)'
96
+ },
97
+ L2: {
98
+ name: '局部机制',
99
+ tag: 'L2 · 局部机制',
100
+ desc: '具体工作机制与逻辑流动',
101
+ color: 'var(--level-l2)'
102
+ },
103
+ L3: {
104
+ name: '实现细节',
105
+ tag: 'L3 · 实现细节',
106
+ desc: '算法、数据结构或代码实现',
107
+ color: 'var(--level-l3)'
108
+ },
109
+ L4: {
110
+ name: '边界与反例',
111
+ tag: 'L4 · 边界反例',
112
+ desc: '边界情况、异常分支与典型反例',
113
+ color: 'var(--level-l4)'
114
+ }
90
115
  };