dsh-chef 0.3.39 → 0.3.42
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/dist/client.js +509 -164
- package/dist/client.js.map +1 -1
- package/package.json +2 -2
package/dist/client.js
CHANGED
|
@@ -49,8 +49,19 @@ window.__ModuleLoader__.load({
|
|
|
49
49
|
3e3,
|
|
50
50
|
8e3
|
|
51
51
|
];
|
|
52
|
-
/**
|
|
53
|
-
|
|
52
|
+
/** T1 交互 tokens(#1160,唯一定义地,真相源 #1159 参数表)。
|
|
53
|
+
*
|
|
54
|
+
* 按压 .97、焦点隔离 2px+主题色 5px、过渡 .15s——取值逐字照原型 V1
|
|
55
|
+
*(`.scratch/1155-real-panel-prototype.html`:`btn:active{transform:scale(.97)}`、
|
|
56
|
+
* `btn:focus-visible{box-shadow:0 0 0 2px #0b0b0d,0 0 0 5px var(--focus)}`、
|
|
57
|
+
* 主题橙 #f6ad55/蓝 #0a84ff/绿 #30d158、过渡 background/transform/box-shadow/border-color 各 .15s)。
|
|
58
|
+
*
|
|
59
|
+
* 颜色全走主题变量、永不写死蓝:隔离环取卡面底(深浅自适应),焦点环取
|
|
60
|
+
* `--ilife-focus`(缺席时退到宿主品牌色,宿主品牌色本身跟主题走)。
|
|
61
|
+
* 悬停/长按/折叠/复制变勾/提示/液态归后票,本件只定按压与焦点四格。 */
|
|
62
|
+
const PRESS_SCALE = .97;
|
|
63
|
+
const INTERACTION_TRANSITION = "background .15s ease,transform .15s ease,box-shadow .15s ease,border-color .15s ease";
|
|
64
|
+
const DISABLED_OPACITY = .4;
|
|
54
65
|
/** 宿主给「这是哪一种目录选择能力」时用的那两格原语的名字(软依赖:按名字现取,缺席即没有入口)。 */
|
|
55
66
|
const REMOTE_DIRECTORY_PICKER = "remote.directoryPicker";
|
|
56
67
|
/** 宿主在「这条路不给」时回的那个码(`directory-browser-state` 的 `openRowBrowser` 只照比不认名)。 */
|
|
@@ -630,6 +641,11 @@ window.__ModuleLoader__.load({
|
|
|
630
641
|
if (state.listing === null) return [];
|
|
631
642
|
return filterEntries(visibleEntries(state.listing, state.showHidden), state.filter);
|
|
632
643
|
}
|
|
644
|
+
/** 图上这一层能不能回上一级(根目录不能)。 */
|
|
645
|
+
function canGoUp(state) {
|
|
646
|
+
if (state.listing === null) return false;
|
|
647
|
+
return parentOf(state.listing.path) !== state.listing.path;
|
|
648
|
+
}
|
|
633
649
|
/** 「打开」这颗按钮的目标:选中行优先,没选中就是当前层。 */
|
|
634
650
|
function targetOf(state) {
|
|
635
651
|
return state.selected ?? state.listing?.path ?? null;
|
|
@@ -890,6 +906,8 @@ window.__ModuleLoader__.load({
|
|
|
890
906
|
fontWeight: isCurrent ? 700 : 400
|
|
891
907
|
},
|
|
892
908
|
title: crumb.path,
|
|
909
|
+
"data-ilife-press": "dialog-crumb",
|
|
910
|
+
"data-ilife-longpress": "dialog-crumb",
|
|
893
911
|
onClick: () => onEnter(crumb.path)
|
|
894
912
|
}, crumb.name));
|
|
895
913
|
});
|
|
@@ -907,6 +925,8 @@ window.__ModuleLoader__.load({
|
|
|
907
925
|
...S$3.rootButton
|
|
908
926
|
},
|
|
909
927
|
title: ROOT_KIND_TEXT[root.kind] ?? ROOT_KIND_TEXT.other,
|
|
928
|
+
"data-ilife-press": "dialog-root",
|
|
929
|
+
"data-ilife-longpress": "dialog-root",
|
|
910
930
|
onClick: () => onEnter(root.path)
|
|
911
931
|
}, root.path));
|
|
912
932
|
return react.createElement("div", { style: S$3.roots }, parts);
|
|
@@ -927,6 +947,8 @@ window.__ModuleLoader__.load({
|
|
|
927
947
|
flex: 1,
|
|
928
948
|
border: "none"
|
|
929
949
|
},
|
|
950
|
+
"data-ilife-press": "dialog-entry",
|
|
951
|
+
"data-ilife-longpress": "dialog-entry",
|
|
930
952
|
onClick: () => onEnter(entry.path)
|
|
931
953
|
}, "📁 " + entry.name), react.createElement("button", {
|
|
932
954
|
type: "button",
|
|
@@ -937,12 +959,15 @@ window.__ModuleLoader__.load({
|
|
|
937
959
|
},
|
|
938
960
|
"aria-pressed": selected,
|
|
939
961
|
title: selected ? labels.selected : labels.select,
|
|
962
|
+
"data-ilife-press": "dialog-select",
|
|
963
|
+
"data-ilife-longpress": "dialog-select",
|
|
940
964
|
onClick: () => onToggleSelect(entry.path)
|
|
941
965
|
}, selected ? "✓" : labels.select));
|
|
942
966
|
}
|
|
943
967
|
/** 「新建文件夹」那一行(`creatingName === null` 时收起)。 */
|
|
944
968
|
function createRow(labels, onName, onCancel, onCreate, creatingName) {
|
|
945
969
|
if (creatingName === null) return null;
|
|
970
|
+
const createEmpty = creatingName.trim() === "";
|
|
946
971
|
return react.createElement("div", { style: {
|
|
947
972
|
...S$3.pathRow,
|
|
948
973
|
borderTop: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.25))"
|
|
@@ -951,6 +976,7 @@ window.__ModuleLoader__.load({
|
|
|
951
976
|
value: creatingName,
|
|
952
977
|
placeholder: labels.newFolder,
|
|
953
978
|
"aria-label": labels.newFolder,
|
|
979
|
+
"data-ilife-focus": "dialog-input",
|
|
954
980
|
onChange: (event) => onName(event.currentTarget.value),
|
|
955
981
|
onKeyDown: (event) => {
|
|
956
982
|
if (event.key === "Enter") onCreate(creatingName);
|
|
@@ -959,10 +985,15 @@ window.__ModuleLoader__.load({
|
|
|
959
985
|
}), react.createElement("button", {
|
|
960
986
|
type: "button",
|
|
961
987
|
style: S$3.button,
|
|
988
|
+
disabled: createEmpty,
|
|
989
|
+
"data-ilife-press": "dialog-create",
|
|
990
|
+
"data-ilife-longpress": "dialog-create",
|
|
962
991
|
onClick: () => onCreate(creatingName)
|
|
963
992
|
}, labels.createConfirm), react.createElement("button", {
|
|
964
993
|
type: "button",
|
|
965
994
|
style: S$3.button,
|
|
995
|
+
"data-ilife-press": "dialog-create-cancel",
|
|
996
|
+
"data-ilife-longpress": "dialog-create-cancel",
|
|
966
997
|
onClick: onCancel
|
|
967
998
|
}, labels.createCancel));
|
|
968
999
|
}
|
|
@@ -988,6 +1019,9 @@ window.__ModuleLoader__.load({
|
|
|
988
1019
|
const rows = rowsOf(state);
|
|
989
1020
|
const target = targetOf(state);
|
|
990
1021
|
const hidden = hiddenCount(state.listing ?? EMPTY_LISTING);
|
|
1022
|
+
const upOff = !canGoUp(state);
|
|
1023
|
+
const goOff = state.draft.trim() === "";
|
|
1024
|
+
const pickOff = target === null;
|
|
991
1025
|
const body = [];
|
|
992
1026
|
body.push(crumbRow(state, props.onEnter));
|
|
993
1027
|
body.push(rootsRow(state, props.onEnter));
|
|
@@ -996,6 +1030,7 @@ window.__ModuleLoader__.load({
|
|
|
996
1030
|
value: state.draft,
|
|
997
1031
|
placeholder: labels.pathPlaceholder,
|
|
998
1032
|
"aria-label": labels.pathPlaceholder,
|
|
1033
|
+
"data-ilife-focus": "dialog-input",
|
|
999
1034
|
onChange: (event) => props.onDraft(event.currentTarget.value),
|
|
1000
1035
|
onKeyDown: (event) => {
|
|
1001
1036
|
if (event.key === "Enter") props.onCommitDraft();
|
|
@@ -1003,10 +1038,16 @@ window.__ModuleLoader__.load({
|
|
|
1003
1038
|
}), react.createElement("button", {
|
|
1004
1039
|
type: "button",
|
|
1005
1040
|
style: S$3.button,
|
|
1041
|
+
disabled: upOff,
|
|
1042
|
+
"data-ilife-press": "dialog-up",
|
|
1043
|
+
"data-ilife-longpress": "dialog-up",
|
|
1006
1044
|
onClick: props.onUp
|
|
1007
1045
|
}, labels.up), react.createElement("button", {
|
|
1008
1046
|
type: "button",
|
|
1009
1047
|
style: S$3.button,
|
|
1048
|
+
disabled: goOff,
|
|
1049
|
+
"data-ilife-press": "dialog-go",
|
|
1050
|
+
"data-ilife-longpress": "dialog-go",
|
|
1010
1051
|
onClick: props.onCommitDraft
|
|
1011
1052
|
}, labels.go)));
|
|
1012
1053
|
body.push(react.createElement("div", {
|
|
@@ -1022,6 +1063,7 @@ window.__ModuleLoader__.load({
|
|
|
1022
1063
|
} }, react.createElement("input", {
|
|
1023
1064
|
type: "checkbox",
|
|
1024
1065
|
checked: state.showHidden,
|
|
1066
|
+
"data-ilife-focus": "dialog-check",
|
|
1025
1067
|
onChange: props.onToggleHidden
|
|
1026
1068
|
}), " " + labels.showHidden(hidden)) : null, state.creating === null ? react.createElement("button", {
|
|
1027
1069
|
type: "button",
|
|
@@ -1029,6 +1071,8 @@ window.__ModuleLoader__.load({
|
|
|
1029
1071
|
...S$3.chromeButton,
|
|
1030
1072
|
textDecoration: "underline"
|
|
1031
1073
|
},
|
|
1074
|
+
"data-ilife-press": "dialog-newfolder",
|
|
1075
|
+
"data-ilife-longpress": "dialog-newfolder",
|
|
1032
1076
|
onClick: () => props.onCreatingChange("")
|
|
1033
1077
|
}, labels.newFolder) : null, state.notice !== null ? react.createElement("div", { style: S$3.error }, state.notice) : null, state.phase === "failed" && state.failure !== null ? react.createElement("div", { style: S$3.error }, state.failure.message) : null));
|
|
1034
1078
|
body.push(react.createElement("div", { style: S$3.foot }, react.createElement("span", {
|
|
@@ -1038,12 +1082,17 @@ window.__ModuleLoader__.load({
|
|
|
1038
1082
|
type: "button",
|
|
1039
1083
|
style: {
|
|
1040
1084
|
...S$3.button,
|
|
1041
|
-
...
|
|
1085
|
+
...pickOff ? S$3.buttonOff : {}
|
|
1042
1086
|
},
|
|
1087
|
+
disabled: pickOff,
|
|
1088
|
+
"data-ilife-press": "dialog-pick",
|
|
1089
|
+
"data-ilife-longpress": "dialog-pick",
|
|
1043
1090
|
onClick: props.onPick
|
|
1044
1091
|
}, labels.open), react.createElement("button", {
|
|
1045
1092
|
type: "button",
|
|
1046
1093
|
style: S$3.button,
|
|
1094
|
+
"data-ilife-press": "dialog-cancel",
|
|
1095
|
+
"data-ilife-longpress": "dialog-cancel",
|
|
1047
1096
|
onClick: props.onClose
|
|
1048
1097
|
}, labels.cancel)));
|
|
1049
1098
|
return react.createElement("div", {
|
|
@@ -1065,6 +1114,8 @@ window.__ModuleLoader__.load({
|
|
|
1065
1114
|
},
|
|
1066
1115
|
"aria-label": labels.close,
|
|
1067
1116
|
title: labels.close,
|
|
1117
|
+
"data-ilife-press": "dialog-close",
|
|
1118
|
+
"data-ilife-longpress": "dialog-close",
|
|
1068
1119
|
onClick: props.onClose
|
|
1069
1120
|
}, "✕")), body));
|
|
1070
1121
|
}
|
|
@@ -1157,6 +1208,233 @@ window.__ModuleLoader__.load({
|
|
|
1157
1208
|
}, react.createElement("span", { style: S$2.product }, props.product), react.createElement("span", { style: S$2.purpose }, props.purpose));
|
|
1158
1209
|
}
|
|
1159
1210
|
//#endregion
|
|
1211
|
+
//#region ../plugin-manager/src/seal-paper-schemes.ts
|
|
1212
|
+
/** 卷轴纸面字排 + 关闭钮样子 · **定稿件**(2026-10-06 定档,原型选型期结束)。
|
|
1213
|
+
*
|
|
1214
|
+
* 定稿形状(逐值锁死,改动须同步 `test/seal-scroll.test.mjs` 与 `test/seal-bundle-1158.test.mjs`):
|
|
1215
|
+
* 纸面:三段紧凑行内(进展/状态/计划),行首一枚朱砂小方印(进/状/计),标签与正文同行基线对齐;
|
|
1216
|
+
* 末行吃回 0.5em 行距(不然底比顶空一截);饰线上距加宽到 `0.5em 0 0.75em`;纸底与头部沿用原样式。
|
|
1217
|
+
* 档位语:该档金属渐变压进字里(金=鎏金/银=冷银/铜=暖铜),不再一律金。
|
|
1218
|
+
* 关闭钮:右上角斜披的朱砂菱形绦带(正立「收卷」字独立成层),两条飘尾沿菱形两条下边各向底尖收,
|
|
1219
|
+
* 各自朝外 26°(左尾朝左下、右尾朝右下);尾是两层——外层过糙边出毛边,内层纯色芯不受滤镜。
|
|
1220
|
+
*
|
|
1221
|
+
* 为什么单独一件:`seal-scroll.ts` 已接近告警线(外框/纸/浮层/滤镜都住那里),纸面字排与关闭钮住这里。
|
|
1222
|
+
* 本件是纯函数:吃 ctx 回五件,不留状态、不取数。原型期的二十余档方案已按「定稿后只留胜出那一档」删除。
|
|
1223
|
+
*/
|
|
1224
|
+
/** 材质底层:**糙边滤镜只挂这一层**——文字住在它外面,所以字是清晰的(照插件章「金属带+印文」的老做法)。 */
|
|
1225
|
+
function bgLayer(style, children) {
|
|
1226
|
+
return react.createElement("span", {
|
|
1227
|
+
"aria-hidden": true,
|
|
1228
|
+
style: {
|
|
1229
|
+
position: "absolute",
|
|
1230
|
+
inset: 0,
|
|
1231
|
+
...style
|
|
1232
|
+
}
|
|
1233
|
+
}, children ?? null);
|
|
1234
|
+
}
|
|
1235
|
+
/** 清晰字面:压在材质层之上,不参与任何滤镜。 */
|
|
1236
|
+
function crisp(text, style) {
|
|
1237
|
+
return react.createElement("span", { style: {
|
|
1238
|
+
position: "relative",
|
|
1239
|
+
zIndex: 1,
|
|
1240
|
+
...style
|
|
1241
|
+
} }, text);
|
|
1242
|
+
}
|
|
1243
|
+
/** 档位语三档金属(鎏金/冷银/暖铜):主色+渐变(`backgroundClip:text` 描出金属光泽)。 */
|
|
1244
|
+
const TIER_METAL = {
|
|
1245
|
+
gold: {
|
|
1246
|
+
flat: "#b8912a",
|
|
1247
|
+
gradient: "linear-gradient(180deg,#f6e27a 0%,#d9b53c 45%,#a5811b 100%)"
|
|
1248
|
+
},
|
|
1249
|
+
silver: {
|
|
1250
|
+
flat: "#8b959d",
|
|
1251
|
+
gradient: "linear-gradient(180deg,#f7fafc 0%,#c3ccd3 45%,#8b959d 100%)"
|
|
1252
|
+
},
|
|
1253
|
+
copper: {
|
|
1254
|
+
flat: "#a8663a",
|
|
1255
|
+
gradient: "linear-gradient(180deg,#f0bd8e 0%,#c07b45 45%,#8a4a24 100%)"
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
/** 档位金属边(铜/银/金):章与绦带共用这一份取值。 */
|
|
1259
|
+
const TIER_EDGE = {
|
|
1260
|
+
gold: "#f5d97a",
|
|
1261
|
+
silver: "#d8dee3",
|
|
1262
|
+
copper: "#a5652f"
|
|
1263
|
+
};
|
|
1264
|
+
const KAI = "\"Kaiti SC\",\"KaiTi\",\"STKaiti\",serif";
|
|
1265
|
+
/** 关闭钮(定稿:绦带·飘尾)。右上角一枚斜披 45° 的朱砂菱形,两条飘尾分挂两条下边,尾先画、带后画压住尾根。 */
|
|
1266
|
+
function closeLook(tierKey) {
|
|
1267
|
+
const crimson = "linear-gradient(135deg,#c63d2a 8%,#a32216 50%,#7e1a10)";
|
|
1268
|
+
/** 档位金属边(铜/银/金):绦带**只借这一条**——主体恒朱砂,边随档走,跟章「红底+金属边」同构。 */
|
|
1269
|
+
const edge = TIER_EDGE[tierKey] ?? TIER_EDGE["gold"];
|
|
1270
|
+
const ribbon = bgLayer({
|
|
1271
|
+
borderRadius: "0.375em",
|
|
1272
|
+
background: crimson,
|
|
1273
|
+
boxShadow: "0 0 0 1px #5c110a59, 0 2px 8px #3d241066, inset 0 0 0 2px " + edge,
|
|
1274
|
+
transform: "rotate(45deg)",
|
|
1275
|
+
filter: "url(#" + SEAL_ROUGH_METAL_ID + ")"
|
|
1276
|
+
}, null);
|
|
1277
|
+
/** 尾色=绦带上亮一档的朱砂(悬在纸上也不发灰、不发黑):两条尾同色。 */
|
|
1278
|
+
const TAIL_FILL = "linear-gradient(180deg,#e8573c 0%,#c33a24 55%,#a52612 100%)";
|
|
1279
|
+
/** 飘尾:屏幕坐标(不随菱形旋转)——左尾往左下、右尾往右下(CSS 正角=尾梢往左)。
|
|
1280
|
+
* 两层:外层过糙边滤镜出毛边,内层纯色芯不受滤镜——尾悬在纸上还是悬在暗底上都是同一色。 */
|
|
1281
|
+
const loose = (key, left, deg, len, top) => react.createElement("span", {
|
|
1282
|
+
key,
|
|
1283
|
+
"aria-hidden": true,
|
|
1284
|
+
style: {
|
|
1285
|
+
position: "absolute",
|
|
1286
|
+
left,
|
|
1287
|
+
top,
|
|
1288
|
+
width: "0.4375em",
|
|
1289
|
+
height: len,
|
|
1290
|
+
transformOrigin: "top center",
|
|
1291
|
+
transform: "rotate(" + deg + "deg)"
|
|
1292
|
+
}
|
|
1293
|
+
}, bgLayer({
|
|
1294
|
+
borderRadius: "0 0 0.1875em 0.1875em",
|
|
1295
|
+
background: TAIL_FILL,
|
|
1296
|
+
boxShadow: "0 0 0 1.5px " + edge + "cc, 0 1px 3px #00000055",
|
|
1297
|
+
filter: "url(#" + SEAL_ROUGH_METAL_ID + ")"
|
|
1298
|
+
}), react.createElement("span", {
|
|
1299
|
+
"aria-hidden": true,
|
|
1300
|
+
style: {
|
|
1301
|
+
position: "absolute",
|
|
1302
|
+
inset: "0.5px",
|
|
1303
|
+
borderRadius: "0 0 0.15625em 0.15625em",
|
|
1304
|
+
background: TAIL_FILL
|
|
1305
|
+
}
|
|
1306
|
+
}));
|
|
1307
|
+
return {
|
|
1308
|
+
label: crisp("收卷", {
|
|
1309
|
+
fontFamily: KAI,
|
|
1310
|
+
fontSize: "0.8125em",
|
|
1311
|
+
letterSpacing: "0.22em",
|
|
1312
|
+
textIndent: "0.22em",
|
|
1313
|
+
color: "#f8f1e2",
|
|
1314
|
+
textShadow: "0 1px 2px #000000aa"
|
|
1315
|
+
}),
|
|
1316
|
+
decor: react.createElement(react.Fragment, null, loose("tL", "calc(50% - 0.8125em)", 26, "2em", "2.8125em"), loose("tR", "calc(50% + 0.4375em)", -26, "2em", "2.8125em"), ribbon),
|
|
1317
|
+
style: {
|
|
1318
|
+
boxSizing: "border-box",
|
|
1319
|
+
padding: 0,
|
|
1320
|
+
position: "absolute",
|
|
1321
|
+
right: "-1.5em",
|
|
1322
|
+
top: "-1.5em",
|
|
1323
|
+
width: "3.25em",
|
|
1324
|
+
height: "3.25em",
|
|
1325
|
+
display: "flex",
|
|
1326
|
+
alignItems: "center",
|
|
1327
|
+
justifyContent: "center",
|
|
1328
|
+
cursor: "pointer",
|
|
1329
|
+
border: "none",
|
|
1330
|
+
background: "transparent"
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
/** 画一条饰线(方向 90/270 决定渐变朝向;定稿的段上距是 0.5em 0 0.75em)。 */
|
|
1335
|
+
function ornament(st, ruler) {
|
|
1336
|
+
const line = (key, dir) => react.createElement("span", {
|
|
1337
|
+
key,
|
|
1338
|
+
style: {
|
|
1339
|
+
...st.ornLine,
|
|
1340
|
+
background: "linear-gradient(" + dir + "deg,#0000," + ruler + ")"
|
|
1341
|
+
}
|
|
1342
|
+
});
|
|
1343
|
+
return react.createElement("div", { style: {
|
|
1344
|
+
...st.orn,
|
|
1345
|
+
margin: "0.5em 0 0.75em"
|
|
1346
|
+
} }, line("l", "90"), react.createElement("i", { style: {
|
|
1347
|
+
...st.ornDot,
|
|
1348
|
+
background: ruler
|
|
1349
|
+
} }), line("r", "270"));
|
|
1350
|
+
}
|
|
1351
|
+
/** 行首那枚朱砂小印(进/状/计):**两层**——材质层过印那条糙边滤镜(印泥压出来的毛边与斑驳),
|
|
1352
|
+
* 字独立成层保持清晰;方块各带一点歪斜(真印章不会次次压得方正)。
|
|
1353
|
+
* 外框仍是 0.7em 字/1.6 行高/左右 0.375em 垫——换的是质感,版面逐值不动。 */
|
|
1354
|
+
function inkMark(name) {
|
|
1355
|
+
const tilt = name === "进展" ? -2.4 : name === "状态" ? 1.6 : -1.2;
|
|
1356
|
+
return react.createElement("span", { style: {
|
|
1357
|
+
position: "relative",
|
|
1358
|
+
flex: "0 0 auto",
|
|
1359
|
+
fontSize: "0.7em",
|
|
1360
|
+
lineHeight: 1.6,
|
|
1361
|
+
padding: "0 0.375em",
|
|
1362
|
+
transform: "rotate(" + tilt + "deg)"
|
|
1363
|
+
} }, react.createElement("span", {
|
|
1364
|
+
"aria-hidden": true,
|
|
1365
|
+
style: {
|
|
1366
|
+
position: "absolute",
|
|
1367
|
+
inset: 0,
|
|
1368
|
+
borderRadius: "0.1875em",
|
|
1369
|
+
background: "#d92b1c",
|
|
1370
|
+
filter: "url(#" + SEAL_ROUGH_INK_ID + ")"
|
|
1371
|
+
}
|
|
1372
|
+
}, react.createElement("span", {
|
|
1373
|
+
"aria-hidden": true,
|
|
1374
|
+
style: {
|
|
1375
|
+
position: "absolute",
|
|
1376
|
+
inset: 0,
|
|
1377
|
+
borderRadius: "inherit",
|
|
1378
|
+
background: "radial-gradient(circle at 72% 76%,#a81a0e33 0%,#0000 58%), radial-gradient(circle at 20% 62%,#f0715a3d 0%,#0000 52%), radial-gradient(circle at 52% 12%,#ee6a5233 0%,#0000 46%)"
|
|
1379
|
+
}
|
|
1380
|
+
})), react.createElement("span", { style: {
|
|
1381
|
+
position: "relative",
|
|
1382
|
+
color: "#fdf7ea",
|
|
1383
|
+
opacity: .95
|
|
1384
|
+
} }, name.slice(0, 1)));
|
|
1385
|
+
}
|
|
1386
|
+
/** 三段:一行紧凑(行首朱砂小方印+标签+正文同一基线)。 */
|
|
1387
|
+
function inlineRows(st, ctx) {
|
|
1388
|
+
const one = (key, name, text, last = false) => react.createElement("div", {
|
|
1389
|
+
key,
|
|
1390
|
+
style: {
|
|
1391
|
+
margin: last ? "0 0 -0.5em" : "0 0 0.5em",
|
|
1392
|
+
display: "flex",
|
|
1393
|
+
alignItems: "baseline",
|
|
1394
|
+
gap: "0.5em"
|
|
1395
|
+
}
|
|
1396
|
+
}, inkMark(name), react.createElement("span", { style: {
|
|
1397
|
+
...st.label,
|
|
1398
|
+
flex: "0 0 auto",
|
|
1399
|
+
display: "inline",
|
|
1400
|
+
marginBottom: 0,
|
|
1401
|
+
fontSize: "0.8em",
|
|
1402
|
+
color: ctx.accent
|
|
1403
|
+
} }, name + ":"), react.createElement("span", { style: {
|
|
1404
|
+
...st.text,
|
|
1405
|
+
flex: "1 1 auto",
|
|
1406
|
+
display: "inline",
|
|
1407
|
+
margin: 0,
|
|
1408
|
+
fontSize: "0.9em"
|
|
1409
|
+
} }, text));
|
|
1410
|
+
return react.createElement(react.Fragment, null, one("progress", "进展", ctx.progress), one("status", "状态", ctx.status), one("plan", "计划", ctx.plan, true));
|
|
1411
|
+
}
|
|
1412
|
+
/** 档位语(一行):该档金属渐变压进字里。 */
|
|
1413
|
+
function tierNode(ctx) {
|
|
1414
|
+
const metal = TIER_METAL[ctx.tierKey] ?? TIER_METAL["gold"];
|
|
1415
|
+
return react.createElement("div", { style: {
|
|
1416
|
+
...ctx.styles.tier,
|
|
1417
|
+
fontFamily: KAI,
|
|
1418
|
+
fontSize: "1.0625em",
|
|
1419
|
+
letterSpacing: "0.34em",
|
|
1420
|
+
textIndent: "0.34em",
|
|
1421
|
+
color: "transparent",
|
|
1422
|
+
backgroundImage: metal.gradient,
|
|
1423
|
+
WebkitBackgroundClip: "text",
|
|
1424
|
+
backgroundClip: "text"
|
|
1425
|
+
} }, ctx.tierText);
|
|
1426
|
+
}
|
|
1427
|
+
/** 组装一件:纸底/头部/档位语/饰线/三段(定稿不覆盖纸底与头部,故两者缺席=用 `seal-scroll.ts` 的原样式)。 */
|
|
1428
|
+
function paperParts(ctx) {
|
|
1429
|
+
return {
|
|
1430
|
+
paper: void 0,
|
|
1431
|
+
head: void 0,
|
|
1432
|
+
tier: tierNode(ctx),
|
|
1433
|
+
orn: ornament(ctx.styles, ctx.ruler),
|
|
1434
|
+
body: inlineRows(ctx.styles, ctx)
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
//#endregion
|
|
1160
1438
|
//#region ../plugin-manager/src/seal-scroll.ts
|
|
1161
1439
|
/** 印章卷轴 · 纯组件(`title-seal.ts` 的配套件,不认任何一家)。
|
|
1162
1440
|
*
|
|
@@ -1183,10 +1461,25 @@ window.__ModuleLoader__.load({
|
|
|
1183
1461
|
/** 糙边滤镜 id(文档作用域,故每页只许挂一次 `SealFilterDefs`)。 */
|
|
1184
1462
|
const ROUGH_EDGE = "dshLifeSealRoughEdge";
|
|
1185
1463
|
const ROUGH_FRAME = "dshLifeSealRoughFrame";
|
|
1464
|
+
/** 中等件(轴杆/纸筒/绦带这类几十像素宽的件)那条糙边:2.2 太细、5 会抖过头。 */
|
|
1465
|
+
const ROUGH_METAL = "dshLifeSealRoughMetal";
|
|
1466
|
+
/** 印泥那条(行首那几枚小印):同 2.2 的抖动,末尾再加一点高斯模糊——印泥压在纸上边缘会洇开,
|
|
1467
|
+
* 光有抖动边只会读成「毛边贴纸」。字住在滤镜之外,所以糊的只有泥、不是字。 */
|
|
1468
|
+
const ROUGH_INK = "dshLifeSealInkEdge";
|
|
1469
|
+
/** 中等件那条糙边 id(关闭钮引用;定义只此一处)。 */
|
|
1470
|
+
const SEAL_ROUGH_METAL_ID = ROUGH_METAL;
|
|
1471
|
+
/** 印泥那条糙边 id(纸面行首小印引用;定义只此一处)。 */
|
|
1472
|
+
const SEAL_ROUGH_INK_ID = ROUGH_INK;
|
|
1473
|
+
/** 档位话:标题下那一行不再印档位字,直接说档位所处的阶段(渲染期用,顶层可放行)。 */
|
|
1474
|
+
const TIER_TEXT = {
|
|
1475
|
+
gold: "精雕细琢中",
|
|
1476
|
+
silver: "全打通中",
|
|
1477
|
+
copper: "基础建设中"
|
|
1478
|
+
};
|
|
1186
1479
|
/** 纸面四色是印自带的(羊皮纸底+ availability 墨色),不跟宿主主题跑——
|
|
1187
1480
|
* 深色下宿主变量会把纸染黑,故这里写死定稿值;字族仍继承(定稿零字族)。 */
|
|
1188
1481
|
const PAPER_BG = "#fdfaf2";
|
|
1189
|
-
const
|
|
1482
|
+
const PAPER_EDGE = "#e6d9bd";
|
|
1190
1483
|
const LABEL_SUB = "#4b4335";
|
|
1191
1484
|
/** 九档材质(3 角色 × 3 档)。键就是原型里的 `role`/`tier`。 */
|
|
1192
1485
|
const MATERIALS = {
|
|
@@ -1321,16 +1614,13 @@ window.__ModuleLoader__.load({
|
|
|
1321
1614
|
},
|
|
1322
1615
|
inner: {
|
|
1323
1616
|
position: "relative",
|
|
1324
|
-
padding: "1.75em 2em
|
|
1617
|
+
padding: "1.75em 2em"
|
|
1325
1618
|
},
|
|
1326
|
-
head: {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
fontSize: "1em",
|
|
1330
|
-
fontWeight: 600,
|
|
1331
|
-
letterSpacing: "0.16em",
|
|
1332
|
-
color: LABEL_MAIN
|
|
1619
|
+
head: {
|
|
1620
|
+
textAlign: "center",
|
|
1621
|
+
marginBottom: "0.5em"
|
|
1333
1622
|
},
|
|
1623
|
+
/** 档位语(标题下那一行):档位字退役,改说档位话(金=精雕细琢中/银=全打通中/铜=基础建设中)。 */
|
|
1334
1624
|
tier: {
|
|
1335
1625
|
marginTop: "0.4375em",
|
|
1336
1626
|
fontSize: "0.66em",
|
|
@@ -1382,17 +1672,21 @@ window.__ModuleLoader__.load({
|
|
|
1382
1672
|
position: "absolute",
|
|
1383
1673
|
left: "0.5em",
|
|
1384
1674
|
right: "0.5em",
|
|
1385
|
-
top: "8em",
|
|
1675
|
+
top: "8.8em",
|
|
1386
1676
|
zIndex: 10,
|
|
1387
1677
|
display: "flex",
|
|
1388
1678
|
justifyContent: "center",
|
|
1389
1679
|
pointerEvents: "auto"
|
|
1390
1680
|
},
|
|
1391
|
-
/**
|
|
1681
|
+
/** 浮层内框:**宽随内容**(`max-content`,正好包住最长那一行;不是固定 25em 那块大纸)。
|
|
1682
|
+
* `maxWidth:100%` 是窄卡的兜底(收满可用宽、永不捅破卡片),此时长行换行、高度自己长。
|
|
1683
|
+
* 挂卷轴展开动画(从上而下舒卷,240ms;纯声明式,无 hook,纯函数可直测)。 */
|
|
1392
1684
|
popInner: {
|
|
1393
1685
|
position: "relative",
|
|
1394
|
-
width: "
|
|
1395
|
-
maxWidth: "100%"
|
|
1686
|
+
width: "max-content",
|
|
1687
|
+
maxWidth: "100%",
|
|
1688
|
+
transformOrigin: "50% 0",
|
|
1689
|
+
animation: "dshLifeSealUnroll 240ms ease-out"
|
|
1396
1690
|
},
|
|
1397
1691
|
close: {
|
|
1398
1692
|
position: "absolute",
|
|
@@ -1415,9 +1709,11 @@ window.__ModuleLoader__.load({
|
|
|
1415
1709
|
}
|
|
1416
1710
|
/** 糙边滤镜定义:两条分开(印用 edge,卷轴外框用 frame),每页只挂一次。
|
|
1417
1711
|
*
|
|
1418
|
-
* 挂在文档任意位置都行(`width/height=0` 不占位),同页重复挂会撞 id。
|
|
1712
|
+
* 挂在文档任意位置都行(`width/height=0` 不占位),同页重复挂会撞 id。
|
|
1713
|
+
* 印章交互(悬停上浮高亮/按压回缩/焦点环/级别 tooltip)也住这里:scoped 类名,纯 CSS、无 hook。
|
|
1714
|
+
* 悬停高亮须把糙边 url 原样带上(filter 单属性,另写会把糙边冲掉)。 */
|
|
1419
1715
|
function SealFilterDefs() {
|
|
1420
|
-
return react.createElement("svg", {
|
|
1716
|
+
return react.createElement(react.Fragment, null, react.createElement("style", null, ".dshLifeSealBtn{position:relative;transition:transform 160ms ease-out,filter 160ms ease-out}.dshLifeSealBtn:hover{transform:translateY(-2px);filter:url(#dshLifeSealRoughEdge) brightness(1.12)}.dshLifeSealBtn:active{transform:translateY(0) scale(.96)}.dshLifeSealBtn:focus-visible{outline:2px solid #f5d97a;outline-offset:2px}.dshLifeSealBtn::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);background:#241f19ee;color:#f8f1e2;font-size:.72em;letter-spacing:.1em;padding:.4em .9em;border-radius:.5em;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity 150ms ease;z-index:30}.dshLifeSealBtn:hover::after,.dshLifeSealBtn:focus-visible::after{opacity:1}"), react.createElement("svg", {
|
|
1421
1717
|
width: 0,
|
|
1422
1718
|
height: 0,
|
|
1423
1719
|
"aria-hidden": true,
|
|
@@ -1441,6 +1737,21 @@ window.__ModuleLoader__.load({
|
|
|
1441
1737
|
y: "-6%",
|
|
1442
1738
|
width: "112%",
|
|
1443
1739
|
height: "112%"
|
|
1740
|
+
}, react.createElement("feTurbulence", {
|
|
1741
|
+
baseFrequency: .6,
|
|
1742
|
+
numOctaves: 3,
|
|
1743
|
+
result: "n"
|
|
1744
|
+
}), react.createElement("feDisplacementMap", {
|
|
1745
|
+
in: "SourceGraphic",
|
|
1746
|
+
in2: "n",
|
|
1747
|
+
scale: 6.5
|
|
1748
|
+
})), react.createElement("filter", {
|
|
1749
|
+
id: ROUGH_METAL,
|
|
1750
|
+
key: ROUGH_METAL,
|
|
1751
|
+
x: "-8%",
|
|
1752
|
+
y: "-14%",
|
|
1753
|
+
width: "116%",
|
|
1754
|
+
height: "128%"
|
|
1444
1755
|
}, react.createElement("feTurbulence", {
|
|
1445
1756
|
baseFrequency: .9,
|
|
1446
1757
|
numOctaves: 2,
|
|
@@ -1448,8 +1759,43 @@ window.__ModuleLoader__.load({
|
|
|
1448
1759
|
}), react.createElement("feDisplacementMap", {
|
|
1449
1760
|
in: "SourceGraphic",
|
|
1450
1761
|
in2: "n",
|
|
1451
|
-
scale:
|
|
1452
|
-
}))
|
|
1762
|
+
scale: 3.2
|
|
1763
|
+
})), react.createElement("filter", {
|
|
1764
|
+
id: ROUGH_INK,
|
|
1765
|
+
key: ROUGH_INK,
|
|
1766
|
+
x: "-25%",
|
|
1767
|
+
y: "-25%",
|
|
1768
|
+
width: "150%",
|
|
1769
|
+
height: "150%"
|
|
1770
|
+
}, react.createElement("feTurbulence", {
|
|
1771
|
+
type: "fractalNoise",
|
|
1772
|
+
baseFrequency: .9,
|
|
1773
|
+
numOctaves: 2,
|
|
1774
|
+
result: "n"
|
|
1775
|
+
}), react.createElement("feDisplacementMap", {
|
|
1776
|
+
in: "SourceGraphic",
|
|
1777
|
+
in2: "n",
|
|
1778
|
+
scale: 2.2,
|
|
1779
|
+
result: "d"
|
|
1780
|
+
}), react.createElement("feGaussianBlur", {
|
|
1781
|
+
in: "d",
|
|
1782
|
+
stdDeviation: .3,
|
|
1783
|
+
result: "b"
|
|
1784
|
+
}), react.createElement("feTurbulence", {
|
|
1785
|
+
type: "fractalNoise",
|
|
1786
|
+
baseFrequency: .75,
|
|
1787
|
+
numOctaves: 3,
|
|
1788
|
+
result: "g"
|
|
1789
|
+
}), react.createElement("feColorMatrix", {
|
|
1790
|
+
in: "g",
|
|
1791
|
+
type: "matrix",
|
|
1792
|
+
values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .7 .45 0 0 .35",
|
|
1793
|
+
result: "mask"
|
|
1794
|
+
}), react.createElement("feComposite", {
|
|
1795
|
+
in: "b",
|
|
1796
|
+
in2: "mask",
|
|
1797
|
+
operator: "in"
|
|
1798
|
+
}))));
|
|
1453
1799
|
}
|
|
1454
1800
|
/** 一卷:外框材质 + 纯纸 + 进展/状态/计划三段。 */
|
|
1455
1801
|
function SealScroll(props) {
|
|
@@ -1492,36 +1838,40 @@ window.__ModuleLoader__.load({
|
|
|
1492
1838
|
}
|
|
1493
1839
|
})
|
|
1494
1840
|
] : [];
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1841
|
+
/** 纸面字排:定稿件直出五件。 */
|
|
1842
|
+
const parts = paperParts({
|
|
1843
|
+
tierKey: props.tier,
|
|
1844
|
+
tierText: TIER_TEXT[props.tier],
|
|
1845
|
+
progress: props.progress,
|
|
1846
|
+
status: props.status,
|
|
1847
|
+
plan: props.plan,
|
|
1848
|
+
accent: material.accent,
|
|
1849
|
+
ruler: material.ruler,
|
|
1850
|
+
paperEdge: PAPER_EDGE,
|
|
1851
|
+
styles: {
|
|
1852
|
+
head: S$1.head,
|
|
1853
|
+
paper: S$1.paper,
|
|
1854
|
+
tier: S$1.tier,
|
|
1855
|
+
orn: S$1.orn,
|
|
1856
|
+
ornLine: S$1.ornLine,
|
|
1857
|
+
ornDot: S$1.ornDot,
|
|
1858
|
+
block: S$1.block,
|
|
1859
|
+
blockDivided: S$1.blockDivided,
|
|
1860
|
+
blockLast: S$1.blockLast,
|
|
1861
|
+
label: S$1.label,
|
|
1862
|
+
text: S$1.text
|
|
1500
1863
|
}
|
|
1501
1864
|
});
|
|
1502
|
-
const block = (key, name, text, divided, last = false) => react.createElement("div", {
|
|
1503
|
-
key,
|
|
1504
|
-
style: last ? divided ? {
|
|
1505
|
-
...S$1.blockLast,
|
|
1506
|
-
paddingTop: "0.9375em",
|
|
1507
|
-
borderTop: "1px solid #e6d9bd"
|
|
1508
|
-
} : S$1.blockLast : divided ? S$1.blockDivided : S$1.block
|
|
1509
|
-
}, react.createElement("div", { style: {
|
|
1510
|
-
...S$1.label,
|
|
1511
|
-
color: material.accent
|
|
1512
|
-
} }, name), react.createElement("p", { style: S$1.text }, text));
|
|
1513
1865
|
return react.createElement("div", { style: S$1.scroll }, react.createElement("div", { style: {
|
|
1514
1866
|
...S$1.frame,
|
|
1515
1867
|
...material.frame
|
|
1516
|
-
} }, ...frameChildren), react.createElement("div", { style: S$1.paper }, react.createElement("div", { style: S$1.inner }, react.createElement("div", { style:
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
}
|
|
1524
|
-
/** 卷轴浮层:无遮罩 popover + 卷轴 + 关闭。`open` 为假时不渲染(纯函数,不收自己的状态)。 */
|
|
1868
|
+
} }, ...frameChildren), react.createElement("div", { style: parts.paper === void 0 ? S$1.paper : parts.paper }, react.createElement("div", { style: S$1.inner }, react.createElement("div", { style: parts.head === void 0 ? S$1.head : parts.head }, react.createElement(SealStamp, {
|
|
1869
|
+
role: props.role,
|
|
1870
|
+
tier: props.tier,
|
|
1871
|
+
label: props.title
|
|
1872
|
+
}), parts.tier), parts.orn, parts.body)));
|
|
1873
|
+
}
|
|
1874
|
+
/** 卷轴浮层:popover + 点击别处关闭 + 卷轴展开动画 + 关闭。`open` 为假时不渲染(纯函数,不收自己的状态)。 */
|
|
1525
1875
|
function SealScrollDialog(props) {
|
|
1526
1876
|
if (!props.open) return null;
|
|
1527
1877
|
const scroll = {
|
|
@@ -1532,16 +1882,37 @@ window.__ModuleLoader__.load({
|
|
|
1532
1882
|
status: props.status,
|
|
1533
1883
|
plan: props.plan
|
|
1534
1884
|
};
|
|
1535
|
-
return react.createElement("div", {
|
|
1536
|
-
style:
|
|
1885
|
+
return react.createElement(react.Fragment, null, react.createElement("div", {
|
|
1886
|
+
style: {
|
|
1887
|
+
position: "fixed",
|
|
1888
|
+
inset: 0,
|
|
1889
|
+
zIndex: 9,
|
|
1890
|
+
background: "transparent"
|
|
1891
|
+
},
|
|
1892
|
+
"aria-hidden": true,
|
|
1893
|
+
onClick: props.onClose
|
|
1894
|
+
}), react.createElement("div", {
|
|
1895
|
+
style: props.anchor === void 0 ? S$1.dialog : {
|
|
1896
|
+
...S$1.dialog,
|
|
1897
|
+
...props.anchor
|
|
1898
|
+
},
|
|
1537
1899
|
role: "dialog",
|
|
1538
1900
|
"aria-modal": false,
|
|
1539
1901
|
"aria-label": props.title
|
|
1540
|
-
}, react.createElement("div", { style: S$1.popInner },
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1902
|
+
}, react.createElement("style", null, "@keyframes dshLifeSealUnroll{from{opacity:0;transform:translateY(-10px) scaleY(.7)}to{opacity:1;transform:none}}"), react.createElement("div", { style: S$1.popInner }, (() => {
|
|
1903
|
+
const look = closeLook(props.tier);
|
|
1904
|
+
return react.createElement("button", {
|
|
1905
|
+
type: "button",
|
|
1906
|
+
className: "dshLifeSealBtn",
|
|
1907
|
+
style: {
|
|
1908
|
+
zIndex: 20,
|
|
1909
|
+
...look.style
|
|
1910
|
+
},
|
|
1911
|
+
"data-ilife-press": "seal-close",
|
|
1912
|
+
"data-ilife-close": "tie",
|
|
1913
|
+
onClick: props.onClose
|
|
1914
|
+
}, look.decor ?? null, look.label);
|
|
1915
|
+
})(), react.createElement(SealScroll, scroll))));
|
|
1545
1916
|
}
|
|
1546
1917
|
//#endregion
|
|
1547
1918
|
//#region ../plugin-manager/src/seal-stamp.ts
|
|
@@ -1650,21 +2021,25 @@ window.__ModuleLoader__.load({
|
|
|
1650
2021
|
function SealStamp(props) {
|
|
1651
2022
|
const face = FACE[props.role][props.tier];
|
|
1652
2023
|
if (face === void 0) throw new Error("未知印章组合:" + String(props.role) + "/" + String(props.tier));
|
|
2024
|
+
const style = {
|
|
2025
|
+
display: "inline-flex",
|
|
2026
|
+
alignItems: "center",
|
|
2027
|
+
cursor: "pointer",
|
|
2028
|
+
fontWeight: 800,
|
|
2029
|
+
lineHeight: 1.2,
|
|
2030
|
+
whiteSpace: "nowrap",
|
|
2031
|
+
filter: "url(#dshLifeSealRoughEdge)",
|
|
2032
|
+
...ROLE_BASE[props.role],
|
|
2033
|
+
...face
|
|
2034
|
+
};
|
|
2035
|
+
const tierName = props.tier === "copper" ? "铜" : props.tier === "silver" ? "银" : "金";
|
|
1653
2036
|
const buttonProps = {
|
|
1654
2037
|
type: "button",
|
|
1655
|
-
style
|
|
1656
|
-
|
|
1657
|
-
alignItems: "center",
|
|
1658
|
-
cursor: "pointer",
|
|
1659
|
-
fontWeight: 800,
|
|
1660
|
-
lineHeight: 1.2,
|
|
1661
|
-
whiteSpace: "nowrap",
|
|
1662
|
-
filter: "url(#dshLifeSealRoughEdge)",
|
|
1663
|
-
...ROLE_BASE[props.role],
|
|
1664
|
-
...face
|
|
1665
|
-
},
|
|
2038
|
+
style,
|
|
2039
|
+
className: "dshLifeSealBtn",
|
|
1666
2040
|
"aria-label": props.label,
|
|
1667
2041
|
"aria-haspopup": "dialog",
|
|
2042
|
+
"data-tip": tierName + "章 · " + TIER_TEXT[props.tier],
|
|
1668
2043
|
onClick: props.onSelect
|
|
1669
2044
|
};
|
|
1670
2045
|
if (props.role !== "plugin") return react.createElement("button", buttonProps, props.label);
|
|
@@ -1769,6 +2144,9 @@ window.__ModuleLoader__.load({
|
|
|
1769
2144
|
const PANEL_FIELD_EDGE = inkMix(24);
|
|
1770
2145
|
/** 骨架条:浅色 ≈`#c9ccd2`(1.6:1)⇔ 深色 ≈`#404143`。 */
|
|
1771
2146
|
const PANEL_SKELETON_FILL = inkMix(21);
|
|
2147
|
+
function interactionCss() {
|
|
2148
|
+
return "[data-ilife-press]{transition:" + INTERACTION_TRANSITION + "}[data-ilife-focus]{transition:" + INTERACTION_TRANSITION + "}[data-ilife-press]:active{transform:scale(" + String(PRESS_SCALE) + ")}[data-ilife-press]:focus-visible,[data-ilife-focus]:focus-visible{outline:none;box-shadow:0 0 0 " + String(2) + "px var(--dsw-alias-bg-layer-1, #232324),0 0 0 " + String(5) + "px var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55))}[data-ilife-press]{position:relative;overflow:hidden}[data-ilife-press]:hover:not(:disabled){background:color-mix(in srgb, var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)) " + String(13) + "%, transparent);border-color:var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55));box-shadow:0 0 0 1px color-mix(in srgb, var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)) " + String(55) + "%, transparent),0 4px 16px color-mix(in srgb, var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)) " + String(25) + "%, transparent);transform:translateY(-" + String(1) + "px)}[data-ilife-press]:active:hover:not(:disabled){transform:scale(" + String(PRESS_SCALE) + ")}[data-ilife-press]:focus-visible:hover:not(:disabled){box-shadow:0 0 0 " + String(2) + "px var(--dsw-alias-bg-layer-1, #232324),0 0 0 " + String(5) + "px var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)),0 4px 16px color-mix(in srgb, var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)) " + String(25) + "%, transparent)}[data-ilife-press]::before{content:\"\";position:absolute;inset:0;background:radial-gradient(" + String(120) + "px circle at var(--mx,50%) var(--my,50%),color-mix(in srgb, var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55)) " + String(22) + "%, transparent),transparent 65%);opacity:0;transition:opacity " + String(180 / 1e3) + "s ease;pointer-events:none}[data-ilife-press]:hover:not(:disabled)::before{opacity:1}[data-ilife-press]:disabled{cursor:not-allowed;opacity:" + String(DISABLED_OPACITY) + "}[data-ilife-press]:disabled:hover{animation:ilifeShake " + String(300 / 1e3) + "s ease}@keyframes ilifeShake{0%,100%{transform:translateX(0)}25%{transform:translateX(-2px)}75%{transform:translateX(2px)}}[data-ilife-longpress]{position:relative;overflow:hidden}[data-ilife-longpress]::after{content:\"\";position:absolute;left:0;bottom:0;height:" + String(3) + "px;width:0;background:var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55));pointer-events:none}[data-ilife-longpress]:active:not(:disabled)::after{animation:ilifeLongRing " + String(500 / 1e3) + "s linear forwards}@keyframes ilifeLongRing{from{width:0}to{width:100%}}[data-ilife-advanced=\"head\"]{transition:background .15s ease,transform .15s ease,box-shadow .15s ease,border-color .15s ease}[data-ilife-advanced=\"mark\"]{display:inline-block;transition:transform " + String(200 / 1e3) + "s ease}[data-ilife-advanced=\"group\"][open] [data-ilife-advanced=\"mark\"]{transform:rotate(90deg)}[data-ilife-advanced=\"head\"]:hover [data-ilife-advanced=\"mark\"]{color:var(--ilife-focus, var(--dsw-alias-brand-primary, #f6ad55));transform:translateX(" + String(2) + "px)}[data-ilife-advanced=\"group\"][open] [data-ilife-advanced=\"body\"]{animation:ilifeFoldIn " + String(220 / 1e3) + "s ease}@keyframes ilifeFoldIn{from{max-height:0;opacity:0}to{max-height:" + String(300) + "px;opacity:1}}[data-ilife-notice=\"line\"]{animation:ilifeToastIn " + String(180 / 1e3) + "s ease}@keyframes ilifeToastIn{from{opacity:0;transform:translateY(" + String(8) + "px)}to{opacity:1;transform:none}}@media (hover:none){[data-ilife-press]:hover:not(:disabled){transform:none}[data-ilife-press]::before{display:none}}@media (prefers-reduced-motion:reduce){[data-ilife-press],[data-ilife-focus]{transition:none}[data-ilife-press]:disabled:hover{animation:none}[data-ilife-longpress]:active:not(:disabled)::after{animation:none;width:100%}[data-ilife-advanced=\"mark\"]{transition:none}[data-ilife-advanced=\"group\"][open] [data-ilife-advanced=\"body\"]{animation:none}[data-ilife-notice=\"line\"]{animation:none}}@media (update: slow){[data-ilife-press],[data-ilife-focus]{transition:none}[data-ilife-press]::before{display:none}[data-ilife-press]:disabled:hover{animation:none}[data-ilife-longpress]:active:not(:disabled)::after{animation:none;width:100%}[data-ilife-advanced=\"mark\"]{transition:none}[data-ilife-advanced=\"group\"][open] [data-ilife-advanced=\"body\"]{animation:none}[data-ilife-notice=\"line\"]{animation:none}}";
|
|
2149
|
+
}
|
|
1772
2150
|
const S = {
|
|
1773
2151
|
/** `.ic-card`:`background:var(--ic-surface)`(=bg-layer-1)+`border:1px solid var(--ic-line-strong)`
|
|
1774
2152
|
* +`border-radius:12px`+`padding:14px`+`box-shadow:inset 0 1px 0 rgba(255,255,255,.06)`。
|
|
@@ -2311,6 +2689,8 @@ window.__ModuleLoader__.load({
|
|
|
2311
2689
|
style: S.btnPick,
|
|
2312
2690
|
type: "button",
|
|
2313
2691
|
disabled: props.onCopy === void 0,
|
|
2692
|
+
"data-ilife-press": "copy",
|
|
2693
|
+
"data-ilife-longpress": "copy",
|
|
2314
2694
|
onClick: () => props.onCopy?.(item.key, props.value)
|
|
2315
2695
|
}, copyLabelOf(props.copyState));
|
|
2316
2696
|
const follow = props.follow === true ? react.createElement("span", { style: S.follow }, react.createElement("span", { style: S.followMark }, "↳"), "将跟随更新") : null;
|
|
@@ -2325,6 +2705,7 @@ window.__ModuleLoader__.load({
|
|
|
2325
2705
|
style: S.checkbox,
|
|
2326
2706
|
checked: props.value === "true",
|
|
2327
2707
|
disabled,
|
|
2708
|
+
"data-ilife-focus": "input",
|
|
2328
2709
|
onChange: (e) => props.onChange(item.key, e.target.checked ? "true" : "false")
|
|
2329
2710
|
}) : react.createElement("input", {
|
|
2330
2711
|
style: props.dirty === true ? S.inputDirty : S.input,
|
|
@@ -2332,6 +2713,7 @@ window.__ModuleLoader__.load({
|
|
|
2332
2713
|
value: props.value,
|
|
2333
2714
|
disabled,
|
|
2334
2715
|
spellCheck: false,
|
|
2716
|
+
"data-ilife-focus": "input",
|
|
2335
2717
|
onChange
|
|
2336
2718
|
});
|
|
2337
2719
|
/** 目录入口:只读行不画(定稿 v3 ①),供不了(`none`/缺席)也不画。 */
|
|
@@ -2340,6 +2722,8 @@ window.__ModuleLoader__.load({
|
|
|
2340
2722
|
style: S.btnPick,
|
|
2341
2723
|
type: "button",
|
|
2342
2724
|
disabled,
|
|
2725
|
+
"data-ilife-press": "browse",
|
|
2726
|
+
"data-ilife-longpress": "browse",
|
|
2343
2727
|
onClick: () => entry.onOpen(item.key)
|
|
2344
2728
|
}, "浏览文件夹") : null;
|
|
2345
2729
|
return react.createElement("div", { style: S.master }, react.createElement("div", { style: S.label }, item.title, react.createElement("span", { style: S.chip }, "可改")), react.createElement("div", { style: S.hint }, item.hint), control, react.createElement("div", { style: S.acts }, browse, copy), props.alert == null ? null : react.createElement("div", { style: S.invalid }, props.alert.message));
|
|
@@ -2369,85 +2753,33 @@ window.__ModuleLoader__.load({
|
|
|
2369
2753
|
const surface = state.kind === "ready" ? state.surface : null;
|
|
2370
2754
|
const product = title ?? "";
|
|
2371
2755
|
const seals = props.seals ?? [];
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
-1,
|
|
2377
|
-
-3,
|
|
2378
|
-
1.5,
|
|
2379
|
-
3,
|
|
2380
|
-
-1.5,
|
|
2381
|
-
2,
|
|
2382
|
-
4,
|
|
2383
|
-
-3.5,
|
|
2384
|
-
.5,
|
|
2385
|
-
2.5,
|
|
2386
|
-
-4.5,
|
|
2756
|
+
const seed = props.sealSeed ?? 0;
|
|
2757
|
+
/** 三行定序(六家一致:HELP 上/技能中/插件下;HELP 永远 z 最上)。 */
|
|
2758
|
+
const order = [
|
|
2759
|
+
0,
|
|
2387
2760
|
1,
|
|
2388
|
-
|
|
2389
|
-
3.5,
|
|
2390
|
-
-.5,
|
|
2391
|
-
4.5
|
|
2761
|
+
2
|
|
2392
2762
|
];
|
|
2393
|
-
/**
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
right: "0.2em",
|
|
2399
|
-
top: "0.3em"
|
|
2400
|
-
},
|
|
2401
|
-
{
|
|
2402
|
-
left: "2%",
|
|
2403
|
-
top: "3.2em"
|
|
2404
|
-
},
|
|
2405
|
-
{
|
|
2406
|
-
right: "6%",
|
|
2407
|
-
top: "5.6em"
|
|
2408
|
-
}
|
|
2763
|
+
/** 三行行高(上/中/下;纵向净空各留约 10px,糙边抖动也碰不到)。 */
|
|
2764
|
+
const TOPS = [
|
|
2765
|
+
"0.3em",
|
|
2766
|
+
"3.4em",
|
|
2767
|
+
"6.2em"
|
|
2409
2768
|
];
|
|
2410
|
-
|
|
2411
|
-
const
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
[
|
|
2418
|
-
1,
|
|
2419
|
-
2,
|
|
2420
|
-
0
|
|
2421
|
-
],
|
|
2422
|
-
[
|
|
2423
|
-
2,
|
|
2424
|
-
0,
|
|
2425
|
-
1
|
|
2426
|
-
],
|
|
2427
|
-
[
|
|
2428
|
-
0,
|
|
2429
|
-
2,
|
|
2430
|
-
1
|
|
2431
|
-
],
|
|
2432
|
-
[
|
|
2433
|
-
1,
|
|
2434
|
-
0,
|
|
2435
|
-
2
|
|
2436
|
-
],
|
|
2437
|
-
[
|
|
2438
|
-
2,
|
|
2439
|
-
1,
|
|
2440
|
-
0
|
|
2441
|
-
]
|
|
2442
|
-
][seed % 6];
|
|
2443
|
-
const tiltOfSlot = (slot) => String(TILT18[(seed * 3 + slot) % 18]);
|
|
2769
|
+
/** 轻微倾角(±0.5°~±2.5°,方向随机):家下标×槽位哈希,纯函数、每次同值,不过大。 */
|
|
2770
|
+
const tiltOfSlot = (slot) => {
|
|
2771
|
+
const q = (seed * 5 + slot * 11 + 3) % 10;
|
|
2772
|
+
return String((q % 2 === 0 ? -1 : 1) * (.5 + Math.floor(q / 2) * .5));
|
|
2773
|
+
};
|
|
2774
|
+
/** 右间距(三枚全部居右收敛,各家各行 0.2em~1.1em 错开,永不出面板右边界)。 */
|
|
2775
|
+
const padRightOfSlot = (slot) => String(.2 + (seed * 7 + slot * 3 + 1) % 6 * .18) + "em";
|
|
2444
2776
|
const zOfRole = (role) => role === "help" ? 4 : role === "skill" ? 3 : 2;
|
|
2445
2777
|
const overlay = seals.length === 0 ? null : react.createElement("div", { style: S.sealOverlay }, react.createElement(SealFilterDefs, {}), ...order.map((dataIndex, slot) => react.createElement("span", {
|
|
2446
2778
|
key: seals[dataIndex].role + ":" + seals[dataIndex].tier,
|
|
2447
2779
|
style: {
|
|
2448
2780
|
position: "absolute",
|
|
2449
|
-
top:
|
|
2450
|
-
|
|
2781
|
+
top: TOPS[slot],
|
|
2782
|
+
right: padRightOfSlot(slot),
|
|
2451
2783
|
zIndex: zOfRole(seals[dataIndex].role),
|
|
2452
2784
|
pointerEvents: "auto",
|
|
2453
2785
|
display: "inline-flex",
|
|
@@ -2463,6 +2795,16 @@ window.__ModuleLoader__.load({
|
|
|
2463
2795
|
onSelect: props.onSealSelect === void 0 ? void 0 : props.onSealSelect.bind(null, dataIndex)
|
|
2464
2796
|
})))));
|
|
2465
2797
|
const openSeal = props.selectedSeal === null || props.selectedSeal === void 0 ? null : seals[props.selectedSeal] ?? null;
|
|
2798
|
+
/** 卷轴浮层跟着**被点的那枚章**:贴在该行下方一小段(1.9em = 章高约 1.5em + 0.4em 缝),
|
|
2799
|
+
* 右缘与那枚章的右缘对齐,再往左让 1.25em 给绦带(关闭钮骑在浮层右上方,不让它越出卡片)。 */
|
|
2800
|
+
const openSlot = props.selectedSeal ?? -1;
|
|
2801
|
+
const anchor = openSlot < 0 || openSlot >= order.length ? void 0 : {
|
|
2802
|
+
top: "calc(" + TOPS[openSlot] + " + 1.9em)",
|
|
2803
|
+
right: "calc(" + padRightOfSlot(openSlot) + " + 1.25em)",
|
|
2804
|
+
left: "auto",
|
|
2805
|
+
justifyContent: "flex-end",
|
|
2806
|
+
maxWidth: "calc(100% - " + padRightOfSlot(openSlot) + " - 1.75em)"
|
|
2807
|
+
};
|
|
2466
2808
|
const dialog = openSeal === null ? null : react.createElement(SealScrollDialog, {
|
|
2467
2809
|
open: true,
|
|
2468
2810
|
onClose: props.onSealClose ?? (() => void 0),
|
|
@@ -2471,7 +2813,8 @@ window.__ModuleLoader__.load({
|
|
|
2471
2813
|
title: openSeal.label,
|
|
2472
2814
|
progress: openSeal.progress,
|
|
2473
2815
|
status: openSeal.status,
|
|
2474
|
-
plan: openSeal.plan
|
|
2816
|
+
plan: openSeal.plan,
|
|
2817
|
+
anchor
|
|
2475
2818
|
});
|
|
2476
2819
|
const headDataDir = surface === null ? "" : surface.resolved?.["dbDir"] ?? surface.dataDir;
|
|
2477
2820
|
const ready = state.kind === "ready";
|
|
@@ -2521,12 +2864,16 @@ window.__ModuleLoader__.load({
|
|
|
2521
2864
|
if (state.kind === "failed") return react.createElement("div", { style: S.card }, head, fileLines, react.createElement("div", { style: S.error }, state.message), extra, overlay, react.createElement("div", { style: S.bar }, react.createElement("button", {
|
|
2522
2865
|
style: S.btn,
|
|
2523
2866
|
type: "button",
|
|
2867
|
+
"data-ilife-press": "retry",
|
|
2868
|
+
"data-ilife-longpress": "retry",
|
|
2524
2869
|
onClick: props.onRetry
|
|
2525
2870
|
}, "重试"), react.createElement("button", {
|
|
2526
2871
|
style: S.btn,
|
|
2527
2872
|
type: "button",
|
|
2873
|
+
"data-ilife-press": "reset",
|
|
2874
|
+
"data-ilife-longpress": "reset",
|
|
2528
2875
|
onClick: props.onReset
|
|
2529
|
-
}, "重置为默认")));
|
|
2876
|
+
}, "重置为默认")), react.createElement("style", { "data-ilife-interaction": "t1" }, interactionCss()));
|
|
2530
2877
|
const common = props.items.filter((item) => item.tier === "common");
|
|
2531
2878
|
const advanced = props.items.filter((item) => item.tier === "advanced");
|
|
2532
2879
|
/** 还没读到整面(`loading`)时**框架照画**:行表与控件形状是客户端常量,不必等任何回执。
|
|
@@ -2556,20 +2903,38 @@ window.__ModuleLoader__.load({
|
|
|
2556
2903
|
const commonLast = lastIndexOf(common);
|
|
2557
2904
|
const advancedLast = lastIndexOf(advanced);
|
|
2558
2905
|
const dirty = ready && dirtyCount > 0;
|
|
2559
|
-
return react.createElement("div", { style: S.card }, head, fileLines, react.createElement("div", { style: S.rows }, common.map((item, index) => renderRow(item, index === commonLast))), advanced.length === 0 ? null : react.createElement("details", {
|
|
2906
|
+
return react.createElement("div", { style: S.card }, head, fileLines, react.createElement("div", { style: S.rows }, common.map((item, index) => renderRow(item, index === commonLast))), advanced.length === 0 ? null : react.createElement("details", {
|
|
2907
|
+
style: S.advanced,
|
|
2908
|
+
"data-ilife-advanced": "group"
|
|
2909
|
+
}, react.createElement("summary", {
|
|
2910
|
+
style: S.summary,
|
|
2911
|
+
"data-ilife-advanced": "head"
|
|
2912
|
+
}, react.createElement("span", {
|
|
2913
|
+
style: S.groupMark,
|
|
2914
|
+
"data-ilife-advanced": "mark"
|
|
2915
|
+
}, "›"), ADVANCED_GROUP_TITLE), react.createElement("div", {
|
|
2916
|
+
style: S.groupBody,
|
|
2917
|
+
"data-ilife-advanced": "body"
|
|
2918
|
+
}, advanced.map((item, index) => renderRow(item, index === advancedLast)))), extra, react.createElement("div", { style: S.bar }, react.createElement("button", {
|
|
2560
2919
|
style: dirty ? S.btnPrimary : S.btn,
|
|
2561
2920
|
type: "button",
|
|
2562
2921
|
disabled: frozen || !dirty,
|
|
2922
|
+
"data-ilife-press": "save",
|
|
2923
|
+
"data-ilife-longpress": "save",
|
|
2563
2924
|
onClick: props.onSave
|
|
2564
2925
|
}, props.busy ? "处理中" : dirty ? `保存(${dirtyCount} 项未保存)` : "保存"), react.createElement("button", {
|
|
2565
2926
|
style: S.btn,
|
|
2566
2927
|
type: "button",
|
|
2567
2928
|
disabled: frozen,
|
|
2929
|
+
"data-ilife-press": "reset",
|
|
2930
|
+
"data-ilife-longpress": "reset",
|
|
2568
2931
|
onClick: props.onReset
|
|
2569
2932
|
}, "重置为默认"), react.createElement("button", {
|
|
2570
2933
|
style: S.btn,
|
|
2571
2934
|
type: "button",
|
|
2572
2935
|
disabled: frozen,
|
|
2936
|
+
"data-ilife-press": "retry",
|
|
2937
|
+
"data-ilife-longpress": "retry",
|
|
2573
2938
|
onClick: props.onRetry
|
|
2574
2939
|
}, "重新读取"), dirty ? react.createElement("div", { style: S.saveMsg }, `浏览改动后请点保存(${dirtyCount} 项未保存),保存后跟随项自动更新`) : ready ? react.createElement("div", { style: S.barNote }, "没有未保存的改动") : react.createElement("div", { style: S.barNote }, "配置读取中")), props.picking ? react.createElement("div", { style: S.muted }, "已唤起系统文件夹对话框:选中后自动填上,取消则不动。") : null, props.browseRow !== null ? react.createElement(DirectoryBrowserFromRow, {
|
|
2575
2940
|
open: true,
|
|
@@ -2578,7 +2943,10 @@ window.__ModuleLoader__.load({
|
|
|
2578
2943
|
}) : null, props.writeError !== null ? react.createElement("div", {
|
|
2579
2944
|
style: S.error,
|
|
2580
2945
|
role: "alert"
|
|
2581
|
-
}, props.writeError) : null, props.error !== null ? react.createElement("div", { style: S.error }, props.error) : null, props.notice !== null ? react.createElement("div", {
|
|
2946
|
+
}, props.writeError) : null, props.error !== null ? react.createElement("div", { style: S.error }, props.error) : null, props.notice !== null ? react.createElement("div", {
|
|
2947
|
+
style: S.okText,
|
|
2948
|
+
"data-ilife-notice": "line"
|
|
2949
|
+
}, props.notice) : null, overlay, react.createElement("style", { "data-ilife-interaction": "t1" }, interactionCss()));
|
|
2582
2950
|
}
|
|
2583
2951
|
//#endregion
|
|
2584
2952
|
//#region ../plugin-manager/src/directory-browser-roots.ts
|
|
@@ -2616,36 +2984,13 @@ window.__ModuleLoader__.load({
|
|
|
2616
2984
|
}
|
|
2617
2985
|
};
|
|
2618
2986
|
}
|
|
2619
|
-
/** 载体:宿主注册 `connection.fetch.register` 的路径 / 面板 `connection.rpc.call` 的两段参数。 */
|
|
2620
2987
|
const MANAGER_RPC = {
|
|
2621
|
-
/** 载体基段(`connection.rpc.call` 的**第一段**参数)。传错第一段就是 404:真机上踩过一次。 */
|
|
2622
2988
|
base: "/api",
|
|
2623
|
-
/** 单段通道名,须 match `/^\/[A-Za-z0-9._~-]+$/`(cookbook §6)。 */
|
|
2624
2989
|
channel: "/ilife-manager",
|
|
2625
|
-
/** 面板侧第二段参数(等于通道名去掉前导斜杠那一段)。 */
|
|
2626
2990
|
endpoint: "ilife-manager",
|
|
2627
|
-
/** 宿主侧注册的完整路径(= `base` + `channel`)。 */
|
|
2628
2991
|
path: "/api/ilife-manager"
|
|
2629
2992
|
};
|
|
2630
|
-
|
|
2631
|
-
const MANAGER_ACTIONS = {
|
|
2632
|
-
/** 装上缺席的目标包:入参 `{packageName, version}`,回包 `{packageName, version}`。 */
|
|
2633
|
-
install: "ilife-manager.install",
|
|
2634
|
-
/** 七个更新目标的表:入参 `{}`,回包 `{targets: [{key, title, packageName, phones, runningVersion, installedVersion, panelRegistered, skill}]}`。
|
|
2635
|
-
*
|
|
2636
|
-
* 电话名为什么由宿主转交而不是面板侧写死:更新包的三个电话名只有它自己知道
|
|
2637
|
-
* (`update.phoneNames`,`host.ts:335`);面板侧既不能 import 更新包(浏览器产物纯度门)
|
|
2638
|
-
* 也不该把名字再写一份(写两份必然走散)。宿主把名字表连同版本行一起交出去,
|
|
2639
|
-
* 面板一行字面量都不留。 */
|
|
2640
|
-
targets: "ilife-manager.targets",
|
|
2641
|
-
/** 本机「根」清单(票 #744):入参 `{}`,回包 `{roots: [{path, kind}]}`。
|
|
2642
|
-
*
|
|
2643
|
-
* 为什么这条能力住在总管:浏览器里没有卷清单接口,而宿主那条目录选择接缝只有
|
|
2644
|
-
* `list`/`createDirectory` 两格——「这台机器上有哪些盘」只能由宿主去问操作系统。
|
|
2645
|
-
* 六家的目录浏览器都取这一通电话,故名字与实现都只有这一处(清单本身见 `roots.ts`)。
|
|
2646
|
-
* 回包**恒成功**:列不出来是空清单,不是错误码(界面据此只是不画那一行)。 */
|
|
2647
|
-
roots: "ilife-manager.roots"
|
|
2648
|
-
};
|
|
2993
|
+
const MANAGER_ACTIONS = { roots: "ilife-manager.roots" };
|
|
2649
2994
|
//#endregion
|
|
2650
2995
|
//#region ../plugin-manager/src/config-panel.ts
|
|
2651
2996
|
/** 共用配置面板 · 组件本体:一台状态机 + 一圈副作用,渲染交给 `config-panel-view.ts`。
|
|
@@ -2874,7 +3219,7 @@ window.__ModuleLoader__.load({
|
|
|
2874
3219
|
});
|
|
2875
3220
|
if (opened === void 0 || await opened === "refused") await openNative(key);
|
|
2876
3221
|
};
|
|
2877
|
-
/** 复制一行(定稿 v3 第三条):写完就地变「已复制」(写不进去就地变「复制失败」),
|
|
3222
|
+
/** 复制一行(定稿 v3 第三条):写完就地变「已复制」(写不进去就地变「复制失败」),900ms 后复位,不弹提示(#1162 差值终结:终值 900ms,行为跟 COPY_FEEDBACK_MS 走)。 */
|
|
2878
3223
|
const onCopy = (key, text) => {
|
|
2879
3224
|
writeClipboard(text).then((ok) => {
|
|
2880
3225
|
setCopy({
|
|
@@ -2885,7 +3230,7 @@ window.__ModuleLoader__.load({
|
|
|
2885
3230
|
copyTimer.current = setTimeout(() => {
|
|
2886
3231
|
copyTimer.current = null;
|
|
2887
3232
|
setCopy(null);
|
|
2888
|
-
},
|
|
3233
|
+
}, 900);
|
|
2889
3234
|
});
|
|
2890
3235
|
};
|
|
2891
3236
|
const onSave = async () => {
|