skill-forge-hub 0.5.4 → 1.0.1

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +5 -4
  3. package/annual-report/SKILL.md +4 -3
  4. package/annual-report/resources/disk-and-html.md +1 -1
  5. package/annual-report/resources/reference.html +33 -18
  6. package/annual-report/user-config.md +1 -1
  7. package/article-to-html/SKILL.md +1 -39
  8. package/article-to-html/resources/usage-guide.md +41 -0
  9. package/cli.js +40 -7
  10. package/daily-report/SKILL.md +4 -3
  11. package/daily-report/resources/disk-and-html.md +1 -1
  12. package/daily-report/resources/reference.html +42 -18
  13. package/daily-report/user-config.md +1 -1
  14. package/deck-stage/SKILL.md +24 -4
  15. package/deck-stage/resources/cover-template.html +3 -2
  16. package/deck-stage/resources/data-schema.md +1 -1
  17. package/deck-stage/resources/pptx-builder.js +1 -1
  18. package/deck-stage/resources/usage-guide.md +2 -2
  19. package/deck-stage/user-config.md +2 -2
  20. package/magic-deck/SKILL.md +8 -3
  21. package/magic-deck/resources/deck-spec.md +15 -8
  22. package/magic-deck/resources/reference.html +18 -10
  23. package/magic-deck/resources/usage-guide.md +2 -2
  24. package/magic-deck/user-config.md +2 -2
  25. package/package.json +1 -1
  26. package/prompt-pouch/SKILL.md +12 -11
  27. package/prompt-pouch/resources/data-format.md +2 -1
  28. package/prompt-pouch/resources/reference.html +345 -32
  29. package/prompt-pouch/resources/usage-guide.md +11 -4
  30. package/prompt-pouch/user-config.md +1 -1
  31. package/spec-doc2spec/SKILL.md +1 -0
  32. package/spec-spec2doc/SKILL.md +1 -0
  33. package/weekly-report/SKILL.md +4 -3
  34. package/weekly-report/resources/disk-and-html.md +1 -1
  35. package/weekly-report/resources/reference.html +43 -19
  36. package/weekly-report/user-config.md +1 -1
@@ -15,6 +15,7 @@
15
15
  --tag-bg:rgba(232,176,75,.1);
16
16
  --star:#f7d9a0;
17
17
  --glow:rgba(232,176,75,.35);
18
+ --scan:rgba(232,176,75,.2); --scan-dim:rgba(232,176,75,.04);
18
19
  --btn-ink:#241505;
19
20
  --bar-hi:rgba(23,17,12,.96); --bar-lo:rgba(23,17,12,.88);
20
21
  }
@@ -27,37 +28,71 @@
27
28
  --tag-bg:rgba(56,189,248,.1);
28
29
  --star:#7dd3fc;
29
30
  --glow:rgba(56,189,248,.35);
31
+ --scan:rgba(56,189,248,.2); --scan-dim:rgba(56,189,248,.04);
30
32
  --btn-ink:#041018;
31
33
  --bar-hi:rgba(10,25,41,.96); --bar-lo:rgba(10,25,41,.88);
32
34
  }
33
- /* ═══ mono 深灰蓝:JetBrains Darcula 色系(深灰底 + 蓝灰文字 + 灰阶面板,IDE 同款观感) ═══ */
35
+ /* ═══ mono IDEA 黑亮:JetBrains New UI Dark 官方色系(编辑区 #1e1f22 + 面板/弹框 #2b2d30 + 描边 #3c3f41,IDE 同款) ═══ */
34
36
  [data-theme="mono"]{
35
- --bg:#2b2b2b; --bg2:#313335;
36
- --panel:#3c3f41; --panel2:#313335;
37
- --text:#a9b7c6; --muted:#808080;
38
- --gold:#a9b7c6; --gold2:#6b7280; --gold-dim:rgba(169,183,198,.12);
39
- --border:#4e5254;
40
- --tag-bg:#3c3f41;
41
- --star:#d7dce3;
42
- --glow:rgba(169,183,198,.18);
43
- --btn-ink:#2b2b2b;
44
- --bar-hi:rgba(43,43,43,.96); --bar-lo:rgba(43,43,43,.88);
45
- }
46
- /* mono 深灰蓝组件适配:魔法棒灰化、蓝灰标签、浅蓝灰星标、深灰弹层、输入区微亮蓝灰、色点蓝灰描边 */
47
- [data-theme="mono"] .lg{ filter:grayscale(1) brightness(.45); }
37
+ --bg:#1e1f22; --bg2:#2b2d30;
38
+ --panel:#2b2d30; --panel2:#313438;
39
+ --text:#dfe1e5; --muted:#9aa0a6;
40
+ --gold:#3574f0; --gold2:#5e9aff; --gold-dim:rgba(53,116,240,.14);
41
+ --border:#3c3f41;
42
+ --tag-bg:rgba(53,116,240,.1);
43
+ --star:#dfe1e5;
44
+ --glow:rgba(53,116,240,.22);
45
+ --scan:rgba(223,225,229,.18); --scan-dim:rgba(223,225,229,.05);
46
+ --btn-ink:#1e1f22;
47
+ --bar-hi:rgba(30,31,34,.96); --bar-lo:rgba(30,31,34,.88);
48
+ }
49
+ /* mono IDEA 黑亮组件适配:魔法棒提亮、图标灰白提亮、蓝标签、白星标、深灰弹层、输入区微亮、色点蓝描边 */
50
+ [data-theme="mono"] .lg{ filter:grayscale(1) brightness(.5); }
48
51
  [data-theme="mono"] .nav-item .icon,
49
- [data-theme="mono"] .search .kw{ filter:grayscale(1) brightness(1.15); }
50
- [data-theme="mono"] .tpl-badge{ color:#a9b7c6; background:rgba(169,183,198,.14); }
51
- [data-theme="mono"] .op.star-on{ color:#d7dce3; border-color:rgba(169,183,198,.45); background:rgba(169,183,198,.16); }
52
- [data-theme="mono"] .gpop{ background:#3c3f41; border-color:#4e5254; box-shadow:0 12px 32px rgba(0,0,0,.6); }
52
+ [data-theme="mono"] .search .kw{ filter:grayscale(1) brightness(1.25); }
53
+ [data-theme="mono"] .tpl-badge{ color:#dfe1e5; background:rgba(223,225,229,.12); }
54
+ [data-theme="mono"] .op.star-on{ color:#dfe1e5; border-color:rgba(223,225,229,.5); background:rgba(223,225,229,.16); }
55
+ [data-theme="mono"] .gpop{ background:#2b2d30; border-color:#3c3f41; box-shadow:0 12px 32px rgba(0,0,0,.55); }
53
56
  [data-theme="mono"] .fp-preview,
54
57
  [data-theme="mono"] .fp-field input,
55
58
  [data-theme="mono"] .fp-field textarea,
56
59
  [data-theme="mono"] .fp-field select,
57
60
  [data-theme="mono"] .fp-live textarea,
58
61
  [data-theme="mono"] .bk-item,
59
- [data-theme="mono"] .detail-content{ background:rgba(169,183,198,.07); }
60
- [data-theme="mono"] .theme-dock .th-dot[data-theme="mono"]{ border:1.5px solid rgba(169,183,198,.55); }
62
+ [data-theme="mono"] .detail-content{ background:rgba(223,225,229,.06); }
63
+ [data-theme="mono"] .theme-dock .th-dot[data-theme="mono"]{ border:1.5px solid rgba(94,154,255,.6); }
64
+ [data-theme="mono"] body{ background:var(--bg); } /* 主体纯 #1e1f22:去掉顶部光晕/160° 渐变,消除上灰下黑断层(JetBrains New UI Dark 编辑区同色);四层氛围独立于 body,mono 下星点换装灰白、条纹灰白不泛蓝 */
65
+
66
+ /* ═══ light IDEA 白亮:IntelliJ Light 官方色系(白编辑区 + 浅灰面板 #f2f2f2 + IDEA 蓝强调) ═══ */
67
+ [data-theme="light"]{
68
+ --bg:#ffffff; --bg2:#f2f2f2;
69
+ --panel:#f2f2f2; --panel2:#ffffff;
70
+ --text:#1e1f22; --muted:#6e7781;
71
+ --gold:#2675bf; --gold2:#4a9be0; --gold-dim:rgba(38,117,191,.12);
72
+ --border:#d1d1d1;
73
+ --tag-bg:rgba(38,117,191,.08);
74
+ --star:#e5a33c;
75
+ --glow:rgba(38,117,191,.16);
76
+ --scan:rgba(38,117,191,.12); --scan-dim:rgba(38,117,191,.03);
77
+ --btn-ink:#ffffff;
78
+ --bar-hi:rgba(255,255,255,.96); --bar-lo:rgba(255,255,255,.88);
79
+ }
80
+ /* light IDEA 白亮组件适配:魔法棒灰黑、图标灰化、蓝标签、暖金星标、白弹层、输入区浅灰、色点蓝描边 */
81
+ [data-theme="light"] .lg{ filter:grayscale(1) brightness(.7); }
82
+ [data-theme="light"] .nav-item .icon,
83
+ [data-theme="light"] .search .kw{ filter:grayscale(1) brightness(.85); }
84
+ [data-theme="light"] .tpl-badge{ color:#2675bf; background:rgba(38,117,191,.1); }
85
+ [data-theme="light"] .op.star-on{ color:#e5a33c; border-color:rgba(229,163,60,.5); background:rgba(229,163,60,.14); }
86
+ [data-theme="light"] .gpop{ background:#ffffff; border-color:#d1d1d1; box-shadow:0 12px 32px rgba(30,31,34,.14); }
87
+ [data-theme="light"] .fp-preview,
88
+ [data-theme="light"] .fp-field input,
89
+ [data-theme="light"] .fp-field textarea,
90
+ [data-theme="light"] .fp-field select,
91
+ [data-theme="light"] .fp-live textarea,
92
+ [data-theme="light"] .bk-item,
93
+ [data-theme="light"] .detail-content{ background:#f7f9fb; }
94
+ [data-theme="light"] .theme-dock .th-dot[data-theme="light"]{ border:1.5px solid rgba(38,117,191,.5); }
95
+ [data-theme="light"] body{ background:var(--bg); } /* 主体纯白 #ffffff:去掉顶部光晕/160° 渐变,对齐 IntelliJ Light 编辑区;四层氛围独立于 body */
61
96
  [data-theme="mint"]{ /* 薄荷绿 */
62
97
  --bg:#0d1a12; --bg2:#12241a;
63
98
  --panel:#182f22; --panel2:#1e3a2a;
@@ -67,6 +102,7 @@
67
102
  --tag-bg:rgba(74,222,128,.1);
68
103
  --star:#b9ffd8;
69
104
  --glow:rgba(74,222,128,.35);
105
+ --scan:rgba(74,222,128,.2); --scan-dim:rgba(74,222,128,.04);
70
106
  --btn-ink:#04150a;
71
107
  --bar-hi:rgba(13,26,18,.96); --bar-lo:rgba(13,26,18,.88);
72
108
  }
@@ -75,12 +111,52 @@ html,body{ height:100%; }
75
111
  body{
76
112
  background:
77
113
  radial-gradient(1200px 500px at 70% -10%, var(--gold-dim), transparent 60%),
78
- repeating-linear-gradient(90deg, rgba(255,255,255,.012) 0 1px, transparent 1px 90px),
79
114
  linear-gradient(160deg, var(--bg) 0%, var(--bg2) 100%);
80
115
  color:var(--text);
81
116
  font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,'PingFang SC','Microsoft YaHei',monospace;
82
117
  min-height:100%;
83
118
  }
119
+
120
+ /* ============ 四层科技氛围(与日报/周报/年报同源,透明度淡半档——工具页不扰读) ============ */
121
+ .grid-pattern{
122
+ position:fixed; inset:0; z-index:0; pointer-events:none;
123
+ background-image:linear-gradient(var(--scan-dim) 1px, transparent 1px),linear-gradient(90deg, var(--scan-dim) 1px, transparent 1px);
124
+ background-size:60px 60px;
125
+ }
126
+ .stars{
127
+ position:fixed; inset:0; z-index:0; pointer-events:none;
128
+ background-image:
129
+ radial-gradient(1px 1px at 12% 18%, rgba(255,255,255,.3), transparent),
130
+ radial-gradient(1px 1px at 28% 64%, var(--scan), transparent),
131
+ radial-gradient(1.5px 1.5px at 41% 32%, rgba(255,255,255,.24), transparent),
132
+ radial-gradient(1px 1px at 56% 78%, var(--scan), transparent),
133
+ radial-gradient(1px 1px at 67% 12%, var(--scan), transparent),
134
+ radial-gradient(1.5px 1.5px at 79% 52%, var(--scan), transparent),
135
+ radial-gradient(1px 1px at 88% 86%, rgba(255,255,255,.26), transparent),
136
+ radial-gradient(1px 1px at 93% 24%, var(--scan), transparent);
137
+ }
138
+ .scanlines{
139
+ position:fixed; inset:0; z-index:999; pointer-events:none;
140
+ background:repeating-linear-gradient(0deg, transparent 0 2px, var(--scan-dim) 2px 4px);
141
+ }
142
+ .scanband{
143
+ position:fixed; left:0; right:0; height:150px; z-index:998; pointer-events:none;
144
+ background:linear-gradient(180deg, transparent, var(--scan-dim) 50%, transparent);
145
+ animation:scanMove 11s linear infinite;
146
+ }
147
+ @keyframes scanMove{ from{top:-22%;} to{top:112%;} }
148
+ /* mono 黑亮下氛围换装:条纹留存、颜色去彩——星点改中性灰白(IDEA 文本色系),与报表 mono 同源 */
149
+ [data-theme="mono"] .stars{ background-image:
150
+ radial-gradient(1px 1px at 12% 18%, rgba(223,225,229,.26), transparent),
151
+ radial-gradient(1px 1px at 28% 64%, rgba(223,225,229,.22), transparent),
152
+ radial-gradient(1.5px 1.5px at 41% 32%, rgba(223,225,229,.2), transparent),
153
+ radial-gradient(1px 1px at 56% 78%, rgba(223,225,229,.18), transparent),
154
+ radial-gradient(1px 1px at 67% 12%, rgba(223,225,229,.2), transparent),
155
+ radial-gradient(1.5px 1.5px at 79% 52%, rgba(223,225,229,.22), transparent),
156
+ radial-gradient(1px 1px at 88% 86%, rgba(223,225,229,.24), transparent),
157
+ radial-gradient(1px 1px at 93% 24%, rgba(223,225,229,.24), transparent); }
158
+ /* 浅色主题下星点氛围自然淡出 */
159
+ [data-theme="light"] .stars{ opacity:.28; }
84
160
  /* ============ 顶栏 ============ */
85
161
  header{
86
162
  position:sticky; top:0; z-index:30;
@@ -190,7 +266,9 @@ main{ flex:1; min-width:0; }
190
266
  /* 卡片列表 */
191
267
  .list{ display:grid; grid-template-columns:repeat(auto-fill,minmax(360px,1fr)); gap:14px; }
192
268
  .card{
193
- background:linear-gradient(180deg, var(--panel) 0%, var(--panel2) 100%);
269
+ background:
270
+ repeating-linear-gradient(180deg, var(--scan-dim) 0 1px, transparent 1px 8px),
271
+ linear-gradient(180deg, var(--panel) 0%, var(--panel2) 100%);
194
272
  border:1px solid var(--border); border-radius:14px;
195
273
  padding:16px 18px 14px; position:relative;
196
274
  transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
@@ -211,7 +289,7 @@ main{ flex:1; min-width:0; }
211
289
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
212
290
  }
213
291
 
214
- /* 搜索命中高亮(四主题令牌适配) */
292
+ /* 搜索命中高亮(五主题令牌适配) */
215
293
  mark.hl{ background:var(--gold-dim); color:var(--gold); border-radius:3px; padding:0 2px; font-weight:700; }
216
294
  .hl-note{ font-size:10px; color:var(--gold); background:var(--gold-dim); border:1px solid var(--border); border-radius:4px; padding:0 5px; line-height:16px; margin-left:6px; vertical-align:middle; }
217
295
  .gbadge{
@@ -238,9 +316,49 @@ mark.hl{ background:var(--gold-dim); color:var(--gold); border-radius:3px; paddi
238
316
  .card-time .ct-ico{ color:var(--gold); flex:0 0 auto; }
239
317
  .card-foot{ display:flex; align-items:center; gap:8px; margin-top:2px; }
240
318
  .tag{
319
+ display:inline-flex; align-items:center; gap:2px;
241
320
  font-size:10px; color:var(--muted); background:var(--panel2);
242
321
  border:1px solid var(--border); border-radius:999px; padding:2px 8px; letter-spacing:.5px;
322
+ cursor:pointer; transition:color .15s ease, border-color .15s ease, background .15s ease;
323
+ }
324
+ .tag:hover{ color:var(--gold); border-color:var(--gold2); }
325
+ .tag.on{ color:var(--btn-ink); background:var(--gold); border-color:var(--gold); }
326
+ .tag .tag-x{
327
+ display:none; border:none; background:none; color:inherit; cursor:pointer;
328
+ font-size:11px; line-height:1; padding:0 2px; margin-right:-3px;
329
+ }
330
+ .tag:hover .tag-x{ display:inline-block; }
331
+ .tag .tag-x:hover{ color:var(--gold); }
332
+ .tag-add{
333
+ display:none; border:1px dashed var(--border); background:none; color:var(--muted);
334
+ border-radius:999px; font-size:10px; line-height:1; padding:3px 7px; cursor:pointer;
335
+ }
336
+ .tags-wrap:hover .tag-add{ display:inline-block; }
337
+ .tag-add:hover{ color:var(--gold); border-color:var(--gold2); }
338
+ .emoji-pick{
339
+ display:grid; grid-template-columns:repeat(9,1fr); gap:6px;
340
+ max-height:200px; overflow-y:auto; padding:4px 4px 4px 0;
341
+ }
342
+ .emoji-pick button{
343
+ font-size:28px; line-height:1.4; padding:5px 0; text-align:center;
344
+ background:none; border:1px solid transparent; border-radius:8px; cursor:pointer;
243
345
  }
346
+ .emoji-pick button:hover{ background:var(--tag-bg); border-color:var(--border); transform:scale(1.12); }
347
+ .emoji-pick button.sel{ background:var(--gold-dim); border-color:var(--gold); }
348
+ .tag-filter{
349
+ display:inline-flex; align-items:center; gap:6px;
350
+ font-size:11px; color:var(--gold); background:var(--gold-dim);
351
+ border:1px solid var(--border); border-radius:999px; padding:3px 6px 3px 10px;
352
+ }
353
+ .tag-filter b{ font-weight:600; max-width:140px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
354
+ .tag-filter .tf-x{
355
+ border:none; background:var(--border); color:var(--text); width:16px; height:16px;
356
+ border-radius:50%; cursor:pointer; font-size:10px; line-height:1; padding:0;
357
+ display:inline-flex; align-items:center; justify-content:center;
358
+ }
359
+ .tag-filter .tf-x:hover{ background:var(--gold); color:var(--btn-ink); }
360
+ .nav-item.drag-over{ opacity:.35; }
361
+ .nav-item.drop-target{ box-shadow:inset 0 2px 0 var(--gold); }
244
362
  .card-ops{ margin-left:auto; display:flex; gap:6px; opacity:0; transition:opacity .18s ease; }
245
363
  .card:hover .card-ops{ opacity:1; }
246
364
  .op{
@@ -463,7 +581,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
463
581
  .list{ grid-template-columns:1fr; }
464
582
  .card-ops{ opacity:1; }
465
583
  }
466
- /* 主题换肤坞:右下角四色点随点随换,记忆上次选择;打印隐藏 */
584
+ /* 主题换肤坞:右下角五色点随点随换,记忆上次选择;打印隐藏 */
467
585
  .theme-dock{ position:fixed; right:18px; bottom:18px; z-index:1001; display:flex; gap:8px;
468
586
  padding:8px 10px; border-radius:999px; background:var(--panel2); border:1px solid var(--border);
469
587
  box-shadow:0 4px 18px rgba(0,0,0,.3); }
@@ -473,12 +591,17 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
473
591
  .theme-dock .th-dot.on{ border-color:var(--text); }
474
592
  .theme-dock .th-dot[data-theme="gold"]{ background:#e8b04b; }
475
593
  .theme-dock .th-dot[data-theme="tech"]{ background:#0ea5e9; }
476
- .theme-dock .th-dot[data-theme="mono"]{ background:#2b2b2b; }
594
+ .theme-dock .th-dot[data-theme="mono"]{ background:#1e1f22; }
595
+ .theme-dock .th-dot[data-theme="light"]{ background:#ffffff; }
477
596
  .theme-dock .th-dot[data-theme="mint"]{ background:#4ade80; }
478
597
  @media print{ .theme-dock{ display:none; } }
479
598
  </style>
480
599
  </head>
481
600
  <body>
601
+ <div class="grid-pattern"></div>
602
+ <div class="stars"></div>
603
+ <div class="scanband"></div>
604
+ <div class="scanlines"></div>
482
605
 
483
606
  <header>
484
607
  <div class="hd-row">
@@ -502,6 +625,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
502
625
  <div class="bar">
503
626
  <h2 id="curTitle">全部提示词</h2>
504
627
  <span class="total" id="curTotal"></span>
628
+ <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>
505
629
  <button class="btn primary" id="btnAddItem">+ 新增提示词</button>
506
630
  <div class="sort-box">
507
631
  <label for="sortSel">排序</label>
@@ -522,6 +646,9 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
522
646
  <span class="bk-status" id="bkStatus">本地快照备份中</span>
523
647
  <button class="btn" id="btnBkChange" style="display:none">📂 换目录</button>
524
648
  <button class="btn" id="btnBkRestore" style="display:none">↩ 恢复备份</button>
649
+ <button class="btn" id="btnBkExport" title="把当前全部数据导出为 JSON 文件">⤓ 导出</button>
650
+ <button class="btn" id="btnBkImport" title="从 JSON 文件导入(覆盖现有数据,导入前自动备份)">⤒ 导入</button>
651
+ <input type="file" id="importFile" accept=".json,application/json" style="display:none" />
525
652
  </div>
526
653
  </div>
527
654
  <div class="list" id="cardList"></div>
@@ -587,7 +714,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
587
714
 
588
715
  <!-- 新建/编辑分组 -->
589
716
  <div class="modal-mask" id="groupMask">
590
- <div class="fill-panel" style="width:460px;">
717
+ <div class="fill-panel" style="width:640px;">
591
718
  <div class="fp-head">
592
719
  <div class="fp-title" id="groupTitle">新建分组</div>
593
720
  <span class="fp-count">落盘 data/prompts.json · 刷新即见</span>
@@ -595,6 +722,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
595
722
  <div class="fp-fields">
596
723
  <div class="fp-field"><label for="groupName">分组名</label><input id="groupName" placeholder="如:灵感" /></div>
597
724
  <div class="fp-field"><label for="groupIcon">图标(一个 emoji)</label><input id="groupIcon" placeholder="如:✨" maxlength="4" /></div>
725
+ <div class="fp-field"><label>快捷选择(点击填入,输入框仍可手输/粘贴任意字符)</label><div class="emoji-pick" id="emojiPick"></div></div>
598
726
  </div>
599
727
  <div class="fp-ops">
600
728
  <button class="btn" id="groupCancel">取消</button>
@@ -664,6 +792,7 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
664
792
  sortMode: 'added', // 'added' 最新添加 | 'recent' 最近使用 | 'freq' 使用频率 | 'manual' 手动顺序
665
793
  usage: {}, // id -> { lastUsed: ts, useCount: n }(复制时统计,存浏览器本地态)
666
794
  moves: [], // 跨组移动待办 [{title, from, to}](随变更指令交给 AI 落盘)
795
+ tagFilter: '', // 标签过滤(点卡片标签设置,再点取消;切分组自动清除)
667
796
  };
668
797
 
669
798
  /* ---------- 数据加载 ---------- */
@@ -723,10 +852,25 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
723
852
  function showErr(msg){
724
853
  listEl.innerHTML = '<div class="empty">' + msg + '</div>';
725
854
  }
855
+ function applyTagFilter(t){
856
+ state.tagFilter = (state.tagFilter === t) ? '' : t;
857
+ syncTagFilterUI();
858
+ render();
859
+ }
860
+ function syncTagFilterUI(){
861
+ var chip = document.getElementById('tagFilterChip');
862
+ var nameEl = document.getElementById('tagFilterName');
863
+ if (!chip) return;
864
+ if (!state.tagFilter){ chip.style.display = 'none'; }
865
+ else { chip.style.display = ''; nameEl.textContent = state.tagFilter; }
866
+ }
726
867
  function visiblePrompts(){
727
868
  var ps = state.data.prompts.slice();
728
869
  if (state.curGroup === 'fav') ps = ps.filter(function(p){ return p.favorite; });
729
870
  else if (state.curGroup !== 'all') ps = ps.filter(function(p){ return p.group === state.curGroup; });
871
+ if (state.tagFilter){
872
+ ps = ps.filter(function(p){ return (p.tags || []).indexOf(state.tagFilter) > -1; });
873
+ }
730
874
  if (state.query){
731
875
  var q = state.query.toLowerCase();
732
876
  ps = ps.filter(function(p){
@@ -797,16 +941,17 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
797
941
  html += '<div class="nav-item' + (state.curGroup==='fav'?' on':'') + '" data-g="fav"><span class="icon">⭐</span>收藏<span class="cnt">' + favN + '</span></div>';
798
942
  state.data.groups.forEach(function(g){
799
943
  var n = state.data.prompts.filter(function(p){ return p.group === g.id; }).length;
800
- html += '<div class="nav-item' + (state.curGroup===g.id?' on':'') + '" data-g="' + g.id + '"><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>';
944
+ 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>';
801
945
  });
802
946
  html += '</div>';
803
947
  html += '<div class="nav-add" id="navAdd">+ 新建分组</div>';
804
- html += '<div class="side-tip"><b>锦囊用法</b><br>· 页面直接增删改:+ 新建分组 / + 新增提示词 / ✎ 编辑 / 🗑 删除(授权目录即写即存)<br>· 也可对 AI 说「把 XX 加到写作输出分组」<br>· 顶栏切换排序;⇄ 移组、拖卡片排序自动保存<br>· ⭐ 收藏常用 · 复制次数在卡片右上角</div>';
948
+ html += '<div class="side-tip"><b>锦囊用法</b><br>· 页面直接增删改:+ 新建分组 / + 新增提示词 / ✎ 编辑 / 🗑 删除(授权目录即写即存)<br>· 也可对 AI 说「把 XX 加到写作输出分组」<br>· 顶栏切换排序;⇄ 移组、拖卡片排序自动保存;拖分组条调整分组顺序<br>· 点卡片标签按标签筛选(再点取消);标签悬停 ✕ 删 / + 加;⤓ 导出 / ⤒ 导入 JSON 备份<br>· ⭐ 收藏常用 · 复制次数在卡片右上角</div>';
805
949
  sideNav.innerHTML = html;
806
950
  sideNav.querySelectorAll('.nav-item').forEach(function(el){
807
951
  el.addEventListener('click', function(){
808
952
  var gv = el.getAttribute('data-g');
809
953
  state.curGroup = (gv === 'all' || gv === 'fav') ? gv : Number(gv);
954
+ state.tagFilter = ''; syncTagFilterUI();
810
955
  renderNav(); render();
811
956
  });
812
957
  });
@@ -824,6 +969,29 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
824
969
  delGroup(groupOf(gid));
825
970
  });
826
971
  });
972
+ var dragGid = null;
973
+ sideNav.querySelectorAll('.nav-item[draggable="true"]').forEach(function(el){
974
+ el.addEventListener('dragstart', function(e){
975
+ dragGid = Number(el.getAttribute('data-g'));
976
+ el.classList.add('drag-over');
977
+ try { e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', String(dragGid)); } catch(err){}
978
+ });
979
+ el.addEventListener('dragover', function(e){ e.preventDefault(); });
980
+ el.addEventListener('dragenter', function(e){
981
+ if (el.getAttribute('data-g') !== String(dragGid)) el.classList.add('drop-target');
982
+ });
983
+ el.addEventListener('dragleave', function(){ el.classList.remove('drop-target'); });
984
+ el.addEventListener('drop', function(e){
985
+ e.preventDefault();
986
+ el.classList.remove('drop-target');
987
+ if (dragGid === null || el.getAttribute('data-g') === String(dragGid)) return;
988
+ reorderGroups(dragGid, Number(el.getAttribute('data-g')));
989
+ });
990
+ el.addEventListener('dragend', function(){
991
+ sideNav.querySelectorAll('.nav-item').forEach(function(x){ x.classList.remove('drag-over','drop-target'); });
992
+ dragGid = null;
993
+ });
994
+ });
827
995
  var addBtn = sideNav.querySelector('#navAdd');
828
996
  if (addBtn) addBtn.addEventListener('click', function(){ openGroupForm(null); });
829
997
  }
@@ -877,7 +1045,32 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
877
1045
  card.querySelector('.card-top').appendChild(note);
878
1046
  }
879
1047
  var tw = card.querySelector('.tags-wrap');
880
- (p.tags || []).forEach(function(t){ tw.insertAdjacentHTML('beforeend', '<span class="tag">' + hlHtml(t, state.query) + '</span>'); });
1048
+ (p.tags || []).forEach(function(t){
1049
+ var tg = document.createElement('span');
1050
+ tg.className = 'tag' + (state.tagFilter === t ? ' on' : '');
1051
+ var lb = document.createElement('span');
1052
+ lb.innerHTML = hlHtml(t, state.query);
1053
+ var x = document.createElement('button');
1054
+ x.type = 'button';
1055
+ x.className = 'tag-x';
1056
+ x.textContent = '✕';
1057
+ x.title = '删除标签「' + t + '」';
1058
+ x.addEventListener('click', function(e){ e.stopPropagation(); removeTag(p, t); });
1059
+ tg.appendChild(lb);
1060
+ tg.appendChild(x);
1061
+ tg.title = '点击筛选该标签(再点取消)';
1062
+ tg.addEventListener('click', function(){ applyTagFilter(t); });
1063
+ tw.appendChild(tg);
1064
+ });
1065
+ if ((p.tags || []).length < 3){
1066
+ var ta = document.createElement('button');
1067
+ ta.type = 'button';
1068
+ ta.className = 'tag-add';
1069
+ ta.textContent = '+';
1070
+ ta.title = '添加标签(多个用逗号分隔,最多 3 个)';
1071
+ ta.addEventListener('click', function(e){ e.stopPropagation(); quickAddTag(p); });
1072
+ tw.appendChild(ta);
1073
+ }
881
1074
 
882
1075
  /* 详情弹窗 */
883
1076
  card.querySelector('.card-expand').addEventListener('click', function(){ openDetail(p); });
@@ -1421,6 +1614,42 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
1421
1614
  cmd: '请删除锦囊里「' + p.title + '」这条'
1422
1615
  }).then(function(ok){ if (ok) toast('已删除「' + p.title + '」'); });
1423
1616
  }
1617
+ /* 标签快捷操作:卡片标签悬停 ✕ 删 / + 加(授权目录即写即存,未授权生成指令) */
1618
+ function removeTag(p, t){
1619
+ writePromptsJson({
1620
+ apply: function(data){
1621
+ var item = data.prompts.find(function(x){ return x.id === p.id; });
1622
+ if (!item){ toast('该提示词已不存在,请刷新后重试', true); return null; }
1623
+ item.tags = (item.tags || []).filter(function(x){ return x !== t; });
1624
+ item.updatedAt = nowStamp();
1625
+ return data;
1626
+ },
1627
+ cmd: '请删除锦囊里「' + p.title + '」的标签「' + t + '」(tags 中移除该项,同时把 updatedAt 更新为当前时间 YYYY-MM-DD HH:mm:ss)'
1628
+ }).then(function(ok){
1629
+ if (ok){
1630
+ if (state.tagFilter === t) applyTagFilter(t);
1631
+ toast('已删除标签「' + t + '」');
1632
+ }
1633
+ });
1634
+ }
1635
+ function quickAddTag(p){
1636
+ var cur = (p.tags || []).slice(0, 3);
1637
+ var input = window.prompt('为「' + p.title + '」添加标签(多个用逗号分隔,最多 3 个):', cur.join(', '));
1638
+ if (input === null) return;
1639
+ var adds = input.split(/[,,]/).map(function(s){ return s.trim(); }).filter(Boolean);
1640
+ if (!adds.length) return;
1641
+ var merged = cur.concat(adds).slice(0, 3);
1642
+ writePromptsJson({
1643
+ apply: function(data){
1644
+ var item = data.prompts.find(function(x){ return x.id === p.id; });
1645
+ if (!item){ toast('该提示词已不存在,请刷新后重试', true); return null; }
1646
+ item.tags = merged;
1647
+ item.updatedAt = nowStamp();
1648
+ return data;
1649
+ },
1650
+ cmd: '请把锦囊里「' + p.title + '」的标签更新为:' + merged.join(', ') + '(同时把 updatedAt 更新为当前时间 YYYY-MM-DD HH:mm:ss)'
1651
+ }).then(function(ok){ if (ok) toast('标签已更新'); });
1652
+ }
1424
1653
  document.getElementById('itemCancel').addEventListener('click', closeItemForm);
1425
1654
  document.getElementById('itemSave').addEventListener('click', saveItem);
1426
1655
  itemName.addEventListener('keydown', function(e){ if (e.key === 'Enter'){ e.preventDefault(); saveItem(); } });
@@ -1432,11 +1661,28 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
1432
1661
  var groupName = document.getElementById('groupName');
1433
1662
  var groupIcon = document.getElementById('groupIcon');
1434
1663
  var editingGroupId = null;
1664
+ /* 分组图标快捷面板:预置 emoji 点击填入,输入框仍可手输/粘贴任意字符 */
1665
+ var EMOJI_PRESETS = ['✨','✍️','🖋','✏️','📝','📄','📋','🗒','📚','📖','📎','🔗','🧾','📊','📈','📉','🗂','📁','📦','🗃','🧰','💬','🗣','📣','☎️','📧','✉️','🤝','🔄','👥','🎙','🎧','📌','🗓','📅','⏰','⏱','⚙️','🔧','🛠','🧭','🗺','🚀','🏁','🎯','📍','🧠','💡','🔍','🧩','🔬','🧪','🏆','🥇','⭐','🌟','🔥','✅','✔️','⚠️','🚨','🔒','🛡','💎','🎨','🖌','🎬','🎵','📷','🌈','🍀','🌱','🌸','⚡','❄️','☀️','🌙','🍎','☕','🍵','🎂','🎁','🎉','🎊','🧸','🐣','🦄','💻','🖥','⌨️','🖱','📱','🔋','💾','📡'];
1666
+ var emojiPickEl = document.getElementById('emojiPick');
1667
+ EMOJI_PRESETS.forEach(function(e){
1668
+ var b = document.createElement('button');
1669
+ b.type = 'button';
1670
+ b.textContent = e;
1671
+ b.title = e;
1672
+ b.addEventListener('click', function(){ groupIcon.value = e; syncEmojiSel(); });
1673
+ emojiPickEl.appendChild(b);
1674
+ });
1675
+ function syncEmojiSel(){
1676
+ var v = groupIcon.value.trim();
1677
+ Array.prototype.forEach.call(emojiPickEl.children, function(b){ b.classList.toggle('sel', b.textContent === v); });
1678
+ }
1679
+ groupIcon.addEventListener('input', syncEmojiSel);
1435
1680
  function openGroupForm(g){
1436
1681
  editingGroupId = g ? g.id : null;
1437
1682
  groupTitleEl.textContent = g ? '编辑分组' : '新建分组';
1438
1683
  groupName.value = g ? g.name : '';
1439
1684
  groupIcon.value = g ? g.icon : '✨';
1685
+ syncEmojiSel();
1440
1686
  groupMask.classList.add('open');
1441
1687
  setTimeout(function(){ groupName.focus(); }, 60);
1442
1688
  }
@@ -1482,6 +1728,22 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
1482
1728
  cmd: '请删除锦囊分组「' + g.name + '」'
1483
1729
  }).then(function(ok){ if (ok) toast('分组「' + g.name + '」已删除'); });
1484
1730
  }
1731
+ function reorderGroups(moveId, beforeId){
1732
+ var ids = state.data.groups.map(function(g){ return g.id; });
1733
+ var mi = ids.indexOf(moveId), bi = ids.indexOf(beforeId);
1734
+ if (mi < 0 || bi < 0 || mi === bi) return;
1735
+ ids.splice(mi, 1);
1736
+ ids.splice(ids.indexOf(beforeId), 0, moveId);
1737
+ writePromptsJson({
1738
+ apply: function(data){
1739
+ var byId = {};
1740
+ data.groups.forEach(function(g){ byId[g.id] = g; });
1741
+ data.groups = ids.map(function(id){ return byId[id]; });
1742
+ return data;
1743
+ },
1744
+ cmd: '请把锦囊分组顺序调整为:' + ids.map(function(id){ var g = groupOf(id); return g ? g.name : id; }).join('、')
1745
+ }).then(function(ok){ if (ok) toast('分组顺序已保存'); });
1746
+ }
1485
1747
  document.getElementById('groupCancel').addEventListener('click', closeGroupForm);
1486
1748
  document.getElementById('groupSave').addEventListener('click', saveGroup);
1487
1749
  groupName.addEventListener('keydown', function(e){ if (e.key === 'Enter'){ e.preventDefault(); saveGroup(); } });
@@ -1489,6 +1751,56 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
1489
1751
  var btnAddItem = document.getElementById('btnAddItem');
1490
1752
  if (btnAddItem) btnAddItem.addEventListener('click', function(){ openItemForm(null); });
1491
1753
 
1754
+ /* ---------- 导入 / 导出 ---------- */
1755
+ var btnBkExport = document.getElementById('btnBkExport');
1756
+ var btnBkImport = document.getElementById('btnBkImport');
1757
+ var importFile = document.getElementById('importFile');
1758
+ function doExport(){
1759
+ if (!state.data){ toast('暂无数据可导出', true); return; }
1760
+ var blob = new Blob([JSON.stringify(state.data, null, 2)], { type: 'application/json' });
1761
+ var url = URL.createObjectURL(blob);
1762
+ var a = document.createElement('a');
1763
+ function p(n){ return (n < 10 ? '0' : '') + n; }
1764
+ var d = new Date();
1765
+ a.href = url;
1766
+ a.download = 'prompts-backup-' + d.getFullYear() + p(d.getMonth()+1) + p(d.getDate()) + '-' + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds()) + '.json';
1767
+ document.body.appendChild(a);
1768
+ a.click();
1769
+ document.body.removeChild(a);
1770
+ setTimeout(function(){ URL.revokeObjectURL(url); }, 1500);
1771
+ toast('已导出 ' + state.data.prompts.length + ' 条提示词');
1772
+ }
1773
+ function doImport(){
1774
+ if (!bkDirHandle){ toast('请先授权目录(页面顶部「💾 授权目录备份」)', true); return; }
1775
+ importFile.value = '';
1776
+ importFile.click();
1777
+ }
1778
+ importFile.addEventListener('change', function(){
1779
+ var f = importFile.files[0];
1780
+ if (!f) return;
1781
+ var reader = new FileReader();
1782
+ reader.onload = function(){
1783
+ var d = null;
1784
+ try {
1785
+ d = JSON.parse(String(reader.result));
1786
+ if (!d || !Array.isArray(d.groups) || !Array.isArray(d.prompts)){
1787
+ toast('文件格式不对:需要含 groups 与 prompts 的锦囊数据', true);
1788
+ return;
1789
+ }
1790
+ } catch(err){ toast('JSON 解析失败,请确认文件内容', true); return; }
1791
+ var cur = (state.data && state.data.prompts) ? state.data.prompts.length : 0;
1792
+ if (!window.confirm('导入将覆盖现有 ' + cur + ' 条数据为 ' + d.prompts.length + ' 条(导入前自动备份,可从 ↩ 恢复)。确定继续?')) return;
1793
+ writePromptsJson({ apply: function(){ return d; }, cmd: '' }).then(function(ok){
1794
+ if (ok) toast('已导入 ' + d.prompts.length + ' 条提示词');
1795
+ });
1796
+ };
1797
+ reader.readAsText(f, 'utf-8');
1798
+ });
1799
+ btnBkExport.addEventListener('click', doExport);
1800
+ btnBkImport.addEventListener('click', doImport);
1801
+ var tagFilterClear = document.getElementById('tagFilterClear');
1802
+ if (tagFilterClear) tagFilterClear.addEventListener('click', function(){ applyTagFilter(''); });
1803
+
1492
1804
  /* ---------- 排序指令 ---------- */
1493
1805
  function buildSortCmd(){
1494
1806
  var lines = ['请帮我调整 prompt-pouch 锦囊(按以下内容落盘 prompts.json):'];
@@ -2009,9 +2321,9 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
2009
2321
  });
2010
2322
  })();
2011
2323
 
2012
- /* 主题换肤:四套配色随点随换;记忆上次选择(localStorage,失败静默) */
2324
+ /* 主题换肤:五套配色随点随换;记忆上次选择(localStorage,失败静默) */
2013
2325
  (function(){
2014
- var THEMES = ['gold','tech','mono','mint'];
2326
+ var THEMES = ['gold','tech','mono','light','mint'];
2015
2327
  function init(){
2016
2328
  var dock = document.getElementById('themeDock');
2017
2329
  if (!dock) return;
@@ -2043,7 +2355,8 @@ footer.open .ht-arrow{ transform:rotate(180deg); }
2043
2355
  <div class="theme-dock" id="themeDock">
2044
2356
  <button class="th-dot" type="button" data-theme="gold" title="gold 暖棕金"></button>
2045
2357
  <button class="th-dot" type="button" data-theme="tech" title="tech 深蓝科技"></button>
2046
- <button class="th-dot" type="button" data-theme="mono" title="mono Darcula 深灰蓝"></button>
2358
+ <button class="th-dot" type="button" data-theme="mono" title="mono IDEA 黑亮"></button>
2359
+ <button class="th-dot" type="button" data-theme="light" title="light IDEA 白亮"></button>
2047
2360
  <button class="th-dot" type="button" data-theme="mint" title="mint 薄荷绿"></button>
2048
2361
  </div>
2049
2362
  </body>
@@ -1,6 +1,6 @@
1
1
  # 锦囊使用指南
2
2
 
3
- 锦囊(prompt-pouch)是一个本地 HTML 提示词管理台:暖棕金默认配色,内置四套主题(暖棕金/深蓝科技/Darcula 深灰蓝/薄荷绿,右下角换肤坞随时切换),分组侧栏 + 搜索 + 卡片网格,妙计入囊、随取随用。页面与数据分离——页面可直写、AI 可代笔(双笔协作),你只管说,刷新即见。
3
+ 锦囊(prompt-pouch)是一个本地 HTML 提示词管理台:暖棕金默认配色,内置五套主题(暖棕金/深蓝科技/IDEA 黑亮/IDEA 白亮/薄荷绿,右下角换肤坞随时切换),分组侧栏 + 搜索 + 卡片网格(背景四层科技氛围与卡片细纹,与日报/周报/年报同源),妙计入囊、随取随用。页面与数据分离——页面可直写、AI 可代笔(双笔协作),你只管说,刷新即见。
4
4
 
5
5
  ## 怎么用
6
6
 
@@ -10,17 +10,23 @@
10
10
  4. **删除**:页面点卡片「🗑」;或对 AI 说「删掉锦囊里『XX』这条」
11
11
  5. **排序与移组**:顶栏「排序」切换四种方式——最新添加(默认)/ 最近使用 / 使用频率 / 手动顺序;想手动排时拖动卡片或点 ▲▼(自动切回手动),点卡片 ⇄ 可把提示词移到其它分组;已授权目录时排序/移组 2 秒内自动保存,未授权时点「📋 复制变更指令」把指令发给 AI 落盘;复制过提示词后卡片右上角会显示「⧉ N 次 · 最近时间」(最近使用/使用频率排序即按复制统计);AI 落盘后回页面点「✓ 已落盘」清除未保存标记
12
12
  6. **收藏**:卡片右上角星标,收藏/取消收藏指令由 AI 同步到数据文件
13
- 7. **分组管理**:侧栏底部「+ 新建分组」;悬停分组名出现「✎ 改名 / 🗑 删除」(组内还有提示词时不允许删,先移出或删条目);重名分组会提示
13
+ 7. **分组管理**:侧栏底部「+ 新建分组」;悬停分组名出现「✎ 改名 / 🗑 删除」(组内还有提示词时不允许删,先移出或删条目);重名分组会提示;新建/编辑分组时图标输入框下方有快捷 emoji 面板(点击即填入、选中高亮,输入框仍可手输/粘贴任意 emoji)
14
+ 8. **标签全交互**:点卡片标签立即按标签筛选(顶栏出现「🏷 标签」胶囊,点 ✕ 或再点同标签取消,切分组自动清除,与搜索叠加);标签悬停出「✕」点它直接删除该标签;标签不满 3 个时悬停出「+」快速加标签(多个用逗号分隔)——已授权目录即写即存,未授权时操作指令复制给 AI 落盘
15
+ 9. **分组排序**:左侧分组条可直接拖拽调整顺序(已授权目录即写即存,未授权时指令自动复制给 AI 落盘)
16
+ 10. **导入 / 导出**:顶栏「⤓ 导出」把当前全部数据下载为 JSON 备份文件(文件名带时间戳);「⤒ 导入」选择 JSON 文件整库覆盖现有数据(导入前自动备份,可从「↩ 恢复」回滚;未授权目录时导出仍可用、导入需先授权)
14
17
 
15
18
  ## 特色功能
16
19
 
17
- - **搜索高亮**:搜索框输入关键词,命中卡片的标题/正文/标签中匹配词以主题色徽标高亮(四主题自适应);命中落在正文三行折叠区之外时,卡片顶部提示「正文命中,详见详情」,点开详情弹窗全文同样高亮
20
+ - **搜索高亮**:搜索框输入关键词,命中卡片的标题/正文/标签中匹配词以主题色徽标高亮(五主题自适应);命中落在正文三行折叠区之外时,卡片顶部提示「正文命中,详见详情」,点开详情弹窗全文同样高亮
18
21
  - **{变量} 插值**:内容含花括号占位(如「{功能名}」)的提示词,点复制会自动弹出填充面板,填入变量后实时预览再复制
19
22
  - **自动备份(默认开启)**:数据一有变更 2 秒内自动备份——首次变更会请求授权写入 prompt-pouch.html 所在目录(弹窗选同目录即可,选一次后浏览器记住),写 backup/pouch-backup.json 并滚动保留上一版 .prev.json;未授权或浏览器不支持时自动降级为本地快照(浏览器内保留最近 5 份),页内「↩ 恢复」均可一键回滚;顶栏「📂 换目录」可随时重新配置备份目录
20
23
  - **详情弹窗**:点卡片「👁 详情」弹出全文查看(超长内容限高 52vh 内滚动),带复制与修改入口,附时间线(创建 / 上次修改 / 最近使用);含 {变量} 的模板会在弹窗里标出变量清单,复制时自动进入填充面板
21
24
  - **页面直写(双笔)**:页面增删改直接写入 data/prompts.json(与自动备份共用同一目录授权);未授权时自动降级——生成操作指令复制到剪贴板,粘贴给 AI 落盘
22
25
  - **侧栏局部滚动**:分组较多时,左侧「收藏 + 分组列表」区域独立滚动(窄滚动条),「全部」「+ 新建分组」「锦囊用法」固定不滚;窄屏下自动恢复平铺排列
23
- - **批量整理入囊**:把一堆文字/文件交给 AI,或说「把最近对话框内容整理进锦囊」,AI 按现有分组归档、装不下的推荐新分组、含具体词的可泛化为 {变量} 插值(附改写示例),你调整确认后一次性写入
26
+ - **批量整理入囊**:把一堆文字/文件交给 AI,或说「把最近对话框内容整理进锦囊」——两段确认:先定条目(AI 默认智能打标——每条自动配 1-3 个语义标签,可改可删;含具体词的可泛化为 {变量} 插值,附改写示例)→ 再定分组(归组理由 + 装不下的推荐新分组名),都确认后一次性写入;条目少(≤3 条)两段合一
27
+ - **标签全交互**:点标签即筛选(顶栏胶囊一键清除,再点取消,切分组自动清除,与搜索叠加);标签悬停「✕」删、「+」加(最多 3 个),授权目录即写即存,未授权指令交 AI
28
+ - **导入 / 导出 JSON**:顶栏「⤓ 导出」一键下载全量数据为 JSON 备份文件(文件名带时间戳);「⤒ 导入」选择 JSON 文件整库覆盖(导入前自动备份、可恢复);未授权目录时导出仍可用、导入需先授权
29
+ - **分组拖拽排序**:左侧分组条拖拽即可重排分组顺序(授权目录即写即存;未授权时生成「请把锦囊分组顺序调整为…」指令复制给 AI 落盘)
24
30
  - **四种排序**:最新添加(按添加时间倒序,全时间范围)/ 最近使用 / 使用频率 / 手动顺序;排序选择会自动记住,下次打开不变
25
31
  - **使用统计**:每次点复制,页面自动记录该提示词的最近使用时间与累计次数(存浏览器本地),供「最近使用」「使用频率」排序使用,数据文件不写这些字段
26
32
  - **修改时间**:每次修改提示词(页面直写或 AI 代笔),数据文件会记下 updatedAt 修改时间,详情弹窗时间线可见;新增不写、仅排序不写
@@ -29,4 +35,5 @@
29
35
  ## 提醒
30
36
 
31
37
  - 数据在 data/prompts.json(备份在 backup/ 目录);迁移/备份复制 data/ 与 backup/ 两个目录即可
38
+ - 「⤓ 导出」的 JSON 文件可直接在另一台电脑「⤒ 导入」整库恢复(含分组与标签)
32
39
  - 页面样式与脚本升级由仓库 reference.html 重新复制完成,不影响你的数据
@@ -15,7 +15,7 @@ BACKUP_DIR: backup
15
15
  INIT_DATA: example
16
16
 
17
17
  # 页面主题(初始化时写入页面根标签 data-theme;页面右下角换肤坞可随时切换)
18
- # 可选:gold 暖棕金(默认)/ tech 深蓝科技 / mono Darcula 深灰蓝 / mint 薄荷绿
18
+ # 可选:gold 暖棕金(默认)/ tech 深蓝科技 / mono IDEA 黑亮 / light IDEA 白亮 / mint 薄荷绿
19
19
  THEME: gold
20
20
 
21
21
  # 初始化/落盘前是否先确认目标目录