zcode-pro 1.4.0 → 1.4.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.
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/dist/inject.js +116 -55
- package/package.json +1 -1
- package/src/host/helper.mjs +13 -6
- package/src/inject/core.js +20 -10
- package/src/inject/features/settings-dialog.js +37 -17
- package/src/inject/features/theme.js +25 -13
- package/src/inject/ui.js +7 -2
package/README.en.md
CHANGED
|
@@ -37,8 +37,8 @@ Grouped by where each feature lives in the settings window: the category column
|
|
|
37
37
|
| | UI style adjustments | Fine-tune paragraph spacing, content width, line heights, list/quote/table spacing and cell padding; focusing an input highlights the affected areas; applies instantly |
|
|
38
38
|
| Appearance · Status bar | Status bar statistics | Shows statistics at the bottom-right of the input box and at the end of each answer: context usage (color-shifts when high), questions asked, today/total tokens and task count, all from official data; reorder or hide each item under Settings → Appearance → Status bar |
|
|
39
39
|
| | Per-turn token usage | Shows that turn's in/out tokens and cache hit rate after the time in each answer's action row (local records keep only a recent window; older answers stay unlabelled) |
|
|
40
|
-
| Appearance · Theme | UI skins | Eleven famous editor theme palettes (Dracula / Nord / Tokyo Night / Catppuccin / Gruvbox / One Dark / Solarized / Rosé Pine / Everforest / Night Owl / Kanagawa),
|
|
41
|
-
| Appearance · Background | Background image | Window-wide background from four sources: none / local library (upload many, pick the active one, delete freely) / folder (read in place, rotate on a timer, random or by filename) / URL (refresh on a timer for random-image APIs);
|
|
40
|
+
| Appearance · Theme | UI skins | Eleven famous editor theme palettes (Dracula / Nord / Tokyo Night / Catppuccin / Gruvbox / One Dark / Solarized / Rosé Pine / Everforest / Night Owl / Kanagawa), auto-matching ZCode's light / dark mode; plus a custom theme: pick 5 colors each for light and dark to derive the whole palette, applying live |
|
|
41
|
+
| Appearance · Background | Background image | Window-wide background from four sources: none / local library (upload many, pick the active one, delete freely) / folder (read in place, rotate on a timer, random or by filename) / URL (refresh on a timer for random-image APIs); three sliders — mask opacity (image fading toward the theme background color), image blur, panel opacity (sidebar/panels/tab bar); sidebar, chat and composer reveal the background while menus and dialogs stay opaque; the library uploads with the zcode-pro WebDAV sync group (overwrite, no history versions) |
|
|
42
42
|
| Performance | Idle project memory reclaim | Projects unused for a while with no running tasks release their memory automatically, and unused ones are reclaimed once after startup; sessions are untouched and reload when reopened (durations adjustable) |
|
|
43
43
|
| Proxy | Software proxy | Set an HTTP proxy for plugin updates/installs and tool upgrades, with connectivity test |
|
|
44
44
|
| Sync | Settings sync | Manually back up ZCode Pro settings and model settings to WebDAV, or restore them on a new computer; transfers only on click |
|
package/README.md
CHANGED
|
@@ -37,8 +37,8 @@ ZCode 桌面版界面增强工具。不修改客户端文件,通过 ZCode Pro
|
|
|
37
37
|
| | 界面样式调整 | 微调段落间距、内容宽度、各类行高、列表/引用块/表格间距与单元格边距;聚焦输入框时高亮预览受影响区域,即改即生效 |
|
|
38
38
|
| 外观 · 状态栏 | 状态栏统计 | 提问输入框右下角和每轮回答最后显示统计项:上下文占用(占用高时变色)、提问次数、今日/累计 token、任务总数,全部取自官方数据;各项的顺序与显隐在 设置 → 外观 → 状态栏 调整 |
|
|
39
39
|
| | 每轮回答 token 用量 | 在每条回答末尾操作按钮的时间后面显示该轮的输入/输出 token 与缓存命中率(本地记录只保留最近一段,更早的回答不标注) |
|
|
40
|
-
| 外观 · 主题 | 界面皮肤 | 内置 11 套知名编辑器主题配色(Dracula / Nord / Tokyo Night / Catppuccin / Gruvbox / One Dark / Solarized / Rosé Pine / Everforest / Night Owl / Kanagawa
|
|
41
|
-
| 外观 · 背景图 | 背景图 | 整窗铺背景,四种来源:无背景 / 本地图库(可传多张、点选当前、可单删)/ 文件夹(原地读取,按间隔定时轮换,可选随机或按文件名顺序)/ 网址(可按间隔定时刷新,配合随机图 API
|
|
40
|
+
| 外观 · 主题 | 界面皮肤 | 内置 11 套知名编辑器主题配色(Dracula / Nord / Tokyo Night / Catppuccin / Gruvbox / One Dark / Solarized / Rosé Pine / Everforest / Night Owl / Kanagawa),自动匹配 ZCode 的浅色 / 深色模式;另可自定义主题:浅色、深色各选 5 个颜色生成整套配色,改色实时生效 |
|
|
41
|
+
| 外观 · 背景图 | 背景图 | 整窗铺背景,四种来源:无背景 / 本地图库(可传多张、点选当前、可单删)/ 文件夹(原地读取,按间隔定时轮换,可选随机或按文件名顺序)/ 网址(可按间隔定时刷新,配合随机图 API);遮罩不透明度(图片向主题背景色淡化程度)、图片模糊、面板不透明度(侧栏、面板与标签栏的不透明程度)三个滑杆调节;侧栏 / 会话流 / 输入框透出背景,弹窗与菜单保持不透明保可读;图库随 WebDAV 同步的 zcode-pro 组一起上传(覆盖式,不留历史版本) |
|
|
42
42
|
| 性能 | 空闲项目内存回收 | 长时间未使用且无任务运行的项目自动释放其占用的内存,启动后也会自动回收一次未使用的项目;会话记录不受影响,再次打开时自动恢复(时长可调) |
|
|
43
43
|
| 代理 | 软件代理 | 为插件更新安装与本体升级设置 HTTP 代理,附连通性检测 |
|
|
44
44
|
| 同步 | 设置同步 | 手动把 ZCode Pro 设置与模型设置备份到 WebDAV,或在新电脑上恢复;仅在点击时传输 |
|
package/dist/inject.js
CHANGED
|
@@ -304,12 +304,12 @@
|
|
|
304
304
|
themeBgRegionRight: "\u53F3\u4FA7\u8FB9\u680F",
|
|
305
305
|
themeBgPane: "\u80CC\u666F\u56FE",
|
|
306
306
|
themeSkinTitle: "\u76AE\u80A4",
|
|
307
|
-
themeSkinDesc: "\u77E5\u540D\u7F16\u8F91\u5668\u4E3B\u9898\u914D\u8272\uFF0C\
|
|
307
|
+
themeSkinDesc: "\u77E5\u540D\u7F16\u8F91\u5668\u4E3B\u9898\u914D\u8272\uFF0C\u81EA\u52A8\u5339\u914D ZCode \u7684\u6D45\u8272 / \u6DF1\u8272\u6A21\u5F0F\uFF1B\u9ED8\u8BA4\u4FDD\u6301 ZCode \u539F\u6837\uFF0C\u81EA\u5B9A\u4E49\u5728\u4E0B\u65B9\u81EA\u884C\u8C03\u8272\u3002",
|
|
308
308
|
themeSkinCustom: "\u81EA\u5B9A\u4E49",
|
|
309
309
|
themeCustomTitle: "\u81EA\u5B9A\u4E49\u4E3B\u9898",
|
|
310
|
-
themeCustomHint: "\u6539\u989C\u8272\u5373\u5B9E\u65F6\u751F\u6548\uFF08\u81EA\u52A8\u5207\u5230\u81EA\u5B9A\u4E49\u76AE\u80A4\uFF09\uFF1B\
|
|
311
|
-
themeCustomLight: "\
|
|
312
|
-
themeCustomDark: "\
|
|
310
|
+
themeCustomHint: "\u6539\u989C\u8272\u5373\u5B9E\u65F6\u751F\u6548\uFF08\u81EA\u52A8\u5207\u5230\u81EA\u5B9A\u4E49\u76AE\u80A4\uFF09\uFF1B\u6D45\u8272\u3001\u6DF1\u8272\u5404\u914D\u4E00\u6B21\uFF0C\u9009\u597D 5 \u4E2A\u989C\u8272\u5373\u53EF\u751F\u6210\u6574\u5957\u754C\u9762\u914D\u8272\u3002",
|
|
311
|
+
themeCustomLight: "\u6D45\u8272",
|
|
312
|
+
themeCustomDark: "\u6DF1\u8272",
|
|
313
313
|
themeCustomBg: "\u80CC\u666F",
|
|
314
314
|
themeCustomCard: "\u5361\u7247",
|
|
315
315
|
themeCustomFg: "\u6B63\u6587",
|
|
@@ -341,7 +341,12 @@
|
|
|
341
341
|
themeBgFitContain: "\u9002\u5E94",
|
|
342
342
|
themeBgFitFill: "\u62C9\u4F38",
|
|
343
343
|
themeBgFitTile: "\u5E73\u94FA",
|
|
344
|
-
|
|
344
|
+
themeBgMask: "\u906E\u7F69\u4E0D\u900F\u660E\u5EA6",
|
|
345
|
+
themeBgMaskHint: "\u6570\u503C\u8D8A\u9AD8\uFF0C\u56FE\u7247\u8D8A\u5411\u4E3B\u9898\u80CC\u666F\u8272\u6DE1\u5316\uFF0C\u6587\u5B57\u5BF9\u6BD4\u8D8A\u6E05\u6670",
|
|
346
|
+
themeBgMaskHint2: "\u56FE\u7247\u5411\u4E3B\u9898\u80CC\u666F\u8272\u6DE1\u5316\u7684\u7A0B\u5EA6",
|
|
347
|
+
themeBgBlur: "\u56FE\u7247\u6A21\u7CCA",
|
|
348
|
+
themeBgPanel: "\u9762\u677F\u4E0D\u900F\u660E\u5EA6",
|
|
349
|
+
themeBgPanelHint: "\u4FA7\u680F\u3001\u9762\u677F\u4E0E\u6807\u7B7E\u680F\u7684\u4E0D\u900F\u660E\u7A0B\u5EA6\u3002\u8D8A\u4F4E\uFF0C\u900F\u51FA\u7684\u56FE\u7247\u8D8A\u591A\u3002",
|
|
345
350
|
themeBgDeletedActive: "\u5F53\u524D\u80CC\u666F\u5DF2\u5220\u9664\uFF0C\u5DF2\u81EA\u52A8\u505C\u7528\u80CC\u666F",
|
|
346
351
|
sbItemCtx: "\u4E0A\u4E0B\u6587\u5360\u7528",
|
|
347
352
|
sbItemQuestions: "\u63D0\u95EE\u6B21\u6570",
|
|
@@ -805,12 +810,12 @@
|
|
|
805
810
|
themeBgRegionRight: "Right sidebar",
|
|
806
811
|
themeBgPane: "Background",
|
|
807
812
|
themeSkinTitle: "Skins",
|
|
808
|
-
themeSkinDesc: 'Famous editor theme palettes
|
|
813
|
+
themeSkinDesc: 'Famous editor theme palettes, auto-matching ZCode\u2019s light / dark mode; "Default" keeps ZCode as-is, "Custom" is tuned below.',
|
|
809
814
|
themeSkinCustom: "Custom",
|
|
810
815
|
themeCustomTitle: "Custom theme",
|
|
811
|
-
themeCustomHint: "Color changes apply live (auto-switches to the custom skin); light and dark
|
|
812
|
-
themeCustomLight: "Light
|
|
813
|
-
themeCustomDark: "Dark
|
|
816
|
+
themeCustomHint: "Color changes apply live (auto-switches to the custom skin); set light and dark separately \u2014 pick 5 colors and the whole palette is derived.",
|
|
817
|
+
themeCustomLight: "Light",
|
|
818
|
+
themeCustomDark: "Dark",
|
|
814
819
|
themeCustomBg: "Background",
|
|
815
820
|
themeCustomCard: "Card",
|
|
816
821
|
themeCustomFg: "Text",
|
|
@@ -842,7 +847,12 @@
|
|
|
842
847
|
themeBgFitContain: "Fit",
|
|
843
848
|
themeBgFitFill: "Stretch",
|
|
844
849
|
themeBgFitTile: "Tile",
|
|
845
|
-
|
|
850
|
+
themeBgMask: "Mask opacity",
|
|
851
|
+
themeBgMaskHint: "Higher values fade the image toward the theme background color for clearer text",
|
|
852
|
+
themeBgMaskHint2: "How much the image fades toward the theme background color",
|
|
853
|
+
themeBgBlur: "Image blur",
|
|
854
|
+
themeBgPanel: "Panel opacity",
|
|
855
|
+
themeBgPanelHint: "Opacity of sidebar, panels and tab bar. Lower reveals more of the image.",
|
|
846
856
|
themeBgDeletedActive: "Active background was deleted; background disabled",
|
|
847
857
|
sbItemCtx: "Context usage",
|
|
848
858
|
sbItemQuestions: "Questions asked",
|
|
@@ -1258,8 +1268,8 @@
|
|
|
1258
1268
|
clearTimeout(toastTimer);
|
|
1259
1269
|
toastTimer = setTimeout(() => el.remove(), kind === "error" ? 5e3 : 2600);
|
|
1260
1270
|
}
|
|
1261
|
-
var overlayClass = "fixed inset-0 isolate z-50 flex items-
|
|
1262
|
-
var overlayClassBare = "fixed inset-0 isolate z-50 flex items-
|
|
1271
|
+
var overlayClass = "fixed inset-0 isolate z-50 flex items-start justify-center bg-black/60 supports-backdrop-filter:backdrop-blur-xs duration-100 p-4 platform-linux-desktop:top-12";
|
|
1272
|
+
var overlayClassBare = "fixed inset-0 isolate z-50 flex items-start justify-center duration-100 p-4 platform-linux-desktop:top-12";
|
|
1263
1273
|
var contentClass = "w-full sm:max-w-md rounded-2xl border-none bg-popover/98 p-5 text-ui-base/relaxed text-foreground ring-border shadow-2xl";
|
|
1264
1274
|
var dialogStack = [];
|
|
1265
1275
|
function openDialog({ title, description, onMount, onClose, width = "sm:max-w-md", overlay = "dim", draggable = false, posKey = "", dismissOnOutside = true, bodyClass = "", closable = false }) {
|
|
@@ -1287,7 +1297,8 @@
|
|
|
1287
1297
|
const content = h("div", {
|
|
1288
1298
|
role: "dialog",
|
|
1289
1299
|
"aria-modal": "true",
|
|
1290
|
-
class: contentClass.replace("sm:max-w-md", width) + " zcodepro-card"
|
|
1300
|
+
class: contentClass.replace("sm:max-w-md", width) + " zcodepro-card",
|
|
1301
|
+
style: "margin-top:12vh;max-height:calc(88vh - 3rem);overflow-y:auto;"
|
|
1291
1302
|
});
|
|
1292
1303
|
const overlayEl = h("div", {
|
|
1293
1304
|
"data-overlay": overlay,
|
|
@@ -1816,6 +1827,8 @@
|
|
|
1816
1827
|
-webkit-appearance: none;
|
|
1817
1828
|
appearance: none;
|
|
1818
1829
|
width: 100%;
|
|
1830
|
+
/* \u4E0D\u7ED9 padding\uFF1Apadding \u4F1A\u7F29\u5C0F thumb \u7684\u53EF\u6ED1\u533A\u95F4\uFF08\u62D6\u4E0D\u5230\u6700\u5DE6/\u6700\u53F3\uFF09\u3002
|
|
1831
|
+
\u8F68\u9053\u8D77\u70B9\u5BF9\u9F50\u7531\u5F39\u7A97\u91CC\u7684\u56FA\u5B9A\u6807\u7B7E\u5217\u5BBD\u8D1F\u8D23 */
|
|
1819
1832
|
height: 4px;
|
|
1820
1833
|
border-radius: 9999px;
|
|
1821
1834
|
background: color-mix(in oklab, var(--color-foreground, #888) 18%, transparent);
|
|
@@ -4131,7 +4144,7 @@
|
|
|
4131
4144
|
var bgStyleEl = null;
|
|
4132
4145
|
var injectedKeys = /* @__PURE__ */ new Set();
|
|
4133
4146
|
var classObserver = null;
|
|
4134
|
-
var currentTheme = { skin: "default", custom: null, bg: { mode: "none",
|
|
4147
|
+
var currentTheme = { skin: "default", custom: null, bg: { mode: "none", maskOpacity: 0.82, blurPx: 0, panelOpacity: 0.3 } };
|
|
4135
4148
|
var lastModeSig = "";
|
|
4136
4149
|
var bgTimer = null;
|
|
4137
4150
|
var regionStyleEl = null;
|
|
@@ -4240,12 +4253,15 @@
|
|
|
4240
4253
|
await applyRegionBackgrounds(bg);
|
|
4241
4254
|
return;
|
|
4242
4255
|
}
|
|
4243
|
-
const
|
|
4244
|
-
const
|
|
4256
|
+
const num01 = (v, dflt) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : dflt;
|
|
4257
|
+
const maskOpacity = num01(bg.maskOpacity, 0.82);
|
|
4258
|
+
const alpha = Math.min(0.99, maskOpacity);
|
|
4259
|
+
const blurPx = typeof bg.blurPx === "number" && Number.isFinite(bg.blurPx) ? Math.min(24, Math.max(0, Math.round(bg.blurPx))) : 0;
|
|
4260
|
+
const panelOpacity = num01(bg.panelOpacity, 0.3);
|
|
4245
4261
|
const resolvedBg = resolvedColor("--color-background");
|
|
4246
4262
|
const mHex = resolvedBg.match(/^rgba?\(([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
|
|
4247
4263
|
const rgb = mHex ? [Math.round(+mHex[1]), Math.round(+mHex[2]), Math.round(+mHex[3])].join(",") : isDarkMode() ? "13,13,13" : "248,248,248";
|
|
4248
|
-
const panelMix = Math.
|
|
4264
|
+
const panelMix = Math.round(panelOpacity * 100);
|
|
4249
4265
|
if (panelMix < 100) {
|
|
4250
4266
|
for (const t2 of SURFACE_TOKENS) {
|
|
4251
4267
|
const v = resolvedColor(t2);
|
|
@@ -4255,7 +4271,7 @@
|
|
|
4255
4271
|
}
|
|
4256
4272
|
}
|
|
4257
4273
|
}
|
|
4258
|
-
await applyRegionBackgrounds(bg, {
|
|
4274
|
+
await applyRegionBackgrounds(bg, { rgb, alpha, fit: bg.fit, seq });
|
|
4259
4275
|
if (seq !== applySeq) return;
|
|
4260
4276
|
if (!bgActive) return;
|
|
4261
4277
|
const FIT_CSS = {
|
|
@@ -4265,8 +4281,10 @@
|
|
|
4265
4281
|
tile: "background-size:100% 100%,auto !important;background-repeat:no-repeat,repeat !important;"
|
|
4266
4282
|
};
|
|
4267
4283
|
const fitCss = FIT_CSS[bg.fit] || FIT_CSS.cover;
|
|
4284
|
+
const blurCss = blurPx > 0 ? `filter:blur(${blurPx}px);` : "";
|
|
4285
|
+
const spread = blurPx > 0 ? Math.max(20, blurPx * 2) : 0;
|
|
4268
4286
|
const setImage = (image) => {
|
|
4269
|
-
bgStyleEl.textContent = `html.zcodepro-bg-on{background-color:rgb(${rgb}) !important;background-image:linear-gradient(rgba(${rgb},${alpha}),rgba(${rgb},${alpha})),${image} !important;${fitCss}background-position:center !important
|
|
4287
|
+
bgStyleEl.textContent = `html.zcodepro-bg-on{background-color:rgb(${rgb}) !important;}html.zcodepro-bg-on::before{content:'' !important;position:fixed;inset:-${spread}px;z-index:-1;pointer-events:none;background-image:linear-gradient(rgba(${rgb},${alpha}),rgba(${rgb},${alpha})),${image} !important;${fitCss}background-position:center !important;${blurCss}}`;
|
|
4270
4288
|
root.classList.add("zcodepro-bg-on");
|
|
4271
4289
|
};
|
|
4272
4290
|
const helperUrl = liveBoot().helperUrl || HELPER_URL;
|
|
@@ -4325,7 +4343,7 @@
|
|
|
4325
4343
|
const flush = () => {
|
|
4326
4344
|
regionStyleEl.textContent = [...rules.values()].join("");
|
|
4327
4345
|
};
|
|
4328
|
-
const alpha = pre ? pre.alpha : 0.
|
|
4346
|
+
const alpha = pre ? pre.alpha : 0.82;
|
|
4329
4347
|
const rgb = pre ? pre.rgb : "13,13,13";
|
|
4330
4348
|
const FIT_CSS = {
|
|
4331
4349
|
cover: "100% 100%,cover",
|
|
@@ -4379,7 +4397,7 @@
|
|
|
4379
4397
|
}
|
|
4380
4398
|
function startTheme() {
|
|
4381
4399
|
if (!document.head && !document.documentElement) return;
|
|
4382
|
-
applyAll({ skin: "default", custom: null, bg: { mode: "none",
|
|
4400
|
+
applyAll({ skin: "default", custom: null, bg: { mode: "none", maskOpacity: 0.82, blurPx: 0, panelOpacity: 0.3 } });
|
|
4383
4401
|
void getConfig().then((cfg) => applyAll(cfg.theme)).catch(() => {
|
|
4384
4402
|
});
|
|
4385
4403
|
window.addEventListener("zcodepro:config-changed", () => {
|
|
@@ -5333,21 +5351,18 @@
|
|
|
5333
5351
|
turnList
|
|
5334
5352
|
);
|
|
5335
5353
|
let themeCfg = structuredClone(config.theme || {});
|
|
5354
|
+
const numOrBg = (v, d) => typeof v === "number" && Number.isFinite(v) ? v : d;
|
|
5336
5355
|
themeCfg.skin = themeCfg.skin || "default";
|
|
5337
5356
|
themeCfg.custom = {
|
|
5338
5357
|
light: themeCfg.custom && themeCfg.custom.light || {},
|
|
5339
5358
|
dark: themeCfg.custom && themeCfg.custom.dark || {}
|
|
5340
5359
|
};
|
|
5341
5360
|
themeCfg.bg = {
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
intervalMin: 0,
|
|
5348
|
-
fit: "cover",
|
|
5349
|
-
visibility: 0.8,
|
|
5350
|
-
...themeCfg.bg || {}
|
|
5361
|
+
...themeCfg.bg || {},
|
|
5362
|
+
mode: themeCfg.bg?.mode || "none",
|
|
5363
|
+
maskOpacity: numOrBg(themeCfg.bg?.maskOpacity, 0.82),
|
|
5364
|
+
blurPx: numOrBg(themeCfg.bg?.blurPx, 0),
|
|
5365
|
+
panelOpacity: numOrBg(themeCfg.bg?.panelOpacity, 0.3)
|
|
5351
5366
|
};
|
|
5352
5367
|
themeCfg.bg.regions = themeCfg.bg.regions && typeof themeCfg.bg.regions === "object" ? themeCfg.bg.regions : {};
|
|
5353
5368
|
let bgFiles = [];
|
|
@@ -5590,27 +5605,73 @@
|
|
|
5590
5605
|
);
|
|
5591
5606
|
};
|
|
5592
5607
|
const renderThemeBg = () => {
|
|
5593
|
-
const
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
}
|
|
5613
|
-
|
|
5608
|
+
const sliderRow = (label, title, min, max, step, val, unit, commit, hint) => {
|
|
5609
|
+
const lab = h("span", { class: "shrink-0 whitespace-nowrap text-ui-xs font-medium text-foreground-subtle", title, style: "width:72px" }, label);
|
|
5610
|
+
const valLabel = h("span", { class: "w-12 text-right text-ui-xs tabular-nums text-foreground-subtle" }, val + unit);
|
|
5611
|
+
const range = h("input", {
|
|
5612
|
+
type: "range",
|
|
5613
|
+
min: String(min),
|
|
5614
|
+
max: String(max),
|
|
5615
|
+
step: String(step),
|
|
5616
|
+
value: String(val),
|
|
5617
|
+
class: "zcodepro-range",
|
|
5618
|
+
"aria-label": label,
|
|
5619
|
+
style: "flex:1"
|
|
5620
|
+
});
|
|
5621
|
+
let timer = null;
|
|
5622
|
+
range.addEventListener("input", () => {
|
|
5623
|
+
const v = Number(range.value);
|
|
5624
|
+
valLabel.textContent = v + unit;
|
|
5625
|
+
clearTimeout(timer);
|
|
5626
|
+
timer = setTimeout(() => commit(v), 300);
|
|
5627
|
+
});
|
|
5628
|
+
return h(
|
|
5629
|
+
"div",
|
|
5630
|
+
{ class: "flex flex-col gap-0.5" },
|
|
5631
|
+
h("div", { class: "flex items-center gap-3" }, lab, range, valLabel),
|
|
5632
|
+
hint ? h("span", { class: "text-ui-xs/relaxed text-foreground-subtle" }, hint) : null
|
|
5633
|
+
);
|
|
5634
|
+
};
|
|
5635
|
+
const numOr = (v, d) => typeof v === "number" && Number.isFinite(v) ? v : d;
|
|
5636
|
+
const maskRow = () => sliderRow(
|
|
5637
|
+
L.themeBgMask,
|
|
5638
|
+
L.themeBgMaskHint,
|
|
5639
|
+
0,
|
|
5640
|
+
99,
|
|
5641
|
+
1,
|
|
5642
|
+
Math.round(numOr(themeCfg.bg.maskOpacity, 0.82) * 100),
|
|
5643
|
+
"%",
|
|
5644
|
+
(v) => {
|
|
5645
|
+
void saveTheme({ bg: { maskOpacity: v / 100 } });
|
|
5646
|
+
},
|
|
5647
|
+
L.themeBgMaskHint2
|
|
5648
|
+
);
|
|
5649
|
+
const blurRow = () => sliderRow(
|
|
5650
|
+
L.themeBgBlur,
|
|
5651
|
+
"",
|
|
5652
|
+
0,
|
|
5653
|
+
24,
|
|
5654
|
+
1,
|
|
5655
|
+
numOr(themeCfg.bg.blurPx, 0),
|
|
5656
|
+
"px",
|
|
5657
|
+
(v) => {
|
|
5658
|
+
void saveTheme({ bg: { blurPx: v } });
|
|
5659
|
+
},
|
|
5660
|
+
""
|
|
5661
|
+
);
|
|
5662
|
+
const panelRow = () => sliderRow(
|
|
5663
|
+
L.themeBgPanel,
|
|
5664
|
+
"",
|
|
5665
|
+
0,
|
|
5666
|
+
100,
|
|
5667
|
+
1,
|
|
5668
|
+
Math.round(numOr(themeCfg.bg.panelOpacity, 0.3) * 100),
|
|
5669
|
+
"%",
|
|
5670
|
+
(v) => {
|
|
5671
|
+
void saveTheme({ bg: { panelOpacity: v / 100 } });
|
|
5672
|
+
},
|
|
5673
|
+
L.themeBgPanelHint
|
|
5674
|
+
);
|
|
5614
5675
|
const modeBtn = (id, label) => h("button", {
|
|
5615
5676
|
type: "button",
|
|
5616
5677
|
class: "zcodepro-tab",
|
|
@@ -5785,10 +5846,10 @@
|
|
|
5785
5846
|
),
|
|
5786
5847
|
h(
|
|
5787
5848
|
"div",
|
|
5788
|
-
{ class: "mt-3 flex
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5849
|
+
{ class: "mt-3 flex flex-col gap-2" },
|
|
5850
|
+
maskRow(),
|
|
5851
|
+
blurRow(),
|
|
5852
|
+
panelRow()
|
|
5792
5853
|
),
|
|
5793
5854
|
bgInput
|
|
5794
5855
|
);
|
package/package.json
CHANGED
package/src/host/helper.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { reorderWorkspaceTasks, reorderGroupMembers } from './taskOrder.mjs';
|
|
|
17
17
|
import { webdavRequest, webdavPutWithMkcol, webdavHttpText, parseWebdavListing, findCurl } from './webdav.mjs';
|
|
18
18
|
import { resolveZcodeExecutable } from './paths.mjs';
|
|
19
19
|
|
|
20
|
-
const VERSION = '1.4.
|
|
20
|
+
const VERSION = '1.4.1';
|
|
21
21
|
|
|
22
22
|
// 全局提示词固定在用户主目录:官方加载器按 HOME/USERPROFILE 拼 .zcode/AGENTS.md,
|
|
23
23
|
// 不读 ZCODE_DATA_BASE_DIR(数据根迁走时全局指令仍在原位)。
|
|
@@ -68,8 +68,10 @@ function listBgFiles(dataRoot) {
|
|
|
68
68
|
// 主题配置(设置 → 外观 → 主题/背景图):skin 为皮肤 id(default = 不覆盖,
|
|
69
69
|
// custom = 用 custom 锚点色现算色阶);bg.mode 选背景来源——none 无背景 /
|
|
70
70
|
// library 本地图库(file 为当前文件)/ folder 文件夹(定时切换,folderRandom
|
|
71
|
-
// 随机或顺序)/ url 网址(intervalMin 针对随机图 API 定时刷新);
|
|
72
|
-
//
|
|
71
|
+
// 随机或顺序)/ url 网址(intervalMin 针对随机图 API 定时刷新);
|
|
72
|
+
// maskOpacity 遮罩不透明度 0-0.99(越高图片越向主题背景色淡化,文字对比越
|
|
73
|
+
// 清晰,默认 0.82)、blurPx 图片模糊 0-24px(默认 0)、panelOpacity 面板
|
|
74
|
+
// 不透明度 0-1(侧栏/面板/标签栏,越低透出图片越多,默认 0.3)
|
|
73
75
|
const THEME_SKINS = new Set(['default', 'dracula', 'nord', 'tokyonight', 'catppuccin', 'gruvbox', 'onedark', 'solarized', 'rosepine', 'everforest', 'nightowl', 'kanagawa', 'custom']);
|
|
74
76
|
const BG_MODES = new Set(['none', 'library', 'folder', 'url']);
|
|
75
77
|
const BG_FITS = new Set(['cover', 'contain', 'fill', 'tile']);
|
|
@@ -103,7 +105,6 @@ function mergeBgRegion(src) {
|
|
|
103
105
|
export function mergeThemeConfig(saved) {
|
|
104
106
|
const t = saved && typeof saved === 'object' ? saved : {};
|
|
105
107
|
const bg = t.bg && typeof t.bg === 'object' ? t.bg : {};
|
|
106
|
-
const vis = Number(bg.visibility);
|
|
107
108
|
const cfg = {
|
|
108
109
|
skin: THEME_SKINS.has(t.skin) ? t.skin : 'default',
|
|
109
110
|
custom: mergeCustomSkin(t.custom),
|
|
@@ -115,7 +116,11 @@ export function mergeThemeConfig(saved) {
|
|
|
115
116
|
url: (str(bg.url, 2000) || '').trim(),
|
|
116
117
|
intervalMin: Number.isFinite(Number(bg.intervalMin)) ? Math.min(1440, Math.max(0, Math.round(Number(bg.intervalMin)))) : 0,
|
|
117
118
|
fit: BG_FITS.has(bg.fit) ? bg.fit : 'cover',
|
|
118
|
-
|
|
119
|
+
// null/undefined/非数值都落默认(Number(null)=0 是有限数,须先排除 null)
|
|
120
|
+
maskOpacity: bg.maskOpacity != null && Number.isFinite(Number(bg.maskOpacity))
|
|
121
|
+
? Math.min(0.99, Math.max(0, Number(bg.maskOpacity))) : 0.82,
|
|
122
|
+
blurPx: bg.blurPx != null && Number.isFinite(Number(bg.blurPx)) ? Math.min(24, Math.max(0, Math.round(Number(bg.blurPx)))) : 0,
|
|
123
|
+
panelOpacity: bg.panelOpacity != null && Number.isFinite(Number(bg.panelOpacity)) ? Math.min(1, Math.max(0, Number(bg.panelOpacity))) : 0.3,
|
|
119
124
|
regions: {
|
|
120
125
|
left: mergeBgRegion(bg.regions && bg.regions.left),
|
|
121
126
|
center: mergeBgRegion(bg.regions && bg.regions.center),
|
|
@@ -515,7 +520,9 @@ export function startHelper({ port, token, dataRoot, state, agentsFile = default
|
|
|
515
520
|
url: bt.bg && bt.bg.url !== undefined ? bt.bg.url : cur.bg.url,
|
|
516
521
|
intervalMin: bt.bg && bt.bg.intervalMin !== undefined ? bt.bg.intervalMin : cur.bg.intervalMin,
|
|
517
522
|
fit: bt.bg && bt.bg.fit !== undefined ? bt.bg.fit : cur.bg.fit,
|
|
518
|
-
|
|
523
|
+
maskOpacity: bt.bg && bt.bg.maskOpacity !== undefined ? bt.bg.maskOpacity : cur.bg.maskOpacity,
|
|
524
|
+
blurPx: bt.bg && bt.bg.blurPx !== undefined ? bt.bg.blurPx : cur.bg.blurPx,
|
|
525
|
+
panelOpacity: bt.bg && bt.bg.panelOpacity !== undefined ? bt.bg.panelOpacity : cur.bg.panelOpacity,
|
|
519
526
|
regions: bt.bg && bt.bg.regions !== undefined ? bt.bg.regions : cur.bg.regions,
|
|
520
527
|
},
|
|
521
528
|
};
|
package/src/inject/core.js
CHANGED
|
@@ -317,12 +317,12 @@ const zh = {
|
|
|
317
317
|
themeBgRegionRight: '右侧边栏',
|
|
318
318
|
themeBgPane: '背景图',
|
|
319
319
|
themeSkinTitle: '皮肤',
|
|
320
|
-
themeSkinDesc: '
|
|
320
|
+
themeSkinDesc: '知名编辑器主题配色,自动匹配 ZCode 的浅色 / 深色模式;默认保持 ZCode 原样,自定义在下方自行调色。',
|
|
321
321
|
themeSkinCustom: '自定义',
|
|
322
322
|
themeCustomTitle: '自定义主题',
|
|
323
|
-
themeCustomHint: '
|
|
324
|
-
themeCustomLight: '
|
|
325
|
-
themeCustomDark: '
|
|
323
|
+
themeCustomHint: '改颜色即实时生效(自动切到自定义皮肤);浅色、深色各配一次,选好 5 个颜色即可生成整套界面配色。',
|
|
324
|
+
themeCustomLight: '浅色',
|
|
325
|
+
themeCustomDark: '深色',
|
|
326
326
|
themeCustomBg: '背景',
|
|
327
327
|
themeCustomCard: '卡片',
|
|
328
328
|
themeCustomFg: '正文',
|
|
@@ -354,7 +354,12 @@ const zh = {
|
|
|
354
354
|
themeBgFitContain: '适应',
|
|
355
355
|
themeBgFitFill: '拉伸',
|
|
356
356
|
themeBgFitTile: '平铺',
|
|
357
|
-
|
|
357
|
+
themeBgMask: '遮罩不透明度',
|
|
358
|
+
themeBgMaskHint: '数值越高,图片越向主题背景色淡化,文字对比越清晰',
|
|
359
|
+
themeBgMaskHint2: '图片向主题背景色淡化的程度',
|
|
360
|
+
themeBgBlur: '图片模糊',
|
|
361
|
+
themeBgPanel: '面板不透明度',
|
|
362
|
+
themeBgPanelHint: '侧栏、面板与标签栏的不透明程度。越低,透出的图片越多。',
|
|
358
363
|
themeBgDeletedActive: '当前背景已删除,已自动停用背景',
|
|
359
364
|
sbItemCtx: '上下文占用',
|
|
360
365
|
sbItemQuestions: '提问次数',
|
|
@@ -819,12 +824,12 @@ const en = {
|
|
|
819
824
|
themeBgRegionRight: 'Right sidebar',
|
|
820
825
|
themeBgPane: 'Background',
|
|
821
826
|
themeSkinTitle: 'Skins',
|
|
822
|
-
themeSkinDesc: 'Famous editor theme palettes
|
|
827
|
+
themeSkinDesc: 'Famous editor theme palettes, auto-matching ZCode\u2019s light / dark mode; "Default" keeps ZCode as-is, "Custom" is tuned below.',
|
|
823
828
|
themeSkinCustom: 'Custom',
|
|
824
829
|
themeCustomTitle: 'Custom theme',
|
|
825
|
-
themeCustomHint: 'Color changes apply live (auto-switches to the custom skin); light and dark
|
|
826
|
-
themeCustomLight: 'Light
|
|
827
|
-
themeCustomDark: 'Dark
|
|
830
|
+
themeCustomHint: 'Color changes apply live (auto-switches to the custom skin); set light and dark separately — pick 5 colors and the whole palette is derived.',
|
|
831
|
+
themeCustomLight: 'Light',
|
|
832
|
+
themeCustomDark: 'Dark',
|
|
828
833
|
themeCustomBg: 'Background',
|
|
829
834
|
themeCustomCard: 'Card',
|
|
830
835
|
themeCustomFg: 'Text',
|
|
@@ -856,7 +861,12 @@ const en = {
|
|
|
856
861
|
themeBgFitContain: 'Fit',
|
|
857
862
|
themeBgFitFill: 'Stretch',
|
|
858
863
|
themeBgFitTile: 'Tile',
|
|
859
|
-
|
|
864
|
+
themeBgMask: 'Mask opacity',
|
|
865
|
+
themeBgMaskHint: 'Higher values fade the image toward the theme background color for clearer text',
|
|
866
|
+
themeBgMaskHint2: 'How much the image fades toward the theme background color',
|
|
867
|
+
themeBgBlur: 'Image blur',
|
|
868
|
+
themeBgPanel: 'Panel opacity',
|
|
869
|
+
themeBgPanelHint: 'Opacity of sidebar, panels and tab bar. Lower reveals more of the image.',
|
|
860
870
|
themeBgDeletedActive: 'Active background was deleted; background disabled',
|
|
861
871
|
sbItemCtx: 'Context usage',
|
|
862
872
|
sbItemQuestions: 'Questions asked',
|
|
@@ -869,15 +869,20 @@ export function openSettingsDialog() {
|
|
|
869
869
|
// —— “颜色”子页(paneStylesSub3):预设皮肤卡片 + 自定义主题编辑 ——
|
|
870
870
|
// —— “背景图”子页(paneStylesSub4):无背景 / 图库 / 文件夹轮换 / 网址 ——
|
|
871
871
|
let themeCfg = structuredClone(config.theme || {});
|
|
872
|
+
const numOrBg = (v, d) => (typeof v === 'number' && Number.isFinite(v) ? v : d);
|
|
872
873
|
themeCfg.skin = themeCfg.skin || 'default';
|
|
873
874
|
themeCfg.custom = {
|
|
874
875
|
light: (themeCfg.custom && themeCfg.custom.light) || {},
|
|
875
876
|
dark: (themeCfg.custom && themeCfg.custom.dark) || {},
|
|
876
877
|
};
|
|
877
878
|
themeCfg.bg = {
|
|
878
|
-
mode: 'none', file: '', folder: '', folderRandom: true, url: '', intervalMin: 0, fit: 'cover', visibility: 0.8,
|
|
879
879
|
...(themeCfg.bg || {}),
|
|
880
|
+
mode: themeCfg.bg?.mode || 'none',
|
|
881
|
+
maskOpacity: numOrBg(themeCfg.bg?.maskOpacity, 0.82),
|
|
882
|
+
blurPx: numOrBg(themeCfg.bg?.blurPx, 0),
|
|
883
|
+
panelOpacity: numOrBg(themeCfg.bg?.panelOpacity, 0.3),
|
|
880
884
|
};
|
|
885
|
+
// file/folder/url/fit/folderRandom/intervalMin/regions 由 helper 清洗保证形态,原样保留
|
|
881
886
|
themeCfg.bg.regions = (themeCfg.bg.regions && typeof themeCfg.bg.regions === 'object') ? themeCfg.bg.regions : {};
|
|
882
887
|
let bgFiles = [];
|
|
883
888
|
let bgLoading = false;
|
|
@@ -1061,19 +1066,35 @@ export function openSettingsDialog() {
|
|
|
1061
1066
|
valueCtrl || h('span', { class: 'text-ui-xs text-foreground-subtle' }, ''));
|
|
1062
1067
|
};
|
|
1063
1068
|
const renderThemeBg = () => {
|
|
1064
|
-
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1069
|
+
// 三个调节参数(滑杆行构造器:label + 范围 + 单位 + 提示 + 防抖保存)
|
|
1070
|
+
const sliderRow = (label, title, min, max, step, val, unit, commit, hint) => {
|
|
1071
|
+
// 标签列固定宽(容最长标签六字;内联样式——应用的 Tailwind 按需编译
|
|
1072
|
+
// 不包含 w-[72px] 这类任意值类):多行滑杆的轨道起点对齐同一竖线
|
|
1073
|
+
const lab = h('span', { class: 'shrink-0 whitespace-nowrap text-ui-xs font-medium text-foreground-subtle', title, style: 'width:72px' }, label);
|
|
1074
|
+
const valLabel = h('span', { class: 'w-12 text-right text-ui-xs tabular-nums text-foreground-subtle' }, val + unit);
|
|
1075
|
+
const range = h('input', {
|
|
1076
|
+
type: 'range', min: String(min), max: String(max), step: String(step), value: String(val),
|
|
1077
|
+
class: 'zcodepro-range', 'aria-label': label, style: 'flex:1',
|
|
1078
|
+
});
|
|
1079
|
+
let timer = null;
|
|
1080
|
+
range.addEventListener('input', () => {
|
|
1081
|
+
const v = Number(range.value);
|
|
1082
|
+
valLabel.textContent = v + unit;
|
|
1083
|
+
clearTimeout(timer);
|
|
1084
|
+
timer = setTimeout(() => commit(v), 300);
|
|
1085
|
+
});
|
|
1086
|
+
return h('div', { class: 'flex flex-col gap-0.5' },
|
|
1087
|
+
h('div', { class: 'flex items-center gap-3' }, lab, range, valLabel),
|
|
1088
|
+
hint ? h('span', { class: 'text-ui-xs/relaxed text-foreground-subtle' }, hint) : null);
|
|
1089
|
+
};
|
|
1090
|
+
// 数值兜底:null(旧配置带入)与 undefined 都要落默认,?? 只兜 undefined
|
|
1091
|
+
const numOr = (v, d) => (typeof v === 'number' && Number.isFinite(v) ? v : d);
|
|
1092
|
+
const maskRow = () => sliderRow(L.themeBgMask, L.themeBgMaskHint, 0, 99, 1, Math.round(numOr(themeCfg.bg.maskOpacity, 0.82) * 100), '%',
|
|
1093
|
+
(v) => { void saveTheme({ bg: { maskOpacity: v / 100 } }); }, L.themeBgMaskHint2);
|
|
1094
|
+
const blurRow = () => sliderRow(L.themeBgBlur, '', 0, 24, 1, numOr(themeCfg.bg.blurPx, 0), 'px',
|
|
1095
|
+
(v) => { void saveTheme({ bg: { blurPx: v } }); }, '');
|
|
1096
|
+
const panelRow = () => sliderRow(L.themeBgPanel, '', 0, 100, 1, Math.round(numOr(themeCfg.bg.panelOpacity, 0.3) * 100), '%',
|
|
1097
|
+
(v) => { void saveTheme({ bg: { panelOpacity: v / 100 } }); }, L.themeBgPanelHint);
|
|
1077
1098
|
const modeBtn = (id, label) => h('button', {
|
|
1078
1099
|
type: 'button', class: 'zcodepro-tab',
|
|
1079
1100
|
'data-state': themeCfg.bg.mode === id ? 'active' : 'inactive',
|
|
@@ -1184,9 +1205,8 @@ export function openSettingsDialog() {
|
|
|
1184
1205
|
h('span', { class: 'text-ui-xs font-medium text-foreground-subtle' }, L.themeBgFit),
|
|
1185
1206
|
fitBtn('cover', L.themeBgFitCover), fitBtn('contain', L.themeBgFitContain),
|
|
1186
1207
|
fitBtn('fill', L.themeBgFitFill), fitBtn('tile', L.themeBgFitTile)),
|
|
1187
|
-
h('div', { class: 'mt-3 flex
|
|
1188
|
-
|
|
1189
|
-
visRange, visLabel),
|
|
1208
|
+
h('div', { class: 'mt-3 flex flex-col gap-2' },
|
|
1209
|
+
maskRow(), blurRow(), panelRow()),
|
|
1190
1210
|
bgInput,
|
|
1191
1211
|
);
|
|
1192
1212
|
};
|
|
@@ -194,7 +194,7 @@ let skinStyleEl = null; // 皮肤 token 覆盖
|
|
|
194
194
|
let bgStyleEl = null; // html 背景层(图 + 遮罩)
|
|
195
195
|
let injectedKeys = new Set(); // 半透明化写进 root.style 的变量(重算前先撤)
|
|
196
196
|
let classObserver = null; // 明暗切换(root class 变化)→ 重算遮罩色与透明度
|
|
197
|
-
let currentTheme = { skin: 'default', custom: null, bg: { mode: 'none',
|
|
197
|
+
let currentTheme = { skin: 'default', custom: null, bg: { mode: 'none', maskOpacity: 0.82, blurPx: 0, panelOpacity: 0.3 } };
|
|
198
198
|
let lastModeSig = ''; // 观察器只对明暗模式变化重算:applySkin/applyBackground
|
|
199
199
|
// 自己也会改 root class(zcodepro-skin-*/zcodepro-bg-on),不带这条过滤会自触发循环
|
|
200
200
|
let bgTimer = null; // 文件夹轮换 / 网址刷新定时器(重应用前先清)
|
|
@@ -321,18 +321,23 @@ async function applyBackground(bg) {
|
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
// 三参数(对齐 codeg 语义):maskOpacity 遮罩不透明度(直接作为遮罩 α);
|
|
325
|
+
// blurPx 图片模糊(CSS filter,只糊图片层不糊遮罩);panelOpacity 面板
|
|
326
|
+
// 不透明度(侧栏/面板/标签栏表面混入底色的比例,独立于遮罩)
|
|
327
|
+
const num01 = (v, dflt) => (typeof v === 'number' && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : dflt);
|
|
328
|
+
const maskOpacity = num01(bg.maskOpacity, 0.82);
|
|
329
|
+
const alpha = Math.min(0.99, maskOpacity);
|
|
330
|
+
const blurPx = typeof bg.blurPx === 'number' && Number.isFinite(bg.blurPx)
|
|
331
|
+
? Math.min(24, Math.max(0, Math.round(bg.blurPx))) : 0;
|
|
332
|
+
const panelOpacity = num01(bg.panelOpacity, 0.3);
|
|
327
333
|
// 遮罩色跟随当前明暗的皮肤底色:在皮肤已应用、半透明化未写入时读解析色
|
|
328
334
|
const resolvedBg = resolvedColor('--color-background');
|
|
329
335
|
const mHex = resolvedBg.match(/^rgba?\(([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
|
|
330
336
|
const rgb = mHex
|
|
331
337
|
? [Math.round(+mHex[1]), Math.round(+mHex[2]), Math.round(+mHex[3])].join(',')
|
|
332
338
|
: (isDarkMode() ? '13,13,13' : '248,248,248');
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
const panelMix = Math.min(100, Math.round(alpha * 100) + 10);
|
|
339
|
+
// 表面半透明化:面板不透明度直接用 panelOpacity(0=全透图,1=纯色)
|
|
340
|
+
const panelMix = Math.round(panelOpacity * 100);
|
|
336
341
|
if (panelMix < 100) {
|
|
337
342
|
for (const t of SURFACE_TOKENS) {
|
|
338
343
|
const v = resolvedColor(t);
|
|
@@ -342,7 +347,7 @@ async function applyBackground(bg) {
|
|
|
342
347
|
}
|
|
343
348
|
}
|
|
344
349
|
}
|
|
345
|
-
await applyRegionBackgrounds(bg, {
|
|
350
|
+
await applyRegionBackgrounds(bg, { rgb, alpha, fit: bg.fit, seq });
|
|
346
351
|
if (seq !== applySeq) return; // 分区文件夹列表等待期间配置又变了
|
|
347
352
|
if (!bgActive) return; // 只有分区背景:到此为止,html 层不设图
|
|
348
353
|
|
|
@@ -357,10 +362,17 @@ async function applyBackground(bg) {
|
|
|
357
362
|
tile: 'background-size:100% 100%,auto !important;background-repeat:no-repeat,repeat !important;',
|
|
358
363
|
};
|
|
359
364
|
const fitCss = FIT_CSS[bg.fit] || FIT_CSS.cover;
|
|
365
|
+
// 模糊只作用于背景层:图与遮罩画在 html::before(fixed 铺满视口、z 轴最底),
|
|
366
|
+
// filter 写在伪元素上——写在 html 自身会把整个界面子树一起糊掉。
|
|
367
|
+
// 模糊会把伪元素边缘拉开出现透明缝,按模糊半径外扩 inset 收边
|
|
368
|
+
const blurCss = blurPx > 0 ? `filter:blur(${blurPx}px);` : '';
|
|
369
|
+
const spread = blurPx > 0 ? Math.max(20, blurPx * 2) : 0;
|
|
360
370
|
const setImage = (image) => {
|
|
361
371
|
bgStyleEl.textContent =
|
|
362
|
-
`html.zcodepro-bg-on{background-color:rgb(${rgb}) !important;
|
|
363
|
-
|
|
372
|
+
`html.zcodepro-bg-on{background-color:rgb(${rgb}) !important;}` +
|
|
373
|
+
`html.zcodepro-bg-on::before{content:'' !important;position:fixed;inset:-${spread}px;z-index:-1;pointer-events:none;` +
|
|
374
|
+
`background-image:linear-gradient(rgba(${rgb},${alpha}),rgba(${rgb},${alpha})),${image} !important;` +
|
|
375
|
+
`${fitCss}background-position:center !important;${blurCss}}`;
|
|
364
376
|
root.classList.add('zcodepro-bg-on');
|
|
365
377
|
};
|
|
366
378
|
const helperUrl = liveBoot().helperUrl || HELPER_URL;
|
|
@@ -413,8 +425,8 @@ async function applyRegionBackgrounds(bg, pre) {
|
|
|
413
425
|
regionTimers = [];
|
|
414
426
|
const rules = new Map(); // region -> 规则文本(轮换时覆盖同分区旧规则,不无限追加)
|
|
415
427
|
const flush = () => { regionStyleEl.textContent = [...rules.values()].join(''); };
|
|
416
|
-
// pre.alpha =
|
|
417
|
-
const alpha = pre ? pre.alpha : 0.
|
|
428
|
+
// pre.alpha = 遮罩不透明度(直接配置值),与全局同值
|
|
429
|
+
const alpha = pre ? pre.alpha : 0.82;
|
|
418
430
|
const rgb = pre ? pre.rgb : '13,13,13';
|
|
419
431
|
const FIT_CSS = {
|
|
420
432
|
cover: '100% 100%,cover', contain: '100% 100%,contain', fill: '100% 100%,100% 100%', tile: '100% 100%,auto',
|
|
@@ -468,7 +480,7 @@ function applyAll(theme) {
|
|
|
468
480
|
|
|
469
481
|
export function startTheme() {
|
|
470
482
|
if (!document.head && !document.documentElement) return;
|
|
471
|
-
applyAll({ skin: 'default', custom: null, bg: { mode: 'none',
|
|
483
|
+
applyAll({ skin: 'default', custom: null, bg: { mode: 'none', maskOpacity: 0.82, blurPx: 0, panelOpacity: 0.3 } });
|
|
472
484
|
void getConfig().then((cfg) => applyAll(cfg.theme)).catch(() => { /* 读不到配置保持应用默认 */ });
|
|
473
485
|
window.addEventListener('zcodepro:config-changed', () => {
|
|
474
486
|
void getConfig(true).then((cfg) => applyAll(cfg.theme)).catch(() => { /* ignore */ });
|
package/src/inject/ui.js
CHANGED
|
@@ -26,8 +26,10 @@ export function showToast(text, kind = 'info') {
|
|
|
26
26
|
// 注意:绝不能用 bg-surface 做面板底色——该 token 在应用里是 ~3% 不透明度的着色层(#0d0d0d08),
|
|
27
27
|
// 会导致整卡透明。关键视觉另在 ensureStyle 里以自有样式表兜底(ID 选择器 + 主题变量 + 字面量回退),
|
|
28
28
|
// 应用 Tailwind 类随版本更新变动时遮罩/面板仍能正确绘制。
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// 垂直方向 items-start + 卡片 margin-top:切 tab 内容高度变化时卡片顶边不动
|
|
30
|
+
// (此前 items-center 上下双向伸缩,顶部随内容高度跳动,顶部 tab 没法稳着点)
|
|
31
|
+
const overlayClass = 'fixed inset-0 isolate z-50 flex items-start justify-center bg-black/60 supports-backdrop-filter:backdrop-blur-xs duration-100 p-4 platform-linux-desktop:top-12';
|
|
32
|
+
const overlayClassBare = 'fixed inset-0 isolate z-50 flex items-start justify-center duration-100 p-4 platform-linux-desktop:top-12';
|
|
31
33
|
const contentClass = 'w-full sm:max-w-md rounded-2xl border-none bg-popover/98 p-5 text-ui-base/relaxed text-foreground ring-border shadow-2xl';
|
|
32
34
|
|
|
33
35
|
// overlay: 'dim'(默认,半透明遮罩)| 'none'(透明遮罩)——设置弹窗用 'none',方便边调样式边看会话。
|
|
@@ -59,6 +61,7 @@ export function openDialog({ title, description, onMount, onClose, width = 'sm:m
|
|
|
59
61
|
role: 'dialog',
|
|
60
62
|
'aria-modal': 'true',
|
|
61
63
|
class: contentClass.replace('sm:max-w-md', width) + ' zcodepro-card',
|
|
64
|
+
style: 'margin-top:12vh;max-height:calc(88vh - 3rem);overflow-y:auto;',
|
|
62
65
|
});
|
|
63
66
|
const overlayEl = h('div', {
|
|
64
67
|
'data-overlay': overlay,
|
|
@@ -566,6 +569,8 @@ export function ensureStyle() {
|
|
|
566
569
|
-webkit-appearance: none;
|
|
567
570
|
appearance: none;
|
|
568
571
|
width: 100%;
|
|
572
|
+
/* 不给 padding:padding 会缩小 thumb 的可滑区间(拖不到最左/最右)。
|
|
573
|
+
轨道起点对齐由弹窗里的固定标签列宽负责 */
|
|
569
574
|
height: 4px;
|
|
570
575
|
border-radius: 9999px;
|
|
571
576
|
background: color-mix(in oklab, var(--color-foreground, #888) 18%, transparent);
|