dsh-skill-browser 1.9.9 → 1.9.11

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 (56) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README-es.md +1 -1
  3. package/README-hi.md +1 -1
  4. package/README-pt.md +1 -1
  5. package/README-zh.md +4 -4
  6. package/README.md +75 -68
  7. package/docs/images/panel-browse.png +0 -0
  8. package/docs/images/panel-ledger.png +0 -0
  9. package/lib/client.js +256 -148
  10. package/lib/client.js.bak-6colimp-20261028-230915 +3748 -0
  11. package/lib/client.js.bak-auth12-20261029-020107 +3749 -0
  12. package/lib/client.js.bak-auth12b-20261029-020140 +3749 -0
  13. package/lib/client.js.bak-auth12c-20261029-020206 +3749 -0
  14. package/lib/client.js.bak-auth12d-20261029-020232 +3747 -0
  15. package/lib/client.js.bak-auto-20261028-171351 +3669 -0
  16. package/lib/client.js.bak-auto2-20261028-171422 +3676 -0
  17. package/lib/client.js.bak-auto3-20261028-171545 +3676 -0
  18. package/lib/client.js.bak-followball-20261028-224743 +3720 -0
  19. package/lib/client.js.bak-gearico-20261028-230937 +3748 -0
  20. package/lib/client.js.bak-glow-20261030 +3676 -0
  21. package/lib/client.js.bak-grid-20261028-220142 +3680 -0
  22. package/lib/client.js.bak-guide-20261029-003108 +3750 -0
  23. package/lib/client.js.bak-guide2-20261029-003213 +3751 -0
  24. package/lib/client.js.bak-guide3-20261029-003236 +3763 -0
  25. package/lib/client.js.bak-guide4-20261029-003249 +3768 -0
  26. package/lib/client.js.bak-guidefc-20261029-003535 +3775 -0
  27. package/lib/client.js.bak-guideico-20261029-013809 +3776 -0
  28. package/lib/client.js.bak-guideorder-20261029-004345 +3775 -0
  29. package/lib/client.js.bak-headbtn-20261028-232114 +3750 -0
  30. package/lib/client.js.bak-menu6col-20261028-225126 +3741 -0
  31. package/lib/client.js.bak-menu6col2-20261028-225348 +3741 -0
  32. package/lib/client.js.bak-menu6col2-20261028-225527 +3741 -0
  33. package/lib/client.js.bak-monobtn-20261028-230502 +3741 -0
  34. package/lib/client.js.bak-navsimple-20261029-015235 +3786 -0
  35. package/lib/client.js.bak-nobadge-20261029-015354 +3784 -0
  36. package/lib/client.js.bak-nodrag-20261028-170713 +3651 -0
  37. package/lib/client.js.bak-official-20261028-171240 +3653 -0
  38. package/lib/client.js.bak-official2-20261028-171304 +3668 -0
  39. package/lib/client.js.bak-renumber-20261028-215518 +3681 -0
  40. package/lib/client.js.bak-sbgap-20261029-013144 +3776 -0
  41. package/lib/client.js.bak-sbgap-20261029-013202 +3776 -0
  42. package/lib/client.js.bak-sbrowh-20261029-012307 +3776 -0
  43. package/lib/client.js.bak-sbrowh-20261029-012333 +3776 -0
  44. package/lib/client.js.bak-scope-sb-20261029-011711 +3776 -0
  45. package/lib/client.js.bak-skinclarity-20261029-011027 +3776 -0
  46. package/lib/client.js.bak-skincols-20261028-224614 +3720 -0
  47. package/lib/client.js.bak-star-20261028-231205 +3748 -0
  48. package/lib/client.js.bak-star-20261028-231233 +3748 -0
  49. package/lib/client.js.bak-sync-20261028-220538 +3680 -0
  50. package/lib/index.js +1 -1
  51. package/locale/en.json +1 -1
  52. package/locale/zh.json +1 -1
  53. package/package.json +86 -85
  54. package/scripts/audit-contrast.mjs +215 -0
  55. package/scripts/check-bom.mjs +51 -0
  56. package/docs/images/skill-browser-panel.png +0 -0
package/lib/client.js CHANGED
@@ -83,10 +83,13 @@ window.__ModuleLoader__.load({
83
83
  EX_ORDER.push("27");
84
84
  EX["28"]={no:"28",name:"月白纸墨",en:"PAPER & INK",group:"克制精选",anim:"calm",vars:{bgA:"#f7f5ef",bgB:"#dcd8cd",edge:"rgba(60,55,45,.28)",spec:"rgba(255,255,255,.85)",hi:"rgba(255,255,255,.7)",lbc:"#2c2a24",trk:"rgba(60,55,45,.14)",stI:"#a09c92",stP:"#6e6a60",stA:"#33302a",stD:"#55524a",pbgA:"#faf9f5",pbgB:"#edeae1",pbd:"rgba(60,55,45,.16)",ptx:"#33302a",itm:"#6e6a60",itD:"#8b877d",cctx:"#6e6a60",chipBg:"rgba(60,55,45,.05)",hintC:"#8b877d",hair1:"#33302a",hair2:"#a09c92"},band:"%BAND%{position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:radial-gradient(circle at 50% 122%,var(--st) 0%,transparent 54%);opacity:.13}"};
85
85
  EX_ORDER.push("28");
86
+ EX["129"]={no:"129",name:"官方深色",en:"OFFICIAL DARK",group:"官方主题",anim:"calm",vars:{bgA:"#2c2c2e",bgB:"#151517",edge:"rgba(255,255,255,.13)",spec:"rgba(255,255,255,.14)",hi:"rgba(255,255,255,.10)",lbc:"#f9fafb",trk:"rgba(255,255,255,.10)",stI:"#979da6",stP:"#4176e6",stA:"#5686fe",stD:"#22c55e",pbgA:"#1b1b1c",pbgB:"#0f1115",pbd:"rgba(255,255,255,.09)",ptx:"#e1e5ee",itm:"#adb2b8",itD:"#81858c",cctx:"#adb2b8",chipBg:"rgba(255,255,255,.05)",hintC:"#81858c",hair1:"#5686fe",hair2:"#4176e6"},band:"%BAND%{position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:radial-gradient(circle at 50% 122%,var(--st) 0%,transparent 54%);opacity:0.10}"};
87
+ EX["130"]={no:"130",name:"官方浅色",en:"OFFICIAL LIGHT",group:"官方主题",anim:"calm",vars:{bgA:"#ffffff",bgB:"#e9ecf2",edge:"rgba(20,24,34,.14)",spec:"rgba(255,255,255,.92)",hi:"rgba(255,255,255,.80)",lbc:"#151517",trk:"rgba(20,24,34,.12)",stI:"#81858c",stP:"#4176e6",stA:"#4176e6",stD:"#22c55e",pbgA:"#ffffff",pbgB:"#f1f3f5",pbd:"rgba(20,24,34,.10)",ptx:"#151517",itm:"#43454a",itD:"#61666b",cctx:"#43454a",chipBg:"rgba(20,24,34,.05)",hintC:"#81858c",hair1:"#4176e6",hair2:"#7aaaff"},band:"%BAND%{position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:radial-gradient(circle at 50% 122%,var(--st) 0%,transparent 54%);opacity:0.08}"};
86
88
  var KIND_LABEL={deep:"浓郁深底",muted:"尘埃灰调",soft:"柔光深底",neutral:"中性点缀",light:"浅色纸面"};
87
89
  var TINT="%BAND%{position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:radial-gradient(circle at 50% 122%,var(--st) 0%,transparent 54%);opacity:.13}";
88
90
  var ALL=[],BY_ID={};
89
91
  (function build(){
92
+ ["129","130"].forEach(function(id){var s=EX[id];if(!s)return;s.id=id;s.kind="special";ALL.push(s);BY_ID[id]=s;});
90
93
  EX_ORDER.forEach(function(id){var s=EX[id];s.id=id;s.kind="special";ALL.push(s);BY_ID[id]=s;});
91
94
  var order=["deep","muted","soft","neutral","light"],no=28;
92
95
  order.forEach(function(kind){
@@ -97,28 +100,44 @@ window.__ModuleLoader__.load({
97
100
  ALL.push(s);BY_ID[id]=s;
98
101
  });
99
102
  });
103
+ // 统一显示序号(2026-10-29 用户要求):官方深色=1、官方浅色=2、其余按顺序 3..N
104
+ // 注意:只改显示用 no 字段,内部 id 保持不变(localStorage 兼容)
105
+ ALL.forEach(function(s,idx){ s.no = String(idx+1); });
100
106
  })();
101
- var KEY="dsh-ball-skin",DEFAULT_ID="01";
102
- function getId(){try{var v=localStorage.getItem(KEY);if(v&&BY_ID[v])return v;}catch(e){}return DEFAULT_ID;}
107
+ var KEY="dsh-ball-skin",AUTO_ID="auto",OFFICIAL_DARK="129",OFFICIAL_LIGHT="130",DEFAULT_ID="auto";
108
+ function isDark(){try{return !!(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches);}catch(e){return true;}}
109
+ function pref(){try{var v=localStorage.getItem(KEY);if(v==="legacy")return "legacy";if(v&&(v===AUTO_ID||BY_ID[v]))return v;}catch(e){}return DEFAULT_ID;}
110
+ function resolve(id){
111
+ if(!id||id===AUTO_ID)return isDark()?OFFICIAL_DARK:OFFICIAL_LIGHT;
112
+ if(BY_ID[id])return id;
113
+ return isDark()?OFFICIAL_DARK:OFFICIAL_LIGHT;
114
+ }
115
+ function getId(){return resolve(pref());}
103
116
  function setSkin(id){
104
- if(!BY_ID[id])return false;
117
+ if(id!==AUTO_ID&&id!=="legacy"&&!BY_ID[id])return false;
105
118
  try{localStorage.setItem(KEY,id);}catch(e){}
106
119
  var hooks=window.__dshBallSkinHooks||[];
107
120
  for(var i=0;i<hooks.length;i++){try{hooks[i](id,BY_ID[id]);}catch(e){}}
108
121
  try{window.dispatchEvent(new CustomEvent("dsh-ball-skin-change",{detail:{id:id}}));}catch(e){}
109
122
  return true;
110
123
  }
111
- function varsCss(sel,id){var s=BY_ID[id]||BY_ID[DEFAULT_ID];var out=sel+"{";
124
+ function varsCss(sel,id){var s=BY_ID[resolve(id)]||ALL[0];var out=sel+"{";
112
125
  for(var k in s.vars){out+="--"+k+":"+s.vars[k]+";";}
113
126
  return out+"}";}
114
127
  function varsAll(sel){return varsCss(sel,getId());}
115
- function fx(id,sel){var s=BY_ID[id]||BY_ID[DEFAULT_ID];var out=[];
128
+ function fx(id,sel){var s=BY_ID[resolve(id)]||ALL[0];var out=[];
116
129
  if(s.rim)out.push(s.rim.split("%RIM%").join(sel.RIM));
117
130
  if(s.band)out.push(s.band.split("%BAND%").join(sel.BAND));
118
131
  if(s.extra)out.push(s.extra.split("%B%").join(sel.B));
119
132
  return out.join("\n");}
120
133
  function groups(){var g=[],seen={};ALL.forEach(function(s){if(!seen[s.group]){seen[s.group]=true;g.push(s.group);}});return g;}
121
- window.__DSH_BALL_SKINS={ALL:ALL,BY_ID:BY_ID,getId:getId,setSkin:setSkin,varsCss:varsCss,varsAll:varsAll,fx:fx,groups:groups,KIND_LABEL:KIND_LABEL,KEY:KEY,DEFAULT_ID:DEFAULT_ID};
134
+ window.__DSH_BALL_SKINS={ALL:ALL,BY_ID:BY_ID,getId:getId,getPref:pref,pref:pref,resolve:resolve,isDark:isDark,setSkin:setSkin,varsCss:varsCss,varsAll:varsAll,fx:fx,groups:groups,KIND_LABEL:KIND_LABEL,KEY:KEY,AUTO_ID:AUTO_ID,OFFICIAL_DARK:OFFICIAL_DARK,OFFICIAL_LIGHT:OFFICIAL_LIGHT,DEFAULT_ID:DEFAULT_ID};
135
+ // 跟随客户端深/浅色:DSH 用 prefers-color-scheme(无 data-theme),变化时通知三球重绘
136
+ try{
137
+ var _mq=window.matchMedia?window.matchMedia("(prefers-color-scheme: dark)"):null;
138
+ function _onScheme(){try{window.dispatchEvent(new CustomEvent("dsh-ball-skin-change",{detail:{id:getId(),auto:true}}));}catch(e){}}
139
+ if(_mq){if(_mq.addEventListener)_mq.addEventListener("change",_onScheme);else if(_mq.addListener)_mq.addListener(_onScheme);}
140
+ }catch(e){}
122
141
  })();
123
142
 
124
143
  // v1.5.5(2026-09-06):版本号对齐修复——host 端 index.js 的 VERSION
@@ -1111,10 +1130,10 @@ window.__ModuleLoader__.load({
1111
1130
  '#dsh-skill-browser-panel .dsb-detail-body,#dsh-skill-browser-panel .dsb-groups{scrollbar-width:thin;' +
1112
1131
  'scrollbar-color:var(--dsb-brand,rgba(143,199,255,.75)) transparent;overscroll-behavior:contain}' +
1113
1132
  '.dsb-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px 6px}' +
1114
- '.dsb-title{font-size:16px;font-weight:600}' +
1133
+ '.dsb-title{font-size:14.5px;font-weight:600}' +
1115
1134
  '.dsb-headbtns{display:flex;gap:6px}' +
1116
1135
  '.dsb-btn{background:rgba(255,255,255,.08);color:#dfe3ee;border:1px solid rgba(255,255,255,.12);border-radius:8px;' +
1117
- 'padding:4px 10px;font-size:12px;cursor:pointer}' +
1136
+ 'padding:3px 9px;font-size:11px;cursor:pointer}' +
1118
1137
  '.dsb-btn:hover{background:rgba(255,255,255,.16)}' +
1119
1138
  '.dsb-subtitle{padding:0 16px 6px;font-size:11px;color:#9aa1b5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
1120
1139
  '.dsb-settings{display:none;padding:6px 16px;gap:6px;flex-direction:column;background:rgba(255,255,255,.04);border-bottom:1px solid rgba(255,255,255,.06);margin-bottom:4px}' +
@@ -1131,22 +1150,22 @@ window.__ModuleLoader__.load({
1131
1150
  '.dsb-set-promo .p-desc{font-size:11.5px;color:#c6cbdb;line-height:1.5;margin-top:2px;white-space:normal}' +
1132
1151
  '.dsb-set-promo .p-tag{font-size:10.5px;color:#9aa1b5;margin-top:2px}' +
1133
1152
  '.dsb-q{margin:4px 16px 8px;padding:7px 12px;border-radius:9px;border:1px solid rgba(255,255,255,.14);' +
1134
- 'background:rgba(255,255,255,.06);color:#eef;font-size:13px;outline:none}' +
1153
+ 'background:rgba(255,255,255,.06);color:#eef;font-size:12px;outline:none}' +
1135
1154
  '.dsb-q:focus{border-color:#5b8cff}' +
1136
1155
  '.dsb-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 6px}' +
1137
1156
  '.dsb-chip,.dsb-schip{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);color:#cdd3e3;' +
1138
- 'border-radius:999px;padding:3px 10px;font-size:12px;cursor:pointer;white-space:nowrap}' +
1157
+ 'border-radius:999px;padding:2px 9px;font-size:11px;cursor:pointer;white-space:nowrap}' +
1139
1158
  '.dsb-chip:hover,.dsb-schip:hover{background:rgba(255,255,255,.14)}' +
1140
1159
  '.dsb-chip-on{background:linear-gradient(135deg,#5b6cff,#2fa8ff);color:#fff;border-color:transparent}' +
1141
- '.dsb-n{opacity:.75;font-size:11px;margin-left:2px}' +
1160
+ '.dsb-n{opacity:.75;font-size:10px;margin-left:2px}' +
1142
1161
  '.dsb-subs{display:none;flex-wrap:wrap;gap:6px;padding:0 16px 6px;border-top:1px dashed rgba(255,255,255,.08);padding-top:8px;margin:0 0 2px}' +
1143
1162
  '.dsb-cards{flex:1;min-height:0;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));' +
1144
1163
  'gap:8px;padding:6px 16px 14px;align-content:start}' +
1145
1164
  '.dsb-card{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);border-radius:10px;' +
1146
1165
  'padding:10px 12px;cursor:pointer;transition:background .12s}' +
1147
1166
  '.dsb-card:hover{background:rgba(120,140,255,.14);border-color:rgba(120,140,255,.4)}' +
1148
- '.dsb-card-name{font-family:ui-monospace,Consolas,monospace;font-size:12px;color:#8fc7ff;word-break:break-all}' +
1149
- '.dsb-card-zh{font-size:12.5px;color:#dfe3ee;margin-top:5px;line-height:1.5;' +
1167
+ '.dsb-card-name{font-family:ui-monospace,Consolas,monospace;font-size:11px;color:#8fc7ff;word-break:break-all}' +
1168
+ '.dsb-card-zh{font-size:11.5px;color:#dfe3ee;margin-top:5px;line-height:1.5;' +
1150
1169
  'display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}' +
1151
1170
  '.dsb-card-tag{font-size:10.5px;color:#8b93a8;margin-top:6px}' +
1152
1171
  '.dsb-empty{grid-column:1/-1;text-align:center;color:#9aa1b5;padding:40px 0;font-size:13px;line-height:1.7}' +
@@ -1155,9 +1174,18 @@ window.__ModuleLoader__.load({
1155
1174
  'font-family:ui-monospace,Consolas,monospace;font-size:12px;line-height:1.65;color:#cfd6e8;white-space:pre-wrap;word-break:break-word}' +
1156
1175
  '.dsb-tabs{display:flex;gap:4px;margin:0 8px}' +
1157
1176
  '.dsb-tab{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);color:#cdd3e3;' +
1158
- 'border-radius:8px;padding:4px 12px;font-size:12px;cursor:pointer}' +
1177
+ 'border-radius:8px;padding:4px 12px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:5px}' +
1159
1178
  '.dsb-tab:hover{background:rgba(255,255,255,.14)}' +
1160
1179
  '.dsb-tab-on{background:linear-gradient(135deg,#5b6cff,#2fa8ff);color:#fff;border-color:transparent}' +
1180
+ '.dsb-guide{display:none;flex:1;min-height:0;overflow:auto;padding:14px 18px;color:var(--ptx,#e8eaf2)}' +
1181
+ '.dsb-guide-inner{max-width:640px;margin:0 auto}' +
1182
+ '.dsb-guide h3{margin:0 0 4px;font-size:16px;font-weight:700;color:var(--ptx,#e8eaf2);display:flex;align-items:center;gap:7px}' +
1183
+ '.dsb-gico{display:inline-flex;align-items:center;margin-right:7px;color:var(--stA,#5b8cff);opacity:.95;vertical-align:-2px}' +
1184
+ '.dsb-gico svg{display:block}' +
1185
+ '.dsb-guide-sub{margin:0 0 12px;font-size:12px;color:var(--hintC,#9aa1b5)}' +
1186
+ '.dsb-guide-card{background:var(--chipBg,rgba(128,138,160,.07));border:1px solid var(--pbd,rgba(128,138,160,.25));border-radius:10px;padding:10px 12px;margin-bottom:8px;font-size:12.5px;line-height:1.7;color:var(--ptx,#e8eaf2)}' +
1187
+ '.dsb-guide-card b{color:var(--stA,#5b8cff);font-weight:700}' +
1188
+ '.dsb-guide-tip{font-size:11.5px;color:var(--hintC,#9aa1b5);margin:10px 0 0}' +
1161
1189
  '.dsb-ledger{flex:1;min-height:0;display:flex;flex-direction:column;padding:0 16px 14px}' +
1162
1190
  '.dsb-ledger-sum{display:flex;gap:10px;padding:4px 0 10px}' +
1163
1191
  '.dsb-lsum-card{flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.09);border-radius:10px;' +
@@ -1336,15 +1364,15 @@ window.__ModuleLoader__.load({
1336
1364
  // v1.9.9:工具条/子类按钮的文字色一律走 --dsb-dim(该变量在 semanticVarsCss
1337
1365
  // 里按「卡片真实底色」算到 ≥4.8:1),不再用 --itm —— 实测 --itm 在 6 款皮肤上
1338
1366
  // 只有 4.40~4.50:1,10~11px 小字刚好卡在 WCAG AA 线下方。
1339
- '#dsh-skill-browser-panel .dsb-gadd{height:26px;min-width:0;border-radius:7px;border:1px dashed var(--pbd,rgba(255,255,255,.22));' +
1340
- 'background:var(--chipBg,rgba(255,255,255,.04));color:var(--dsb-dim,#b9c2d8);font-size:11px;cursor:pointer;padding:0 8px;' +
1367
+ '#dsh-skill-browser-panel .dsb-gadd{height:24px;min-width:0;border-radius:7px;border:1px dashed var(--pbd,rgba(255,255,255,.22));' +
1368
+ 'background:var(--chipBg,rgba(255,255,255,.04));color:var(--dsb-dim,#b9c2d8);font-size:10.5px;cursor:pointer;padding:0 7px;' +
1341
1369
  'display:inline-flex;align-items:center;gap:4px;white-space:nowrap}' +
1342
1370
  '#dsh-skill-browser-panel .dsb-gadd:hover{color:var(--ptx,#dfe3ee);border-color:var(--stA,#7c8dff)}' +
1343
1371
  '#dsh-skill-browser-panel .dsb-gadd-on{background:linear-gradient(135deg,var(--dsb-onbrand-bg1,#5b6cff),var(--dsb-onbrand-bg2,#2fa8ff))!important;' +
1344
1372
  'color:var(--dsb-onbrand,#fff)!important;border-style:solid!important;border-color:transparent!important}' +
1345
1373
  '#dsh-skill-browser-panel .dsb-gadd-kw{border-color:var(--dsb-okline,rgba(80,220,150,.34));color:var(--dsb-ok,#9ff5c8)}' +
1346
1374
  '#dsh-skill-browser-panel .dsb-gbusy{opacity:.55;pointer-events:none}' +
1347
- '#dsh-skill-browser-panel .dsb-gtitle{font-size:11px;color:var(--dsb-dim,#8b93a8);white-space:nowrap}' +
1375
+ '#dsh-skill-browser-panel .dsb-gtitle{font-size:10.5px;color:var(--dsb-dim,#8b93a8);white-space:nowrap}' +
1348
1376
  '#dsh-skill-browser-panel .dsb-ghint{font-size:10.5px;color:var(--dsb-dim,#6f778c);white-space:nowrap;' +
1349
1377
  'overflow:hidden;text-overflow:ellipsis;max-width:44%}' +
1350
1378
  // v1.9.9 对比度修正:数字徽标一律「继承父级文字色」,不再写死
@@ -1353,7 +1381,7 @@ window.__ModuleLoader__.load({
1353
1381
  // 必有一处看不清 —— 截图里「全部 111」的白字就是这么来的。
1354
1382
  // 继承父色后:工具条→--itm、激活按钮→--dsb-onbrand、大类行→--dsb-oncard,
1355
1383
  // 三处都天然达标。
1356
- '#dsh-skill-browser-panel .dsb-gn{font-size:10px;color:inherit;opacity:.82;' +
1384
+ '#dsh-skill-browser-panel .dsb-gn{font-size:9.5px;color:inherit;opacity:.82;' +
1357
1385
  'flex:0 0 auto;font-weight:500}' +
1358
1386
  '#dsh-skill-browser-panel .dsb-gadd-on .dsb-gn{opacity:.9}' +
1359
1387
  '#dsh-skill-browser-panel .dsb-gcard .dsb-gn,' +
@@ -1362,7 +1390,7 @@ window.__ModuleLoader__.load({
1362
1390
  /* ── v1.9.8 平铺模式(原样保留,用户可一键切回)── */
1363
1391
  '#dsh-skill-browser-panel .dsb-gflat{display:flex;flex-wrap:wrap;gap:5px;align-items:center}' +
1364
1392
  '#dsh-skill-browser-panel .dsb-gcard,#dsh-skill-browser-panel .dsb-gcard-dom{position:relative;display:flex;align-items:center;gap:5px;' +
1365
- 'min-width:0;max-width:190px;height:30px;padding:0 9px;border-radius:8px;cursor:pointer;overflow:hidden;' +
1393
+ 'min-width:0;max-width:190px;height:27px;padding:0 8px;border-radius:8px;cursor:pointer;overflow:hidden;' +
1366
1394
  'background:linear-gradient(135deg,var(--dsb-tile1,#39406b),var(--dsb-tile2,#232a45));' +
1367
1395
  'border:1px solid var(--pbd,rgba(255,255,255,.18));background-size:cover;background-position:center}' +
1368
1396
  '#dsh-skill-browser-panel .dsb-gcard::after{content:"";position:absolute;inset:0;' +
@@ -1371,7 +1399,7 @@ window.__ModuleLoader__.load({
1371
1399
  '#dsh-skill-browser-panel .dsb-gcard:hover{border-color:var(--stA,#7c8dff)}' +
1372
1400
  '#dsh-skill-browser-panel .dsb-gcard-on{border-color:var(--stA,#7c8dff)!important;' +
1373
1401
  'box-shadow:0 0 0 2px var(--stA,#7c8dff) inset}' +
1374
- '#dsh-skill-browser-panel .dsb-gname{font-size:11.5px;color:var(--dsb-oncard,#fff);font-weight:600;' +
1402
+ '#dsh-skill-browser-panel .dsb-gname{font-size:11px;color:var(--dsb-oncard,#fff);font-weight:600;' +
1375
1403
  'line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:132px;' +
1376
1404
  'text-shadow:0 1px 2px rgba(0,0,0,.55)}' +
1377
1405
  '#dsh-skill-browser-panel .dsb-gkids{font-size:9.5px;color:var(--dsb-oncard-dim,#cfd8ea);' +
@@ -1471,17 +1499,19 @@ window.__ModuleLoader__.load({
1471
1499
  panel.id = PANEL_ID;
1472
1500
  panel.innerHTML =
1473
1501
  '<div class="dsb-head">' +
1474
- '<div class="dsb-title">🧩 技能浏览器</div>' +
1502
+ '<div class="dsb-title">技能浏览器</div>' +
1475
1503
  '<div class="dsb-tabs">' +
1476
1504
  '<button id="dsb-tab-skills" class="dsb-tab" data-view="skills">技能浏览</button>' +
1477
- '<button id="dsb-tab-ledger" class="dsb-tab" data-view="ledger">📊 调用台账</button>' +
1505
+ '<button id="dsb-tab-ledger" class="dsb-tab" data-view="ledger">调用台账</button>' +
1506
+ '<button id="dsb-tab-guide" class="dsb-tab" data-view="guide">' + DSB_ICONS.book + '快速上手</button>' +
1478
1507
  '</div>' +
1479
1508
  '<div class="dsb-headbtns">' +
1480
- '<button id="dsb-skin-btn" class="dsb-btn" title="切换皮肤(三球同步 · 128款)">🎨</button>' +
1481
- '<button id="dsb-setting" class="dsb-btn" title="开关设置">⚙</button>' +
1482
- '<button id="dsb-hot" class="dsb-btn" title="' + esc(T("hotReloadTip")) + '">⚡</button>' +
1483
- '<button id="dsb-refresh" class="dsb-btn" title="重新扫描技能目录">↻ 刷新</button>' +
1484
- '<button id="dsb-close" class="dsb-btn" title="关闭">×</button>' +
1509
+ '<button id="dsb-skin-btn" class="dsb-btn" title="切换皮肤(三球同步 · 130款)">' + DSB_ICONS.palette + '</button>' +
1510
+ '<button id="dsb-setting" class="dsb-btn" title="开关设置">' + DSB_ICONS.gear + '</button>' +
1511
+ '<button id="dsb-hot" class="dsb-btn" title="' + esc(T("hotReloadTip")) + '">' + DSB_ICONS.bolt + '</button>' +
1512
+ '<button id="dsb-refresh" class="dsb-btn" title="刷新">' + DSB_ICONS.refresh + '</button>' +
1513
+ '<button id="dsb-close" class="dsb-btn" title="关闭">' + DSB_ICONS.close + '</button>' +
1514
+ '<a class="dsb-btn dsb-star-link" href="https://github.com/loyalchiiina/dsh-skill-browser" target="_blank" rel="noopener" title="去 GitHub 点个 Star ⭐">' + DSB_ICONS.star + '</a>' +
1485
1515
  '</div>' +
1486
1516
  '</div>' +
1487
1517
  '<div id="dsb-skin" class="dsb-skinmenu"></div>' +
@@ -1530,7 +1560,20 @@ window.__ModuleLoader__.load({
1530
1560
  '<div id="dsb-chips" class="dsb-chips"></div>' +
1531
1561
  '<div id="dsb-subs" class="dsb-subs"></div>' +
1532
1562
  '<div id="dsb-cards" class="dsb-cards"></div>' +
1533
- '<div id="dsb-ledger" class="dsb-ledger" style="display:none">' +
1563
+ '<div id="dsb-guide" class="dsb-guide" style="display:none">' +
1564
+ '<div class="dsb-guide-inner">' +
1565
+ '<h3>' + DSB_ICONS.book + '快速上手</h3>' +
1566
+ '<p class="dsb-guide-sub">60 秒学会用技能浏览器管理你的技能库</p>' +
1567
+ '<div class="dsb-guide-card">' + dsbGico('folder') + '<b>① 先指定技能库位置(第一步)</b><br>点右上角 <b>设置</b> 齿轮 → 找到「<b>技能库位置</b>」→ 点 <b>选择</b> 弹出系统文件夹框,选中你的技能包文件夹(例如 <b>E:\DSHskills</b>)→ 点 <b>保存</b>。输入框留空 = 自动识别(~/.dsh/skills 等默认位置)。<br>保存后会自动重扫,下方状态行显示「当前技能库:…」确认路径正确。</div>' +
1568
+ '<div class="dsb-guide-card">' + dsbGico('refresh') + '<b>② 刷新,让新技能进列表</b><br>技能文件增删改之后,点右上角 <b>刷新</b>(↻)重新扫描技能库。要让它<b>不重启 DSH 立即生效</b>,再点一下 <b>热重载</b>(⚡)。顺序永远是:<b>先选库 → 再刷新 → 最后热重载</b>。</div>' +
1569
+ '<div class="dsb-guide-card">' + dsbGico('search') + '<b>③ 搜索与筛选技能</b><br>顶部搜索框支持<b>技能名 / 中文简介 / 描述</b>关键字。下方分组栏:<b>我的分组</b>(树状/平铺切换)→ <b>关键词分组</b>(按触发词自动归类)→ <b>AI 自动分组</b>(调模型智能归类)。存在自定义分组时,默认分类行会自动隐藏。</div>' +
1570
+ '<div class="dsb-guide-card">' + dsbGico('eye') + '<b>④ 看技能详情 / 启停技能</b><br>点任意技能卡片展开详情:名称、简介、触发词、SKILL.md 全文、路径、最近调用记录。详情里可直接<b>禁用/启用</b>该技能(停用后模型技能目录里即摘除)。</div>' +
1571
+ '<div class="dsb-guide-card">' + dsbGico('chart') + '<b>⑤ 调用台账</b><br>切到「调用台账」:选起止日期 + 粒度(日/周/月/年)→ 看调用次数排行、失败率与趋势图。排查「技能怎么没生效」先来这里。需在设置里勾选「失效台账自动登记」。</div>' +
1572
+ '<div class="dsb-guide-card">' + dsbGico('folders') + '<b>⑥ 分组管理</b><br>「+新建分组」可建大类/子类;技能卡片菜单里可「移动到分组」。删除分组不会删技能文件,只是视图归类。</div>' +
1573
+ '<div class="dsb-guide-card">' + dsbGico('grid') + '<b>⑦ 认识面板其余按钮</b><br>右上角从左到右:<b>皮肤</b>(三球同步换肤,130 款)、<b>设置</b>(本页上面那些开关)、<b>热重载</b>(⚡ 不重启生效)、<b>刷新</b>(↻ 重扫技能库)、<b>关闭</b>、<b>GitHub Star</b>。</div>' +
1574
+ '<p class="dsb-guide-tip">小技巧:改了技能文件先点刷新再搜;AI 分组前先在设置里确认模型探针通过。</p>' +
1575
+ '</div></div>' +
1576
+ '<div id="dsb-ledger" class="dsb-ledger" style="display:none">' +
1534
1577
  '<div id="dsb-lbar" class="dsb-lbar"></div>' +
1535
1578
  '<div id="dsb-lcards" class="dsb-lcards"></div>' +
1536
1579
  '<div id="dsb-ltrend" class="dsb-ltrend"></div>' +
@@ -1713,6 +1756,7 @@ window.__ModuleLoader__.load({
1713
1756
  if (!S.ledger) loadLedger(); else paint();
1714
1757
  if (!S.lstat) loadStats();
1715
1758
  });
1759
+ $("dsb-tab-guide").addEventListener("click", function () { S.view = "guide"; S.detail = null; S.ledgerDetail = null; paint(); });
1716
1760
  $("dsb-ledger-table").addEventListener("click", function (ev) {
1717
1761
  // 排行表头排序
1718
1762
  var sEl = ev.target.closest("[data-lsort]");
@@ -1834,10 +1878,30 @@ window.__ModuleLoader__.load({
1834
1878
  S.panelBuilt = false;
1835
1879
  }
1836
1880
 
1881
+ function positionPanelNearBall() {
1882
+ // m04874: 面板跟随悬浮球(与字体插件一致):水平居中于球并夹在视口内;
1883
+ // 球在屏幕下半部 -> 面板放球上方,否则放球下方。
1884
+ var panel = $(PANEL_ID), ball = $(BALL_ID);
1885
+ if (!panel || !ball) return;
1886
+ var r = ball.getBoundingClientRect();
1887
+ var pw = panel.offsetWidth || 940, ph = panel.offsetHeight || 660;
1888
+ var left = r.left + r.width / 2 - pw / 2;
1889
+ left = Math.max(8, Math.min(window.innerWidth - pw - 8, left));
1890
+ var top = r.top - ph - 10;
1891
+ if (top < 8) top = r.bottom + 10;
1892
+ top = Math.max(8, Math.min(window.innerHeight - ph - 8, top));
1893
+ panel.style.left = left + "px";
1894
+ panel.style.top = top + "px";
1895
+ panel.style.right = "auto";
1896
+ panel.style.bottom = "auto";
1897
+ panel.style.transform = "none";
1898
+ }
1899
+
1837
1900
  function openPanel() {
1838
1901
  buildPanel();
1839
1902
  S.open = true;
1840
1903
  paint();
1904
+ positionPanelNearBall();
1841
1905
  if (!S.data && !S.loading) load(false);
1842
1906
  }
1843
1907
 
@@ -1847,20 +1911,24 @@ window.__ModuleLoader__.load({
1847
1911
  panel.style.display = S.open ? "flex" : "none";
1848
1912
  if (!S.open) return;
1849
1913
  var isLedger = S.view === "ledger";
1850
- var q = $("dsb-q"), chips = $("dsb-chips"), subs = $("dsb-subs"), cards = $("dsb-cards"), lg = $("dsb-ledger"), sortbar = $("dsb-sortbar"), groups = $("dsb-groups");
1851
- if (q) q.style.display = isLedger ? "none" : "";
1852
- if (groups) groups.style.display = isLedger ? "none" : "";
1853
- if (chips) chips.style.display = isLedger ? "none" : "";
1854
- if (subs) subs.style.display = isLedger ? "none" : "";
1855
- if (cards) cards.style.display = isLedger ? "none" : "";
1856
- if (sortbar) sortbar.style.display = isLedger ? "none" : "";
1914
+ var isGuide = S.view === "guide";
1915
+ var q = $("dsb-q"), chips = $("dsb-chips"), subs = $("dsb-subs"), cards = $("dsb-cards"), lg = $("dsb-ledger"), sortbar = $("dsb-sortbar"), groups = $("dsb-groups"), gd = $("dsb-guide");
1916
+ var skillsVis = !isLedger && !isGuide ? "" : "none";
1917
+ if (q) q.style.display = skillsVis;
1918
+ if (groups) groups.style.display = skillsVis;
1919
+ if (chips) chips.style.display = skillsVis;
1920
+ if (subs) subs.style.display = skillsVis;
1921
+ if (cards) cards.style.display = skillsVis;
1922
+ if (sortbar) sortbar.style.display = skillsVis;
1857
1923
  if (lg) lg.style.display = isLedger ? "flex" : "none";
1858
- var t1 = $("dsb-tab-skills"), t2 = $("dsb-tab-ledger");
1859
- if (t1) t1.classList.toggle("dsb-tab-on", !isLedger);
1924
+ if (gd) gd.style.display = isGuide ? "block" : "none";
1925
+ var t1 = $("dsb-tab-skills"), t2 = $("dsb-tab-ledger"), t3 = $("dsb-tab-guide");
1926
+ if (t1) t1.classList.toggle("dsb-tab-on", S.view === "skills");
1860
1927
  if (t2) t2.classList.toggle("dsb-tab-on", isLedger);
1928
+ if (t3) t3.classList.toggle("dsb-tab-on", isGuide);
1861
1929
  paintHeader();
1862
1930
  if (isLedger) paintLedger();
1863
- else { paintGroups(); paintSortbar(); paintChips(); paintSubs(); paintCards(); }
1931
+ else if (!isGuide) { paintGroups(); paintSortbar(); paintChips(); paintSubs(); paintCards(); }
1864
1932
  paintDetail();
1865
1933
  }
1866
1934
 
@@ -2051,6 +2119,11 @@ window.__ModuleLoader__.load({
2051
2119
  function paintChips() {
2052
2120
  var box = $("dsb-chips"); if (!box) return;
2053
2121
  if (!S.data) { box.innerHTML = ""; return; }
2122
+ // 2026-10-28 (m01120): 自定义分组(关键词/AI/手动建的大类)一旦存在,
2123
+ // 默认分类 chip 行就整体隐藏——两排并排表达同一批技能,纯冗余;
2124
+ // 用户删光所有分组后自动恢复默认分类视图。
2125
+ if (topGroups().length) { box.innerHTML = ""; box.style.display = "none"; return; }
2126
+ box.style.display = "";
2054
2127
  var cs = S.data.categories || [];
2055
2128
  var counts = {};
2056
2129
  var sk = S.data.skills || [];
@@ -2762,7 +2835,7 @@ window.__ModuleLoader__.load({
2762
2835
  // ---- 球体样式 + 字体球统一样式 + 显隐规则(纯 CSS,永久生效)----
2763
2836
  var CSS = [
2764
2837
  /* 技能球 */
2765
- '#' + BALL_ID + '{position:fixed;right:74px;bottom:18px;width:46px;height:46px;border-radius:50%;background:radial-gradient(circle at 50% 60%, rgba(255,255,255,.98) 0%, rgba(214,232,247,.9) 9%, rgba(111,158,232,.7) 18%, rgba(165,46,255,.5) 32%, rgba(206,44,203,.35) 46%, rgba(10,14,30,.9) 66%, rgba(4,6,14,.99) 100%);box-shadow:0 0 22px rgba(111,158,232,.45),0 0 4px rgba(206,44,203,.3),0 4px 18px rgba(0,0,0,.55),inset 0 1px 3px rgba(255,255,255,.4),inset 0 -8px 16px rgba(206,44,203,.14),inset 0 0 14px rgba(80,120,255,.2);color:#ffffff;font-size:15px;font-weight:800;display:flex;align-items:center;justify-content:center;text-shadow:0 0 4px rgba(255,255,255,.95),0 0 10px rgba(160,200,255,.9),0 0 20px rgba(120,90,255,.7),0 2px 4px rgba(10,20,60,.8);filter:drop-shadow(0 0 6px rgba(180,210,255,.8));animation:dsbGlow 2.4s ease-in-out infinite;cursor:grab;z-index:2147483600;user-select:none;touch-action:none;animation:orbBreathe 3.2s ease-in-out infinite;}',
2838
+ '#' + BALL_ID + '{position:fixed;right:62px;bottom:18px;width:34px;height:34px;border-radius:50%;background:radial-gradient(circle at 50% 60%, rgba(255,255,255,.98) 0%, rgba(214,232,247,.9) 9%, rgba(111,158,232,.7) 18%, rgba(165,46,255,.5) 32%, rgba(206,44,203,.35) 46%, rgba(10,14,30,.9) 66%, rgba(4,6,14,.99) 100%);box-shadow:0 0 22px rgba(111,158,232,.45),0 0 4px rgba(206,44,203,.3),0 4px 18px rgba(0,0,0,.55),inset 0 1px 3px rgba(255,255,255,.4),inset 0 -8px 16px rgba(206,44,203,.14),inset 0 0 14px rgba(80,120,255,.2);color:#ffffff;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center;text-shadow:0 0 4px rgba(255,255,255,.95),0 0 10px rgba(160,200,255,.9),0 0 20px rgba(120,90,255,.7),0 2px 4px rgba(10,20,60,.8);filter:drop-shadow(0 0 6px rgba(180,210,255,.8));animation:dsbGlow 2.4s ease-in-out infinite;cursor:grab;z-index:2147483600;user-select:none;touch-action:none;animation:orbBreathe 3.2s ease-in-out infinite;}',
2766
2839
  '#' + BALL_ID + ':hover{transform:scale(1.08)}',
2767
2840
  '#' + BALL_ID + '::before{content:"";position:absolute;inset:1px;border-radius:50%;z-index:1;background:radial-gradient(ellipse 85% 26% at 50% 60%, rgba(255,255,255,1) 0%, rgba(235,245,255,.85) 18%, rgba(160,200,255,.5) 38%, rgba(190,120,255,.35) 55%, transparent 75%),radial-gradient(ellipse 70% 18% at 45% 42%, rgba(111,158,232,.55) 0%, transparent 70%),radial-gradient(ellipse 70% 18% at 55% 74%, rgba(206,44,203,.4) 0%, transparent 70%);filter:blur(1px);animation:bandFlow 4.5s ease-in-out infinite;}',
2768
2841
  '#' + BALL_ID + '::after{content:"";position:absolute;inset:-1px;border-radius:50%;z-index:1;background:conic-gradient(from 200deg, rgba(255,255,255,.55), rgba(140,180,255,.35), rgba(206,44,203,.4), rgba(255,255,255,.15), rgba(111,158,232,.4), rgba(255,255,255,.55));-webkit-mask:radial-gradient(circle, transparent 63%, #000 66%, #000 72%, transparent 76%);mask:radial-gradient(circle, transparent 63%, #000 66%, #000 72%, transparent 76%);animation:rimSpin 7s linear infinite;filter:blur(.5px);}',
@@ -2771,14 +2844,18 @@ window.__ModuleLoader__.load({
2771
2844
  '@keyframes orbBreathe{0%,100%{transform:scale(.96);filter:brightness(.92)}50%{transform:scale(1.05);filter:brightness(1.12)}}',
2772
2845
  '@keyframes dsbGlow{0%,100%{text-shadow:0 0 4px rgba(255,255,255,.95),0 0 10px rgba(160,200,255,.9),0 0 20px rgba(120,90,255,.7)}50%{text-shadow:0 0 6px rgba(255,255,255,1),0 0 16px rgba(190,220,255,1),0 0 32px rgba(140,110,255,.9)}}',
2773
2846
  '#' + BALL_ID + ':hover{transform:scale(1.08)}',
2774
- '#' + BALL_ID + ' .dsb-orb-fallback{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:17px;color:#9aa1b5;z-index:1}',
2847
+ '#' + BALL_ID + ' .dsb-orb-fallback{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:#9aa1b5;z-index:1}',
2775
2848
  '#' + BALL_ID + ':hover{transform:scale(1.08)}',
2776
2849
  '#' + BALL_ID + '.dsb-ghost{width:12px!important;height:12px!important;font-size:0!important;right:10px!important;bottom:10px!important;opacity:.3}',
2777
2850
  '#' + BALL_ID + '.dsb-ghost:hover{opacity:.8}',
2778
2851
  /* 字体球视觉:v1.5.9 起 font-enhancer 自带暖色极光玻璃样式,本插件不再代管其外观(避免覆盖);显隐控制见下方 data-dsb-font-hidden 规则 */
2779
2852
  /* 显隐开关:取消勾选=彻底隐藏球(display:none),勾选=显示原版 46px 大球 */
2780
2853
  '[data-dsb-ball-hidden="1"] #' + BALL_ID + '{display:none!important}',
2781
- '[data-dsb-font-hidden="1"] #dsh-fe-toggle{display:none!important}'
2854
+ '[data-dsb-font-hidden="1"] #dsh-fe-toggle{display:none!important}',
2855
+ /* 顶部 40px 是 DSH 窗口拖拽带,必须挖掉 */
2856
+ '#'+BALL_ID+',#'+PANEL_ID+',.dsb-skinmenu{-webkit-app-region:no-drag;app-region:no-drag}',
2857
+ '#'+BALL_ID+'{background:#171c2b!important;text-shadow:none!important;filter:none!important;box-shadow:0 4px 14px rgba(0,0,0,.42)!important}',
2858
+ '#'+BALL_ID+'::before{content:none!important;display:none!important}',
2782
2859
  ].join('\n');
2783
2860
 
2784
2861
  function restoreBallPos(ball) {
@@ -2812,39 +2889,6 @@ window.__ModuleLoader__.load({
2812
2889
 
2813
2890
  // v1.5.3 一键恢复默认位置:清位置记忆与收起/隐藏状态,球立即回右下角默认位。
2814
2891
  // 供 DSH 设置页「悬浮球导航」分区按钮调用(球可能被拖出屏幕外卡住,无法点回)。
2815
- // v1.5.7 推荐位安装徽标:探测三个插件的 client 运行状态,注入「已安装/未安装」徽标。
2816
- function recBadgeInstalled(id) {
2817
- if (id === "font") return !!document.getElementById("dsh-fe-toggle");
2818
- if (id === "todoball") return isTodoBallInstalled();
2819
- if (id === "skillbrowser") return !!document.getElementById(BALL_ID);
2820
- return false; // lightbox 用异步 fetch 判定,不走这里
2821
- }
2822
- function markRecBadge(recId, installed) {
2823
- var row = document.querySelector('[data-rec-id="' + recId + '"]');
2824
- if (!row || row.querySelector(".fe-rec-badge")) return;
2825
- var badge = document.createElement("span");
2826
- badge.className = "fe-rec-badge";
2827
- badge.textContent = installed ? "已安装" : "未安装";
2828
- badge.style.cssText = "flex-shrink:0;margin-left:8px;font-size:11px;padding:2px 8px;border-radius:6px;" +
2829
- (installed ? "background:rgba(120,220,150,.15);border:1px solid rgba(120,220,150,.4);color:#9fe0b5"
2830
- : "background:rgba(255,120,120,.15);border:1px solid rgba(255,120,120,.35);color:#ffb3b3") +
2831
- ";white-space:nowrap";
2832
- var star = row.querySelector("a");
2833
- if (star) row.insertBefore(badge, star); else row.appendChild(badge);
2834
- }
2835
- function applyRecBadges() {
2836
- ["font", "skillbrowser", "lightbox"].forEach(function (id) {
2837
- if (id === "lightbox") {
2838
- try {
2839
- fetch("/api/image-gallery/list").then(function (r) {
2840
- markRecBadge("lightbox", r.ok);
2841
- }).catch(function () { markRecBadge("lightbox", false); });
2842
- } catch (e) { markRecBadge("lightbox", false); }
2843
- } else {
2844
- markRecBadge(id, recBadgeInstalled(id));
2845
- }
2846
- });
2847
- }
2848
2892
  function resetBallToDefault() {
2849
2893
  try { localStorage.removeItem(BALL_POS_KEY); } catch (e) {}
2850
2894
  try { writeStore(BALL_VIS_KEY, true); } catch (e) {}
@@ -2917,6 +2961,7 @@ window.__ModuleLoader__.load({
2917
2961
  ball.style.top = (drag.oy + dy) + "px";
2918
2962
  ball.style.right = "auto";
2919
2963
  ball.style.bottom = "auto";
2964
+ if (S.open) positionPanelNearBall(); // m04874 拖球时面板跟随
2920
2965
  });
2921
2966
  function endDrag() {
2922
2967
  if (!drag.active) return;
@@ -2955,9 +3000,44 @@ window.__ModuleLoader__.load({
2955
3000
  // ---- unified ball skin system (shared 128 skins, three-ball sync) ----
2956
3001
  var SKIN = window.__DSH_BALL_SKINS || null;
2957
3002
  var SKIN_STYLE_ID = "dsb-skin-style";
3003
+
3004
+ // ---------- 三球皮肤同步开关 (m04045/m04323) ----------
3005
+ var SYNC_ON_KEY = "dsh-ball-skin-sync-skill";
3006
+ var SOLO_ID_KEY = "dsh-ball-skin-solo-skill";
3007
+ function isSyncOn() {
3008
+ try { var v = localStorage.getItem(SYNC_ON_KEY); return v === null ? true : v !== "0"; } catch (e) { return true; }
3009
+ }
3010
+ function setSyncOn(on) {
3011
+ try {
3012
+ localStorage.setItem(SYNC_ON_KEY, on ? "1" : "0");
3013
+ if (on) { var g = localStorage.getItem(SKIN.KEY); if (g) localStorage.setItem(SOLO_ID_KEY, g); }
3014
+ else if (!localStorage.getItem(SOLO_ID_KEY)) { var g2 = localStorage.getItem(SKIN.KEY); if (g2) localStorage.setItem(SOLO_ID_KEY, g2); }
3015
+ } catch (e) {}
3016
+ }
3017
+ function soloResolve(id) {
3018
+ if (!SKIN) return null;
3019
+ if (!id || id === "auto") return SKIN.resolve("auto");
3020
+ return SKIN.BY_ID[id] ? id : SKIN.resolve("auto");
3021
+ }
3022
+ function mySkinId() {
3023
+ if (!SKIN) return null;
3024
+ if (isSyncOn()) return SKIN.getId();
3025
+ try { return soloResolve(localStorage.getItem(SOLO_ID_KEY) || (SKIN.getPref ? SKIN.getPref() : "")) || SKIN.getId(); } catch (e) { return SKIN.getId(); }
3026
+ }
3027
+ function mySkinPref() {
3028
+ if (!SKIN) return "";
3029
+ if (isSyncOn()) return SKIN.getPref ? SKIN.getPref() : "";
3030
+ try { return localStorage.getItem(SOLO_ID_KEY) || (SKIN.getPref ? SKIN.getPref() : ""); } catch (e) { return ""; }
3031
+ }
3032
+ function pickSkin(id) {
3033
+ if (!SKIN) return;
3034
+ if (isSyncOn()) { SKIN.setSkin(id); return; }
3035
+ try { localStorage.setItem(SOLO_ID_KEY, id); } catch (e) {}
3036
+ try { applySkinNow(); } catch (e) {}
3037
+ }
2958
3038
  function skinBallCss() {
2959
3039
  if (!SKIN) return "";
2960
- var id = SKIN.getId();
3040
+ var id = mySkinId();
2961
3041
  var s = SKIN.BY_ID[id];
2962
3042
  if (!s) return "";
2963
3043
  var B = "#dsh-skill-browser-ball", BAND = B + "::before", RIM = B + "::after";
@@ -2969,6 +3049,9 @@ window.__ModuleLoader__.load({
2969
3049
  css += "\n@keyframes dshSkinSpin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}\n@keyframes dshSkinSpinR{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}}";
2970
3050
  css += "\n" + SKIN.fx(id, { B: B, BAND: BAND, RIM: RIM });
2971
3051
  if (s.rim) css += "\n" + RIM + "{content:\"\"}";
3052
+ css += "\n" + B + "{background:var(--pbgA,#171c2b)!important;text-shadow:none!important;filter:none!important;box-shadow:0 4px 14px rgba(0,0,0,.42)!important}";
3053
+ css += "\n" + BAND + "{content:none!important;display:none!important}";
3054
+ css += "\n" + RIM + "{content:\"\"!important;display:block!important;position:absolute!important;inset:-1px!important;border-radius:50%!important;background:conic-gradient(from 200deg,var(--stA,#8fd3c0),transparent 30%,var(--stA,#8fd3c0) 55%,transparent 80%,var(--stA,#8fd3c0))!important;-webkit-mask:radial-gradient(circle,transparent 62%,#000 66%,#000 73%,transparent 77%)!important;mask:radial-gradient(circle,transparent 62%,#000 66%,#000 73%,transparent 77%)!important;animation:rimSpin 7s linear infinite!important;pointer-events:none!important}";
2972
3055
  return css;
2973
3056
  }
2974
3057
  // ---- v1.9.2: semantic colour vars so every new UI follows the active skin ----
@@ -3157,23 +3240,29 @@ window.__ModuleLoader__.load({
3157
3240
  // #12151c) until white text clears 4.6:1, then emit --dsb-onbrand-bg1/2.
3158
3241
  // Every active-state background uses those instead of the raw stA/stD.
3159
3242
  var g1 = skinRgb(v.stA) || [91, 108, 255, 1], g2 = skinRgb(v.stP || v.stD) || g1;
3160
- var gmid = skinMix(g1, g2, 0.5);
3161
- var whiteOnMid = skinCr([255, 255, 255], gmid);
3162
- var darkOnMid = skinCr([18, 21, 28], gmid);
3163
- if (whiteOnMid >= 4.6) {
3243
+ // v1.9.10: judge the gradient by its WORST ENDPOINT, not its midpoint.
3244
+ // A linear-gradient paints g1..g2, so the label sits on the whole ramp;
3245
+ // checking only the midpoint let 04/051/113-127 pass at the middle while
3246
+ // their light end was still 3.7-4.4:1 against white text.
3247
+ var worst = function (ink, a1, a2) {
3248
+ return Math.min(skinCr(ink, a1), skinCr(ink, a2));
3249
+ };
3250
+ var W = [255, 255, 255], K = [18, 21, 28];
3251
+ if (worst(W, g1, g2) >= 4.6) {
3164
3252
  d["--dsb-onbrand"] = "#ffffff";
3165
3253
  d["--dsb-onbrand-bg1"] = skinHex(g1);
3166
3254
  d["--dsb-onbrand-bg2"] = skinHex(g2);
3167
- } else if (darkOnMid >= 4.6) {
3255
+ } else if (worst(K, g1, g2) >= 4.6) {
3168
3256
  d["--dsb-onbrand"] = "#12151c";
3169
3257
  d["--dsb-onbrand-bg1"] = skinHex(g1);
3170
3258
  d["--dsb-onbrand-bg2"] = skinHex(g2);
3171
3259
  } else {
3172
- // Neither extreme works → darken the gradient step by step.
3173
- var ink = [18, 21, 28, 1], a1 = g1, a2 = g2, t = 0;
3174
- for (t = 0.1; t <= 0.95; t += 0.05) {
3175
- a1 = skinMix(g1, ink, t); a2 = skinMix(g2, ink, t);
3176
- if (skinCr([255, 255, 255], skinMix(a1, a2, 0.5)) >= 4.6) break;
3260
+ // Neither extreme works → darken the ramp until white clears 4.6 at
3261
+ // BOTH ends.
3262
+ var ink = [18, 21, 28, 1], a1 = g1, a2 = g2, tt = 0;
3263
+ for (tt = 0.1; tt <= 0.95; tt += 0.05) {
3264
+ a1 = skinMix(g1, ink, tt); a2 = skinMix(g2, ink, tt);
3265
+ if (worst(W, a1, a2) >= 4.6) break;
3177
3266
  }
3178
3267
  d["--dsb-onbrand"] = "#ffffff";
3179
3268
  d["--dsb-onbrand-bg1"] = skinHex(a1);
@@ -3186,7 +3275,7 @@ window.__ModuleLoader__.load({
3186
3275
  function skinPanelCss() {
3187
3276
  if (!SKIN) return "";
3188
3277
  var P = "#dsh-skill-browser-panel";
3189
- var id = SKIN.getId();
3278
+ var id = mySkinId();
3190
3279
  var css = SKIN.varsCss(P, id);
3191
3280
  css += "\n" + semanticVarsCss(P, id);
3192
3281
  if (skinIsLight(id)) {
@@ -3321,7 +3410,8 @@ window.__ModuleLoader__.load({
3321
3410
  }
3322
3411
  // 原版皮肤(仅本球):flag 置位时清空皮肤覆盖样式,技能球回到原始星云紫。
3323
3412
  var SKIN_CLASSIC_KEY = "dsh-ball-skin-classic-skill";
3324
- function isSkinClassic() { try { return localStorage.getItem(SKIN_CLASSIC_KEY) === "1"; } catch (e) { return false; } }
3413
+ // 原版皮肤已于 2026-10-29 按用户要求彻底移除;旧标记自动清理,始终返回 false。
3414
+ function isSkinClassic() { try { localStorage.removeItem(SKIN_CLASSIC_KEY); } catch (e) {} return false; }
3325
3415
  function setSkinClassic(on) {
3326
3416
  try { if (on) localStorage.setItem(SKIN_CLASSIC_KEY, "1"); else localStorage.removeItem(SKIN_CLASSIC_KEY); } catch (e) {}
3327
3417
  applySkinNow();
@@ -3339,7 +3429,7 @@ window.__ModuleLoader__.load({
3339
3429
  }
3340
3430
  function skinOptionsHtml() {
3341
3431
  if (!SKIN) return "";
3342
- var html = "", groups = SKIN.groups();
3432
+ var html = '<option value="auto">0 \u00b7 \u8ddf\u968f\u7cfb\u7edf \u00b7 \u6df1/\u6d45\u81ea\u52a8</option>', groups = SKIN.groups();
3343
3433
  for (var g = 0; g < groups.length; g++) {
3344
3434
  html += '<optgroup label="' + groups[g] + '">';
3345
3435
  for (var i = 0; i < SKIN.ALL.length; i++) {
@@ -3354,11 +3444,27 @@ window.__ModuleLoader__.load({
3354
3444
  function fillSkinSelect(sel) {
3355
3445
  if (!sel || !SKIN) return;
3356
3446
  if (!sel.options.length) {
3357
- sel.innerHTML = '<option value="classic">原版 · 星云紫(仅本球)</option>' + skinOptionsHtml();
3447
+ sel.innerHTML = '<option value="auto">0 · 跟随系统 · 深/浅自动</option>' + skinOptionsHtml();
3358
3448
  }
3359
- sel.value = isSkinClassic() ? "classic" : SKIN.getId();
3449
+ sel.value = mySkinPref() === "auto" ? "auto" : mySkinId();
3360
3450
  }
3361
3451
  // ---- todo-style grouped skin menu (panel 🎨) ----
3452
+ var DSB_ICONS = {
3453
+ palette: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 14.2A6.2 6.2 0 1 1 14.2 8c0 1.1-.9 1.8-2 1.8h-1.4c-.9 0-1.6.7-1.6 1.6 0 .4.2.8.4 1.1.3.4.4.7.4 1 0 .4-.4.7-1 .7z"/><circle cx="5.6" cy="6.2" r=".85"/><circle cx="8" cy="4.4" r=".85"/><circle cx="10.4" cy="6.2" r=".85"/></svg>',
3454
+ gear: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="4.6"/><circle cx="8" cy="8" r="1.9"/><path d="M8 3.4v1.4M8 11.2v1.4M3.4 8h1.4M11.2 8h1.4M4.6 4.6l1 1M10.4 10.4l1 1M11.4 4.6l-1 1M5.6 10.4l-1 1"/></svg>',
3455
+ bolt: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" aria-hidden="true"><path d="M8.8 1.8 3.8 9h3.4l-.9 5.2L11.9 7H8.5z"/></svg>',
3456
+ refresh: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.2 8a5.2 5.2 0 1 1-1.6-3.8"/><path d="M13.4 1.8v3h-3"/></svg>',
3457
+ star: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 1.8l1.9 4 4.3.5-3.2 3 .9 4.3L8 11.4l-3.9 2.2.9-4.3-3.2-3 4.3-.5z"/></svg>',
3458
+ close: '<svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9"/></svg>',
3459
+ book: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M8 3.4C7 2.6 5.6 2.2 3.8 2.2c-.6 0-1.2.05-1.8.16V12.6c.6-.11 1.2-.16 1.8-.16 1.8 0 3.2.44 4.2 1.2 1-.76 2.4-1.2 4.2-1.2.6 0 1.2.05 1.8.16V2.36a10.5 10.5 0 00-1.8-.16C10.4 2.2 9 2.6 8 3.4z\"/><path d=\"M8 3.4v10.24\"/></svg>",
3460
+ folder: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M2.2 4.7c0-.5.4-.9.9-.9h2.9l1.3 1.5h5.6c.5 0 .9.4.9.9v6.3c0 .5-.4.9-.9.9H3.1c-.5 0-.9-.4-.9-.9z\"/></svg>",
3461
+ search: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"7.1\" cy=\"7.1\" r=\"4.2\"/><path d=\"M10.3 10.3l3.1 3.1\"/></svg>",
3462
+ eye: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M1.9 8s2.4-4.1 6.1-4.1S14.1 8 14.1 8s-2.4 4.1-6.1 4.1S1.9 8 1.9 8z\"/><circle cx=\"8\" cy=\"8\" r=\"1.8\"/></svg>",
3463
+ chart: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M2.7 2.6v10.8h10.6\"/><path d=\"M5.4 11V8.2M8.2 11V5.4M11 11V7\"/></svg>",
3464
+ folders: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M2.4 5.4c0-.5.4-.9.9-.9h2.6l1.2 1.4h4.2c.5 0 .9.4.9.9v4.9c0 .5-.4.9-.9.9H3.3c-.5 0-.9-.4-.9-.9z\"/><path d=\"M5 3.2h2.5l1.1 1.2\"/></svg>",
3465
+ grid: "<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.55\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2.6\" y=\"2.6\" width=\"4.3\" height=\"4.3\" rx=\"1\"/><rect x=\"9.1\" y=\"2.6\" width=\"4.3\" height=\"4.3\" rx=\"1\"/><rect x=\"2.6\" y=\"9.1\" width=\"4.3\" height=\"4.3\" rx=\"1\"/><rect x=\"9.1\" y=\"9.1\" width=\"4.3\" height=\"4.3\" rx=\"1\"/></svg>"
3466
+ };
3467
+ function dsbGico(n) { return '<span class="dsb-gico">' + (DSB_ICONS[n] || '') + '</span>'; }
3362
3468
  var SKINMENU_STYLE_ID = "dsb-skinmenu-style";
3363
3469
  var SKINMENU_MARGIN = "0 16px 10px";
3364
3470
  function skinMenuHtml() {
@@ -3367,21 +3473,27 @@ window.__ModuleLoader__.load({
3367
3473
  var a = (s.vars && s.vars.stA) || "#888", b = (s.vars && s.vars.bgB) || "#222";
3368
3474
  return '<span class="dot" style="background:linear-gradient(135deg,' + a + ',' + b + ')"></span>';
3369
3475
  }
3370
- var html = '<div class="cap">原版</div>';
3371
- html += '<div class="row' + (isSkinClassic() ? " cur" : "") + '" data-skin-classic="1">' +
3372
- '<span class="chk">' + (isSkinClassic() ? "✓" : "") + '</span>' +
3373
- '<span class="dot" style="background:linear-gradient(135deg,#a5b8fc,#3c1e8f)"></span>' +
3374
- "<span>原版 · 星云紫(仅本球)</span></div>";
3476
+ var html = "";
3477
+ var _auto = mySkinPref() === "auto";
3478
+ var _sync = isSyncOn();
3479
+ html += '<div class="row row-wide sync-row' + (_sync ? " sync-on" : "") + '" data-sync="1" title="\u52fe\u9009 = \u8ddf\u968f\u5168\u5c40\u76ae\u80a4\uff1b\u4e0d\u52fe = \u672c\u7403\u72ec\u7acb\u76ae\u80a4">' +
3480
+ '<span class="chk">' + (_sync ? "\u2713" : "") + '</span>' +
3481
+ "<span>\u4e09\u7403\u76ae\u80a4\u540c\u6b65</span></div>";
3482
+ html += '<div class="cap">\u8ddf\u968f\u7cfb\u7edf</div>';
3483
+ html += '<div class="row row-wide' + (_auto ? " cur" : "") + '" data-skin-id="auto" title="跟随客户端深/浅色自动切换">' +
3484
+ '<span class="chk">' + (_auto ? "\u2713" : "") + '</span>' +
3485
+ '<span class="dot" style="background:linear-gradient(135deg,#f9fafb,#151517)"></span>' +
3486
+ "<span class=\"nm\">0 \u00b7 \u968f\u7cfb\u7edf \u00b7 \u6df1/\u6d45\u81ea\u52a8</span></div>";
3375
3487
  var groups = SKIN.groups();
3376
3488
  for (var g = 0; g < groups.length; g++) {
3377
3489
  html += '<div class="cap">' + groups[g] + "</div>";
3378
3490
  for (var i = 0; i < SKIN.ALL.length; i++) {
3379
3491
  var s = SKIN.ALL[i];
3380
3492
  if (s.group !== groups[g]) continue;
3381
- var cur = !isSkinClassic() && s.id === SKIN.getId();
3493
+ var cur = !isSkinClassic() && !_auto && s.id === mySkinId();
3382
3494
  html += '<div class="row' + (cur ? " cur" : "") + '" data-skin-id="' + s.id + '" title="' + s.en + ' (方案 ' + s.no + ')">' +
3383
3495
  '<span class="chk">' + (cur ? "✓" : "") + "</span>" + dot(s) +
3384
- "<span>" + s.no + " · " + s.name + "</span></div>";
3496
+ "<span class=\"nm\">" + s.no + " · " + s.name + "</span></div>";
3385
3497
  }
3386
3498
  }
3387
3499
  return html;
@@ -3414,11 +3526,12 @@ window.__ModuleLoader__.load({
3414
3526
  var row = t.closest("#dsb-skin .row");
3415
3527
  if (!row) return;
3416
3528
  ev.stopPropagation();
3529
+ if (row.getAttribute("data-sync")) { setSyncOn(!isSyncOn()); applySkinNow(); refreshSkinMenu(); return; }
3417
3530
  if (row.getAttribute("data-skin-classic")) { setSkinClassic(true); return; }
3418
3531
  var id = row.getAttribute("data-skin-id");
3419
- if (id) { setSkinClassic(false); SKIN.setSkin(id); }
3532
+ if (id) { setSkinClassic(false); pickSkin(id); }
3420
3533
  }, true);
3421
- var SKINMENU_CSS = ".dsb-skinmenu,.fe-skinmenu{display:none;max-height:46vh;overflow-y:auto;border:1px solid rgba(255,255,255,.12);border-radius:12px;background:rgba(10,13,20,.98);padding:6px;z-index:5;box-shadow:0 14px 40px rgba(0,0,0,.5)}\n.dsb-skinmenu.open,.fe-skinmenu.open{display:block}\n.dsb-skinmenu .cap,.fe-skinmenu .cap{font-size:10.5px;font-weight:700;color:#8b93a8;padding:6px 8px 2px;letter-spacing:1px}\n.dsb-skinmenu .row,.fe-skinmenu .row{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:8px;cursor:pointer;font-size:12px;color:#dfe4ec;font-family:'Segoe UI','Microsoft YaHei','PingFang SC',system-ui,sans-serif}\n.dsb-skinmenu .row:hover,.fe-skinmenu .row:hover{background:rgba(255,255,255,.08)}\n.dsb-skinmenu .row.cur,.fe-skinmenu .row.cur{color:var(--dsb-warn,#ffd27a);font-weight:600}\n.dsb-skinmenu .dot,.fe-skinmenu .dot{width:10px;height:10px;border-radius:50%;flex-shrink:0;border:1px solid rgba(255,255,255,.2)}\n.dsb-skinmenu .chk,.fe-skinmenu .chk{width:14px;text-align:center;flex-shrink:0}";
3534
+ var SKINMENU_CSS = ".dsb-skinmenu{display:none;max-height:46vh;overflow-y:auto;border:1px solid rgba(255,255,255,.12);border-radius:12px;background:rgba(10,13,20,.98);padding:6px;z-index:5;box-shadow:0 14px 40px rgba(0,0,0,.5)}\n.dsb-skinmenu{max-width:none!important;width:auto}.dsb-skinmenu.open{display:grid!important;grid-template-columns:repeat(8,minmax(0,1fr))!important;gap:5px 3px;align-content:start}\n.dsb-skinmenu .cap{font-size:11px;font-weight:700;color:#9aa3b8;padding:7px 8px 3px;letter-spacing:1px}\n.dsb-skinmenu .cap{grid-column:1/-1}\n.dsb-skinmenu .row-wide{grid-column:1/-1}\n.dsb-skinmenu .row{display:flex;align-items:center;gap:4px;padding:5px 3px;min-height:26px;line-height:1.3;border-radius:8px;cursor:pointer;font-size:11px;white-space:nowrap;overflow:hidden;color:#dfe4ec;font-family:'Segoe UI','Microsoft YaHei','PingFang SC',system-ui,sans-serif;min-width:0}\n.dsb-skinmenu .sync-row{background:rgba(255,255,255,.06);font-weight:600;margin-bottom:2px}\n.dsb-skinmenu .sync-row.sync-on{color:#ffd27a}\n.dsb-skinmenu .row:hover{background:rgba(255,255,255,.08)}\n.dsb-skinmenu .row.cur{color:var(--dsb-warn,#ffd27a);font-weight:600}\n.dsb-skinmenu .dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;border:1px solid rgba(255,255,255,.2)}\n.dsb-skinmenu .chk{width:12px;text-align:center;flex-shrink:0}\n.dsb-skinmenu .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}";
3422
3535
  function ensureSkinMenuMargin() { var m = skinMenuEl(); if (m) m.style.margin = SKINMENU_MARGIN; }
3423
3536
 
3424
3537
  if (SKIN) {
@@ -3474,90 +3587,87 @@ window.__ModuleLoader__.load({
3474
3587
  if (!React) return null;
3475
3588
 
3476
3589
  var rows = [];
3477
- // 未安装的球:开关仍显示但置灰+标注,保证"单独装任何一个,分区界面一致"(生态规格)
3590
+ // ── 简约版悬浮球导航(m05874:去须知块、去说明文字,只留开关/皮肤/复位/作者插件)──
3478
3591
  function mkToggle(id, label, onChange, installed) {
3479
3592
  var on = installed !== false;
3480
- return React.createElement("label", { key: id, style: { display: "flex", alignItems: "center", gap: "8px", fontSize: "13px", cursor: on ? "pointer" : "not-allowed", opacity: on ? 1 : .5 } },
3593
+ return React.createElement("label", { key: id, style: { display: "flex", alignItems: "center", gap: "8px", fontSize: "12.5px", cursor: on ? "pointer" : "not-allowed", opacity: on ? 1 : .45, lineHeight: "1.6" } },
3481
3594
  React.createElement("input", { type: "checkbox", id: id, disabled: !on, onChange: onChange }),
3482
3595
  React.createElement("span", null, label + (on ? "" : "(未安装)")));
3483
3596
  }
3484
- rows.push(React.createElement("div", { key: "head", style: { fontWeight: "600", marginBottom: "4px" } }, "悬浮球导航"));
3485
- rows.push(mkToggle("dsb-set-ball", "技能浏览器悬浮球(🧩)", function (e) {
3597
+ rows.push(React.createElement("div", { key: "head", style: { fontWeight: "600", fontSize: "13px", marginBottom: "2px" } }, "悬浮球"));
3598
+ rows.push(mkToggle("dsb-set-ball", "技能浏览器", function (e) {
3486
3599
  writeStore(BALL_VIS_KEY, e.target.checked);
3487
3600
  applyBallVisibility();
3488
3601
  if (!e.target.checked && S.open) closePanel();
3489
3602
  }, true));
3490
- rows.push(mkToggle("dsb-set-font", "字体插件悬浮球(🔤)", function (e) {
3603
+ rows.push(mkToggle("dsb-set-font", "字体插件", function (e) {
3491
3604
  writeStore(FONT_BALL_VIS_KEY, e.target.checked);
3492
3605
  applyFontBallVisibility();
3493
3606
  }, isFontEnhancerInstalled()));
3494
- rows.push(mkToggle("dsb-set-todo", "Todo 悬浮球(📋)", function (e) {
3607
+ rows.push(mkToggle("dsb-set-todo", "Todo 进度", function (e) {
3495
3608
  writeStore(TODO_BALL_VIS_KEY, e.target.checked);
3496
3609
  if (typeof applyTodoBallVisibility === "function") applyTodoBallVisibility();
3497
3610
  var el = document.getElementById("dsh-tfb-root");
3498
3611
  if (el) el.style.setProperty("display", e.target.checked ? "" : "none", "important");
3499
3612
  }, isTodoBallInstalled()));
3500
- // 悬浮球皮肤(三球同步):<select> 原生控件,不依赖 React hooks
3613
+ // 皮肤(三球同步)
3501
3614
  (function () {
3502
3615
  var SKG = window.__DSH_BALL_SKINS || null;
3503
3616
  if (!SKG || !React) return;
3504
- var optgroups = [];
3617
+ var optgroups = [React.createElement("option", { key: "auto", value: "auto" }, "0 \u00b7 \u8ddf\u968f\u7cfb\u7edf \u00b7 \u6df1/\u6d45\u81ea\u52a8")];
3505
3618
  var groups = SKG.groups();
3506
3619
  for (var g = 0; g < groups.length; g++) {
3507
3620
  var opts = [];
3508
3621
  for (var i = 0; i < SKG.ALL.length; i++) {
3509
3622
  var sp = SKG.ALL[i];
3510
3623
  if (sp.group !== groups[g]) continue;
3511
- opts.push(React.createElement("option", { key: sp.id, value: sp.id }, "方案" + sp.no + " · " + sp.name));
3624
+ opts.push(React.createElement("option", { key: sp.id, value: sp.id }, sp.no + " \u00b7 " + sp.name));
3512
3625
  }
3513
3626
  optgroups.push(React.createElement("optgroup", { key: groups[g], label: groups[g] }, opts));
3514
3627
  }
3515
- rows.push(React.createElement("div", { key: "skin-row", style: { display: "flex", alignItems: "center", gap: "8px", fontSize: "13px" } },
3516
- React.createElement("span", null, "悬浮球皮肤"),
3628
+ rows.push(React.createElement("div", { key: "skin-row", style: { display: "flex", alignItems: "center", gap: "8px", fontSize: "12.5px" } },
3629
+ React.createElement("span", { style: { flexShrink: 0 } }, "皮肤"),
3517
3630
  React.createElement("select", {
3518
3631
  id: "dsh-set-skin-global",
3519
- defaultValue: SKG.getId(),
3632
+ defaultValue: (SKG.getPref && SKG.getPref() === "auto") ? "auto" : SKG.getId(),
3520
3633
  onChange: function (e) { SKG.setSkin(e.target.value); },
3521
- style: { flex: "1", minWidth: "200px", background: "rgba(0,0,0,.35)", border: "1px solid rgba(255,255,255,.14)", borderRadius: "6px", color: "inherit", fontSize: "12px", padding: "4px 6px", outline: "none" }
3522
- }, optgroups),
3523
- React.createElement("span", { style: { fontSize: "12px", color: "#8b93a8" } }, "三球同步 · 128 款")
3634
+ style: { flex: "1", minWidth: "0", background: "rgba(0,0,0,.28)", border: "1px solid rgba(255,255,255,.12)", borderRadius: "6px", color: "inherit", fontSize: "12px", padding: "4px 6px", outline: "none" }
3635
+ }, optgroups)
3524
3636
  ));
3525
3637
  })();
3526
- rows.push(React.createElement("div", { key: "hint", style: { fontSize: "12px", color: "#8b93a8" } },
3527
- "悬浮球可拖动;清单面板始终居中;本分区就在 DSH 设置中,随时可改悬浮球显隐"));
3528
- // ── 安装与更新须知(v1.5.7:24h 供应链政策 + 推荐清单说明)──
3529
- rows.push(React.createElement("div", { key: "notice-block", style: { marginTop: "12px", padding: "10px 12px", background: "rgba(255,255,255,.03)", border: "1px solid rgba(255,255,255,.06)", borderRadius: "10px", fontSize: "12px", color: "#9aa1b5", lineHeight: "1.7" } },
3530
- React.createElement("div", { style: { fontWeight: "600", color: "#cfd4dc", marginBottom: "4px" } }, "📌 安装与更新须知"),
3531
- React.createElement("div", null, "1. 本分区由「技能浏览器」提供;技能球 / 字体球 / Todo 球三个悬浮球的显隐都在这里控制(新装默认全部显示)。"),
3532
- React.createElement("div", null, "2. 推荐插件列表实时显示「已安装 / 未安装」状态:绿色「已安装」= 可直接使用;红色「未安装」= 点击 ⭐ Star 前往仓库,或到插件市场搜索安装。"),
3533
- React.createElement("div", { style: { color: "#e0b0b0" } }, "3. 【重要】安装或更新插件时,若报错含 minimumReleaseAge 或 ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION:这不是插件坏了,是 DSH 对刚发布 npm 包的 24 小时安全观察期(防止刚发布的投毒包)。"),
3534
- React.createElement("div", { style: { color: "#e0b0b0" } }, "4. 遇到 24h 报错的处理:等一天再安装/更新即可自动通过,插件本体没有任何问题。插件作者连发多版时窗口期会顺延一天。"),
3535
- React.createElement("div", null, "5. 悬浮球可拖动换位置;拖到屏幕外找不到时,点 🎯 按钮所有悬浮球一起回到右下角。三球已统一 128 款皮肤:在 DSH 设置页本分区的「悬浮球皮肤」下拉切换(三球同步),或在各球面板里切。")
3536
- ));
3537
- // ── 一键恢复默认位置(v1.5.3 用户要求):悬浮球被拖出屏幕外卡住时,
3538
- // 点此按钮立即回到默认右下角 (right:26px bottom:118px) 46px 常规大小,
3539
- // 并顺带恢复显示、解除收起小圆点状态。无需重启。──
3540
3638
  rows.push(React.createElement("button", { key: "reset-pos",
3541
3639
  onClick: function () { try { resetBallToDefault(); } catch (e) {} },
3542
- style: { alignSelf: "flex-start", fontSize: "13px", cursor: "pointer",
3543
- background: "rgba(255,210,122,.12)", border: "1px solid rgba(255,210,122,.35)",
3544
- borderRadius: "6px", padding: "6px 12px", color: "#ffd27a" }
3545
- }, "🎯 所有悬浮球回到右下角"));
3546
- // ── 推荐插件(v1.5.7 统一三条清单:字体/技能/照片,探测式安装徽标)──
3547
- rows.push(React.createElement("div", { key: "rec-head", style: { fontWeight: "600", marginTop: "12px", marginBottom: "4px", borderTop: "1px solid rgba(255,255,255,.08)", paddingTop: "10px" } }, "推荐插件"));
3548
- function recRow(key, recId, icon, text, repo) {
3549
- return React.createElement("div", { key: key, "data-rec-id": recId, style: { display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: "13px", padding: "3px 0" } },
3550
- React.createElement("span", null, icon + " " + text),
3551
- React.createElement("a", { href: "https://github.com/" + repo, target: "_blank", rel: "noopener", style: { textDecoration: "none", fontSize: "12px", background: "rgba(255,255,255,.06)", border: "1px solid rgba(255,255,255,.12)", borderRadius: "6px", padding: "2px 8px", color: "#ffd27a", cursor: "pointer", whiteSpace: "nowrap" } }, "⭐ Star"));
3640
+ style: { alignSelf: "flex-start", fontSize: "12px", cursor: "pointer",
3641
+ background: "rgba(255,210,122,.14)", border: "1px solid rgba(255,210,122,.45)",
3642
+ borderRadius: "6px", padding: "5px 10px", color: "#ffd27a" }
3643
+ }, "\u25ce \u56de\u5230\u53f3\u4e0b\u89d2"));
3644
+ // ── 作者插件(m05874/m05875:全部摆上做宣传)──
3645
+ rows.push(React.createElement("div", { key: "rec-head", style: { fontWeight: "600", fontSize: "12.5px", marginTop: "10px", paddingTop: "9px", borderTop: "1px solid rgba(255,255,255,.08)" } }, "\u4f5c\u8005\u63d2\u4ef6"));
3646
+ function recRow(key, recId, name, desc, repo) {
3647
+ return React.createElement("a", { key: key, "data-rec-id": recId, href: "https://github.com/" + repo, target: "_blank", rel: "noopener",
3648
+ style: { display: "flex", alignItems: "baseline", gap: "8px", textDecoration: "none", color: "inherit", fontSize: "12.5px", padding: "3px 0", opacity: .92 } },
3649
+ React.createElement("span", { style: { fontWeight: "600", flexShrink: 0 } }, name),
3650
+ React.createElement("span", { style: { fontSize: "11.5px", color: "#8b93a8", flex: "1", minWidth: "0", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, desc),
3651
+ React.createElement("span", { style: { fontSize: "11px", color: "#ffd27a", flexShrink: 0 } }, "\u2b50"));
3652
+ }
3653
+ var AUTH = [
3654
+ ["font", "dsh-font-enhancer", "\u5b57\u4f53\u63d2\u4ef6", "\u533a\u57df\u5b57\u4f53/\u989c\u8272/\u5b57\u53f7 DIY"],
3655
+ ["skillbrowser", "dsh-skill-browser", "\u6280\u80fd\u6d4f\u89c8\u5668", "\u6280\u80fd\u5e93\u6d4f\u89c8\u4e0e\u6cbb\u7406"],
3656
+ ["todoball", "dsh-todo-float-ball", "Todo \u8fdb\u5ea6\u7403", "\u4efb\u52a1\u8fdb\u5ea6\u5e38\u9a7b\u76d1\u63a7"],
3657
+ ["lightbox", "dsh-chat-image-lightbox", "\u56fe\u7247\u706f\u7bb1", "\u804a\u5929\u56fe\u7247\u5168\u5c4f\u4e0e\u7f29\u7565\u56fe"],
3658
+ ["voice", "dsh-voice-alert", "\u8bed\u97f3\u63d0\u9192", "\u5b8c\u6210/\u5931\u8d25\u81ea\u52a8\u64ad\u62a5"],
3659
+ ["litfetch", "dsh-lit-fetch", "\u6587\u732e\u68c0\u7d22", "\u6309 DOI/\u5173\u952e\u8bcd\u4e0b PDF"],
3660
+ ["qqdigest", "dsh-qq-digest", "QQ \u7fa4\u6458\u8981", "\u7fa4\u804a\u8bb0\u5f55\u4e00\u952e\u603b\u7ed3"],
3661
+ ["modelFold", "dsh-model-fold", "\u6a21\u578b\u83dc\u5355\u5206\u7ec4", "\u6a21\u578b\u9009\u62e9\u6309\u6765\u6e90\u5f52\u7c7b"],
3662
+ ["archive", "dsh-archive-favorites-forge", "\u5bf9\u8bdd\u5f52\u6863\u52a9\u624b", "\u6536\u85cf/\u6279\u91cf\u5f52\u6863/\u5220\u9664"],
3663
+ ["vision", "dsh-vision", "\u5916\u6302\u8bc6\u56fe", "\u56fe\u7247\u8bc6\u522b\u4e0e\u622a\u56fe"],
3664
+ ["artifact", "dsh-artifact-linker", "\u6587\u4ef6\u70b9\u51fb\u76f4\u8fbe", "\u8def\u5f84\u70b9\u51fb\u6253\u5f00\u6587\u4ef6"],
3665
+ ["webFree", "dsh-deepseek-web-free", "DeepSeek \u7f51\u9875\u7aef", "\u7f51\u9875\u6a21\u578b\u63a5\u5165"],
3666
+ ];
3667
+ for (var ai = 0; ai < AUTH.length; ai++) {
3668
+ rows.push(recRow("rec-" + AUTH[ai][0], AUTH[ai][0], AUTH[ai][2], AUTH[ai][3], "loyalchiiina/" + AUTH[ai][1]));
3552
3669
  }
3553
- // ── 推荐插件(v1.5.7 统一清单:字体/技能/照片/Todo,探测式安装徽标)──
3554
- // Todo 悬浮球皮肤切换(三皮肤):事件委托到本分区容器——React 合成
3555
- // 事件与 ref 均不可靠(slot 重渲染会重建 DOM),委托到容器上永不失效。
3556
- // 点击写 localStorage + 直调 todo 插件的 __dshtfbApplyTheme 钩子。
3557
- rows.push(recRow("rec-font", "font", "🔤", "字体插件 — 区域自定义字体/颜色/字号", "loyalchiiina/dsh-font-enhancer"));
3558
- rows.push(recRow("rec-skillbrowser", "skillbrowser", "🧩", "技能浏览器 — 悬浮球面板浏览共享技能库 + 失效台账", "loyalchiiina/dsh-skill-browser"));
3559
- rows.push(recRow("rec-lightbox", "lightbox", "🖼️", "照片显示器 — 聊天图片灯箱(放大/下载/浏览)", "loyalchiiina/dsh-chat-image-lightbox"));
3560
- rows.push(recRow("rec-todoball", "todoball", "📋", "Todo 悬浮球 — todo_write 进度常驻监控 + 多会话固定 + 三皮肤(面板内 🎨 切换)", "loyalchiiina/dsh-todo-float-ball"));return React.createElement("div", { "data-dsb-slot": "1", style: { display: "flex", flexDirection: "column", gap: "8px", padding: "8px 0" } }, rows);
3670
+ return React.createElement("div", { "data-dsb-slot": "1", style: { display: "flex", flexDirection: "column", gap: "7px", padding: "6px 0" } }, rows);
3561
3671
  }
3562
3672
 
3563
3673
  function registerSettings(ctx) {
@@ -3631,8 +3741,6 @@ window.__ModuleLoader__.load({
3631
3741
  applyBallVisibility();
3632
3742
  } catch (e) {}
3633
3743
  try { console.log("[dsh-skill-browser] client mounted (v1.7.2: 3-level aggregate switches + batch confirm menu)"); } catch (e3) {}
3634
- setTimeout(applyRecBadges, 1200);
3635
- setInterval(applyRecBadges, 5000);
3636
3744
  };
3637
3745
 
3638
3746
  return module.exports;