dsh-calorie 0.3.38 → 0.3.40
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 +173 -140
- 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
|
}
|
|
@@ -1183,10 +1234,16 @@ window.__ModuleLoader__.load({
|
|
|
1183
1234
|
/** 糙边滤镜 id(文档作用域,故每页只许挂一次 `SealFilterDefs`)。 */
|
|
1184
1235
|
const ROUGH_EDGE = "dshLifeSealRoughEdge";
|
|
1185
1236
|
const ROUGH_FRAME = "dshLifeSealRoughFrame";
|
|
1186
|
-
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1237
|
+
/** 档位话:标题下那一行不再印档位字,直接说档位所处的阶段(渲染期用,顶层可放行)。 */
|
|
1238
|
+
const TIER_TEXT = {
|
|
1239
|
+
gold: "精雕细琢中",
|
|
1240
|
+
silver: "全打通中",
|
|
1241
|
+
copper: "基础建设中"
|
|
1242
|
+
};
|
|
1243
|
+
/** 纸面四色是印自带的(羊皮纸底+ availability 墨色),不跟宿主主题跑——
|
|
1244
|
+
* 深色下宿主变量会把纸染黑,故这里写死定稿值;字族仍继承(定稿零字族)。 */
|
|
1245
|
+
const PAPER_BG = "#fdfaf2";
|
|
1246
|
+
const LABEL_SUB = "#4b4335";
|
|
1190
1247
|
/** 九档材质(3 角色 × 3 档)。键就是原型里的 `role`/`tier`。 */
|
|
1191
1248
|
const MATERIALS = {
|
|
1192
1249
|
skill: {
|
|
@@ -1316,20 +1373,17 @@ window.__ModuleLoader__.load({
|
|
|
1316
1373
|
zIndex: 2,
|
|
1317
1374
|
borderRadius: "0.25em",
|
|
1318
1375
|
background: PAPER_BG,
|
|
1319
|
-
boxShadow: "0 1px 3px #3d241052, 0 0 0 1px
|
|
1376
|
+
boxShadow: "0 1px 3px #3d241052, 0 0 0 1px #e6d9bd, inset 0 1px 0 #fffefb"
|
|
1320
1377
|
},
|
|
1321
1378
|
inner: {
|
|
1322
1379
|
position: "relative",
|
|
1323
1380
|
padding: "1.75em 2em 1.875em"
|
|
1324
1381
|
},
|
|
1325
|
-
head: {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
fontSize: "1em",
|
|
1329
|
-
fontWeight: 600,
|
|
1330
|
-
letterSpacing: "0.16em",
|
|
1331
|
-
color: LABEL_MAIN
|
|
1382
|
+
head: {
|
|
1383
|
+
textAlign: "center",
|
|
1384
|
+
marginBottom: "0.5em"
|
|
1332
1385
|
},
|
|
1386
|
+
/** 档位语(标题下那一行):档位字退役,改说档位话(金=精雕细琢中/银=全打通中/铜=基础建设中)。 */
|
|
1333
1387
|
tier: {
|
|
1334
1388
|
marginTop: "0.4375em",
|
|
1335
1389
|
fontSize: "0.66em",
|
|
@@ -1358,7 +1412,7 @@ window.__ModuleLoader__.load({
|
|
|
1358
1412
|
blockDivided: {
|
|
1359
1413
|
margin: "0 0 0.9375em",
|
|
1360
1414
|
paddingTop: "0.9375em",
|
|
1361
|
-
borderTop: "1px solid "
|
|
1415
|
+
borderTop: "1px solid #e6d9bd"
|
|
1362
1416
|
},
|
|
1363
1417
|
blockLast: { margin: 0 },
|
|
1364
1418
|
label: {
|
|
@@ -1375,21 +1429,26 @@ window.__ModuleLoader__.load({
|
|
|
1375
1429
|
letterSpacing: "0.02em",
|
|
1376
1430
|
color: LABEL_SUB
|
|
1377
1431
|
},
|
|
1378
|
-
/**
|
|
1379
|
-
|
|
1380
|
-
position: "fixed",
|
|
1381
|
-
inset: 0,
|
|
1382
|
-
background: "#241f1966",
|
|
1383
|
-
zIndex: 40
|
|
1384
|
-
},
|
|
1385
|
-
/** 弹层本体:居中,宽度按 em 给(16px 下≈25em)。 */
|
|
1432
|
+
/** 卷轴浮层:卡片内绝对定位(卡片 `S.card` 是 relative 定位祖先),上沿悬在三枚章之下、左右各留半 em——
|
|
1433
|
+
* 不是 modal:无遮罩、不锁滚动,点章切换、点「关闭」收起。 */
|
|
1386
1434
|
dialog: {
|
|
1387
|
-
position: "
|
|
1388
|
-
left: "
|
|
1389
|
-
|
|
1390
|
-
|
|
1435
|
+
position: "absolute",
|
|
1436
|
+
left: "0.5em",
|
|
1437
|
+
right: "0.5em",
|
|
1438
|
+
top: "8.8em",
|
|
1439
|
+
zIndex: 10,
|
|
1440
|
+
display: "flex",
|
|
1441
|
+
justifyContent: "center",
|
|
1442
|
+
pointerEvents: "auto"
|
|
1443
|
+
},
|
|
1444
|
+
/** 浮层内框:宽按 em 给(16px 下≈25em),窄卡上收满可用宽,永不捅破卡片;
|
|
1445
|
+
* 挂卷轴展开动画(从上而下舒卷,240ms;纯声明式,无 hook,纯函数可直测)。 */
|
|
1446
|
+
popInner: {
|
|
1447
|
+
position: "relative",
|
|
1391
1448
|
width: "25em",
|
|
1392
|
-
|
|
1449
|
+
maxWidth: "100%",
|
|
1450
|
+
transformOrigin: "50% 0",
|
|
1451
|
+
animation: "dshLifeSealUnroll 240ms ease-out"
|
|
1393
1452
|
},
|
|
1394
1453
|
close: {
|
|
1395
1454
|
position: "absolute",
|
|
@@ -1501,7 +1560,7 @@ window.__ModuleLoader__.load({
|
|
|
1501
1560
|
style: last ? divided ? {
|
|
1502
1561
|
...S$1.blockLast,
|
|
1503
1562
|
paddingTop: "0.9375em",
|
|
1504
|
-
borderTop: "1px solid "
|
|
1563
|
+
borderTop: "1px solid #e6d9bd"
|
|
1505
1564
|
} : S$1.blockLast : divided ? S$1.blockDivided : S$1.block
|
|
1506
1565
|
}, react.createElement("div", { style: {
|
|
1507
1566
|
...S$1.label,
|
|
@@ -1510,15 +1569,19 @@ window.__ModuleLoader__.load({
|
|
|
1510
1569
|
return react.createElement("div", { style: S$1.scroll }, react.createElement("div", { style: {
|
|
1511
1570
|
...S$1.frame,
|
|
1512
1571
|
...material.frame
|
|
1513
|
-
} }, ...frameChildren), react.createElement("div", { style: S$1.paper }, react.createElement("div", { style: S$1.inner }, react.createElement("div", { style: S$1.head }, react.createElement(
|
|
1572
|
+
} }, ...frameChildren), react.createElement("div", { style: S$1.paper }, react.createElement("div", { style: S$1.inner }, react.createElement("div", { style: S$1.head }, react.createElement(SealStamp, {
|
|
1573
|
+
role: props.role,
|
|
1574
|
+
tier: props.tier,
|
|
1575
|
+
label: props.title
|
|
1576
|
+
}), react.createElement("div", { style: {
|
|
1514
1577
|
...S$1.tier,
|
|
1515
1578
|
color: material.accent
|
|
1516
|
-
} }, props.tier
|
|
1579
|
+
} }, TIER_TEXT[props.tier])), react.createElement("div", { style: S$1.orn }, line("l", "90"), react.createElement("i", { style: {
|
|
1517
1580
|
...S$1.ornDot,
|
|
1518
1581
|
background: material.accent
|
|
1519
1582
|
} }), line("r", "270")), block("progress", "进展", props.progress, false), block("status", "状态", props.status, true), block("plan", "计划", props.plan, true, true))));
|
|
1520
1583
|
}
|
|
1521
|
-
/**
|
|
1584
|
+
/** 卷轴浮层:popover + 点击别处关闭 + 卷轴展开动画 + 关闭。`open` 为假时不渲染(纯函数,不收自己的状态)。 */
|
|
1522
1585
|
function SealScrollDialog(props) {
|
|
1523
1586
|
if (!props.open) return null;
|
|
1524
1587
|
const scroll = {
|
|
@@ -1530,19 +1593,25 @@ window.__ModuleLoader__.load({
|
|
|
1530
1593
|
plan: props.plan
|
|
1531
1594
|
};
|
|
1532
1595
|
return react.createElement(react.Fragment, null, react.createElement("div", {
|
|
1533
|
-
style:
|
|
1534
|
-
|
|
1535
|
-
|
|
1596
|
+
style: {
|
|
1597
|
+
position: "fixed",
|
|
1598
|
+
inset: 0,
|
|
1599
|
+
zIndex: 9,
|
|
1600
|
+
background: "transparent"
|
|
1601
|
+
},
|
|
1602
|
+
"aria-hidden": true,
|
|
1603
|
+
onClick: props.onClose
|
|
1536
1604
|
}), react.createElement("div", {
|
|
1537
1605
|
style: S$1.dialog,
|
|
1538
1606
|
role: "dialog",
|
|
1539
|
-
"aria-modal":
|
|
1607
|
+
"aria-modal": false,
|
|
1540
1608
|
"aria-label": props.title
|
|
1541
|
-
}, react.createElement("button", {
|
|
1609
|
+
}, 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 }, react.createElement("button", {
|
|
1542
1610
|
type: "button",
|
|
1543
1611
|
style: S$1.close,
|
|
1612
|
+
"data-ilife-press": "seal-close",
|
|
1544
1613
|
onClick: props.onClose
|
|
1545
|
-
}, "关闭"), react.createElement(SealScroll, scroll)));
|
|
1614
|
+
}, "关闭"), react.createElement(SealScroll, scroll))));
|
|
1546
1615
|
}
|
|
1547
1616
|
//#endregion
|
|
1548
1617
|
//#region ../plugin-manager/src/seal-stamp.ts
|
|
@@ -1770,6 +1839,9 @@ window.__ModuleLoader__.load({
|
|
|
1770
1839
|
const PANEL_FIELD_EDGE = inkMix(24);
|
|
1771
1840
|
/** 骨架条:浅色 ≈`#c9ccd2`(1.6:1)⇔ 深色 ≈`#404143`。 */
|
|
1772
1841
|
const PANEL_SKELETON_FILL = inkMix(21);
|
|
1842
|
+
function interactionCss() {
|
|
1843
|
+
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}}";
|
|
1844
|
+
}
|
|
1773
1845
|
const S = {
|
|
1774
1846
|
/** `.ic-card`:`background:var(--ic-surface)`(=bg-layer-1)+`border:1px solid var(--ic-line-strong)`
|
|
1775
1847
|
* +`border-radius:12px`+`padding:14px`+`box-shadow:inset 0 1px 0 rgba(255,255,255,.06)`。
|
|
@@ -2312,6 +2384,8 @@ window.__ModuleLoader__.load({
|
|
|
2312
2384
|
style: S.btnPick,
|
|
2313
2385
|
type: "button",
|
|
2314
2386
|
disabled: props.onCopy === void 0,
|
|
2387
|
+
"data-ilife-press": "copy",
|
|
2388
|
+
"data-ilife-longpress": "copy",
|
|
2315
2389
|
onClick: () => props.onCopy?.(item.key, props.value)
|
|
2316
2390
|
}, copyLabelOf(props.copyState));
|
|
2317
2391
|
const follow = props.follow === true ? react.createElement("span", { style: S.follow }, react.createElement("span", { style: S.followMark }, "↳"), "将跟随更新") : null;
|
|
@@ -2326,6 +2400,7 @@ window.__ModuleLoader__.load({
|
|
|
2326
2400
|
style: S.checkbox,
|
|
2327
2401
|
checked: props.value === "true",
|
|
2328
2402
|
disabled,
|
|
2403
|
+
"data-ilife-focus": "input",
|
|
2329
2404
|
onChange: (e) => props.onChange(item.key, e.target.checked ? "true" : "false")
|
|
2330
2405
|
}) : react.createElement("input", {
|
|
2331
2406
|
style: props.dirty === true ? S.inputDirty : S.input,
|
|
@@ -2333,6 +2408,7 @@ window.__ModuleLoader__.load({
|
|
|
2333
2408
|
value: props.value,
|
|
2334
2409
|
disabled,
|
|
2335
2410
|
spellCheck: false,
|
|
2411
|
+
"data-ilife-focus": "input",
|
|
2336
2412
|
onChange
|
|
2337
2413
|
});
|
|
2338
2414
|
/** 目录入口:只读行不画(定稿 v3 ①),供不了(`none`/缺席)也不画。 */
|
|
@@ -2341,6 +2417,8 @@ window.__ModuleLoader__.load({
|
|
|
2341
2417
|
style: S.btnPick,
|
|
2342
2418
|
type: "button",
|
|
2343
2419
|
disabled,
|
|
2420
|
+
"data-ilife-press": "browse",
|
|
2421
|
+
"data-ilife-longpress": "browse",
|
|
2344
2422
|
onClick: () => entry.onOpen(item.key)
|
|
2345
2423
|
}, "浏览文件夹") : null;
|
|
2346
2424
|
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));
|
|
@@ -2370,94 +2448,47 @@ window.__ModuleLoader__.load({
|
|
|
2370
2448
|
const surface = state.kind === "ready" ? state.surface : null;
|
|
2371
2449
|
const product = title ?? "";
|
|
2372
2450
|
const seals = props.seals ?? [];
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
-1,
|
|
2378
|
-
-3,
|
|
2379
|
-
1.5,
|
|
2380
|
-
3,
|
|
2381
|
-
-1.5,
|
|
2382
|
-
2,
|
|
2383
|
-
4,
|
|
2384
|
-
-3.5,
|
|
2385
|
-
.5,
|
|
2386
|
-
2.5,
|
|
2387
|
-
-4.5,
|
|
2451
|
+
const seed = props.sealSeed ?? 0;
|
|
2452
|
+
/** 三行定序(六家一致:HELP 上/技能中/插件下;HELP 永远 z 最上)。 */
|
|
2453
|
+
const order = [
|
|
2454
|
+
0,
|
|
2388
2455
|
1,
|
|
2389
|
-
|
|
2390
|
-
3.5,
|
|
2391
|
-
-.5,
|
|
2392
|
-
4.5
|
|
2456
|
+
2
|
|
2393
2457
|
];
|
|
2394
|
-
/**
|
|
2395
|
-
const
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
},
|
|
2400
|
-
{
|
|
2401
|
-
left: "5%",
|
|
2402
|
-
top: "2.8em"
|
|
2403
|
-
},
|
|
2404
|
-
{
|
|
2405
|
-
left: "50%",
|
|
2406
|
-
top: "5em"
|
|
2407
|
-
}
|
|
2458
|
+
/** 三行行高(上/中/下;纵向净空各留约 10px,糙边抖动也碰不到)。 */
|
|
2459
|
+
const TOPS = [
|
|
2460
|
+
"0.3em",
|
|
2461
|
+
"3.4em",
|
|
2462
|
+
"6.2em"
|
|
2408
2463
|
];
|
|
2409
|
-
|
|
2410
|
-
const
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
[
|
|
2417
|
-
1,
|
|
2418
|
-
2,
|
|
2419
|
-
0
|
|
2420
|
-
],
|
|
2421
|
-
[
|
|
2422
|
-
2,
|
|
2423
|
-
0,
|
|
2424
|
-
1
|
|
2425
|
-
],
|
|
2426
|
-
[
|
|
2427
|
-
0,
|
|
2428
|
-
2,
|
|
2429
|
-
1
|
|
2430
|
-
],
|
|
2431
|
-
[
|
|
2432
|
-
1,
|
|
2433
|
-
0,
|
|
2434
|
-
2
|
|
2435
|
-
],
|
|
2436
|
-
[
|
|
2437
|
-
2,
|
|
2438
|
-
1,
|
|
2439
|
-
0
|
|
2440
|
-
]
|
|
2441
|
-
][seed % 6];
|
|
2442
|
-
const tiltOfSlot = (slot) => String(TILT18[(seed * 3 + slot) % 18]);
|
|
2464
|
+
/** 轻微倾角(±0.5°~±2.5°,方向随机):家下标×槽位哈希,纯函数、每次同值,不过大。 */
|
|
2465
|
+
const tiltOfSlot = (slot) => {
|
|
2466
|
+
const q = (seed * 5 + slot * 11 + 3) % 10;
|
|
2467
|
+
return String((q % 2 === 0 ? -1 : 1) * (.5 + Math.floor(q / 2) * .5));
|
|
2468
|
+
};
|
|
2469
|
+
/** 右间距(三枚全部居右收敛,各家各行 0.2em~1.1em 错开,永不出面板右边界)。 */
|
|
2470
|
+
const padRightOfSlot = (slot) => String(.2 + (seed * 7 + slot * 3 + 1) % 6 * .18) + "em";
|
|
2443
2471
|
const zOfRole = (role) => role === "help" ? 4 : role === "skill" ? 3 : 2;
|
|
2444
2472
|
const overlay = seals.length === 0 ? null : react.createElement("div", { style: S.sealOverlay }, react.createElement(SealFilterDefs, {}), ...order.map((dataIndex, slot) => react.createElement("span", {
|
|
2445
2473
|
key: seals[dataIndex].role + ":" + seals[dataIndex].tier,
|
|
2446
2474
|
style: {
|
|
2447
2475
|
position: "absolute",
|
|
2448
|
-
|
|
2449
|
-
|
|
2476
|
+
top: TOPS[slot],
|
|
2477
|
+
right: padRightOfSlot(slot),
|
|
2450
2478
|
zIndex: zOfRole(seals[dataIndex].role),
|
|
2451
2479
|
pointerEvents: "auto",
|
|
2452
2480
|
display: "inline-flex",
|
|
2453
2481
|
transform: "rotate(" + tiltOfSlot(slot) + "deg)"
|
|
2454
2482
|
}
|
|
2455
|
-
}, react.createElement(
|
|
2483
|
+
}, react.createElement("span", { style: {
|
|
2484
|
+
fontSize: "0.8em",
|
|
2485
|
+
display: "inline-flex"
|
|
2486
|
+
} }, react.createElement(SealStamp, {
|
|
2456
2487
|
role: seals[dataIndex].role,
|
|
2457
2488
|
tier: seals[dataIndex].tier,
|
|
2458
2489
|
label: seals[dataIndex].label,
|
|
2459
2490
|
onSelect: props.onSealSelect === void 0 ? void 0 : props.onSealSelect.bind(null, dataIndex)
|
|
2460
|
-
}))));
|
|
2491
|
+
})))));
|
|
2461
2492
|
const openSeal = props.selectedSeal === null || props.selectedSeal === void 0 ? null : seals[props.selectedSeal] ?? null;
|
|
2462
2493
|
const dialog = openSeal === null ? null : react.createElement(SealScrollDialog, {
|
|
2463
2494
|
open: true,
|
|
@@ -2517,12 +2548,16 @@ window.__ModuleLoader__.load({
|
|
|
2517
2548
|
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", {
|
|
2518
2549
|
style: S.btn,
|
|
2519
2550
|
type: "button",
|
|
2551
|
+
"data-ilife-press": "retry",
|
|
2552
|
+
"data-ilife-longpress": "retry",
|
|
2520
2553
|
onClick: props.onRetry
|
|
2521
2554
|
}, "重试"), react.createElement("button", {
|
|
2522
2555
|
style: S.btn,
|
|
2523
2556
|
type: "button",
|
|
2557
|
+
"data-ilife-press": "reset",
|
|
2558
|
+
"data-ilife-longpress": "reset",
|
|
2524
2559
|
onClick: props.onReset
|
|
2525
|
-
}, "重置为默认")));
|
|
2560
|
+
}, "重置为默认")), react.createElement("style", { "data-ilife-interaction": "t1" }, interactionCss()));
|
|
2526
2561
|
const common = props.items.filter((item) => item.tier === "common");
|
|
2527
2562
|
const advanced = props.items.filter((item) => item.tier === "advanced");
|
|
2528
2563
|
/** 还没读到整面(`loading`)时**框架照画**:行表与控件形状是客户端常量,不必等任何回执。
|
|
@@ -2552,20 +2587,38 @@ window.__ModuleLoader__.load({
|
|
|
2552
2587
|
const commonLast = lastIndexOf(common);
|
|
2553
2588
|
const advancedLast = lastIndexOf(advanced);
|
|
2554
2589
|
const dirty = ready && dirtyCount > 0;
|
|
2555
|
-
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", {
|
|
2590
|
+
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", {
|
|
2591
|
+
style: S.advanced,
|
|
2592
|
+
"data-ilife-advanced": "group"
|
|
2593
|
+
}, react.createElement("summary", {
|
|
2594
|
+
style: S.summary,
|
|
2595
|
+
"data-ilife-advanced": "head"
|
|
2596
|
+
}, react.createElement("span", {
|
|
2597
|
+
style: S.groupMark,
|
|
2598
|
+
"data-ilife-advanced": "mark"
|
|
2599
|
+
}, "›"), ADVANCED_GROUP_TITLE), react.createElement("div", {
|
|
2600
|
+
style: S.groupBody,
|
|
2601
|
+
"data-ilife-advanced": "body"
|
|
2602
|
+
}, advanced.map((item, index) => renderRow(item, index === advancedLast)))), extra, react.createElement("div", { style: S.bar }, react.createElement("button", {
|
|
2556
2603
|
style: dirty ? S.btnPrimary : S.btn,
|
|
2557
2604
|
type: "button",
|
|
2558
2605
|
disabled: frozen || !dirty,
|
|
2606
|
+
"data-ilife-press": "save",
|
|
2607
|
+
"data-ilife-longpress": "save",
|
|
2559
2608
|
onClick: props.onSave
|
|
2560
2609
|
}, props.busy ? "处理中" : dirty ? `保存(${dirtyCount} 项未保存)` : "保存"), react.createElement("button", {
|
|
2561
2610
|
style: S.btn,
|
|
2562
2611
|
type: "button",
|
|
2563
2612
|
disabled: frozen,
|
|
2613
|
+
"data-ilife-press": "reset",
|
|
2614
|
+
"data-ilife-longpress": "reset",
|
|
2564
2615
|
onClick: props.onReset
|
|
2565
2616
|
}, "重置为默认"), react.createElement("button", {
|
|
2566
2617
|
style: S.btn,
|
|
2567
2618
|
type: "button",
|
|
2568
2619
|
disabled: frozen,
|
|
2620
|
+
"data-ilife-press": "retry",
|
|
2621
|
+
"data-ilife-longpress": "retry",
|
|
2569
2622
|
onClick: props.onRetry
|
|
2570
2623
|
}, "重新读取"), 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, {
|
|
2571
2624
|
open: true,
|
|
@@ -2574,7 +2627,10 @@ window.__ModuleLoader__.load({
|
|
|
2574
2627
|
}) : null, props.writeError !== null ? react.createElement("div", {
|
|
2575
2628
|
style: S.error,
|
|
2576
2629
|
role: "alert"
|
|
2577
|
-
}, props.writeError) : null, props.error !== null ? react.createElement("div", { style: S.error }, props.error) : null, props.notice !== null ? react.createElement("div", {
|
|
2630
|
+
}, props.writeError) : null, props.error !== null ? react.createElement("div", { style: S.error }, props.error) : null, props.notice !== null ? react.createElement("div", {
|
|
2631
|
+
style: S.okText,
|
|
2632
|
+
"data-ilife-notice": "line"
|
|
2633
|
+
}, props.notice) : null, overlay, react.createElement("style", { "data-ilife-interaction": "t1" }, interactionCss()));
|
|
2578
2634
|
}
|
|
2579
2635
|
//#endregion
|
|
2580
2636
|
//#region ../plugin-manager/src/directory-browser-roots.ts
|
|
@@ -2612,36 +2668,13 @@ window.__ModuleLoader__.load({
|
|
|
2612
2668
|
}
|
|
2613
2669
|
};
|
|
2614
2670
|
}
|
|
2615
|
-
/** 载体:宿主注册 `connection.fetch.register` 的路径 / 面板 `connection.rpc.call` 的两段参数。 */
|
|
2616
2671
|
const MANAGER_RPC = {
|
|
2617
|
-
/** 载体基段(`connection.rpc.call` 的**第一段**参数)。传错第一段就是 404:真机上踩过一次。 */
|
|
2618
2672
|
base: "/api",
|
|
2619
|
-
/** 单段通道名,须 match `/^\/[A-Za-z0-9._~-]+$/`(cookbook §6)。 */
|
|
2620
2673
|
channel: "/ilife-manager",
|
|
2621
|
-
/** 面板侧第二段参数(等于通道名去掉前导斜杠那一段)。 */
|
|
2622
2674
|
endpoint: "ilife-manager",
|
|
2623
|
-
/** 宿主侧注册的完整路径(= `base` + `channel`)。 */
|
|
2624
2675
|
path: "/api/ilife-manager"
|
|
2625
2676
|
};
|
|
2626
|
-
|
|
2627
|
-
const MANAGER_ACTIONS = {
|
|
2628
|
-
/** 装上缺席的目标包:入参 `{packageName, version}`,回包 `{packageName, version}`。 */
|
|
2629
|
-
install: "ilife-manager.install",
|
|
2630
|
-
/** 七个更新目标的表:入参 `{}`,回包 `{targets: [{key, title, packageName, phones, runningVersion, installedVersion, panelRegistered, skill}]}`。
|
|
2631
|
-
*
|
|
2632
|
-
* 电话名为什么由宿主转交而不是面板侧写死:更新包的三个电话名只有它自己知道
|
|
2633
|
-
* (`update.phoneNames`,`host.ts:335`);面板侧既不能 import 更新包(浏览器产物纯度门)
|
|
2634
|
-
* 也不该把名字再写一份(写两份必然走散)。宿主把名字表连同版本行一起交出去,
|
|
2635
|
-
* 面板一行字面量都不留。 */
|
|
2636
|
-
targets: "ilife-manager.targets",
|
|
2637
|
-
/** 本机「根」清单(票 #744):入参 `{}`,回包 `{roots: [{path, kind}]}`。
|
|
2638
|
-
*
|
|
2639
|
-
* 为什么这条能力住在总管:浏览器里没有卷清单接口,而宿主那条目录选择接缝只有
|
|
2640
|
-
* `list`/`createDirectory` 两格——「这台机器上有哪些盘」只能由宿主去问操作系统。
|
|
2641
|
-
* 六家的目录浏览器都取这一通电话,故名字与实现都只有这一处(清单本身见 `roots.ts`)。
|
|
2642
|
-
* 回包**恒成功**:列不出来是空清单,不是错误码(界面据此只是不画那一行)。 */
|
|
2643
|
-
roots: "ilife-manager.roots"
|
|
2644
|
-
};
|
|
2677
|
+
const MANAGER_ACTIONS = { roots: "ilife-manager.roots" };
|
|
2645
2678
|
//#endregion
|
|
2646
2679
|
//#region ../plugin-manager/src/config-panel.ts
|
|
2647
2680
|
/** 共用配置面板 · 组件本体:一台状态机 + 一圈副作用,渲染交给 `config-panel-view.ts`。
|
|
@@ -2870,7 +2903,7 @@ window.__ModuleLoader__.load({
|
|
|
2870
2903
|
});
|
|
2871
2904
|
if (opened === void 0 || await opened === "refused") await openNative(key);
|
|
2872
2905
|
};
|
|
2873
|
-
/** 复制一行(定稿 v3 第三条):写完就地变「已复制」(写不进去就地变「复制失败」),
|
|
2906
|
+
/** 复制一行(定稿 v3 第三条):写完就地变「已复制」(写不进去就地变「复制失败」),900ms 后复位,不弹提示(#1162 差值终结:终值 900ms,行为跟 COPY_FEEDBACK_MS 走)。 */
|
|
2874
2907
|
const onCopy = (key, text) => {
|
|
2875
2908
|
writeClipboard(text).then((ok) => {
|
|
2876
2909
|
setCopy({
|
|
@@ -2881,7 +2914,7 @@ window.__ModuleLoader__.load({
|
|
|
2881
2914
|
copyTimer.current = setTimeout(() => {
|
|
2882
2915
|
copyTimer.current = null;
|
|
2883
2916
|
setCopy(null);
|
|
2884
|
-
},
|
|
2917
|
+
}, 900);
|
|
2885
2918
|
});
|
|
2886
2919
|
};
|
|
2887
2920
|
const onSave = async () => {
|
|
@@ -2922,7 +2955,7 @@ window.__ModuleLoader__.load({
|
|
|
2922
2955
|
seals: props.seals,
|
|
2923
2956
|
sealSeed: props.sealSeed,
|
|
2924
2957
|
selectedSeal,
|
|
2925
|
-
onSealSelect: (index) => setSelectedSeal(index),
|
|
2958
|
+
onSealSelect: (index) => setSelectedSeal((prev) => prev === index ? null : index),
|
|
2926
2959
|
onSealClose: () => setSelectedSeal(null),
|
|
2927
2960
|
items: props.items,
|
|
2928
2961
|
state,
|