@my-life-buddies/cli 0.13.3 → 0.15.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/README.md +74 -22
- package/dist/bin/buddy.js +29 -10
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +1480 -611
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +324 -27
- package/dist/bin/preview.js.map +4 -4
- package/dist/web/app.css +65 -6
- package/dist/web/app.js +103 -39
- package/dist/web/diagnostics.js +184 -0
- package/dist/web/index.html +34 -34
- package/dist/web/widgets.css +59 -28
- package/dist/web/widgets.js +230 -76
- package/package.json +3 -3
- package/resources/README.md +6 -50
- package/resources/agent-template/package-lock.json +4 -4
- package/resources/agent-template/package.json +2 -2
- package/resources/buddy-creator/INSTALL.md +0 -25
- package/resources/buddy-creator/PATCHES.md +0 -53
- package/resources/buddy-creator/SKILL.md +0 -76
- package/resources/buddy-creator/THIRD_PARTY_NOTICES.md +0 -154
- package/resources/buddy-creator/agents/openai.yaml +0 -4
- package/resources/buddy-creator/assets/licenses/bail.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ccount.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-html4.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-legacy.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-reference-invalid.txt +0 -26
- package/resources/buddy-creator/assets/licenses/comma-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/debug.txt +0 -24
- package/resources/buddy-creator/assets/licenses/decode-named-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/dequal.txt +0 -25
- package/resources/buddy-creator/assets/licenses/devlop.txt +0 -26
- package/resources/buddy-creator/assets/licenses/escape-string-regexp.txt +0 -13
- package/resources/buddy-creator/assets/licenses/estree-util-is-identifier-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/extend.txt +0 -27
- package/resources/buddy-creator/assets/licenses/hast-util-to-jsx-runtime.txt +0 -26
- package/resources/buddy-creator/assets/licenses/hast-util-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/html-url-attributes.txt +0 -25
- package/resources/buddy-creator/assets/licenses/inline-style-parser.txt +0 -13
- package/resources/buddy-creator/assets/licenses/is-alphabetical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-alphanumerical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-decimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-hexadecimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-plain-obj.txt +0 -13
- package/resources/buddy-creator/assets/licenses/longest-streak.txt +0 -26
- package/resources/buddy-creator/assets/licenses/markdown-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-find-and-replace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-from-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-expression.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-jsx.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdxjs-esm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-phrasing.txt +0 -27
- package/resources/buddy-creator/assets/licenses/mdast-util-to-hast.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-core-commonmark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-tagfilter.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-destination.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-label.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-space.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-title.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-chunked.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-classify-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-combine-extensions.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-numeric-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-encode.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-html-tag-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-normalize-identifier.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-resolve-all.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-sanitize-uri.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-subtokenize.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-symbol.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-types.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/parse-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/phosphor-icons--react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/property-information.txt +0 -26
- package/resources/buddy-creator/assets/licenses/react-dom.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react-markdown.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-parse.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-rehype.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-stringify.txt +0 -25
- package/resources/buddy-creator/assets/licenses/scheduler.txt +0 -25
- package/resources/buddy-creator/assets/licenses/space-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/stringify-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-js.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-object.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trim-lines.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trough.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--debug.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree-jsx.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--hast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--mdast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--unist.txt +0 -25
- package/resources/buddy-creator/assets/licenses/ungap--structured-clone.txt +0 -19
- package/resources/buddy-creator/assets/licenses/unified.txt +0 -25
- package/resources/buddy-creator/assets/licenses/unist-util-is.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-stringify-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit-parents.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile-message.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile.txt +0 -25
- package/resources/buddy-creator/assets/licenses/zwitch.txt +0 -26
- package/resources/buddy-creator/assets/preview/assets/index-B5VmkoSx.js +0 -39
- package/resources/buddy-creator/assets/preview/assets/index-DWKP6b-3.css +0 -4
- package/resources/buddy-creator/assets/preview/brand-logo.png +0 -0
- package/resources/buddy-creator/assets/preview/brand.css +0 -100
- package/resources/buddy-creator/assets/preview/index.html +0 -7
- package/resources/buddy-creator/assets/preview/reader.css +0 -165
- package/resources/buddy-creator/assets/preview/reader.js +0 -135
- package/resources/buddy-creator/assets/preview/widgets.css +0 -1
- package/resources/buddy-creator/assets/preview/widgets.js +0 -168
- package/resources/buddy-creator/assets/widget-reference/conversation.png +0 -0
- package/resources/buddy-creator/assets/widget-reference/expanded.png +0 -0
- package/resources/buddy-creator/assets/widget-v2/app.js +0 -62
- package/resources/buddy-creator/assets/widget-v2/style.css +0 -1
- package/resources/buddy-creator/assets/widget-v3/app.js +0 -65
- package/resources/buddy-creator/assets/widget-v3/style.css +0 -103
- package/resources/buddy-creator/assets/widget-v4/app.js +0 -66
- package/resources/buddy-creator/assets/widget-v4/style.css +0 -187
- package/resources/buddy-creator/references/artifact-schema.md +0 -70
- package/resources/buddy-creator/references/catalog.json +0 -401
- package/resources/buddy-creator/references/definition.md +0 -24
- package/resources/buddy-creator/references/dialogue-examples.md +0 -133
- package/resources/buddy-creator/references/host-guide.md +0 -219
- package/resources/buddy-creator/references/interview.md +0 -235
- package/resources/buddy-creator/references/knowledge.md +0 -40
- package/resources/buddy-creator/references/methods.md +0 -77
- package/resources/buddy-creator/references/opening.md +0 -14
- package/resources/buddy-creator/references/preview-panel.md +0 -66
- package/resources/buddy-creator/references/recovery.md +0 -46
- package/resources/buddy-creator/references/service.md +0 -76
- package/resources/buddy-creator/references/widgets-protocol.md +0 -83
- package/resources/buddy-creator/references/widgets.md +0 -99
- package/resources/buddy-creator/scripts/buddy.py +0 -108
- package/resources/buddy-creator/scripts/buddy_client.py +0 -67
- package/resources/buddy-creator/scripts/buddy_core.py +0 -865
- package/resources/buddy-creator/scripts/completion.py +0 -296
- package/resources/buddy-creator/scripts/interview.py +0 -215
- package/resources/buddy-creator/scripts/preview.py +0 -617
- package/resources/buddy-creator/scripts/preview_panel.py +0 -80
- package/resources/buddy-creator/scripts/sources.py +0 -239
- package/resources/buddy-creator/scripts/widget_render.py +0 -66
- package/resources/buddy-creator/scripts/widget_render_v1.py +0 -176
- package/resources/buddy-creator/scripts/widget_render_v2.py +0 -98
- package/resources/buddy-creator/scripts/widget_render_v3.py +0 -86
- package/resources/buddy-creator/scripts/widget_render_v4.py +0 -121
- package/resources/buddy-creator/scripts/widgets.py +0 -227
- package/resources/buddy-creator/version.json +0 -8
- package/resources/buddy-creator.manifest.json +0 -791
- package/resources/dada-object-avatar/SKILL.md +0 -37
- package/resources/dada-object-avatar/agents/openai.yaml +0 -4
- package/resources/dada-object-avatar/assets/examples/cat.png +0 -0
- package/resources/dada-object-avatar/assets/examples/cooking.png +0 -0
- package/resources/dada-object-avatar/assets/examples/divination.png +0 -0
- package/resources/dada-object-avatar/assets/examples/doctor.png +0 -0
- package/resources/dada-object-avatar/assets/examples/relationship.png +0 -0
- package/resources/dada-object-avatar/assets/examples/work.png +0 -0
- package/resources/dada-object-avatar/assets/preview.png +0 -0
- package/resources/dada-object-avatar/references/evaluation-rubric.md +0 -22
- package/resources/dada-object-avatar/references/examples.json +0 -8
- package/resources/dada-object-avatar/references/prompt-template.md +0 -27
- package/resources/dada-object-avatar/references/style-system.md +0 -54
- package/resources/dada-object-avatar/references/subject-design.md +0 -23
- package/resources/dada-object-avatar/references/training-guide.md +0 -14
- package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
- package/resources/dada-object-avatar/references/training-record.schema.json +0 -20
- package/resources/dada-object-avatar/scripts/choose_gaze.py +0 -36
- package/resources/dada-object-avatar/scripts/record_example.py +0 -22
- package/resources/dada-object-avatar/scripts/validate_png.py +0 -52
- package/resources/dada-object-avatar.manifest.json +0 -85
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
// Read-only mirror of the host's saved design workflow. No confirmation writes.
|
|
2
|
-
const el = (tag, text, cls) => {
|
|
3
|
-
const node = document.createElement(tag);
|
|
4
|
-
if (text !== undefined) node.textContent = text;
|
|
5
|
-
if (cls) node.className = cls;
|
|
6
|
-
return node;
|
|
7
|
-
};
|
|
8
|
-
const root = document.getElementById('root');
|
|
9
|
-
const nav = el('nav', undefined, 'design-navigation');
|
|
10
|
-
nav.setAttribute('aria-label', '创作内容');
|
|
11
|
-
const bookButton = el('button', '四册 Booklet');
|
|
12
|
-
const designButton = el('button', '小挂件设计');
|
|
13
|
-
const progress = el('span', '正在读取创作进度', 'design-progress');
|
|
14
|
-
nav.append(bookButton, designButton, progress);
|
|
15
|
-
document.body.prepend(nav);
|
|
16
|
-
const panel = el('main', undefined, 'design-workspace');
|
|
17
|
-
panel.hidden = true;
|
|
18
|
-
document.body.append(panel);
|
|
19
|
-
let chosen = false, previousPhase, version;
|
|
20
|
-
const selectedStates = new Map();
|
|
21
|
-
function choose(design, manual = false) {
|
|
22
|
-
if (manual) chosen = true;
|
|
23
|
-
root.hidden = design; panel.hidden = !design;
|
|
24
|
-
bookButton.setAttribute('aria-pressed', String(!design));
|
|
25
|
-
designButton.setAttribute('aria-pressed', String(design));
|
|
26
|
-
// Do not stop the upstream reader before its first snapshot selects a stage.
|
|
27
|
-
if (manual && root.querySelector('.preview-header')) document.dispatchEvent(new Event('buddy:reader-browse'));
|
|
28
|
-
}
|
|
29
|
-
bookButton.onclick = () => choose(false, true);
|
|
30
|
-
designButton.onclick = () => choose(true, true);
|
|
31
|
-
choose(false);
|
|
32
|
-
const card = title => { const node = el('section', undefined, 'design-card'); node.append(el('h2', title)); return node; };
|
|
33
|
-
const badge = (text, pass = false) => el('span', text, 'design-badge' + (pass ? ' passed' : ''));
|
|
34
|
-
function field(parent, label, value) { const row = el('div', undefined, 'design-field'); row.append(el('dt', label), el('dd', value)); parent.append(row); }
|
|
35
|
-
const reviewLabels = { 'booklet-fit': '符合搭子需求', 'reading-order': '阅读顺序与长内容', 'chat-consistency': '对话卡片与展开页一致', 'conversation-update': '数据随对话逐步更新', 'read-only': '只读交互边界' };
|
|
36
|
-
function render(snapshot) {
|
|
37
|
-
const design = snapshot.widgetDesign;
|
|
38
|
-
if (!design) { nav.hidden = true; return; }
|
|
39
|
-
nav.hidden = false;
|
|
40
|
-
const index = design.steps.findIndex(step => step.id === design.phase);
|
|
41
|
-
progress.textContent = design.enabled ? design.steps.map((step, i) => (i < index ? '✓ ' : '') + step.label).join(' → ') : '已有作品';
|
|
42
|
-
if (!chosen && design.phase !== 'booklets' && design.phase !== 'legacy' && previousPhase !== design.phase) choose(true);
|
|
43
|
-
previousPhase = design.phase;
|
|
44
|
-
panel.replaceChildren();
|
|
45
|
-
const heading = el('div', undefined, 'design-heading');
|
|
46
|
-
heading.append(el('p', 'BOOKLET / 交互设计', 'design-eyebrow'), el('h1', '小挂件,让对话里的内容更好读'), el('p', design.nextStep));
|
|
47
|
-
if (snapshot.paused) heading.append(badge('创作已暂停;确认进度已保留'));
|
|
48
|
-
panel.append(heading);
|
|
49
|
-
const steps = el('ol', undefined, 'design-steps');
|
|
50
|
-
design.steps.forEach((step, i) => {
|
|
51
|
-
const li = el('li', undefined, i === index ? 'current' : i < index ? 'done' : '');
|
|
52
|
-
li.append(el('span', i < index ? '✓' : String(i + 1)), el('strong', step.label));
|
|
53
|
-
if (i === index) li.setAttribute('aria-current', 'step');
|
|
54
|
-
steps.append(li);
|
|
55
|
-
});
|
|
56
|
-
panel.append(steps, el('p', '此页同步清单、原型和验收进度。确认、补充和修改请在主对话中提出。', 'design-callout'));
|
|
57
|
-
const list = card('01 / 小挂件清单');
|
|
58
|
-
list.append(badge(design.catalogConfirmed ? '开发者已确认' : design.phase === 'booklets' ? '四册确认后开始' : '待开发者确认', design.catalogConfirmed));
|
|
59
|
-
if (!design.catalog) list.append(el('p', '完成四册后,将根据搭子的任务、持续服务和数据需求提出清单,供你确认、补充或调整。'));
|
|
60
|
-
else if (!design.items.length) list.append(el('p', design.catalog.data.noWidgetsReason), el('p', design.catalogConfirmed ? '已明确确认本作品不使用小挂件。' : '“不使用小挂件”也需要在主对话明确确认。'));
|
|
61
|
-
else {
|
|
62
|
-
for (const item of design.items) {
|
|
63
|
-
const entry = el('details', undefined, 'design-list-item'); entry.open = true;
|
|
64
|
-
entry.append(el('summary', item.name));
|
|
65
|
-
const fields = el('dl', undefined, 'design-specs');
|
|
66
|
-
for (const [label, key] of [['用途', 'purpose'], ['何时创建 / 展示', 'creationTrigger'], ['首次展示', 'initialContent'], ['对话更新规则', 'updateRules'], ['实例沿用 / 新建', 'instancePolicy'], ['对话摘要', 'conversationSummary']]) field(fields, label, item[key]);
|
|
67
|
-
field(fields, 'Booklet 依据', item.bookletRefs.map(ref => {
|
|
68
|
-
const source = snapshot.artifacts.find(a => a.id === ref.id);
|
|
69
|
-
const [stage, chapter] = ref.id.split('.');
|
|
70
|
-
const label = { definition: '定义', knowledge: '知识', methods: '方法', service: '服务' }[stage];
|
|
71
|
-
return label + '手册 · ' + (source?.title && source.title !== ref.id ? source.title : '第 ' + chapter + ' 章');
|
|
72
|
-
}).join(';'));
|
|
73
|
-
field(fields, '阅读能力', item.readInteractions.map(key => ({ tabs: '分组切换', filter: '预设筛选', collapse: '折叠', detail: '只读详情' })[key]).join('、') || '滚动阅读');
|
|
74
|
-
entry.append(fields);
|
|
75
|
-
const table = el('table'); const head = el('tr'); ['展示字段', '数据来源', '尚未补充时'].forEach(label => head.append(el('th', label))); table.append(head);
|
|
76
|
-
item.fields.forEach(f => { const row = el('tr'); [f.label, f.source, f.emptyText].forEach(value => row.append(el('td', value))); table.append(row); });
|
|
77
|
-
entry.append(table); list.append(entry);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
panel.append(list);
|
|
81
|
-
const prototypes = card('02 / 原型确认');
|
|
82
|
-
prototypes.append(el('p', '同一份数据,两种展示方式。切换下方示例状态,再试用小挂件内的阅读操作。', 'design-muted'));
|
|
83
|
-
if (!design.items.length) prototypes.append(el('p', design.catalogConfirmed ? '已确认不需要小挂件,本阶段无需原型。' : '清单确认后生成原型。'));
|
|
84
|
-
for (const item of design.items) {
|
|
85
|
-
const section = el('section', undefined, 'design-prototype');
|
|
86
|
-
section.append(el('h3', item.name), badge(item.prototypeConfirmed ? '当前原型已确认' : '待确认原型', item.prototypeConfirmed));
|
|
87
|
-
if (!item.prototype || !item.automaticCheck.pass || Object.keys(item.blockers).length) {
|
|
88
|
-
section.append(el('p', !item.prototype ? '确认清单后生成该小挂件的原型。' : Object.keys(item.blockers).length ? '依据或清单已调整,请在主对话继续校准这一项。' : item.automaticCheck.message));
|
|
89
|
-
} else {
|
|
90
|
-
const prototype = item.prototype, data = prototype.data;
|
|
91
|
-
let selected = selectedStates.get(item.id) || 'initial';
|
|
92
|
-
const control = el('div', undefined, 'design-state-tabs'); control.setAttribute('aria-label', item.name + '示例状态');
|
|
93
|
-
const grid = el('div', undefined, 'design-views');
|
|
94
|
-
const refresh = () => {
|
|
95
|
-
grid.replaceChildren();
|
|
96
|
-
for (const view of ['chat', 'expanded']) {
|
|
97
|
-
const figure = el('figure');
|
|
98
|
-
figure.append(el('figcaption', view === 'chat' ? '出现在对话中' : '展开后阅读'));
|
|
99
|
-
const frame = el('iframe'); frame.title = item.name + ' / ' + (view === 'chat' ? '对话卡片' : '展开页');
|
|
100
|
-
frame.width = data.design.screenWidth; frame.height = data.design.screenHeight;
|
|
101
|
-
frame.sandbox = 'allow-scripts';
|
|
102
|
-
frame.src = './widget-assets/' + prototype.hash + '/index.html?view=' + view + '&state=' + selected;
|
|
103
|
-
frame.loading = 'lazy'; figure.append(frame);
|
|
104
|
-
const link = el('a', '查看示意图'); link.target = '_blank'; link.rel = 'noopener';
|
|
105
|
-
link.href = './widget-assets/' + prototype.hash + '/' + view + '-' + selected + '.svg'; figure.append(link);
|
|
106
|
-
grid.append(figure);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
for (const sample of data.states) {
|
|
110
|
-
const button = el('button', sample.label); button.setAttribute('aria-pressed', String(sample.id === selected));
|
|
111
|
-
button.onclick = () => { selected = sample.id; selectedStates.set(item.id, selected); for (const b of control.children) b.setAttribute('aria-pressed', String(b === button)); refresh(); };
|
|
112
|
-
control.append(button);
|
|
113
|
-
}
|
|
114
|
-
const size = data.design;
|
|
115
|
-
section.append(el('p', '示例画布 ' + size.screenWidth + ' × ' + size.screenHeight + ';展开页 ' + (size.screenWidth - 32) + ' × ' + Math.round(size.screenHeight * .65) + '。', 'design-muted'), control, grid);
|
|
116
|
-
refresh();
|
|
117
|
-
section.append(el('p', '原型版本 ' + prototype.hash.slice(0, 10) + ' · 以上为示例数据,用于确认样式和交互。', 'design-muted'));
|
|
118
|
-
}
|
|
119
|
-
prototypes.append(section);
|
|
120
|
-
}
|
|
121
|
-
panel.append(prototypes);
|
|
122
|
-
const acceptance = card('03 / 设计验收');
|
|
123
|
-
acceptance.append(el('p', '自动检查验证结构与资源。开发者验收确认需求、阅读体验和对话更新是否符合预期。生产环境接入另行验证。', 'design-muted'));
|
|
124
|
-
for (const item of design.items) {
|
|
125
|
-
const group = el('section', undefined, 'design-acceptance');
|
|
126
|
-
group.append(el('h3', item.name), badge(item.accepted ? '开发者已验收当前版本' : '待开发者验收', item.accepted));
|
|
127
|
-
group.append(el('p', (item.automaticCheck.pass ? '✓ 自动检查:' : '○ 自动检查:') + item.automaticCheck.message));
|
|
128
|
-
const table = el('table'); const header = el('tr'); ['开发者检查项', '检查记录', '确认状态'].forEach(t => header.append(el('th', t))); table.append(header);
|
|
129
|
-
for (const key of design.reviewChecks) { const row = el('tr'); row.append(el('td', reviewLabels[key]), el('td', item.acceptance?.data.reviews[key] || '尚未记录'), el('td', item.accepted ? '已确认' : '待确认')); table.append(row); }
|
|
130
|
-
group.append(table);
|
|
131
|
-
if (item.acceptance?.unresolved?.length) group.append(el('p', '待处理:' + item.acceptance.unresolved.join(';')));
|
|
132
|
-
acceptance.append(group);
|
|
133
|
-
}
|
|
134
|
-
if (!design.items.length) acceptance.append(el('p', design.catalogConfirmed ? '已确认不需要小挂件,无需逐项设计验收。' : '原型确认后逐项验收。'));
|
|
135
|
-
panel.append(acceptance);
|
|
136
|
-
const deliverables = card('04 / 交付与开发衔接');
|
|
137
|
-
if (snapshot.completion?.status === 'ready' && snapshot.completion.files) {
|
|
138
|
-
deliverables.append(badge('成果已生成', true), el('p', '包含四册、服务模式图、小挂件清单、两视图三态原型和设计验收记录。'));
|
|
139
|
-
deliverables.append(el('p', '完整创建任务将在此处自动衔接开发:由当前 Agent 读取已确认手册与小挂件设计,继续实现,无需再次确认开始。仅设计、流程测试或已暂停的任务按原范围结束。实际开发进度请在主对话查看。', 'design-muted'));
|
|
140
|
-
const downloads = el('details'); downloads.append(el('summary', '查看全部成果文件'));
|
|
141
|
-
for (const file of snapshot.completion.files) {
|
|
142
|
-
const a = el('a', file); a.href = './deliverables/' + snapshot.revision + '/' + file; a.download = file.split('/').pop();
|
|
143
|
-
const row = el('p'); row.append(a); downloads.append(row);
|
|
144
|
-
if (file === 'BUDDY_MANUAL.md' || file === 'WIDGET_DESIGN.md') { const quick = a.cloneNode(true); quick.className = 'design-download'; quick.textContent = file === 'BUDDY_MANUAL.md' ? '下载创作手册' : '下载小挂件设计说明'; deliverables.append(quick); }
|
|
145
|
-
}
|
|
146
|
-
deliverables.append(downloads);
|
|
147
|
-
} else deliverables.append(el('p', snapshot.completion?.message || '清单、当前原型及设计验收确认完成后生成交付。四册内容可先在 Booklet 中阅读。'));
|
|
148
|
-
panel.append(deliverables);
|
|
149
|
-
}
|
|
150
|
-
let loading = false;
|
|
151
|
-
async function update() {
|
|
152
|
-
if (loading) return;
|
|
153
|
-
loading = true;
|
|
154
|
-
try {
|
|
155
|
-
const response = await fetch('./api/snapshot');
|
|
156
|
-
if (!response.ok) throw new Error('snapshot unavailable');
|
|
157
|
-
const snapshot = await response.json();
|
|
158
|
-
const next = JSON.stringify([snapshot.widgetDesign, snapshot.completion, snapshot.paused]);
|
|
159
|
-
if (next !== version) { version = next; render(snapshot); }
|
|
160
|
-
} catch { progress.textContent = '页面暂时无法同步;已展示的内容保留,请回主对话查看进度。'; }
|
|
161
|
-
finally { loading = false; }
|
|
162
|
-
}
|
|
163
|
-
update();
|
|
164
|
-
const events = new EventSource('./api/events');
|
|
165
|
-
events.addEventListener('changed', update);
|
|
166
|
-
events.addEventListener('ready', update);
|
|
167
|
-
events.addEventListener('unavailable', () => { progress.textContent = '内容暂时无法读取,请回主对话检查。'; });
|
|
168
|
-
document.addEventListener('visibilitychange', () => { if (!document.hidden) update(); });
|
|
Binary file
|
|
Binary file
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const params = new URLSearchParams(location.search);
|
|
3
|
-
const requested = params.get('state') || 'initial';
|
|
4
|
-
const screens = [...document.querySelectorAll('.screen')];
|
|
5
|
-
const screen = screens.find(node => node.dataset.state === requested) || screens[0];
|
|
6
|
-
for (const node of screens) node.hidden = node !== screen;
|
|
7
|
-
const overlay = screen.querySelector('.overlay');
|
|
8
|
-
const details = screen.querySelector('.detail-layer');
|
|
9
|
-
const open = screen.querySelector('.open-sheet');
|
|
10
|
-
const close = screen.querySelector('.sheet-close');
|
|
11
|
-
const detailClose = screen.querySelector('.detail-close');
|
|
12
|
-
let returnFocus = null;
|
|
13
|
-
function closeDetail() {
|
|
14
|
-
details.hidden = true;
|
|
15
|
-
if (returnFocus) returnFocus.focus();
|
|
16
|
-
}
|
|
17
|
-
function closeSheet() {
|
|
18
|
-
closeDetail();
|
|
19
|
-
overlay.hidden = true;
|
|
20
|
-
screen.querySelector('.chat-body').inert = false;
|
|
21
|
-
open.focus();
|
|
22
|
-
}
|
|
23
|
-
open.addEventListener('click', () => {
|
|
24
|
-
overlay.hidden = false;
|
|
25
|
-
screen.querySelector('.chat-body').inert = true;
|
|
26
|
-
close.focus();
|
|
27
|
-
});
|
|
28
|
-
close.addEventListener('click', closeSheet);
|
|
29
|
-
detailClose.addEventListener('click', closeDetail);
|
|
30
|
-
for (const button of screen.querySelectorAll('[data-group]')) {
|
|
31
|
-
button.addEventListener('click', () => {
|
|
32
|
-
const selected = button.dataset.group;
|
|
33
|
-
for (const option of screen.querySelectorAll('[data-group]')) option.setAttribute('aria-pressed', String(option.dataset.group === selected));
|
|
34
|
-
for (const section of screen.querySelectorAll('[data-section]')) section.hidden = selected !== 'all' && section.dataset.section !== selected;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
for (const button of screen.querySelectorAll('.detail-open')) {
|
|
38
|
-
button.addEventListener('click', () => {
|
|
39
|
-
returnFocus = button;
|
|
40
|
-
const row = button.closest('.row');
|
|
41
|
-
screen.querySelector('.detail-title').textContent = row.querySelector('.row-label').textContent;
|
|
42
|
-
screen.querySelector('.detail-text').textContent = row.querySelector('.detail-copy').textContent;
|
|
43
|
-
details.hidden = false;
|
|
44
|
-
detailClose.focus();
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
document.addEventListener('keydown', event => {
|
|
48
|
-
if (event.key === 'Escape') {
|
|
49
|
-
if (!details.hidden) closeDetail();
|
|
50
|
-
else if (!overlay.hidden) closeSheet();
|
|
51
|
-
}
|
|
52
|
-
if (event.key === 'Tab' && !overlay.hidden) {
|
|
53
|
-
const scope = details.hidden ? screen.querySelector('.sheet') : screen.querySelector('.detail-box');
|
|
54
|
-
const buttons = [...scope.querySelectorAll('button,summary')].filter(el => el.getClientRects().length);
|
|
55
|
-
const first = buttons[0], last = buttons[buttons.length - 1];
|
|
56
|
-
if (event.shiftKey && document.activeElement === first) {event.preventDefault();last.focus();}
|
|
57
|
-
else if (!event.shiftKey && document.activeElement === last) {event.preventDefault();first.focus();}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
overlay.hidden = params.get('view') !== 'expanded';
|
|
61
|
-
screen.querySelector('.chat-body').inert = !overlay.hidden;
|
|
62
|
-
if (!overlay.hidden) close.focus({preventScroll:true});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;font:400 16px/1.5 -apple-system,BlinkMacSystemFont,"PingFang SC","Segoe UI",sans-serif;color:#243C37;background:#FCFCF9}button{font:inherit;color:inherit;cursor:pointer}button,summary{-webkit-tap-highlight-color:transparent}button:focus-visible,summary:focus-visible{outline:3px solid var(--accent);outline-offset:3px}[hidden]{display:none!important}h1,h2,h3,p{margin:0}h1,h2,h3{font-size:var(--title-size,16px);font-weight:500}svg{display:block;flex:none}button{border:0}button:active{transform:scale(.97)}.screen{font:400 16px/1.5 -apple-system,BlinkMacSystemFont,"PingFang SC","Segoe UI",sans-serif;color:#243C37;position:relative;width:100%;height:100%;overflow:hidden;--accent:#28645B;--soft:#EAF1E9;--muted:#75817B;--line:#E5E9E1;background:#FCFCF9}.icon{width:22px;height:22px;stroke:currentColor;stroke-width:1.65;fill:none;stroke-linecap:round;stroke-linejoin:round}.statusbar{height:38px;padding:12px 25px 0;display:flex;justify-content:space-between;align-items:center;font-size:13px;font-weight:500}.statusbar .device{display:flex;align-items:center;gap:5px}.device .icon{width:17px;height:17px}.chat-header{height:61px;padding:5px 19px 14px;display:flex;align-items:center;gap:12px;border-bottom:1px solid #E9ECE6;background:#FCFCF9}.chat-header .back{margin-right:2px}.buddy-identity{flex:1}.buddy-identity strong{display:block;font-size:16px;font-weight:500;letter-spacing:-.3px}.buddy-identity small{display:block;font-size:11px;color:var(--muted);margin-top:1px}.header-mark{width:33px;height:33px;border-radius:12px;background:var(--accent);color:white;display:grid;place-items:center;font-size:16px;font-weight:500}.chat-body{height:calc(100% - 178px);overflow-y:auto;padding:20px 16px 30px;scrollbar-width:none}.chat-date{text-align:center;font-size:11px;color:#929A93;margin:0 0 17px;letter-spacing:.3px}.message{display:flex;gap:9px;margin:13px 0;align-items:flex-start}.avatar{width:26px;height:26px;border-radius:10px;background:var(--soft);color:var(--accent);display:grid;place-items:center;font-size:13px;font-weight:500;flex:none;margin-top:3px}.bubble{padding:12px 14px;max-width:calc(100% - 41px);font-size:16px;line-height:1.65;border-radius:16px;white-space:pre-wrap;overflow-wrap:anywhere}.message.user{justify-content:flex-end;margin-bottom:20px}.user .bubble{background:#E6EEEB;border-top-right-radius:5px}.assistant .bubble{background:#F1F2EC;border-top-left-radius:5px}.chat-card{margin:16px 0 0 35px;border:1px solid #E2E7DC;border-radius:21px;background:#fff;overflow:hidden;box-shadow:0 5px 22px #334F3710}.card-top{padding:16px 16px 13px;display:flex;align-items:center;gap:11px}.identity-icon{display:grid;place-items:center;width:37px;height:37px;flex:none;border-radius:13px;color:var(--accent);background:var(--soft)}.card-kind{font-size:11px;color:var(--muted);letter-spacing:.4px;margin-bottom:2px}.chat-card h1{font-size:16px;letter-spacing:-.3px}.card-summary{font-size:16px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;padding:0 16px 14px}.card-meta{margin:0 16px 15px;padding:10px 0;border-top:1px solid var(--line);display:flex;gap:16px}.card-meta .metric{flex:1;min-width:0}.metric-label{font-size:11px;color:var(--muted);display:block}.metric-value{font-size:16px;font-weight:500;display:block;margin-top:3px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.open-sheet{width:calc(100% - 32px);margin:0 16px 15px;padding:10px 14px;border-radius:12px;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:space-between;font-size:14px;font-weight:500}.open-sheet .icon{width:17px;height:17px}.card-foot{font-size:11px;color:var(--muted);padding:0 16px 14px;display:flex;align-items:center;gap:5px}.card-foot .icon{width:12px;height:12px}.composer{position:absolute;bottom:19px;left:16px;right:16px;display:flex;align-items:center;gap:10px;border:1px solid #E5E8DE;border-radius:16px;background:#fff;padding:12px;color:#859087;font-size:12px;min-height:49px;box-shadow:0 3px 17px #334F3708}.composer span{flex:1}.home-indicator{position:absolute;bottom:7px;left:36%;right:36%;height:4px;background:#35433E;border-radius:9px}.overlay{position:absolute;inset:0;display:grid;place-items:center;background:#263F3552;backdrop-filter:blur(2px);z-index:2}.sheet{width:calc(100% - 32px);height:65%;border-radius:25px;background:#FFFEFB;box-shadow:0 22px 60px #17362B30;display:flex;flex-direction:column;overflow:hidden;position:relative}.sheet-header{padding:14px 16px;display:flex;gap:10px;align-items:center;flex:none;min-height:66px;border-bottom:1px solid #E8ECE2}.sheet-header .identity-icon{width:32px;height:32px;border-radius:11px}.sheet-header .icon{width:19px;height:19px}.sheet-header h2{flex:1;font-size:16px;letter-spacing:-.2px}.close{width:32px;height:32px;flex:none;border:1px solid #E5E8DF;border-radius:50%;background:#FFFEFB;display:grid;place-items:center;color:#526B5E}.close .icon{width:16px;height:16px}.sheet-body{overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:#CBD3C5 transparent;min-height:0;flex:1;padding:0 16px 16px}.overview{padding:18px 0 15px;border-bottom:1px solid var(--line)}.eyebrow{font-size:10px;color:var(--accent);letter-spacing:1.2px;font-weight:500;margin-bottom:6px}.overview-title{font-size:20px;line-height:1.4;letter-spacing:-.5px;font-weight:500;color:#203D31}.overview-subtitle{font-size:12px;color:var(--muted);margin-top:5px;line-height:1.5;white-space:pre-wrap}.overview-metrics{display:grid;grid-template-columns:repeat(var(--metric-count),1fr);gap:10px;margin-top:14px}.overview-metrics .metric{padding-left:10px;border-left:1px solid #DDE4D7;min-width:0}.overview-metrics .metric:first-child{padding-left:0;border-left:0}.overview-metrics .metric-value{font-size:20px;line-height:1.35;letter-spacing:-.4px}.progress-track{height:5px;background:#E4EADB;border-radius:9px;overflow:hidden;margin-top:14px}.progress-fill{height:100%;background:var(--accent);border-radius:9px}.progress-caption{font-size:11px;color:var(--muted);margin-top:6px}.reading-nav{position:sticky;top:0;z-index:1;background:#FFFEFB;padding:13px 0 10px;display:flex;gap:7px;overflow-x:auto;scrollbar-width:none;box-shadow:0 3px 0 #FFFEFB}.reading-nav button{border:1px solid #E3E8DC;background:#F5F6EF;border-radius:10px;padding:8px 12px;flex:none;font-size:13px;white-space:nowrap;color:#6B7C6D}.reading-nav button[aria-pressed=true]{border-color:var(--accent);background:var(--accent);color:#fff;box-shadow:0 3px 7px #205C4120}.section{margin:8px 0 18px}.section-heading{font-size:13px;font-weight:500;color:#53694F;margin:0 0 9px;padding:5px 0;display:flex;align-items:center;gap:8px;cursor:default;list-style:none}.section-heading::-webkit-details-marker{display:none}.section-heading .icon{width:14px;height:14px;margin-left:auto;transition:transform .16s ease}summary.section-heading{cursor:pointer}details[open]>summary .icon{transform:rotate(90deg)}.section-count{font-size:10px;color:#809077;background:#EEF1E7;padding:1px 6px;border-radius:5px}.row{display:flex;gap:10px;position:relative;align-items:flex-start;padding:13px 0;border-bottom:1px solid #E8ECE2}.row:last-child{border-bottom:0}.row-symbol{width:29px;height:29px;flex:none;color:var(--accent);border:1px solid #E0E7D8;background:#F4F6EE;border-radius:10px;display:grid;place-items:center;margin-top:1px}.row-symbol .icon{width:17px;height:17px}.row-content{flex:1;min-width:0}.row-label{font-size:16px;font-weight:500;line-height:1.45;overflow-wrap:anywhere}.row-value{font-size:16px;font-weight:400;line-height:1.6;margin-top:3px;white-space:pre-wrap;overflow-wrap:anywhere;color:#405348}.row-caption{font-size:12px;line-height:1.55;color:var(--muted);margin-top:5px;white-space:pre-wrap;overflow-wrap:anywhere}.status{display:inline-flex;align-items:center;gap:4px;font-size:10px;line-height:1.5;padding:3px 7px;border-radius:6px;margin-top:7px;color:#687565;background:#EEF1E8}.status:before{content:"";width:4px;height:4px;border-radius:50%;background:currentColor}.status.positive{color:#2D6A50;background:#EAF2E7}.status.pending{color:#92662E;background:#F7EFDC}.status.changed{color:#416B7A;background:#E9F0F1}.status.neutral{color:#73806E;background:#EDF0E8}.detail-open{flex:none;background:transparent;padding:8px 0 8px 4px;border-radius:9px;color:#849477;margin-top:2px;min-width:28px;min-height:36px}.detail-open .icon{width:17px;height:17px}.timeline .row{border:0;padding-left:63px;min-height:88px;padding-top:7px;padding-bottom:17px}.timeline .row:before{content:"";position:absolute;left:46px;top:15px;bottom:-8px;width:1px;background:#DAE3D1}.timeline .row:last-child:before{bottom:15px}.timeline .row:after{content:"";position:absolute;left:42px;top:13px;width:9px;height:9px;background:var(--accent);border:2px solid #FFFEFB;border-radius:50%;box-shadow:0 0 0 1px #BDD0B6}.timeline .row-label{position:absolute;left:0;top:10px;width:35px;font-size:11px;line-height:1.5;font-weight:500;font-variant-numeric:tabular-nums;color:#6F826A}.timeline .row-value{font-size:16px;color:#243C37;margin:0}.timeline .row-symbol{display:none}.cards .row{background:#F5F6F0;border:1px solid #E6EADF;border-radius:16px;padding:14px 12px;margin-bottom:10px}.cards .row:last-child{border-bottom:1px solid #E6EADF}.cards .row-symbol{background:#FFFEFB}.ledger .row{align-items:center}.ledger .row-content{display:grid;grid-template-columns:1fr auto;gap:2px 10px;align-items:baseline}.ledger .row-label{font-size:16px;font-weight:400}.ledger .row-value{font-size:16px;font-weight:500;margin:0;text-align:right;font-variant-numeric:tabular-nums}.ledger .row-caption,.ledger .status{grid-column:1/-1}.ledger .status{justify-self:start}.checklist .row{padding:12px 0}.checklist .row-symbol{border-radius:50%;width:24px;height:24px;margin-top:2px;background:transparent}.checklist .row.positive .row-symbol{background:#EAF2E7;color:#2D6A50;border-color:#C4D4BD}.checklist .row-value{font-size:16px;color:#687B60}.note{display:flex;align-items:flex-start;gap:6px;border-top:1px solid var(--line);padding-top:13px;font-size:11px;color:#8A9580;line-height:1.5}.note .icon{width:13px;height:13px;margin-top:1px}.detail-layer{position:absolute;inset:0;background:#263F3566;display:grid;place-items:center;z-index:3}.detail-box{width:calc(100% - 32px);max-height:65%;overflow-y:auto;background:#FFFEFB;border-radius:23px;padding:18px;box-shadow:0 15px 40px #18382B26}.detail-head{display:flex;align-items:center;gap:10px;margin-bottom:14px}.detail-head h3{flex:1;font-size:16px}.detail-text{font-size:16px;line-height:1.75;white-space:pre-wrap;overflow-wrap:anywhere}.detail-foot{font-size:11px;color:var(--muted);border-top:1px solid var(--line);margin-top:18px;padding-top:12px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(prefers-reduced-motion:no-preference){button{transition:background .16s ease,transform .16s ease,box-shadow .16s ease}.overlay{animation:veil .18s ease both}.sheet{animation:arrive .24s cubic-bezier(.2,.8,.2,1) both}.detail-box{animation:arrive .2s ease both}@keyframes arrive{from{transform:translateY(8px) scale(.99);opacity:.3}to{transform:none;opacity:1}}@keyframes veil{from{opacity:0}to{opacity:1}}}.svg-export *{animation:none!important;transition:none!important}.svg-export .overlay{backdrop-filter:none}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const params = new URLSearchParams(location.search);
|
|
3
|
-
const requested = params.get('state') || 'initial';
|
|
4
|
-
const screens = [...document.querySelectorAll('.screen')];
|
|
5
|
-
const screen = screens.find(node => node.dataset.state === requested) || screens[0];
|
|
6
|
-
for (const node of screens) node.hidden = node !== screen;
|
|
7
|
-
const overlay = screen.querySelector('.overlay');
|
|
8
|
-
const details = screen.querySelector('.detail-layer');
|
|
9
|
-
const sheet = screen.querySelector('.sheet');
|
|
10
|
-
const open = screen.querySelector('.open-sheet');
|
|
11
|
-
const close = screen.querySelector('.sheet-close');
|
|
12
|
-
const detailClose = screen.querySelector('.detail-close');
|
|
13
|
-
let returnFocus = null;
|
|
14
|
-
function closeDetail() {
|
|
15
|
-
details.hidden = true;
|
|
16
|
-
sheet.inert = false;
|
|
17
|
-
if (returnFocus) returnFocus.focus();
|
|
18
|
-
}
|
|
19
|
-
function closeSheet() {
|
|
20
|
-
closeDetail();
|
|
21
|
-
overlay.hidden = true;
|
|
22
|
-
screen.querySelector('.chat-body').inert = false;
|
|
23
|
-
open.focus();
|
|
24
|
-
}
|
|
25
|
-
open.addEventListener('click', event => {
|
|
26
|
-
overlay.hidden = false;
|
|
27
|
-
screen.querySelector('.chat-body').inert = true;
|
|
28
|
-
(event.detail === 0 ? close : sheet).focus({preventScroll:true});
|
|
29
|
-
});
|
|
30
|
-
close.addEventListener('click', closeSheet);
|
|
31
|
-
detailClose.addEventListener('click', closeDetail);
|
|
32
|
-
for (const button of screen.querySelectorAll('[data-group]')) {
|
|
33
|
-
button.addEventListener('click', () => {
|
|
34
|
-
const selected = button.dataset.group;
|
|
35
|
-
for (const option of screen.querySelectorAll('[data-group]')) option.setAttribute('aria-pressed', String(option.dataset.group === selected));
|
|
36
|
-
for (const section of screen.querySelectorAll('[data-section]')) section.hidden = selected !== 'all' && section.dataset.section !== selected;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
for (const button of screen.querySelectorAll('.detail-open')) {
|
|
40
|
-
button.addEventListener('click', () => {
|
|
41
|
-
returnFocus = button;
|
|
42
|
-
const row = button.closest('.row');
|
|
43
|
-
screen.querySelector('.detail-title').textContent = row.querySelector('.row-label, .row-value').textContent;
|
|
44
|
-
screen.querySelector('.detail-text').textContent = row.querySelector('.detail-copy').textContent;
|
|
45
|
-
details.hidden = false;
|
|
46
|
-
sheet.inert = true;
|
|
47
|
-
detailClose.focus();
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
document.addEventListener('keydown', event => {
|
|
51
|
-
if (event.key === 'Escape') {
|
|
52
|
-
if (!details.hidden) closeDetail();
|
|
53
|
-
else if (!overlay.hidden) closeSheet();
|
|
54
|
-
}
|
|
55
|
-
if (event.key === 'Tab' && !overlay.hidden) {
|
|
56
|
-
const scope = details.hidden ? screen.querySelector('.sheet') : screen.querySelector('.detail-box');
|
|
57
|
-
const buttons = [...scope.querySelectorAll('button,summary')].filter(el => el.getClientRects().length);
|
|
58
|
-
const first = buttons[0], last = buttons[buttons.length - 1];
|
|
59
|
-
if (event.shiftKey && (document.activeElement === first || document.activeElement === sheet)) {event.preventDefault();last.focus();}
|
|
60
|
-
else if (!event.shiftKey && document.activeElement === last) {event.preventDefault();first.focus();}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
overlay.hidden = params.get('view') !== 'expanded';
|
|
64
|
-
screen.querySelector('.chat-body').inert = !overlay.hidden;
|
|
65
|
-
if (!overlay.hidden) sheet.focus({preventScroll:true});
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
* { box-sizing: border-box; }
|
|
2
|
-
html, body { margin: 0; width: 100%; height: 100%; background: #fff; }
|
|
3
|
-
button { font: inherit; color: inherit; border: 0; cursor: pointer; }
|
|
4
|
-
button, summary { -webkit-tap-highlight-color: transparent; }
|
|
5
|
-
button:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
6
|
-
[hidden] { display: none !important; }
|
|
7
|
-
h1, h2, h3, p { margin: 0; }
|
|
8
|
-
h1, h2, h3 { font-size: var(--title-size, 16px); font-weight: 500; }
|
|
9
|
-
.screen { font: 400 16px/1.5 -apple-system, BlinkMacSystemFont, "PingFang SC", "Segoe UI", sans-serif; color: #202733; position: relative; width: 100%; height: 100%; overflow: hidden; background: #fff; --accent: #326BC4; --muted: #7C8490; --line: #E9EDF2; }
|
|
10
|
-
.icon { display: block; flex: none; width: 22px; height: 22px; stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }
|
|
11
|
-
.statusbar { height: 40px; padding: 10px 25px 0; display: flex; align-items: center; justify-content: space-between; font-size: 13px; font-weight: 500; }
|
|
12
|
-
.device { display: flex; gap: 5px; }
|
|
13
|
-
.device .icon { width: 16px; height: 16px; }
|
|
14
|
-
.chat-header { height: 56px; padding: 0 20px 10px; display: flex; align-items: center; gap: 16px; border-bottom: 1px solid var(--line); }
|
|
15
|
-
.chat-header strong { flex: 1; text-align: center; font-size: 16px; font-weight: 500; }
|
|
16
|
-
.back { font-size: 28px; line-height: 1; }
|
|
17
|
-
.chat-body { height: calc(100% - 176px); overflow-y: auto; padding: 20px 16px 28px; scrollbar-width: none; }
|
|
18
|
-
.chat-date { color: #9299A3; text-align: center; font-size: 11px; margin-bottom: 18px; }
|
|
19
|
-
.message { display: flex; gap: 9px; align-items: flex-start; margin: 14px 0; }
|
|
20
|
-
.avatar { flex: none; width: 26px; height: 26px; border-radius: 8px; background: #E9F0FB; color: var(--accent); display: grid; place-items: center; font-size: 12px; font-weight: 500; margin-top: 3px; }
|
|
21
|
-
.bubble { max-width: calc(100% - 38px); font-size: 16px; line-height: 1.65; padding: 12px 14px; border-radius: 12px; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
22
|
-
.user { justify-content: flex-end; }
|
|
23
|
-
.user .bubble { background: #EAF1FB; border-top-right-radius: 3px; }
|
|
24
|
-
.assistant .bubble { background: #F4F5F7; border-top-left-radius: 3px; }
|
|
25
|
-
.chat-card { margin: 16px 0 0 35px; border: 1px solid #DFE5ED; border-radius: 14px; background: #fff; overflow: hidden; }
|
|
26
|
-
.card-content { padding: 17px 16px 18px; }
|
|
27
|
-
.card-kind { font-size: 12px; color: var(--accent); margin-bottom: 8px; }
|
|
28
|
-
.chat-card h1 { font-size: 16px; font-weight: 500; line-height: 1.45; }
|
|
29
|
-
.card-summary { font-size: 16px; line-height: 1.65; color: #66707E; margin-top: 9px; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
30
|
-
.open-sheet { width: 100%; padding: 12px 16px; display: flex; align-items: center; justify-content: space-between; border-top: 1px solid var(--line); background: #fff; color: var(--accent); font-size: 14px; font-weight: 500; }
|
|
31
|
-
.open-sheet .icon { width: 17px; height: 17px; }
|
|
32
|
-
.open-sheet:hover { background: #F6F8FC; }
|
|
33
|
-
.composer { position: absolute; bottom: 19px; left: 16px; right: 16px; display: flex; align-items: center; gap: 10px; min-height: 49px; padding: 12px; border: 1px solid #E6E9EF; border-radius: 14px; background: #fff; color: #9299A3; font-size: 12px; }
|
|
34
|
-
.composer span { flex: 1; }
|
|
35
|
-
.home-indicator { position: absolute; bottom: 7px; left: 36%; right: 36%; height: 4px; border-radius: 8px; background: #252C37; }
|
|
36
|
-
.overlay { position: absolute; inset: 0; z-index: 2; background: #17243B45; display: grid; place-items: center; }
|
|
37
|
-
.sheet { width: calc(100% - 32px); height: 65%; border-radius: 22px; background: #fff; display: flex; flex-direction: column; overflow: hidden; position: relative; box-shadow: 0 12px 36px #192B4720; outline: none; }
|
|
38
|
-
.sheet-header { flex: none; height: 60px; display: flex; align-items: center; padding: 0 16px 0 20px; border-bottom: 1px solid var(--line); }
|
|
39
|
-
.sheet-header h2 { flex: 1; font-size: 16px; font-weight: 500; }
|
|
40
|
-
.close { width: 32px; height: 32px; background: transparent; color: #8490A0; border-radius: 8px; display: grid; place-items: center; flex: none; }
|
|
41
|
-
.close .icon { width: 20px; height: 20px; }
|
|
42
|
-
.close:hover { background: #F3F5F8; color: #26344C; }
|
|
43
|
-
.sheet-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 20px 20px; scrollbar-width: thin; scrollbar-color: #D5DBE5 transparent; }
|
|
44
|
-
.overview { padding: 22px 0 15px; }
|
|
45
|
-
.overview h3 { font-size: 20px; line-height: 1.4; font-weight: 500; letter-spacing: -.4px; }
|
|
46
|
-
.overview-subtitle { color: var(--muted); font-size: 13px; margin-top: 6px; line-height: 1.6; white-space: pre-wrap; }
|
|
47
|
-
.reading-meta { color: #606E81; font-size: 13px; margin-top: 12px; }
|
|
48
|
-
.overview-metrics { display: grid; grid-template-columns: repeat(var(--metric-count), 1fr); gap: 16px; margin-top: 22px; }
|
|
49
|
-
.metric-label { display: block; font-size: 12px; color: var(--muted); }
|
|
50
|
-
.metric-value { display: block; font-size: 20px; font-weight: 500; line-height: 1.4; margin-top: 4px; letter-spacing: -.3px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
|
|
51
|
-
.overview-metrics .metric:first-child .metric-value { color: var(--accent); }
|
|
52
|
-
.progress-track { height: 3px; overflow: hidden; background: #ECF0F5; margin-top: 16px; }
|
|
53
|
-
.progress-track > div { height: 100%; background: var(--accent); }
|
|
54
|
-
.progress-caption { font-size: 11px; color: var(--muted); margin-top: 7px; }
|
|
55
|
-
.reading-nav { position: sticky; top: 0; z-index: 1; display: flex; gap: 22px; background: #fff; border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; }
|
|
56
|
-
.reading-nav button { flex: none; position: relative; padding: 12px 0; font-size: 14px; background: transparent; color: #8A93A1; white-space: nowrap; }
|
|
57
|
-
.reading-nav button[aria-pressed=true] { color: var(--accent); font-weight: 500; }
|
|
58
|
-
.reading-nav button[aria-pressed=true]:after { position: absolute; content: ""; height: 2px; background: var(--accent); left: 0; right: 0; bottom: 0; }
|
|
59
|
-
.reading-nav button:hover { color: var(--accent); }
|
|
60
|
-
.section { margin: 20px 0 24px; }
|
|
61
|
-
.section-heading { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; color: #8A93A1; font-size: 12px; font-weight: 400; line-height: 1.5; list-style: none; }
|
|
62
|
-
.section-heading::-webkit-details-marker { display: none; }
|
|
63
|
-
summary.section-heading { cursor: pointer; padding: 4px 0; }
|
|
64
|
-
.section-heading .icon { margin-left: auto; width: 13px; height: 13px; }
|
|
65
|
-
details[open] > summary .icon { transform: rotate(90deg); }
|
|
66
|
-
.row { display: flex; align-items: flex-start; gap: 10px; padding: 15px 0; border-bottom: 1px solid var(--line); }
|
|
67
|
-
.row:last-child { border-bottom: none; }
|
|
68
|
-
.row-content { flex: 1; min-width: 0; }
|
|
69
|
-
.row-label { font-size: 16px; font-weight: 500; line-height: 1.5; overflow-wrap: anywhere; }
|
|
70
|
-
.row-value { font-size: 16px; font-weight: 400; line-height: 1.6; margin-top: 4px; color: #263243; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
71
|
-
.row-caption { font-size: 13px; color: #87909D; line-height: 1.6; margin-top: 6px; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
72
|
-
.status { display: inline-block; font-size: 12px; line-height: 1.5; color: #8893A2; margin-top: 8px; }
|
|
73
|
-
.status.pending { color: #956B40; }
|
|
74
|
-
.status.changed { color: var(--accent); }
|
|
75
|
-
.detail-open { min-height: 38px; width: 26px; background: transparent; color: #9BA5B3; display: grid; place-items: center; padding: 0; flex: none; border-radius: 5px; }
|
|
76
|
-
.detail-open .icon { width: 15px; height: 15px; }
|
|
77
|
-
.timeline .row { position: relative; border: 0; gap: 21px; padding: 9px 0 23px; min-height: 82px; }
|
|
78
|
-
.timeline .time { flex: none; width: 36px; color: #738196; font-size: 12px; font-variant-numeric: tabular-nums; line-height: 1.6; padding-top: 3px; overflow-wrap: anywhere; }
|
|
79
|
-
.timeline .row:before { position: absolute; content: ""; left: 45px; top: 19px; bottom: -11px; width: 1px; background: #E2EAF6; }
|
|
80
|
-
.timeline .row:last-child:before { display: none; }
|
|
81
|
-
.timeline .row:after { position: absolute; content: ""; left: 43px; top: 17px; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
|
|
82
|
-
.timeline .row-value { margin-top: 0; }
|
|
83
|
-
.cards .row { padding: 16px 0 18px; }
|
|
84
|
-
.cards .row-value { color: #68758A; }
|
|
85
|
-
.ledger .row-content { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; align-items: baseline; }
|
|
86
|
-
.ledger .row-label { font-size: 16px; font-weight: 400; }
|
|
87
|
-
.ledger .row-value { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
|
|
88
|
-
.ledger .row-caption, .ledger .status { grid-column: 1 / -1; }
|
|
89
|
-
.checklist .row-value { color: #718098; }
|
|
90
|
-
.note { border-top: 1px solid var(--line); padding-top: 14px; color: #A1A8B2; font-size: 11px; }
|
|
91
|
-
.detail-layer { position: absolute; inset: 0; z-index: 3; background: #17243B45; display: grid; place-items: center; }
|
|
92
|
-
.detail-box { width: calc(100% - 32px); max-height: 65%; overflow-y: auto; padding: 20px; border-radius: 22px; background: #fff; box-shadow: 0 12px 36px #192B4720; }
|
|
93
|
-
.detail-head { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
|
|
94
|
-
.detail-head h3 { flex: 1; font-size: 16px; }
|
|
95
|
-
.detail-text { font-size: 16px; line-height: 1.75; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
96
|
-
.detail-foot { color: var(--muted); font-size: 11px; border-top: 1px solid var(--line); margin-top: 20px; padding-top: 14px; }
|
|
97
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
98
|
-
button { transition: color .15s, background .15s; }
|
|
99
|
-
button:active { opacity: .7; }
|
|
100
|
-
.sheet, .detail-box { animation: enter .18s ease-out both; }
|
|
101
|
-
@keyframes enter { from { transform: translateY(6px); opacity: .5; } to { transform: none; opacity: 1; } }
|
|
102
|
-
}
|
|
103
|
-
.svg-export * { animation: none !important; transition: none !important; }
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const params = new URLSearchParams(location.search);
|
|
3
|
-
const requested = params.get('state') || 'initial';
|
|
4
|
-
const screens = [...document.querySelectorAll('.screen')];
|
|
5
|
-
const screen = screens.find(node => node.dataset.state === requested) || screens[0];
|
|
6
|
-
for (const node of screens) node.hidden = node !== screen;
|
|
7
|
-
const overlay = screen.querySelector('.overlay');
|
|
8
|
-
const details = screen.querySelector('.detail-layer');
|
|
9
|
-
const sheet = screen.querySelector('.sheet');
|
|
10
|
-
const open = screen.querySelector('.open-sheet');
|
|
11
|
-
const close = screen.querySelector('.sheet-close');
|
|
12
|
-
const detailClose = screen.querySelector('.detail-close');
|
|
13
|
-
let returnFocus = null;
|
|
14
|
-
function closeDetail() {
|
|
15
|
-
details.hidden = true;
|
|
16
|
-
sheet.inert = false;
|
|
17
|
-
if (returnFocus) returnFocus.focus();
|
|
18
|
-
}
|
|
19
|
-
function closeSheet() {
|
|
20
|
-
closeDetail();
|
|
21
|
-
overlay.hidden = true;
|
|
22
|
-
screen.querySelector('.chat-body').inert = false;
|
|
23
|
-
open.focus();
|
|
24
|
-
}
|
|
25
|
-
open.addEventListener('click', event => {
|
|
26
|
-
overlay.hidden = false;
|
|
27
|
-
screen.querySelector('.chat-body').inert = true;
|
|
28
|
-
(event.detail === 0 ? close : sheet).focus({preventScroll:true});
|
|
29
|
-
});
|
|
30
|
-
close.addEventListener('click', closeSheet);
|
|
31
|
-
detailClose.addEventListener('click', closeDetail);
|
|
32
|
-
for (const button of screen.querySelectorAll('[data-group]')) {
|
|
33
|
-
button.addEventListener('click', () => {
|
|
34
|
-
const selected = button.dataset.group;
|
|
35
|
-
for (const option of screen.querySelectorAll('[data-group]')) option.setAttribute('aria-pressed', String(option.dataset.group === selected));
|
|
36
|
-
for (const section of screen.querySelectorAll('[data-section]')) section.hidden = selected !== 'all' && section.dataset.section !== selected;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
for (const button of screen.querySelectorAll('.detail-open')) {
|
|
40
|
-
button.addEventListener('click', () => {
|
|
41
|
-
returnFocus = button;
|
|
42
|
-
const row = button.closest('.row');
|
|
43
|
-
screen.querySelector('.detail-title').textContent = row.querySelector('.row-label, .row-value').textContent;
|
|
44
|
-
screen.querySelector('.detail-text').textContent = row.querySelector('.detail-copy').textContent;
|
|
45
|
-
details.hidden = false;
|
|
46
|
-
sheet.inert = true;
|
|
47
|
-
detailClose.focus();
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
document.addEventListener('keydown', event => {
|
|
51
|
-
if (event.key === 'Escape') {
|
|
52
|
-
if (!details.hidden) closeDetail();
|
|
53
|
-
else if (!overlay.hidden) closeSheet();
|
|
54
|
-
}
|
|
55
|
-
if (event.key === 'Tab' && !overlay.hidden) {
|
|
56
|
-
const scope = details.hidden ? screen.querySelector('.sheet') : screen.querySelector('.detail-box');
|
|
57
|
-
const buttons = [...scope.querySelectorAll('button,summary')].filter(el => el.getClientRects().length);
|
|
58
|
-
const first = buttons[0], last = buttons[buttons.length - 1];
|
|
59
|
-
if (event.shiftKey && (document.activeElement === first || document.activeElement === sheet)) {event.preventDefault();last.focus();}
|
|
60
|
-
else if (!event.shiftKey && document.activeElement === last) {event.preventDefault();first.focus();}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
overlay.hidden = params.get('view') !== 'expanded';
|
|
64
|
-
screen.querySelector('.chat-body').inert = !overlay.hidden;
|
|
65
|
-
// Embedded examples must not steal the Booklet's focus or reading position.
|
|
66
|
-
if (!overlay.hidden && window === window.top) sheet.focus({preventScroll:true});
|