skill-forge-hub 1.0.7 → 1.2.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/CHANGELOG.en.md +19 -0
- package/CHANGELOG.md +19 -0
- package/README.en.md +20 -7
- package/README.md +20 -7
- package/SKILLS_CATALOG.md +119 -0
- package/annual-report/SKILL.md +13 -3
- package/annual-report/resources/disk-and-html.md +1 -0
- package/annual-report/resources/reference.html +3 -3
- package/annual-report/resources/skillforge-guide.html +409 -0
- package/annual-report/resources/skillforge-guide.txt +132 -0
- package/annual-report/user-config.md +1 -1
- package/article-to-html/SKILL.md +13 -1
- package/article-to-html/resources/skillforge-guide.html +409 -0
- package/article-to-html/resources/skillforge-guide.txt +132 -0
- package/article-to-html/user-config.md +1 -1
- package/cli.js +60 -19
- package/commit-heatmap/SKILL.md +70 -0
- package/commit-heatmap/resources/collect.md +22 -0
- package/commit-heatmap/resources/generate.md +15 -0
- package/commit-heatmap/resources/html-rules.md +21 -0
- package/commit-heatmap/resources/reference.html +228 -0
- package/commit-heatmap/resources/skillforge-guide.html +409 -0
- package/commit-heatmap/resources/skillforge-guide.txt +132 -0
- package/commit-heatmap/resources/usage-guide.md +23 -0
- package/commit-heatmap/user-config.md +12 -0
- package/daily-report/SKILL.md +12 -2
- package/daily-report/resources/disk-and-html.md +1 -1
- package/daily-report/resources/reference.html +1 -1
- package/daily-report/resources/skillforge-guide.html +409 -0
- package/daily-report/resources/skillforge-guide.txt +132 -0
- package/daily-report/user-config.md +1 -1
- package/data-prepper/SKILL.md +54 -0
- package/data-prepper/resources/clean-rules.md +18 -0
- package/data-prepper/resources/overview.md +17 -0
- package/data-prepper/resources/read-data.md +13 -0
- package/data-prepper/resources/skillforge-guide.html +409 -0
- package/data-prepper/resources/skillforge-guide.txt +132 -0
- package/data-prepper/resources/usage-guide.md +24 -0
- package/data-prepper/user-config.md +11 -0
- package/decision-log/SKILL.md +53 -0
- package/decision-log/resources/index.md +21 -0
- package/decision-log/resources/record.md +19 -0
- package/decision-log/resources/skillforge-guide.html +409 -0
- package/decision-log/resources/skillforge-guide.txt +132 -0
- package/decision-log/resources/usage-guide.md +23 -0
- package/decision-log/user-config.md +9 -0
- package/deck-stage/SKILL.md +14 -11
- package/deck-stage/resources/cover-template.html +1 -1
- package/deck-stage/resources/skillforge-guide.html +409 -0
- package/deck-stage/resources/skillforge-guide.txt +132 -0
- package/docs/architecture.en.md +2 -1
- package/docs/architecture.md +2 -1
- package/docs/articles/ai-daily-report-correct-pose.md +39 -0
- package/docs/articles/ai-prompt-management-skill-pouch.md +37 -0
- package/docs/directory-submission.md +106 -0
- package/docs/install.en.md +57 -1
- package/docs/install.md +57 -1
- package/docs/usage-examples.en.md +50 -0
- package/docs/usage-examples.md +50 -0
- package/magic-deck/SKILL.md +15 -6
- package/magic-deck/resources/deck-spec.md +1 -1
- package/magic-deck/resources/reference.html +1 -1
- package/magic-deck/resources/skillforge-guide.html +409 -0
- package/magic-deck/resources/skillforge-guide.txt +132 -0
- package/magic-deck/user-config.md +1 -1
- package/meeting-minutes/SKILL.md +11 -1
- package/meeting-minutes/resources/disk-and-html.md +1 -0
- package/meeting-minutes/resources/reference.html +1 -1
- package/meeting-minutes/resources/skillforge-guide.html +409 -0
- package/meeting-minutes/resources/skillforge-guide.txt +132 -0
- package/meeting-minutes/user-config.md +1 -1
- package/meta-forge/SKILL.md +13 -3
- package/meta-forge/resources/forge-rules.md +4 -1
- package/meta-forge/resources/skillforge-guide.html +409 -0
- package/meta-forge/resources/skillforge-guide.txt +132 -0
- package/meta-forge/user-config.md +1 -1
- package/monthly-report/SKILL.md +11 -1
- package/monthly-report/resources/disk-and-html.md +1 -0
- package/monthly-report/resources/reference.html +1 -1
- package/monthly-report/resources/skillforge-guide.html +409 -0
- package/monthly-report/resources/skillforge-guide.txt +132 -0
- package/monthly-report/user-config.md +1 -1
- package/one-pager/SKILL.md +83 -0
- package/one-pager/resources/content.md +18 -0
- package/one-pager/resources/design-process.md +117 -0
- package/one-pager/resources/generate.md +28 -0
- package/one-pager/resources/html-rules.md +66 -0
- package/one-pager/resources/reference.html +1290 -0
- package/one-pager/resources/skillforge-guide.html +409 -0
- package/one-pager/resources/skillforge-guide.txt +132 -0
- package/one-pager/resources/usage-guide.md +37 -0
- package/one-pager/resources/user-template-example.html +63 -0
- package/one-pager/user-config.md +14 -0
- package/package.json +12 -2
- package/prompt-pouch/SKILL.md +16 -16
- package/prompt-pouch/resources/reference.html +181 -43
- package/prompt-pouch/resources/skillforge-guide.html +409 -0
- package/prompt-pouch/resources/skillforge-guide.txt +132 -0
- package/prompt-pouch/resources/usage-guide.md +3 -3
- package/quarterly-report/SKILL.md +11 -1
- package/quarterly-report/resources/disk-and-html.md +1 -0
- package/quarterly-report/resources/reference.html +1 -1
- package/quarterly-report/resources/skillforge-guide.html +409 -0
- package/quarterly-report/resources/skillforge-guide.txt +132 -0
- package/quarterly-report/user-config.md +1 -1
- package/release-notes/SKILL.md +54 -0
- package/release-notes/resources/collect.md +17 -0
- package/release-notes/resources/publish-checklist.md +11 -0
- package/release-notes/resources/skillforge-guide.html +409 -0
- package/release-notes/resources/skillforge-guide.txt +132 -0
- package/release-notes/resources/usage-guide.md +25 -0
- package/release-notes/resources/write.md +27 -0
- package/release-notes/user-config.md +15 -0
- package/skill-doctor/SKILL.md +53 -0
- package/skill-doctor/resources/checks.md +27 -0
- package/skill-doctor/resources/report.md +26 -0
- package/skill-doctor/resources/skillforge-guide.html +409 -0
- package/skill-doctor/resources/skillforge-guide.txt +132 -0
- package/skill-doctor/resources/usage-guide.md +22 -0
- package/skill-doctor/user-config.md +9 -0
- package/spec-doc2spec/SKILL.md +13 -9
- package/spec-doc2spec/resources/skillforge-guide.html +409 -0
- package/spec-doc2spec/resources/skillforge-guide.txt +132 -0
- package/spec-doc2spec/user-config.md +1 -1
- package/spec-spec2doc/SKILL.md +13 -12
- package/spec-spec2doc/resources/skillforge-guide.html +409 -0
- package/spec-spec2doc/resources/skillforge-guide.txt +132 -0
- package/spec-spec2doc/user-config.md +1 -1
- package/team-report-collector/SKILL.md +70 -0
- package/team-report-collector/resources/collect.md +23 -0
- package/team-report-collector/resources/generate.md +14 -0
- package/team-report-collector/resources/html-rules.md +22 -0
- package/team-report-collector/resources/reference.html +384 -0
- package/team-report-collector/resources/skillforge-guide.html +409 -0
- package/team-report-collector/resources/skillforge-guide.txt +132 -0
- package/team-report-collector/resources/usage-guide.md +25 -0
- package/team-report-collector/user-config.md +12 -0
- package/template/SKILL.md +2 -2
- package/template/user-config.md +1 -1
- package/twin-docs/SKILL.md +53 -0
- package/twin-docs/resources/glossary.md +12 -0
- package/twin-docs/resources/skillforge-guide.html +409 -0
- package/twin-docs/resources/skillforge-guide.txt +132 -0
- package/twin-docs/resources/sync-check.md +15 -0
- package/twin-docs/resources/translate.md +20 -0
- package/twin-docs/resources/usage-guide.md +24 -0
- package/twin-docs/user-config.md +11 -0
- package/weekly-report/SKILL.md +12 -2
- package/weekly-report/resources/disk-and-html.md +1 -1
- package/weekly-report/resources/reference.html +1 -1
- package/weekly-report/resources/skillforge-guide.html +409 -0
- package/weekly-report/resources/skillforge-guide.txt +132 -0
- package/weekly-report/user-config.md +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta name="sf-template" content="prompt-pouch@
|
|
6
|
+
<meta name="sf-template" content="prompt-pouch@9">
|
|
7
7
|
<meta name="pouch-id" content="REF-POUCH-0000">
|
|
8
8
|
<title>锦囊 Prompt Pouch — 提示词管理台</title>
|
|
9
9
|
<style>
|
|
@@ -113,7 +113,7 @@ html,body{ height:100%; }
|
|
|
113
113
|
body{
|
|
114
114
|
background:var(--bg); /* 主体纯色:光晕/160° 渐变移入 fixed 氛围层 body::before——避免背景传播到画布后滚动出现上下颜色断层(html,body 锁 height:100% 时 body 背景只覆盖第一屏,跨浏览器传播行为不一致);四层氛围与光晕层均 fixed 覆盖视口,滚动恒定 */
|
|
115
115
|
color:var(--text);
|
|
116
|
-
font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,
|
|
116
|
+
font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,monospace;
|
|
117
117
|
min-height:100%;
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -200,12 +200,13 @@ header{
|
|
|
200
200
|
/* 侧栏 */
|
|
201
201
|
aside{ width:200px; flex:0 0 auto;
|
|
202
202
|
display:flex; flex-direction:column;
|
|
203
|
-
|
|
204
|
-
height:calc(100vh - 100px);
|
|
203
|
+
align-self:flex-start; /* 自然流式随页面整体滚动:说明卡完整展示,页面滚到底即可读完 */
|
|
205
204
|
}
|
|
206
|
-
/* 侧栏分组滚动区:收藏 +
|
|
205
|
+
/* 侧栏分组滚动区:收藏 + 分组局部滚动——滚动区最大高度 = 视口高度减去顶栏、「全部」行与底部「锦囊用法」说明卡(完整展示不裁剪),分组再多说明卡也完整可见;窄滚动条 */
|
|
207
206
|
.nav-scroll{
|
|
208
|
-
flex:
|
|
207
|
+
flex:0 0 auto; min-height:0;
|
|
208
|
+
max-height:calc(100vh - 360px);
|
|
209
|
+
overflow-y:auto;
|
|
209
210
|
margin:0 -4px 0 0; padding-right:4px;
|
|
210
211
|
scrollbar-width:thin; scrollbar-color:var(--border) transparent;
|
|
211
212
|
}
|
|
@@ -231,8 +232,8 @@ aside{ width:200px; flex:0 0 auto;
|
|
|
231
232
|
}
|
|
232
233
|
.nav-item.on .cnt{ color:var(--gold); background:var(--gold-dim); }
|
|
233
234
|
.side-tip{
|
|
234
|
-
flex:0 0 auto;
|
|
235
|
-
margin:
|
|
235
|
+
flex:0 0 auto; /* 完整展示不裁剪:分组滚动区为其留出空间,侧栏随页面整体滚动即可读完 */
|
|
236
|
+
margin:12px 0 0 0; padding:12px 14px 14px; border-radius:10px;
|
|
236
237
|
border:1px dashed var(--border); font-size:11px; line-height:1.9; color:var(--muted);
|
|
237
238
|
}
|
|
238
239
|
.side-tip b{ color:var(--gold); font-weight:700; }
|
|
@@ -246,13 +247,38 @@ main{ flex:1; min-width:0; }
|
|
|
246
247
|
font-weight:900;
|
|
247
248
|
}
|
|
248
249
|
.bar .total{ font-size:12px; color:var(--muted); }
|
|
249
|
-
.sort-box{ margin-left:auto; display:flex; align-items:center; gap:6px; font-size:11px; color:var(--muted); }
|
|
250
|
-
.sort-
|
|
250
|
+
.sort-box{ margin-left:auto; display:flex; align-items:center; gap:6px; font-size:11px; color:var(--muted); position:relative; }
|
|
251
|
+
.sort-sel{
|
|
252
|
+
display:flex; align-items:center; gap:7px;
|
|
251
253
|
background:var(--panel2); border:1px solid var(--border); color:var(--text);
|
|
252
254
|
font-family:inherit; font-size:12px; letter-spacing:1px;
|
|
253
|
-
border-radius:999px; padding:5px
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
border-radius:999px; padding:5px 13px; outline:none; cursor:pointer;
|
|
256
|
+
transition:border-color .15s ease;
|
|
257
|
+
}
|
|
258
|
+
.sort-sel:hover,.sort-sel.open{ border-color:var(--gold); }
|
|
259
|
+
.sort-arrow{ font-size:9px; color:var(--gold); line-height:1; transition:transform .2s ease; }
|
|
260
|
+
.sort-sel.open .sort-arrow{ transform:rotate(180deg); }
|
|
261
|
+
.sort-menu{
|
|
262
|
+
position:absolute; top:calc(100% + 6px); right:0; z-index:130;
|
|
263
|
+
display:flex; flex-direction:column; gap:2px; min-width:136px;
|
|
264
|
+
background:var(--panel2); border:1px solid var(--border); border-radius:12px;
|
|
265
|
+
padding:5px; box-shadow:0 12px 32px rgba(0,0,0,.45);
|
|
266
|
+
animation:sortMenuIn .16s ease;
|
|
267
|
+
}
|
|
268
|
+
.sort-menu[hidden]{ display:none; }
|
|
269
|
+
@keyframes sortMenuIn{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:none; } }
|
|
270
|
+
.sort-opt{
|
|
271
|
+
display:flex; align-items:center; gap:8px; width:100%;
|
|
272
|
+
background:transparent; border:none; border-radius:8px;
|
|
273
|
+
color:var(--text); font-family:inherit; font-size:12px; letter-spacing:1px;
|
|
274
|
+
padding:7px 10px; cursor:pointer; text-align:left;
|
|
275
|
+
transition:background .12s ease,color .12s ease;
|
|
276
|
+
}
|
|
277
|
+
.sort-opt:hover{ background:var(--gold-dim); color:var(--gold); }
|
|
278
|
+
.sort-check{ width:14px; font-size:11px; color:var(--gold); opacity:0; flex:0 0 auto; }
|
|
279
|
+
.sort-opt.on{ color:var(--gold); font-weight:600; }
|
|
280
|
+
.sort-opt.on .sort-check{ opacity:1; }
|
|
281
|
+
[data-theme="light"] .sort-menu{ box-shadow:0 10px 28px rgba(30,31,34,.16); }
|
|
256
282
|
.sort-status{
|
|
257
283
|
font-size:12px; color:var(--muted);
|
|
258
284
|
display:flex; align-items:center; gap:10px;
|
|
@@ -521,9 +547,10 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
521
547
|
}
|
|
522
548
|
/* 页面直写:侧栏分组管理 / 提示词表单 / toast */
|
|
523
549
|
.nav-add{
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
550
|
+
flex:0 0 auto; /* 「全部」行右侧迷你 + 图标(新建分组),行内不占独立高度 */
|
|
551
|
+
width:22px; height:22px; margin-left:6px;
|
|
552
|
+
display:flex; align-items:center; justify-content:center;
|
|
553
|
+
border-radius:6px; cursor:pointer; font-size:14px; line-height:1; color:var(--gold);
|
|
527
554
|
border:1px dashed var(--border); background:var(--gold-dim);
|
|
528
555
|
transition:all .18s ease; user-select:none;
|
|
529
556
|
}
|
|
@@ -636,13 +663,16 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
636
663
|
<span class="tag-filter" id="tagFilterChip" style="display:none"><span class="tf-ico">🏷</span><b id="tagFilterName"></b><button class="tf-x" id="tagFilterClear" title="清除标签过滤">✕</button></span>
|
|
637
664
|
<button class="btn primary" id="btnAddItem">+ 新增提示词</button>
|
|
638
665
|
<div class="sort-box">
|
|
639
|
-
<label
|
|
640
|
-
<
|
|
641
|
-
<
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
<
|
|
645
|
-
|
|
666
|
+
<label>排序</label>
|
|
667
|
+
<button class="sort-sel" id="sortSel" type="button" title="切换卡片排序方式">
|
|
668
|
+
<span class="sort-sel-txt" id="sortTxt">最新添加</span><span class="sort-arrow">▾</span>
|
|
669
|
+
</button>
|
|
670
|
+
<div class="sort-menu" id="sortMenu" hidden>
|
|
671
|
+
<button class="sort-opt on" data-mode="added" type="button"><span class="sort-check">✓</span>最新添加</button>
|
|
672
|
+
<button class="sort-opt" data-mode="recent" type="button"><span class="sort-check">✓</span>最近使用</button>
|
|
673
|
+
<button class="sort-opt" data-mode="freq" type="button"><span class="sort-check">✓</span>使用频率</button>
|
|
674
|
+
<button class="sort-opt" data-mode="manual" type="button"><span class="sort-check">✓</span>手动顺序</button>
|
|
675
|
+
</div>
|
|
646
676
|
</div>
|
|
647
677
|
<div class="sort-status" id="sortStatus">
|
|
648
678
|
<button class="btn" id="btnSortCmd" disabled>📋 复制变更指令</button>
|
|
@@ -812,6 +842,9 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
812
842
|
var searchClear = document.getElementById('searchClear');
|
|
813
843
|
var sortStatus = document.getElementById('sortStatus');
|
|
814
844
|
var sortSel = document.getElementById('sortSel');
|
|
845
|
+
var sortMenu = document.getElementById('sortMenu');
|
|
846
|
+
var sortTxt = document.getElementById('sortTxt');
|
|
847
|
+
var SORT_LABELS = { added:'最新添加', recent:'最近使用', freq:'使用频率', manual:'手动顺序' };
|
|
815
848
|
var btnSortCmd = document.getElementById('btnSortCmd');
|
|
816
849
|
var btnMarkSaved = document.getElementById('btnMarkSaved');
|
|
817
850
|
var bkStatus = document.getElementById('bkStatus');
|
|
@@ -944,16 +977,15 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
944
977
|
var html = '';
|
|
945
978
|
var all = state.data.prompts.length;
|
|
946
979
|
var favN = state.data.prompts.filter(function(p){ return p.favorite; }).length;
|
|
947
|
-
html += '<div class="nav-item' + (state.curGroup==='all'?' on':'') + '" data-g="all"><span class="icon">🗂️</span>全部<span class="cnt">' + all + '</span></div>';
|
|
980
|
+
html += '<div class="nav-item' + (state.curGroup==='all'?' on':'') + '" data-g="all"><span class="icon">🗂️</span>全部<span class="cnt">' + all + '</span><span class="nav-add" id="navAdd" title="新建分组">+</span></div>';
|
|
948
981
|
html += '<div class="nav-scroll">';
|
|
949
982
|
html += '<div class="nav-item' + (state.curGroup==='fav'?' on':'') + '" data-g="fav"><span class="icon">⭐</span>收藏<span class="cnt">' + favN + '</span></div>';
|
|
950
983
|
state.data.groups.forEach(function(g){
|
|
951
984
|
var n = state.data.prompts.filter(function(p){ return p.group === g.id; }).length;
|
|
952
985
|
html += '<div class="nav-item' + (state.curGroup===g.id?' on':'') + '" data-g="' + g.id + '" draggable="true" title="拖拽调整分组顺序"><span class="icon">' + g.icon + '</span><span class="g-name">' + escapeHtml(g.name) + '</span><span class="cnt">' + n + '</span><span class="g-ops"><button class="g-edit" title="编辑分组">✎</button><button class="g-del" title="删除分组">🗑</button></span></div>';
|
|
953
986
|
});
|
|
954
|
-
html += '<div class="nav-add" id="navAdd">+ 新建分组</div>';
|
|
955
|
-
html += '<div class="side-tip"><b>锦囊用法</b><br>· 页面直接增删改:+ 新建分组 / + 新增提示词 / ✎ 编辑 / 🗑 删除(授权目录即写即存)<br>· 也可对 AI 说「把 XX 加到写作输出分组」<br>· 顶栏切换排序;⇄ 移组、拖卡片排序自动保存;拖分组条调整分组顺序<br>· 点卡片标签按标签筛选(再点取消);标签悬停 ✕ 删 / + 加;⤓ 导出 / ⤒ 导入 JSON 备份<br>· ⭐ 收藏常用 · 复制次数在卡片右上角</div>';
|
|
956
987
|
html += '</div>';
|
|
988
|
+
html += '<div class="side-tip"><b>锦囊用法</b><br>· 页面直接增删改:+ 新建分组 / + 新增提示词 / ✎ 编辑 / 🗑 删除(授权目录即写即存)<br>· 也可对 AI 说「把 XX 加到写作输出分组」<br>· 顶栏切换排序;⇄ 移组、拖卡片排序自动保存;拖分组条调整分组顺序<br>· 点卡片标签按标签筛选(再点取消);标签悬停 ✕ 删 / + 加;⤓ 导出 / ⤒ 导入 JSON 备份<br>· ⭐ 收藏常用 · 复制次数在卡片右上角</div>';
|
|
957
989
|
sideNav.innerHTML = html;
|
|
958
990
|
sideNav.querySelectorAll('.nav-item').forEach(function(el){
|
|
959
991
|
el.addEventListener('click', function(){
|
|
@@ -1001,7 +1033,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1001
1033
|
});
|
|
1002
1034
|
});
|
|
1003
1035
|
var addBtn = sideNav.querySelector('#navAdd');
|
|
1004
|
-
if (addBtn) addBtn.addEventListener('click', function(){ openGroupForm(null); });
|
|
1036
|
+
if (addBtn) addBtn.addEventListener('click', function(e){ e.stopPropagation(); openGroupForm(null); });
|
|
1005
1037
|
}
|
|
1006
1038
|
|
|
1007
1039
|
function render(){
|
|
@@ -1198,7 +1230,12 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1198
1230
|
persistUserState();
|
|
1199
1231
|
scheduleBackup();
|
|
1200
1232
|
}
|
|
1201
|
-
function syncSortUI(){
|
|
1233
|
+
function syncSortUI(){
|
|
1234
|
+
if (sortTxt) sortTxt.textContent = SORT_LABELS[state.sortMode] || SORT_LABELS.added;
|
|
1235
|
+
if (sortMenu) sortMenu.querySelectorAll('.sort-opt').forEach(function(o){
|
|
1236
|
+
o.classList.toggle('on', o.getAttribute('data-mode') === state.sortMode);
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1202
1239
|
function ensureManual(){
|
|
1203
1240
|
if (state.sortMode === 'manual') return;
|
|
1204
1241
|
state.sortMode = 'manual';
|
|
@@ -1279,10 +1316,30 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1279
1316
|
if (!gpopEl.contains(e.target) && !onAnchor){ closeGpop(); }
|
|
1280
1317
|
}
|
|
1281
1318
|
});
|
|
1282
|
-
|
|
1283
|
-
|
|
1319
|
+
function toggleSortMenu(force){
|
|
1320
|
+
if (!sortMenu) return;
|
|
1321
|
+
var willOpen = (force !== undefined) ? force : sortMenu.hidden;
|
|
1322
|
+
sortMenu.hidden = !willOpen;
|
|
1323
|
+
sortSel.classList.toggle('open', willOpen);
|
|
1324
|
+
}
|
|
1325
|
+
sortSel.addEventListener('click', function(e){
|
|
1326
|
+
e.stopPropagation();
|
|
1327
|
+
toggleSortMenu();
|
|
1328
|
+
});
|
|
1329
|
+
sortMenu.addEventListener('click', function(e){
|
|
1330
|
+
var opt = e.target.closest('.sort-opt');
|
|
1331
|
+
if (!opt) return;
|
|
1332
|
+
state.sortMode = opt.getAttribute('data-mode');
|
|
1284
1333
|
persistUserState();
|
|
1285
1334
|
render();
|
|
1335
|
+
syncSortUI();
|
|
1336
|
+
toggleSortMenu(false);
|
|
1337
|
+
});
|
|
1338
|
+
document.addEventListener('click', function(e){
|
|
1339
|
+
if (!sortMenu.hidden){
|
|
1340
|
+
var onSel = e.target.closest && e.target.closest('#sortSel');
|
|
1341
|
+
if (!sortMenu.contains(e.target) && !onSel){ toggleSortMenu(false); }
|
|
1342
|
+
}
|
|
1286
1343
|
});
|
|
1287
1344
|
|
|
1288
1345
|
/* ---------- 模板插值({{变量}} / {变量}) ---------- */
|
|
@@ -1448,6 +1505,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1448
1505
|
if (next === null) return false;
|
|
1449
1506
|
return bkWrite('prompts.json', 'data', JSON.stringify(next, null, 2)).then(function(){
|
|
1450
1507
|
state.data = next;
|
|
1508
|
+
syncMirror(next);
|
|
1451
1509
|
applyUserState();
|
|
1452
1510
|
state.dirty = false; state.moves = [];
|
|
1453
1511
|
persistUserState(); refreshDirtyUI();
|
|
@@ -1484,6 +1542,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1484
1542
|
});
|
|
1485
1543
|
return bkWrite('prompts.json', 'data', JSON.stringify(latest, null, 2)).then(function(){
|
|
1486
1544
|
state.data = latest;
|
|
1545
|
+
syncMirror(latest);
|
|
1487
1546
|
applyUserState();
|
|
1488
1547
|
state.dirty = false; state.moves = [];
|
|
1489
1548
|
persistUserState(); refreshDirtyUI();
|
|
@@ -1868,6 +1927,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
|
|
|
1868
1927
|
if (e.key === 'Escape'){
|
|
1869
1928
|
closeFillPanel();
|
|
1870
1929
|
closeGpop();
|
|
1930
|
+
toggleSortMenu(false);
|
|
1871
1931
|
closeItemForm();
|
|
1872
1932
|
closeGroupForm();
|
|
1873
1933
|
document.getElementById('bkMask').classList.remove('open');
|
|
@@ -2030,6 +2090,19 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2030
2090
|
});
|
|
2031
2091
|
});
|
|
2032
2092
|
}
|
|
2093
|
+
/* 数据镜像:localStorage 存全量数据快照(file:// 下 IndexedDB 偶发不可用时兜底恢复,键按 pouch-id 隔离) */
|
|
2094
|
+
function syncMirror(data){
|
|
2095
|
+
try{ localStorage.setItem(SF_NS + '-mirror', JSON.stringify(data)); }catch(e){}
|
|
2096
|
+
}
|
|
2097
|
+
function readMirror(){
|
|
2098
|
+
try{
|
|
2099
|
+
var raw = localStorage.getItem(SF_NS + '-mirror');
|
|
2100
|
+
if (!raw) return null;
|
|
2101
|
+
var d = JSON.parse(raw);
|
|
2102
|
+
if (d && d.groups && d.prompts) return d;
|
|
2103
|
+
}catch(e){}
|
|
2104
|
+
return null;
|
|
2105
|
+
}
|
|
2033
2106
|
/* 备份文件读:backup/ 优先,读不到回退根目录旧文件(旧目录结构兼容) */
|
|
2034
2107
|
function readBk(name){
|
|
2035
2108
|
return bkRead(name, 'backup').then(function(text){
|
|
@@ -2122,6 +2195,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2122
2195
|
try{ localStorage.removeItem(SF_NS + '-bk-declined'); }catch(e){}
|
|
2123
2196
|
idbSet('bkHandle', bkDirHandle);
|
|
2124
2197
|
updateBkUI();
|
|
2198
|
+
reloadFromDirIfNeeded();
|
|
2125
2199
|
return true;
|
|
2126
2200
|
})
|
|
2127
2201
|
.catch(function(){ pendingAuth = false; updateBkUI(); return false; });
|
|
@@ -2168,6 +2242,43 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2168
2242
|
pendingAuth = false;
|
|
2169
2243
|
}).catch(function(){});
|
|
2170
2244
|
}
|
|
2245
|
+
/* file:// 直开补洞:fetch 被浏览器拦截读不到数据文件时,授权目录后直读 data/prompts.json 替换示例/快照 */
|
|
2246
|
+
function reloadFromDirIfNeeded(){
|
|
2247
|
+
if (!bkDirHandle || bootMode === 'live') return;
|
|
2248
|
+
readPouch().then(function(text){
|
|
2249
|
+
if (text === null) return;
|
|
2250
|
+
var data = JSON.parse(text);
|
|
2251
|
+
state.data = data;
|
|
2252
|
+
idbSet('lastData', data);
|
|
2253
|
+
syncMirror(data);
|
|
2254
|
+
bootMode = 'live';
|
|
2255
|
+
cacheBadge.style.display = 'none';
|
|
2256
|
+
applyUserState();
|
|
2257
|
+
renderNav(); render();
|
|
2258
|
+
toast('✓ 已直读 data/prompts.json,你的分组与提示词已载入');
|
|
2259
|
+
}).catch(function(){});
|
|
2260
|
+
}
|
|
2261
|
+
/* 「🔓 恢复数据」:已授权过目录但刷新后权限需重新确认(file:// 权限不跨会话持久)→ 一键 requestPermission 后直读,免重新选目录 */
|
|
2262
|
+
function restoreAuth(){
|
|
2263
|
+
if (!bkDirHandle || typeof bkDirHandle.requestPermission !== 'function') return;
|
|
2264
|
+
bkDirHandle.requestPermission({ mode: 'readwrite' }).then(function(st){
|
|
2265
|
+
if (st === 'granted'){
|
|
2266
|
+
pendingAuth = false; updateBkUI();
|
|
2267
|
+
reloadFromDirIfNeeded();
|
|
2268
|
+
} else {
|
|
2269
|
+
toast('未获授权:点「💾 授权目录」重新选择目录', true);
|
|
2270
|
+
}
|
|
2271
|
+
}).catch(function(){ toast('权限恢复失败,请重新授权目录', true); });
|
|
2272
|
+
}
|
|
2273
|
+
function updateBootBadge(){
|
|
2274
|
+
if (bootMode === 'live' || !bkDirHandle || !bootRendered) return;
|
|
2275
|
+
var link = ' <a id="bootRestore" style="cursor:pointer;text-decoration:underline">🔓 恢复数据</a>';
|
|
2276
|
+
cacheBadge.innerHTML = (bootMode === 'cache'
|
|
2277
|
+
? '⚠️ 快照模式:当前显示上次快照,目录权限需确认后直读最新数据'
|
|
2278
|
+
: '📌 示例模式:检测到曾授权过目录,点击确认权限即可载入你的数据') + link;
|
|
2279
|
+
cacheBadge.style.display = '';
|
|
2280
|
+
document.getElementById('bootRestore').addEventListener('click', restoreAuth);
|
|
2281
|
+
}
|
|
2171
2282
|
btnBkEnable.addEventListener('click', function(){
|
|
2172
2283
|
if (bkDirHandle && !pendingAuth){
|
|
2173
2284
|
writeBackupNow().then(function(ok){ toast(ok ? '✓ 备份完成 · backup/pouch-backup.json' : '备份失败,请重新授权目录', !ok); });
|
|
@@ -2179,7 +2290,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2179
2290
|
}
|
|
2180
2291
|
if (bkDirHandle && pendingAuth){
|
|
2181
2292
|
bkDirHandle.requestPermission({ mode: 'readwrite' }).then(function(st){
|
|
2182
|
-
if (st === 'granted'){ pendingAuth = false; updateBkUI(); writeBackupNow(); }
|
|
2293
|
+
if (st === 'granted'){ pendingAuth = false; updateBkUI(); writeBackupNow(); reloadFromDirIfNeeded(); }
|
|
2183
2294
|
else bkStatus.textContent = '未获授权,备份暂停';
|
|
2184
2295
|
}).catch(function(){});
|
|
2185
2296
|
return;
|
|
@@ -2191,6 +2302,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2191
2302
|
idbSet('bkHandle', bkDirHandle);
|
|
2192
2303
|
updateBkUI();
|
|
2193
2304
|
writeBackupNow();
|
|
2305
|
+
reloadFromDirIfNeeded();
|
|
2194
2306
|
})
|
|
2195
2307
|
.catch(function(){});
|
|
2196
2308
|
});
|
|
@@ -2204,6 +2316,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2204
2316
|
idbSet('bkHandle', bkDirHandle);
|
|
2205
2317
|
updateBkUI();
|
|
2206
2318
|
writeBackupNow();
|
|
2319
|
+
reloadFromDirIfNeeded();
|
|
2207
2320
|
})
|
|
2208
2321
|
.catch(function(){});
|
|
2209
2322
|
});
|
|
@@ -2267,6 +2380,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2267
2380
|
// 先把当前状态固化进备份(目录备份滚入 .prev.json / 快照环记一份),再应用所选备份
|
|
2268
2381
|
(bkDirHandle ? writeBackupNow() : writeSnapNow()).then(function(){
|
|
2269
2382
|
state.data = snap.data;
|
|
2383
|
+
syncMirror(snap.data);
|
|
2270
2384
|
applyUserStateFrom(snap.userState || {});
|
|
2271
2385
|
state.dirty = false; state.moves = [];
|
|
2272
2386
|
persistUserState();
|
|
@@ -2303,7 +2417,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2303
2417
|
render();
|
|
2304
2418
|
if (bootMode === 'cache') cacheBadge.style.display = '';
|
|
2305
2419
|
if (bootMode === 'demo'){
|
|
2306
|
-
cacheBadge.textContent = '📌 示例模式:未读到 data/prompts.json
|
|
2420
|
+
cacheBadge.textContent = '📌 示例模式:未读到 data/prompts.json,当前展示系统自带示例。若你有自己的数据文件:点顶部「💾 授权目录」选 prompt-pouch.html 所在文件夹即可直读载入;或经 HTTP 打开页面(file:// 直开会被浏览器拦截文件读取)。';
|
|
2307
2421
|
cacheBadge.style.display = '';
|
|
2308
2422
|
}
|
|
2309
2423
|
}
|
|
@@ -2319,26 +2433,49 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2319
2433
|
.then(function(data){
|
|
2320
2434
|
state.data = data;
|
|
2321
2435
|
idbSet('lastData', data);
|
|
2436
|
+
syncMirror(data);
|
|
2322
2437
|
bootMode = 'live';
|
|
2323
2438
|
firstRender();
|
|
2324
2439
|
})
|
|
2325
2440
|
.catch(function(){
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2441
|
+
// file:// 场景:fetch 被浏览器拦截 → 已授权目录则直读 data/prompts.json(File System Access API)
|
|
2442
|
+
return dirHandleReady.then(function(){
|
|
2443
|
+
return readPouch().then(function(text){
|
|
2444
|
+
if (text !== null) return JSON.parse(text);
|
|
2445
|
+
throw new Error('no-fs');
|
|
2446
|
+
});
|
|
2447
|
+
}).then(function(data){
|
|
2448
|
+
state.data = data;
|
|
2449
|
+
idbSet('lastData', data);
|
|
2450
|
+
syncMirror(data);
|
|
2451
|
+
bootMode = 'live';
|
|
2452
|
+
firstRender();
|
|
2453
|
+
}).catch(function(){
|
|
2454
|
+
idbGet('lastData').then(function(cached){
|
|
2455
|
+
if (cached){
|
|
2456
|
+
state.data = cached;
|
|
2457
|
+
bootMode = 'cache';
|
|
2458
|
+
firstRender();
|
|
2459
|
+
} else {
|
|
2460
|
+
var mirror = readMirror();
|
|
2461
|
+
if (mirror){
|
|
2462
|
+
state.data = mirror;
|
|
2463
|
+
bootMode = 'cache';
|
|
2464
|
+
firstRender();
|
|
2465
|
+
} else {
|
|
2466
|
+
state.data = DEFAULT_POUCH;
|
|
2467
|
+
bootMode = 'demo';
|
|
2468
|
+
firstRender();
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
});
|
|
2336
2472
|
});
|
|
2337
2473
|
});
|
|
2338
2474
|
// 本地态并行:可用则应用收藏与排序并刷新备份区(不阻塞数据展示)
|
|
2475
|
+
var dirHandleReady = idbOpen().then(function(){ return loadDirHandle(); }).catch(function(){});
|
|
2339
2476
|
idbOpen()
|
|
2340
2477
|
.then(loadLocalState)
|
|
2341
|
-
.then(
|
|
2478
|
+
.then(function(){ return dirHandleReady; })
|
|
2342
2479
|
.catch(function(){})
|
|
2343
2480
|
.then(function(){
|
|
2344
2481
|
applyUserState();
|
|
@@ -2346,6 +2483,7 @@ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(POUC
|
|
|
2346
2483
|
refreshDirtyUI();
|
|
2347
2484
|
if (bootRendered){ renderNav(); render(); }
|
|
2348
2485
|
updateBkUI();
|
|
2486
|
+
updateBootBadge();
|
|
2349
2487
|
});
|
|
2350
2488
|
})();
|
|
2351
2489
|
|