concept-atlas-dense-explain 0.2.0 → 0.2.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/package.json +12 -3
- package/skill/SKILL.md +84 -59
- package/skill/assets/template/content/compile-runtime.mdx +158 -158
- package/skill/assets/template/index.html +16 -16
- package/skill/assets/template/package.json +20 -20
- package/skill/assets/template/scripts/build.mjs +37 -37
- package/skill/assets/template/scripts/clean-temp.mjs +27 -27
- package/skill/assets/template/src/app/App.jsx +239 -239
- package/skill/assets/template/src/components/MDXComponents.jsx +503 -477
- package/skill/assets/template/src/components/index.js +1 -1
- package/skill/assets/template/src/main.jsx +16 -16
- package/skill/assets/template/src/model/concept-schema.js +169 -169
- package/skill/assets/template/src/model/normalize-content.js +241 -236
- package/skill/assets/template/src/model/relation-types.js +90 -90
- package/skill/assets/template/src/styles/concept-explain.css +290 -9
- package/skill/assets/template/src/views/NodeExplorer.jsx +59 -20
- package/skill/assets/template/src/views/RelationGraph.jsx +16 -1
- package/skill/assets/template/vite.config.js +21 -21
- package/skill/references/components.md +74 -64
- package/skill/references/prompting.md +77 -77
|
@@ -1,479 +1,505 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import mermaid from 'mermaid';
|
|
3
|
-
|
|
4
|
-
let mermaidReady = false;
|
|
5
|
-
|
|
6
|
-
function ensureMermaid() {
|
|
7
|
-
if (mermaidReady) return;
|
|
8
|
-
mermaid.initialize({
|
|
9
|
-
startOnLoad: false,
|
|
10
|
-
securityLevel: 'loose',
|
|
11
|
-
theme: 'base',
|
|
12
|
-
look: 'handDrawn',
|
|
13
|
-
themeVariables: {
|
|
14
|
-
primaryColor: '#172554',
|
|
15
|
-
primaryTextColor: '#e0f2fe',
|
|
16
|
-
primaryBorderColor: '#38bdf8',
|
|
17
|
-
lineColor: '#64748b',
|
|
18
|
-
secondaryColor: '#172554',
|
|
19
|
-
tertiaryColor: '#0f172a',
|
|
20
|
-
fontFamily: 'Plus Jakarta Sans, sans-serif',
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
mermaidReady = true;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Data Layer Components
|
|
27
|
-
export function ExplainPage({ id, title, summary, layout = 'editorial', density = 'reading', children }) {
|
|
28
|
-
return <div data-component="ExplainPage" data-id={id} data-title={title} data-summary={summary} data-layout={layout} data-density={density}>{children}</div>;
|
|
29
|
-
}
|
|
30
|
-
ExplainPage.displayName = 'ExplainPage';
|
|
31
|
-
|
|
32
|
-
export function ConceptGraph({ root, children }) {
|
|
33
|
-
return <div data-component="ConceptGraph" data-root={root}>{children}</div>;
|
|
34
|
-
}
|
|
35
|
-
ConceptGraph.displayName = 'ConceptGraph';
|
|
36
|
-
|
|
37
|
-
export function ConceptNode({ id, title, level = 'L2', parent = null, children, input, output, summary }) {
|
|
38
|
-
return <div data-component="ConceptNode" data-id={id} data-title={title} data-level={level} data-parent={parent}>{children}</div>;
|
|
39
|
-
}
|
|
40
|
-
ConceptNode.displayName = 'ConceptNode';
|
|
41
|
-
|
|
42
|
-
export function ConceptRef({ id }) {
|
|
43
|
-
return <span data-component="ConceptRef" data-id={id} />;
|
|
44
|
-
}
|
|
45
|
-
ConceptRef.displayName = 'ConceptRef';
|
|
46
|
-
|
|
47
|
-
export function Children({ children }) {
|
|
48
|
-
return <div data-component="Children">{children}</div>;
|
|
49
|
-
}
|
|
50
|
-
Children.displayName = 'Children';
|
|
51
|
-
|
|
52
|
-
export function Relation({ from, to, type = 'depends-on', label, description, children }) {
|
|
53
|
-
return <div data-component="Relation" data-from={from} data-to={to} data-type={type} data-label={label}>{children || description}</div>;
|
|
54
|
-
}
|
|
55
|
-
Relation.displayName = 'Relation';
|
|
56
|
-
|
|
57
|
-
// Content Layer Components
|
|
58
|
-
export function Overview({ children }) {
|
|
59
|
-
return <div className="semantic-overview">{children}</div>;
|
|
60
|
-
}
|
|
61
|
-
Overview.displayName = 'Overview';
|
|
62
|
-
|
|
63
|
-
export function Definition({ children }) {
|
|
64
|
-
return <div className="semantic-definition">{children}</div>;
|
|
65
|
-
}
|
|
66
|
-
Definition.displayName = 'Definition';
|
|
67
|
-
|
|
68
|
-
export function Mechanism({ children }) {
|
|
69
|
-
return <div className="semantic-mechanism">{children}</div>;
|
|
70
|
-
}
|
|
71
|
-
Mechanism.displayName = 'Mechanism';
|
|
72
|
-
|
|
73
|
-
export function Implementation({ language = 'text', title = '实现代码', children }) {
|
|
74
|
-
return (
|
|
75
|
-
<div className="semantic-implementation" data-language={language}>
|
|
76
|
-
{title && <div className="impl-header">{title} <span className="lang-badge">{language}</span></div>}
|
|
77
|
-
<pre><code>{typeof children === 'string' ? children.trim() : children}</code></pre>
|
|
78
|
-
</div>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
Implementation.displayName = 'Implementation';
|
|
82
|
-
|
|
83
|
-
export function Boundary({ title = '边界与约束', children }) {
|
|
84
|
-
return (
|
|
85
|
-
<div className="semantic-boundary">
|
|
86
|
-
<div className="semantic-tag">⚠ {title}</div>
|
|
87
|
-
<div className="boundary-body">{children}</div>
|
|
88
|
-
</div>
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
Boundary.displayName = 'Boundary';
|
|
92
|
-
|
|
93
|
-
export function Example({ title = '典型示例', children }) {
|
|
94
|
-
return (
|
|
95
|
-
<div className="semantic-example">
|
|
96
|
-
<div className="semantic-tag">✦ {title}</div>
|
|
97
|
-
<div className="example-body">{children}</div>
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
Example.displayName = 'Example';
|
|
102
|
-
|
|
103
|
-
export function Counterexample({ title = '反例与误区', children }) {
|
|
104
|
-
return (
|
|
105
|
-
<div className="semantic-counterexample">
|
|
106
|
-
<div className="semantic-tag">✕ {title}</div>
|
|
107
|
-
<div className="counter-body">{children}</div>
|
|
108
|
-
</div>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
Counterexample.displayName = 'Counterexample';
|
|
112
|
-
|
|
113
|
-
export function Prerequisite({ children }) {
|
|
114
|
-
return <div className="semantic-prerequisite">{children}</div>;
|
|
115
|
-
}
|
|
116
|
-
Prerequisite.displayName = 'Prerequisite';
|
|
117
|
-
|
|
118
|
-
export function Input({ children }) {
|
|
119
|
-
return <div className="semantic-input">{children}</div>;
|
|
120
|
-
}
|
|
121
|
-
Input.displayName = 'Input';
|
|
122
|
-
|
|
123
|
-
export function Output({ children }) {
|
|
124
|
-
return <div className="semantic-output">{children}</div>;
|
|
125
|
-
}
|
|
126
|
-
Output.displayName = 'Output';
|
|
127
|
-
|
|
128
|
-
export function Glossary({ term, children }) {
|
|
129
|
-
return (
|
|
130
|
-
<div className="semantic-glossary-item">
|
|
131
|
-
<span className="term">{term}</span>: <span className="def">{children}</span>
|
|
132
|
-
</div>
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
Glossary.displayName = 'Glossary';
|
|
136
|
-
|
|
137
|
-
// Presentation Semantic Layer Components (for structuring inside nodes without direct CSS)
|
|
138
|
-
export function Compare({ items = [], children }) {
|
|
139
|
-
if (items && items.length > 0) {
|
|
140
|
-
return (
|
|
141
|
-
<div className="semantic-compare-table">
|
|
142
|
-
<table className="compare-grid">
|
|
143
|
-
<thead>
|
|
144
|
-
<tr>
|
|
145
|
-
<th>维度 / 对象</th>
|
|
146
|
-
{items.map((it, idx) => (
|
|
147
|
-
<th key={idx}>{it.label || it.title || `方案 ${idx + 1}`}</th>
|
|
148
|
-
))}
|
|
149
|
-
</tr>
|
|
150
|
-
</thead>
|
|
151
|
-
<tbody>
|
|
152
|
-
{items[0]?.rows ? (
|
|
153
|
-
items[0].rows.map((rowKey, rIdx) => (
|
|
154
|
-
<tr key={rIdx}>
|
|
155
|
-
<td className="compare-row-label">{rowKey}</td>
|
|
156
|
-
{items.map((it, idx) => (
|
|
157
|
-
<td key={idx}>{it.values?.[rIdx] || '-'}</td>
|
|
158
|
-
))}
|
|
159
|
-
</tr>
|
|
160
|
-
))
|
|
161
|
-
) : null}
|
|
162
|
-
</tbody>
|
|
163
|
-
</table>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
return <div className="semantic-compare-block">{children}</div>;
|
|
168
|
-
}
|
|
169
|
-
Compare.displayName = 'Compare';
|
|
170
|
-
|
|
171
|
-
export function DecisionMatrix({ title = '权衡矩阵', headers = [], rows = [], children }) {
|
|
172
|
-
if (headers.length > 0 && rows.length > 0) {
|
|
173
|
-
return (
|
|
174
|
-
<div className="semantic-decision-matrix">
|
|
175
|
-
{title && <div className="matrix-title">⚖ {title}</div>}
|
|
176
|
-
<table className="matrix-table">
|
|
177
|
-
<thead>
|
|
178
|
-
<tr>
|
|
179
|
-
{headers.map((h, i) => <th key={i}>{h}</th>)}
|
|
180
|
-
</tr>
|
|
181
|
-
</thead>
|
|
182
|
-
<tbody>
|
|
183
|
-
{rows.map((row, i) => (
|
|
184
|
-
<tr key={i}>
|
|
185
|
-
{row.map((cell, j) => <td key={j}>{cell}</td>)}
|
|
186
|
-
</tr>
|
|
187
|
-
))}
|
|
188
|
-
</tbody>
|
|
189
|
-
</table>
|
|
190
|
-
</div>
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
return <div className="semantic-decision-matrix">{children}</div>;
|
|
194
|
-
}
|
|
195
|
-
DecisionMatrix.displayName = 'DecisionMatrix';
|
|
196
|
-
|
|
197
|
-
export function Flow({ steps = [], children }) {
|
|
198
|
-
if (steps.length > 0) {
|
|
199
|
-
return (
|
|
200
|
-
<div className="semantic-flow-steps">
|
|
201
|
-
{steps.map((step, idx) => (
|
|
202
|
-
<div key={idx} className="flow-step">
|
|
203
|
-
<span className="step-num">{idx + 1}</span>
|
|
204
|
-
<span className="step-text">{step}</span>
|
|
205
|
-
{idx < steps.length - 1 && <span className="step-arrow">→</span>}
|
|
206
|
-
</div>
|
|
207
|
-
))}
|
|
208
|
-
</div>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
return <div className="semantic-flow-block">{children}</div>;
|
|
212
|
-
}
|
|
213
|
-
Flow.displayName = 'Flow';
|
|
214
|
-
|
|
215
|
-
export function Timeline({ events = [], children }) {
|
|
216
|
-
if (events.length > 0) {
|
|
217
|
-
return (
|
|
218
|
-
<div className="semantic-timeline">
|
|
219
|
-
{events.map((ev, i) => (
|
|
220
|
-
<div key={i} className="timeline-item">
|
|
221
|
-
<div className="timeline-point" />
|
|
222
|
-
<div className="timeline-label">{ev.label || ev.time}</div>
|
|
223
|
-
<div className="timeline-content">{ev.content || ev.desc}</div>
|
|
224
|
-
</div>
|
|
225
|
-
))}
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
return <div className="semantic-timeline">{children}</div>;
|
|
230
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import mermaid from 'mermaid';
|
|
3
|
+
|
|
4
|
+
let mermaidReady = false;
|
|
5
|
+
|
|
6
|
+
function ensureMermaid() {
|
|
7
|
+
if (mermaidReady) return;
|
|
8
|
+
mermaid.initialize({
|
|
9
|
+
startOnLoad: false,
|
|
10
|
+
securityLevel: 'loose',
|
|
11
|
+
theme: 'base',
|
|
12
|
+
look: 'handDrawn',
|
|
13
|
+
themeVariables: {
|
|
14
|
+
primaryColor: '#172554',
|
|
15
|
+
primaryTextColor: '#e0f2fe',
|
|
16
|
+
primaryBorderColor: '#38bdf8',
|
|
17
|
+
lineColor: '#64748b',
|
|
18
|
+
secondaryColor: '#172554',
|
|
19
|
+
tertiaryColor: '#0f172a',
|
|
20
|
+
fontFamily: 'Plus Jakarta Sans, sans-serif',
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
mermaidReady = true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Data Layer Components
|
|
27
|
+
export function ExplainPage({ id, title, summary, layout = 'editorial', density = 'reading', children }) {
|
|
28
|
+
return <div data-component="ExplainPage" data-id={id} data-title={title} data-summary={summary} data-layout={layout} data-density={density}>{children}</div>;
|
|
29
|
+
}
|
|
30
|
+
ExplainPage.displayName = 'ExplainPage';
|
|
31
|
+
|
|
32
|
+
export function ConceptGraph({ root, children }) {
|
|
33
|
+
return <div data-component="ConceptGraph" data-root={root}>{children}</div>;
|
|
34
|
+
}
|
|
35
|
+
ConceptGraph.displayName = 'ConceptGraph';
|
|
36
|
+
|
|
37
|
+
export function ConceptNode({ id, title, level = 'L2', parent = null, children, input, output, summary }) {
|
|
38
|
+
return <div data-component="ConceptNode" data-id={id} data-title={title} data-level={level} data-parent={parent}>{children}</div>;
|
|
39
|
+
}
|
|
40
|
+
ConceptNode.displayName = 'ConceptNode';
|
|
41
|
+
|
|
42
|
+
export function ConceptRef({ id }) {
|
|
43
|
+
return <span data-component="ConceptRef" data-id={id} />;
|
|
44
|
+
}
|
|
45
|
+
ConceptRef.displayName = 'ConceptRef';
|
|
46
|
+
|
|
47
|
+
export function Children({ children }) {
|
|
48
|
+
return <div data-component="Children">{children}</div>;
|
|
49
|
+
}
|
|
50
|
+
Children.displayName = 'Children';
|
|
51
|
+
|
|
52
|
+
export function Relation({ from, to, type = 'depends-on', label, description, children }) {
|
|
53
|
+
return <div data-component="Relation" data-from={from} data-to={to} data-type={type} data-label={label}>{children || description}</div>;
|
|
54
|
+
}
|
|
55
|
+
Relation.displayName = 'Relation';
|
|
56
|
+
|
|
57
|
+
// Content Layer Components
|
|
58
|
+
export function Overview({ children }) {
|
|
59
|
+
return <div className="semantic-overview">{children}</div>;
|
|
60
|
+
}
|
|
61
|
+
Overview.displayName = 'Overview';
|
|
62
|
+
|
|
63
|
+
export function Definition({ children }) {
|
|
64
|
+
return <div className="semantic-definition">{children}</div>;
|
|
65
|
+
}
|
|
66
|
+
Definition.displayName = 'Definition';
|
|
67
|
+
|
|
68
|
+
export function Mechanism({ children }) {
|
|
69
|
+
return <div className="semantic-mechanism">{children}</div>;
|
|
70
|
+
}
|
|
71
|
+
Mechanism.displayName = 'Mechanism';
|
|
72
|
+
|
|
73
|
+
export function Implementation({ language = 'text', title = '实现代码', children }) {
|
|
74
|
+
return (
|
|
75
|
+
<div className="semantic-implementation" data-language={language}>
|
|
76
|
+
{title && <div className="impl-header">{title} <span className="lang-badge">{language}</span></div>}
|
|
77
|
+
<pre><code>{typeof children === 'string' ? children.trim() : children}</code></pre>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
Implementation.displayName = 'Implementation';
|
|
82
|
+
|
|
83
|
+
export function Boundary({ title = '边界与约束', children }) {
|
|
84
|
+
return (
|
|
85
|
+
<div className="semantic-boundary">
|
|
86
|
+
<div className="semantic-tag">⚠ {title}</div>
|
|
87
|
+
<div className="boundary-body">{children}</div>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
Boundary.displayName = 'Boundary';
|
|
92
|
+
|
|
93
|
+
export function Example({ title = '典型示例', children }) {
|
|
94
|
+
return (
|
|
95
|
+
<div className="semantic-example">
|
|
96
|
+
<div className="semantic-tag">✦ {title}</div>
|
|
97
|
+
<div className="example-body">{children}</div>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
Example.displayName = 'Example';
|
|
102
|
+
|
|
103
|
+
export function Counterexample({ title = '反例与误区', children }) {
|
|
104
|
+
return (
|
|
105
|
+
<div className="semantic-counterexample">
|
|
106
|
+
<div className="semantic-tag">✕ {title}</div>
|
|
107
|
+
<div className="counter-body">{children}</div>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
Counterexample.displayName = 'Counterexample';
|
|
112
|
+
|
|
113
|
+
export function Prerequisite({ children }) {
|
|
114
|
+
return <div className="semantic-prerequisite">{children}</div>;
|
|
115
|
+
}
|
|
116
|
+
Prerequisite.displayName = 'Prerequisite';
|
|
117
|
+
|
|
118
|
+
export function Input({ children }) {
|
|
119
|
+
return <div className="semantic-input">{children}</div>;
|
|
120
|
+
}
|
|
121
|
+
Input.displayName = 'Input';
|
|
122
|
+
|
|
123
|
+
export function Output({ children }) {
|
|
124
|
+
return <div className="semantic-output">{children}</div>;
|
|
125
|
+
}
|
|
126
|
+
Output.displayName = 'Output';
|
|
127
|
+
|
|
128
|
+
export function Glossary({ term, children }) {
|
|
129
|
+
return (
|
|
130
|
+
<div className="semantic-glossary-item">
|
|
131
|
+
<span className="term">{term}</span>: <span className="def">{children}</span>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
Glossary.displayName = 'Glossary';
|
|
136
|
+
|
|
137
|
+
// Presentation Semantic Layer Components (for structuring inside nodes without direct CSS)
|
|
138
|
+
export function Compare({ items = [], children }) {
|
|
139
|
+
if (items && items.length > 0) {
|
|
140
|
+
return (
|
|
141
|
+
<div className="semantic-compare-table">
|
|
142
|
+
<table className="compare-grid">
|
|
143
|
+
<thead>
|
|
144
|
+
<tr>
|
|
145
|
+
<th>维度 / 对象</th>
|
|
146
|
+
{items.map((it, idx) => (
|
|
147
|
+
<th key={idx}>{it.label || it.title || `方案 ${idx + 1}`}</th>
|
|
148
|
+
))}
|
|
149
|
+
</tr>
|
|
150
|
+
</thead>
|
|
151
|
+
<tbody>
|
|
152
|
+
{items[0]?.rows ? (
|
|
153
|
+
items[0].rows.map((rowKey, rIdx) => (
|
|
154
|
+
<tr key={rIdx}>
|
|
155
|
+
<td className="compare-row-label">{rowKey}</td>
|
|
156
|
+
{items.map((it, idx) => (
|
|
157
|
+
<td key={idx}>{it.values?.[rIdx] || '-'}</td>
|
|
158
|
+
))}
|
|
159
|
+
</tr>
|
|
160
|
+
))
|
|
161
|
+
) : null}
|
|
162
|
+
</tbody>
|
|
163
|
+
</table>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return <div className="semantic-compare-block">{children}</div>;
|
|
168
|
+
}
|
|
169
|
+
Compare.displayName = 'Compare';
|
|
170
|
+
|
|
171
|
+
export function DecisionMatrix({ title = '权衡矩阵', headers = [], rows = [], children }) {
|
|
172
|
+
if (headers.length > 0 && rows.length > 0) {
|
|
173
|
+
return (
|
|
174
|
+
<div className="semantic-decision-matrix">
|
|
175
|
+
{title && <div className="matrix-title">⚖ {title}</div>}
|
|
176
|
+
<table className="matrix-table">
|
|
177
|
+
<thead>
|
|
178
|
+
<tr>
|
|
179
|
+
{headers.map((h, i) => <th key={i}>{h}</th>)}
|
|
180
|
+
</tr>
|
|
181
|
+
</thead>
|
|
182
|
+
<tbody>
|
|
183
|
+
{rows.map((row, i) => (
|
|
184
|
+
<tr key={i}>
|
|
185
|
+
{row.map((cell, j) => <td key={j}>{cell}</td>)}
|
|
186
|
+
</tr>
|
|
187
|
+
))}
|
|
188
|
+
</tbody>
|
|
189
|
+
</table>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
return <div className="semantic-decision-matrix">{children}</div>;
|
|
194
|
+
}
|
|
195
|
+
DecisionMatrix.displayName = 'DecisionMatrix';
|
|
196
|
+
|
|
197
|
+
export function Flow({ steps = [], children }) {
|
|
198
|
+
if (steps.length > 0) {
|
|
199
|
+
return (
|
|
200
|
+
<div className="semantic-flow-steps">
|
|
201
|
+
{steps.map((step, idx) => (
|
|
202
|
+
<div key={idx} className="flow-step">
|
|
203
|
+
<span className="step-num">{idx + 1}</span>
|
|
204
|
+
<span className="step-text">{step}</span>
|
|
205
|
+
{idx < steps.length - 1 && <span className="step-arrow">→</span>}
|
|
206
|
+
</div>
|
|
207
|
+
))}
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return <div className="semantic-flow-block">{children}</div>;
|
|
212
|
+
}
|
|
213
|
+
Flow.displayName = 'Flow';
|
|
214
|
+
|
|
215
|
+
export function Timeline({ events = [], children }) {
|
|
216
|
+
if (events.length > 0) {
|
|
217
|
+
return (
|
|
218
|
+
<div className="semantic-timeline">
|
|
219
|
+
{events.map((ev, i) => (
|
|
220
|
+
<div key={i} className="timeline-item">
|
|
221
|
+
<div className="timeline-point" />
|
|
222
|
+
<div className="timeline-label">{ev.label || ev.time}</div>
|
|
223
|
+
<div className="timeline-content">{ev.content || ev.desc}</div>
|
|
224
|
+
</div>
|
|
225
|
+
))}
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return <div className="semantic-timeline">{children}</div>;
|
|
230
|
+
}
|
|
231
231
|
Timeline.displayName = 'Timeline';
|
|
232
232
|
|
|
233
|
-
export function
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return (
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
export function
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
</
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
233
|
+
export function FrameworkModel({ title = '结构化模型', type = 'elements', elements = [], question, children }) {
|
|
234
|
+
const labels = { elements: '要素', stages: '阶段', layers: '层级', cycle: '循环' };
|
|
235
|
+
return <section className={`semantic-framework-model model-${type}`}><div className="framework-model-head"><span className="semantic-tag">▦ {title}</span><span className="framework-model-type">{labels[type] || type}</span></div>{question && <div className="framework-model-question">{question}</div>}{elements.length > 0 ? <div className="framework-model-elements">{elements.map((element, index) => <div className="framework-model-element" key={index}><span className="framework-model-index">{String(index + 1).padStart(2, '0')}</span><strong>{element.title || element.label || element.name}</strong>{element.description && <span>{element.description}</span>}</div>)}</div> : children}</section>;
|
|
236
|
+
}
|
|
237
|
+
FrameworkModel.displayName = 'FrameworkModel';
|
|
238
|
+
|
|
239
|
+
export function MatrixModel({ title = '二维矩阵', xLabel = '横轴', yLabel = '纵轴', cells = [], children }) {
|
|
240
|
+
return <section className="semantic-model-matrix"><div className="framework-model-head"><span className="semantic-tag">▦ {title}</span></div>{cells.length > 0 ? <div className="model-matrix-grid"><div className="model-matrix-axis model-matrix-y">{yLabel}</div><div className="model-matrix-axis model-matrix-x">{xLabel}</div>{cells.map((cell, index) => <div className={`model-matrix-cell tone-${cell.tone || 'info'}`} key={index}><strong>{cell.title || cell.label}</strong>{cell.description && <span>{cell.description}</span>}</div>)}</div> : children}</section>;
|
|
241
|
+
}
|
|
242
|
+
MatrixModel.displayName = 'MatrixModel';
|
|
243
|
+
|
|
244
|
+
export function FormulaModel({ title = '公式模型', formula, variables = [], children }) {
|
|
245
|
+
return <section className="semantic-model-formula"><div className="framework-model-head"><span className="semantic-tag">∑ {title}</span></div>{formula && <div className="model-formula-expression"><code>{formula}</code></div>}{variables.length > 0 ? <dl className="model-formula-variables">{variables.map((variable, index) => <React.Fragment key={index}><dt>{variable.symbol || variable.name}</dt><dd>{variable.description || variable.value}</dd></React.Fragment>)}</dl> : children}</section>;
|
|
246
|
+
}
|
|
247
|
+
FormulaModel.displayName = 'FormulaModel';
|
|
248
|
+
|
|
249
|
+
export function PyramidModel({ title = '金字塔模型', levels = [], children }) {
|
|
250
|
+
return <section className="semantic-model-pyramid"><div className="framework-model-head"><span className="semantic-tag">△ {title}</span></div>{levels.length > 0 ? <div className="model-pyramid-levels">{levels.map((level, index) => <div className="model-pyramid-level" key={index} style={{ '--pyramid-width': `${Math.max(38, 100 - index * 12)}%` }}><strong>{level.title || level.label}</strong>{level.description && <span>{level.description}</span>}</div>)}</div> : children}</section>;
|
|
251
|
+
}
|
|
252
|
+
PyramidModel.displayName = 'PyramidModel';
|
|
253
|
+
|
|
254
|
+
export function FunnelModel({ title = '漏斗模型', steps = [], children }) {
|
|
255
|
+
return <section className="semantic-model-funnel"><div className="framework-model-head"><span className="semantic-tag">▽ {title}</span></div>{steps.length > 0 ? <div className="model-funnel-steps">{steps.map((step, index) => <div className="model-funnel-step" key={index} style={{ '--funnel-width': `${Math.max(40, 100 - index * 12)}%` }}><strong>{step.title || step.label}</strong>{step.description && <span>{step.description}</span>}</div>)}</div> : children}</section>;
|
|
256
|
+
}
|
|
257
|
+
FunnelModel.displayName = 'FunnelModel';
|
|
258
|
+
|
|
259
|
+
export function Callout({ type = 'info', title, children }) {
|
|
260
|
+
return (
|
|
261
|
+
<div className={`semantic-callout callout-${type}`}>
|
|
262
|
+
{title && <div className="callout-title">{title}</div>}
|
|
263
|
+
<div className="callout-content">{children}</div>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
Callout.displayName = 'Callout';
|
|
268
|
+
|
|
269
|
+
export function Details({ summary = '详细展开', children }) {
|
|
270
|
+
return (
|
|
271
|
+
<details className="semantic-details">
|
|
272
|
+
<summary>{summary}</summary>
|
|
273
|
+
<div className="details-body">{children}</div>
|
|
274
|
+
</details>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
Details.displayName = 'Details';
|
|
278
|
+
|
|
279
|
+
export function LearningObjectives({ items = [], children }) {
|
|
280
|
+
const goals = Array.isArray(items) ? items.filter(Boolean) : [];
|
|
281
|
+
return (
|
|
282
|
+
<section className="semantic-learning-objectives">
|
|
283
|
+
<div className="semantic-tag">◎ 学习目标</div>
|
|
284
|
+
{goals.length > 0 ? <ul>{goals.map((item, index) => <li key={index}>{item}</li>)}</ul> : children}
|
|
285
|
+
</section>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
LearningObjectives.displayName = 'LearningObjectives';
|
|
289
|
+
|
|
290
|
+
export function KeyQuestion({ children }) {
|
|
291
|
+
return (
|
|
292
|
+
<aside className="semantic-key-question">
|
|
293
|
+
<span className="semantic-tag">? 引导问题</span>
|
|
294
|
+
<strong>{children}</strong>
|
|
295
|
+
</aside>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
KeyQuestion.displayName = 'KeyQuestion';
|
|
299
|
+
|
|
300
|
+
export function Evidence({ command, observes, children }) {
|
|
301
|
+
return (
|
|
302
|
+
<div className="semantic-evidence">
|
|
303
|
+
<div className="semantic-tag">⌕ 可验证证据</div>
|
|
304
|
+
{command && <code className="evidence-command">{command}</code>}
|
|
305
|
+
{(observes || children) && <div className="evidence-observes">{observes || children}</div>}
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
Evidence.displayName = 'Evidence';
|
|
310
|
+
|
|
311
|
+
export function Invariant({ title = '不变量', children }) {
|
|
312
|
+
return (
|
|
313
|
+
<div className="semantic-invariant">
|
|
314
|
+
<div className="semantic-tag">◆ {title}</div>
|
|
315
|
+
<div>{children}</div>
|
|
316
|
+
</div>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
Invariant.displayName = 'Invariant';
|
|
320
|
+
|
|
321
|
+
export function FailureMode({ symptom, cause, evidence, remedy, children }) {
|
|
322
|
+
const rows = [['现象', symptom], ['原因', cause], ['证据', evidence], ['建议', remedy]].filter(([, value]) => value);
|
|
323
|
+
return (
|
|
324
|
+
<div className="semantic-failure-mode">
|
|
325
|
+
<div className="semantic-tag">⚠ 故障模式</div>
|
|
326
|
+
{rows.length > 0 && <dl>{rows.map(([label, value]) => <React.Fragment key={label}><dt>{label}</dt><dd>{value}</dd></React.Fragment>)}</dl>}
|
|
327
|
+
{children && <div className="failure-details">{children}</div>}
|
|
328
|
+
</div>
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
FailureMode.displayName = 'FailureMode';
|
|
332
|
+
|
|
333
|
+
export function Tradeoff({ title = '工程权衡', options = [], children }) {
|
|
334
|
+
return (
|
|
335
|
+
<div className="semantic-tradeoff">
|
|
336
|
+
<div className="semantic-tag">⚖ {title}</div>
|
|
337
|
+
{options.length > 0 ? (
|
|
338
|
+
<div className="tradeoff-options">
|
|
339
|
+
{options.map((option, index) => (
|
|
340
|
+
<div className="tradeoff-option" key={index}>
|
|
341
|
+
<strong>{option.name || option.label || `方案 ${index + 1}`}</strong>
|
|
342
|
+
{option.benefit && <span><b>收益</b>{option.benefit}</span>}
|
|
343
|
+
{option.cost && <span><b>代价</b>{option.cost}</span>}
|
|
344
|
+
{option.when && <span><b>适用</b>{option.when}</span>}
|
|
345
|
+
</div>
|
|
346
|
+
))}
|
|
347
|
+
</div>
|
|
348
|
+
) : children}
|
|
349
|
+
</div>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
Tradeoff.displayName = 'Tradeoff';
|
|
353
|
+
|
|
354
|
+
export function Columns({ children }) {
|
|
355
|
+
return <div className="semantic-columns">{children}</div>;
|
|
356
|
+
}
|
|
357
|
+
Columns.displayName = 'Columns';
|
|
358
|
+
|
|
359
|
+
/** Optional layout primitives. They express intent while the template owns the CSS. */
|
|
360
|
+
export function Stack({ gap = 'md', children }) {
|
|
361
|
+
return <div className={`semantic-stack gap-${gap}`}>{children}</div>;
|
|
362
|
+
}
|
|
363
|
+
Stack.displayName = 'Stack';
|
|
364
|
+
|
|
365
|
+
export function Grid({ columns = 'auto', gap = 'md', children }) {
|
|
366
|
+
return <div className={`semantic-grid grid-${columns} gap-${gap}`}>{children}</div>;
|
|
367
|
+
}
|
|
368
|
+
Grid.displayName = 'Grid';
|
|
369
|
+
|
|
370
|
+
export function Split({ ratio = '1fr 1fr', children }) {
|
|
371
|
+
return <div className="semantic-split" style={{ '--split-ratio': ratio }}>{children}</div>;
|
|
372
|
+
}
|
|
373
|
+
Split.displayName = 'Split';
|
|
374
|
+
|
|
375
|
+
export function Tabs({ items = [], children }) {
|
|
376
|
+
return <div className="semantic-tabs" data-tab-count={items.length || undefined}>{items.length ? items.map((item, i) => <details key={i} open={i === 0}><summary>{item.label || item.title}</summary><div>{item.content}</div></details>) : children}</div>;
|
|
377
|
+
}
|
|
378
|
+
Tabs.displayName = 'Tabs';
|
|
379
|
+
|
|
380
|
+
export function Mermaid({ chart = '', title = '关系草图', width = 'auto', height = 'auto', x = 0, y = 0, position = 'flow' }) {
|
|
381
|
+
const ref = React.useRef(null);
|
|
382
|
+
const id = React.useId().replace(/:/g, '');
|
|
383
|
+
const [error, setError] = React.useState('');
|
|
384
|
+
const [scale, setScale] = React.useState(1);
|
|
385
|
+
const [pan, setPan] = React.useState({ x: 0, y: 0 });
|
|
386
|
+
|
|
387
|
+
React.useEffect(() => {
|
|
388
|
+
let cancelled = false;
|
|
389
|
+
async function renderChart() {
|
|
390
|
+
if (!ref.current || !chart.trim()) return;
|
|
391
|
+
try {
|
|
392
|
+
ensureMermaid();
|
|
393
|
+
const { svg } = await mermaid.render(`mermaid-${id}`, chart.trim());
|
|
394
|
+
if (!cancelled && ref.current) {
|
|
395
|
+
ref.current.innerHTML = svg;
|
|
396
|
+
setError('');
|
|
397
|
+
}
|
|
398
|
+
} catch (err) {
|
|
399
|
+
if (!cancelled) setError(err.message || 'Mermaid 图表语法错误');
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
renderChart();
|
|
403
|
+
return () => { cancelled = true; };
|
|
404
|
+
}, [chart, id]);
|
|
405
|
+
|
|
406
|
+
const zoom = (delta) => setScale(value => Math.max(0.5, Math.min(3, +(value + delta).toFixed(2))));
|
|
407
|
+
const reset = () => { setScale(1); setPan({ x: 0, y: 0 }); };
|
|
408
|
+
return (
|
|
409
|
+
<div className={`semantic-mermaid ${widgetClass(position)}`} style={widgetStyle({ width, height, x, y, position })}>
|
|
410
|
+
<div className="semantic-widget-head">
|
|
411
|
+
<span>{title}</span>
|
|
412
|
+
<div className="mermaid-tools"><code>MERMAID</code><button type="button" onClick={() => zoom(-0.1)} aria-label="缩小图表">−</button><span>{Math.round(scale * 100)}%</span><button type="button" onClick={() => zoom(0.1)} aria-label="放大图表">+</button><button type="button" onClick={reset} aria-label="重置图表">↺</button></div>
|
|
413
|
+
</div>
|
|
414
|
+
{error ? <pre className="mermaid-error">{error}</pre> : <div className="mermaid-canvas" onWheel={(event) => { event.preventDefault(); zoom(event.deltaY < 0 ? 0.1 : -0.1); }}><div className="mermaid-canvas-inner" style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${scale})` }} ref={ref} /></div>}
|
|
415
|
+
</div>
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
Mermaid.displayName = 'Mermaid';
|
|
419
|
+
|
|
420
|
+
export function RelationMap({ title = '关系速览', items = [], children, width = 'auto', height = 'auto', x = 0, y = 0, position = 'flow' }) {
|
|
421
|
+
return (
|
|
422
|
+
<div className={`semantic-relation-map ${widgetClass(position)}`} style={widgetStyle({ width, height, x, y, position })}>
|
|
423
|
+
<div className="semantic-widget-head"><span>{title}</span><code>RELATIONS</code></div>
|
|
424
|
+
{items.length > 0 ? (
|
|
425
|
+
<div className="relation-map-grid">
|
|
426
|
+
{items.map((item, index) => (
|
|
427
|
+
<div className="relation-map-row" key={index}>
|
|
428
|
+
<span className="relation-map-source">{item.from || item.source}</span>
|
|
429
|
+
<span className="relation-map-arrow">{item.type || '→'}</span>
|
|
430
|
+
<span className="relation-map-target">{item.to || item.target}</span>
|
|
431
|
+
{item.note && <small>{item.note}</small>}
|
|
432
|
+
</div>
|
|
433
|
+
))}
|
|
434
|
+
</div>
|
|
435
|
+
) : children}
|
|
436
|
+
</div>
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
RelationMap.displayName = 'RelationMap';
|
|
440
|
+
|
|
441
|
+
export function RelationPath({ title = '关系链', steps = [], children }) {
|
|
442
|
+
const safeSteps = Array.isArray(steps) ? steps.filter(Boolean) : [];
|
|
443
|
+
return (
|
|
444
|
+
<div className="semantic-relation-path">
|
|
445
|
+
{title && <div className="semantic-widget-head"><span>{title}</span><code>PATH</code></div>}
|
|
446
|
+
{safeSteps.length > 0 ? (
|
|
447
|
+
<div className="relation-path-steps">
|
|
448
|
+
{safeSteps.map((step, index) => (
|
|
449
|
+
<React.Fragment key={index}>
|
|
450
|
+
<div className={`relation-path-node tone-${step.tone || 'info'}`}>
|
|
451
|
+
<span className="relation-path-kicker">{step.level || `0${index + 1}`}</span>
|
|
452
|
+
<strong>{step.node || step.title}</strong>
|
|
453
|
+
{step.note && <small>{step.note}</small>}
|
|
454
|
+
</div>
|
|
455
|
+
{index < safeSteps.length - 1 && <div className="relation-path-edge"><span>{safeSteps[index].relation || '→'}</span></div>}
|
|
456
|
+
</React.Fragment>
|
|
457
|
+
))}
|
|
458
|
+
</div>
|
|
459
|
+
) : children}
|
|
460
|
+
</div>
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
RelationPath.displayName = 'RelationPath';
|
|
464
|
+
|
|
465
|
+
export function Insight({ title = '关键判断', tone = 'info', children, width = 'auto', height = 'auto', x = 0, y = 0, position = 'flow' }) {
|
|
466
|
+
return (
|
|
467
|
+
<aside className={`semantic-insight insight-${tone} ${widgetClass(position)}`} style={widgetStyle({ width, height, x, y, position })}>
|
|
468
|
+
<div className="insight-kicker">{tone === 'warn' ? '⚠' : tone === 'success' ? '✓' : '◆'} {title}</div>
|
|
469
|
+
<div className="insight-body">{children}</div>
|
|
470
|
+
</aside>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
Insight.displayName = 'Insight';
|
|
474
|
+
|
|
475
|
+
export function NoteGrid({ notes = [], children, width = 'auto', height = 'auto', x = 0, y = 0, position = 'flow' }) {
|
|
476
|
+
return (
|
|
477
|
+
<div className={`semantic-note-grid ${widgetClass(position)}`} style={widgetStyle({ width, height, x, y, position })}>
|
|
478
|
+
{notes.length > 0 ? notes.map((note, index) => (
|
|
479
|
+
<div className="semantic-note" key={index}>
|
|
480
|
+
<strong>{note.title || note.label}</strong>
|
|
481
|
+
<span>{note.content || note.text || note.description}</span>
|
|
482
|
+
</div>
|
|
483
|
+
)) : children}
|
|
484
|
+
</div>
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
NoteGrid.displayName = 'NoteGrid';
|
|
488
|
+
|
|
489
|
+
function widgetStyle({ width, height, x, y, position }) {
|
|
490
|
+
const style = {};
|
|
491
|
+
if (width && width !== 'auto') style.width = width;
|
|
492
|
+
if (height && height !== 'auto') style.height = height;
|
|
493
|
+
if (position === 'absolute') {
|
|
494
|
+
style.position = 'absolute';
|
|
495
|
+
style.left = `${x}px`;
|
|
496
|
+
style.top = `${y}px`;
|
|
497
|
+
} else if (x || y) {
|
|
498
|
+
style.transform = `translate(${x}px, ${y}px)`;
|
|
499
|
+
}
|
|
500
|
+
return style;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function widgetClass(position) {
|
|
504
|
+
return position === 'absolute' ? 'semantic-widget-absolute' : '';
|
|
505
|
+
}
|