dsh-niuma 0.2.2 → 0.2.3
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/CHANGELOG.md +18 -0
- package/README.md +2 -1
- package/docs/preview-light-dark.png +0 -0
- package/lib/client.js +193 -161
- package/lib/client.js.map +2 -2
- package/lib/index.js +93 -3
- package/lib/update.js +247 -0
- package/package.json +4 -3
- package/src/client/index.js +154 -122
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
本文件记录用户可感知的变化。版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## 0.2.3 — 2026-10-22
|
|
6
|
+
|
|
7
|
+
### 新增:版本号显示 + 自动更新机制
|
|
8
|
+
|
|
9
|
+
- **面板底部显示版本号**:`牛马加速器 v0.2.x`(取自宿主 package.json,固定放最底部)
|
|
10
|
+
- **自动检查更新**:宿主启动 8 秒后查一次 npm `dsh-niuma@latest`;有新版本自动下载 tarball 解包到
|
|
11
|
+
`$DSH_HOME/niuma/updates/<version>/`,**下次启动 DSH 自动覆盖安装并生效**
|
|
12
|
+
- **手动更新**:面板发现新版本时显示「发现新版本 vX · 立即更新」按钮,点击即下载(重启生效)
|
|
13
|
+
- **安全守卫**:
|
|
14
|
+
- git 开发工作区(存在 `.git`)不自动更新,避免覆盖未提交代码
|
|
15
|
+
- `NIUMA_UPDATE_DISABLED=1` 可整体关闭
|
|
16
|
+
- 网络失败只写日志,面板继续用当前版本,不影响计时
|
|
17
|
+
- 版本比较用内部 semver 实现,不引第三方依赖
|
|
18
|
+
- 新增 `GET/POST /niuma/update` 路由;`GET /niuma/config` 载荷增加 `version`
|
|
19
|
+
- 主金额改为纯文本渲染(逐位轮盘在面板滚动容器里会出现重影);「加速」= 毫秒级刷新(rAF),
|
|
20
|
+
末位小数每帧高速变化,视觉上就是数字持续快速上涨
|
|
21
|
+
- 新增 `lib/update.js`(semver 比较、tarball 解包、暂存/应用)与 `tools/verify-update.mjs`(27 项断言)
|
|
22
|
+
|
|
5
23
|
## 0.2.2 — 2026-10-22
|
|
6
24
|
|
|
7
25
|
### 新增:主金额小数位 + 刷新频率 + 滚动数字/加速
|
package/README.md
CHANGED
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
- 节假日数据内置在插件中(2026 官方 / 2027 预估),设置区不再需要手工维护一长串日期;2027 官方安排公布后随插件更新
|
|
33
33
|
- 午休可设置起止,**可勾选午休是否算工时**;午休不算工时则午休期间金额冻结
|
|
34
34
|
- 状态徽标:休息日 / 未上班 / 搬砖中 / 午休中 / 已下班
|
|
35
|
-
-
|
|
35
|
+
- 面板显示版本号;自动检查 npm 新版本,下载后**重启 DSH 自动生效**(git 开发工作区不覆盖)
|
|
36
|
+
- **加速**:勾选后按屏幕刷新率(≈16ms)刷新,末位小数高速跳动、数字快速上涨;不勾则按刷新频率步进
|
|
36
37
|
- 主金额**小数位可选(0–6)**,右侧下拉即时生效
|
|
37
38
|
- **刷新频率可选**:按秒 / 250ms / 100ms / 50ms / 屏幕刷新率(≈16ms 连续滚动)
|
|
38
39
|
- 今日进度条、距上班/距下班倒计时
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -558,14 +558,6 @@ var CARD = {
|
|
|
558
558
|
boxSizing: "border-box"
|
|
559
559
|
};
|
|
560
560
|
var NUM = { fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" };
|
|
561
|
-
var GOLD = {
|
|
562
|
-
color: "#D9A441",
|
|
563
|
-
backgroundImage: "linear-gradient(180deg, #FFE9A8 0%, #F2C14E 40%, #D79A2B 72%, #B87A16 100%)",
|
|
564
|
-
WebkitBackgroundClip: "text",
|
|
565
|
-
backgroundClip: "text",
|
|
566
|
-
WebkitTextFillColor: "transparent",
|
|
567
|
-
textShadow: "0 1px 0 rgba(0,0,0,.05)"
|
|
568
|
-
};
|
|
569
561
|
var GOLD_TINT = "#E7B84D";
|
|
570
562
|
var STATUS_META = {
|
|
571
563
|
rest: { key: "statusRest", color: C.label3 },
|
|
@@ -612,6 +604,10 @@ var zh = {
|
|
|
612
604
|
"decimalsLabel": "\u5C0F\u6570",
|
|
613
605
|
"decimalsUnit": "\u4F4D",
|
|
614
606
|
"turboLabel": "\u52A0\u901F",
|
|
607
|
+
"updateAvailable": "\u53D1\u73B0\u65B0\u7248\u672C v{version}",
|
|
608
|
+
"updateNow": "\u7ACB\u5373\u66F4\u65B0",
|
|
609
|
+
"updating": "\u6B63\u5728\u4E0B\u8F7D\u65B0\u7248\u672C\u2026",
|
|
610
|
+
"updateStaged": "v{version} \u5DF2\u4E0B\u8F7D \xB7 \u91CD\u542F DSH \u751F\u6548",
|
|
615
611
|
"refreshRate": "\u5237\u65B0\u9891\u7387",
|
|
616
612
|
"rateSecond": "\u6309\u79D2\uFF081s\uFF09",
|
|
617
613
|
"rateFrame": "\u5237\u65B0\u7387\uFF08\u224816ms\uFF09",
|
|
@@ -716,6 +712,10 @@ var en = {
|
|
|
716
712
|
"decimalsLabel": "Decimals",
|
|
717
713
|
"decimalsUnit": "dp",
|
|
718
714
|
"turboLabel": "Turbo",
|
|
715
|
+
"updateAvailable": "New version v{version}",
|
|
716
|
+
"updateNow": "Update now",
|
|
717
|
+
"updating": "Downloading update\u2026",
|
|
718
|
+
"updateStaged": "v{version} downloaded \xB7 restart DSH to apply",
|
|
719
719
|
"refreshRate": "Refresh rate",
|
|
720
720
|
"rateSecond": "Per second (1s)",
|
|
721
721
|
"rateFrame": "Display rate (~16ms)",
|
|
@@ -846,6 +846,35 @@ function useRemoteConfig() {
|
|
|
846
846
|
const refresh = import_react.default.useCallback(() => setTick((n) => n + 1), []);
|
|
847
847
|
return { ...state, refresh };
|
|
848
848
|
}
|
|
849
|
+
function useUpdateInfo() {
|
|
850
|
+
const [state, setState] = import_react.default.useState({ status: "loading", data: null, error: null });
|
|
851
|
+
const load = import_react.default.useCallback(() => {
|
|
852
|
+
if (typeof fetch !== "function") {
|
|
853
|
+
setState({ status: "failed", data: null, error: "fetch unavailable" });
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
fetch(`${ROUTE_BASE}/update`, { cache: "no-store", credentials: "same-origin" }).then(async (response) => {
|
|
857
|
+
const body = await response.json();
|
|
858
|
+
if (!response.ok || !body || body.ok !== true) throw new Error(body && body.error || `HTTP ${response.status}`);
|
|
859
|
+
return body.data || null;
|
|
860
|
+
}).then((data) => setState({ status: "ready", data, error: null })).catch((error) => setState({ status: "failed", data: null, error: String(error && error.message || error) }));
|
|
861
|
+
}, []);
|
|
862
|
+
import_react.default.useEffect(() => {
|
|
863
|
+
load();
|
|
864
|
+
const timer = setInterval(load, 6 * 3600 * 1e3);
|
|
865
|
+
return () => clearInterval(timer);
|
|
866
|
+
}, [load]);
|
|
867
|
+
const download = import_react.default.useCallback(() => {
|
|
868
|
+
setState((prev) => ({ ...prev, status: "updating" }));
|
|
869
|
+
if (typeof fetch !== "function") return;
|
|
870
|
+
fetch(`${ROUTE_BASE}/update`, { method: "POST", credentials: "same-origin" }).then(async (response) => {
|
|
871
|
+
const body = await response.json();
|
|
872
|
+
if (!response.ok || !body || body.ok !== true) throw new Error(body && body.error || `HTTP ${response.status}`);
|
|
873
|
+
return body.data || null;
|
|
874
|
+
}).then((data) => setState({ status: "ready", data, error: null })).catch((error) => setState({ status: "failed", data: null, error: String(error && error.message || error) }));
|
|
875
|
+
}, []);
|
|
876
|
+
return { ...state, reload: load, download };
|
|
877
|
+
}
|
|
849
878
|
function useClock(updateMs) {
|
|
850
879
|
const [now, setNow] = import_react.default.useState(() => /* @__PURE__ */ new Date());
|
|
851
880
|
import_react.default.useEffect(() => {
|
|
@@ -936,97 +965,17 @@ function SectionTitle(props) {
|
|
|
936
965
|
props.hint ? import_react.default.createElement("span", { key: "h", style: { fontSize: 10.5, color: C.label3, ...NUM } }, props.hint) : null
|
|
937
966
|
]);
|
|
938
967
|
}
|
|
939
|
-
var ROLL_BLOCKS = Array.from({ length: 11 }, (_, i) => String(i % 10));
|
|
940
|
-
function RollingDigit(props) {
|
|
941
|
-
const heightEm = 1.22;
|
|
942
|
-
const widthEm = 0.62;
|
|
943
|
-
const pos = Number.isFinite(props.position) ? props.position : 0;
|
|
944
|
-
const wheel = (pos % 10 + 10) % 10;
|
|
945
|
-
return import_react.default.createElement("span", {
|
|
946
|
-
"aria-hidden": "true",
|
|
947
|
-
style: {
|
|
948
|
-
display: "inline-block",
|
|
949
|
-
position: "relative",
|
|
950
|
-
overflow: "hidden",
|
|
951
|
-
width: `${widthEm}em`,
|
|
952
|
-
height: `${heightEm}em`,
|
|
953
|
-
verticalAlign: "baseline"
|
|
954
|
-
}
|
|
955
|
-
}, [
|
|
956
|
-
import_react.default.createElement("span", {
|
|
957
|
-
key: "ghost",
|
|
958
|
-
style: { visibility: "hidden", display: "block", height: `${heightEm}em`, lineHeight: `${heightEm}em` }
|
|
959
|
-
}, "0"),
|
|
960
|
-
import_react.default.createElement("span", {
|
|
961
|
-
key: "strip",
|
|
962
|
-
style: {
|
|
963
|
-
position: "absolute",
|
|
964
|
-
left: 0,
|
|
965
|
-
top: 0,
|
|
966
|
-
display: "flex",
|
|
967
|
-
flexDirection: "column",
|
|
968
|
-
transform: `translateY(${-(wheel * heightEm)}em)`,
|
|
969
|
-
willChange: "transform"
|
|
970
|
-
}
|
|
971
|
-
}, ROLL_BLOCKS.map((value, i) => import_react.default.createElement("span", {
|
|
972
|
-
key: i,
|
|
973
|
-
style: { display: "block", height: `${heightEm}em`, lineHeight: `${heightEm}em` }
|
|
974
|
-
}, value)))
|
|
975
|
-
]);
|
|
976
|
-
}
|
|
977
968
|
function RollingMoney(props) {
|
|
978
969
|
const decimals = Math.max(0, Math.min(6, Number.isInteger(props.decimals) ? props.decimals : 4));
|
|
979
|
-
const text = formatMoney(props.value, decimals);
|
|
980
|
-
const scale = 10 ** decimals;
|
|
981
|
-
const chars = text.split("");
|
|
982
|
-
const significances = new Array(chars.length).fill(-1);
|
|
983
|
-
let seen = 0;
|
|
984
|
-
for (let i = chars.length - 1; i >= 0; i -= 1) {
|
|
985
|
-
if (/[0-9]/.test(chars[i])) {
|
|
986
|
-
significances[i] = seen;
|
|
987
|
-
seen += 1;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
970
|
return import_react.default.createElement("span", {
|
|
991
971
|
style: {
|
|
992
|
-
display: "inline-
|
|
993
|
-
|
|
994
|
-
letterSpacing:
|
|
995
|
-
|
|
996
|
-
// 等宽字体保证每个数字轮宽度稳定(不裁字、不抖动)
|
|
997
|
-
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
972
|
+
display: "inline-block",
|
|
973
|
+
whiteSpace: "nowrap",
|
|
974
|
+
letterSpacing: "-1.2px",
|
|
975
|
+
fontVariantNumeric: "tabular-nums",
|
|
998
976
|
...props.style || {}
|
|
999
977
|
}
|
|
1000
|
-
},
|
|
1001
|
-
import_react.default.createElement("span", {
|
|
1002
|
-
key: "sr",
|
|
1003
|
-
style: {
|
|
1004
|
-
position: "absolute",
|
|
1005
|
-
width: 1,
|
|
1006
|
-
height: 1,
|
|
1007
|
-
padding: 0,
|
|
1008
|
-
margin: -1,
|
|
1009
|
-
overflow: "hidden",
|
|
1010
|
-
clip: "rect(0,0,0,0)",
|
|
1011
|
-
whiteSpace: "nowrap",
|
|
1012
|
-
border: 0
|
|
1013
|
-
}
|
|
1014
|
-
}, text),
|
|
1015
|
-
import_react.default.createElement("span", {
|
|
1016
|
-
key: "visual",
|
|
1017
|
-
"aria-hidden": "true",
|
|
1018
|
-
style: { display: "inline-flex", alignItems: "baseline" }
|
|
1019
|
-
}, chars.map((char, i) => {
|
|
1020
|
-
if (!/[0-9]/.test(char)) {
|
|
1021
|
-
return import_react.default.createElement("span", {
|
|
1022
|
-
key: `s${i}`,
|
|
1023
|
-
style: { display: "inline-block", lineHeight: "1.22em" }
|
|
1024
|
-
}, char);
|
|
1025
|
-
}
|
|
1026
|
-
const position = (Number(props.value) || 0) * scale / 10 ** significances[i];
|
|
1027
|
-
return import_react.default.createElement(RollingDigit, { key: `d${i}`, position });
|
|
1028
|
-
}))
|
|
1029
|
-
]);
|
|
978
|
+
}, formatMoney(props.value, decimals));
|
|
1030
979
|
}
|
|
1031
980
|
function HeroCard(props) {
|
|
1032
981
|
const t = props.t;
|
|
@@ -1083,11 +1032,70 @@ function HeroCard(props) {
|
|
|
1083
1032
|
}) : null,
|
|
1084
1033
|
t("earnedToday")
|
|
1085
1034
|
]),
|
|
1086
|
-
import_react.default.createElement(
|
|
1087
|
-
"
|
|
1088
|
-
{
|
|
1089
|
-
|
|
1090
|
-
|
|
1035
|
+
import_react.default.createElement("div", {
|
|
1036
|
+
key: "b",
|
|
1037
|
+
style: { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4 }
|
|
1038
|
+
}, [
|
|
1039
|
+
import_react.default.createElement(
|
|
1040
|
+
"span",
|
|
1041
|
+
{ key: "d", style: { fontSize: 11, color: C.label3, ...NUM } },
|
|
1042
|
+
`${t("todayOn")} ${snap.dateKey}`
|
|
1043
|
+
),
|
|
1044
|
+
import_react.default.createElement("div", { key: "c", style: { display: "inline-flex", alignItems: "center", gap: 6 } }, [
|
|
1045
|
+
import_react.default.createElement("label", {
|
|
1046
|
+
key: "dec",
|
|
1047
|
+
title: t("decimalsLabel"),
|
|
1048
|
+
style: { display: "inline-flex", alignItems: "center", gap: 3, fontSize: 10, color: C.label3, ...NUM }
|
|
1049
|
+
}, [
|
|
1050
|
+
import_react.default.createElement("span", { key: "l" }, t("decimalsLabel")),
|
|
1051
|
+
import_react.default.createElement("select", {
|
|
1052
|
+
key: "s",
|
|
1053
|
+
value: String(decimals),
|
|
1054
|
+
"aria-label": t("decimalsLabel"),
|
|
1055
|
+
onChange: (event) => onDecimalsChange && onDecimalsChange(Number(event.target.value)),
|
|
1056
|
+
style: {
|
|
1057
|
+
height: 22,
|
|
1058
|
+
padding: "0 2px",
|
|
1059
|
+
borderRadius: 6,
|
|
1060
|
+
border: `1px solid ${C.border1}`,
|
|
1061
|
+
background: C.layer2,
|
|
1062
|
+
color: C.label2,
|
|
1063
|
+
fontSize: 10.5,
|
|
1064
|
+
fontVariantNumeric: "tabular-nums",
|
|
1065
|
+
outline: "none",
|
|
1066
|
+
cursor: "pointer"
|
|
1067
|
+
}
|
|
1068
|
+
}, [0, 1, 2, 3, 4, 5, 6].map((n) => import_react.default.createElement("option", { key: n, value: String(n) }, String(n)))),
|
|
1069
|
+
import_react.default.createElement("span", { key: "u" }, t("decimalsUnit"))
|
|
1070
|
+
]),
|
|
1071
|
+
import_react.default.createElement("label", {
|
|
1072
|
+
key: "turbo",
|
|
1073
|
+
title: t("turboLabel"),
|
|
1074
|
+
style: {
|
|
1075
|
+
display: "inline-flex",
|
|
1076
|
+
alignItems: "center",
|
|
1077
|
+
gap: 3,
|
|
1078
|
+
fontSize: 10,
|
|
1079
|
+
padding: "1px 6px",
|
|
1080
|
+
borderRadius: 999,
|
|
1081
|
+
border: `1px solid ${turbo ? `color-mix(in srgb, ${GOLD_TINT} 60%, ${C.border1})` : C.border1}`,
|
|
1082
|
+
background: turbo ? `color-mix(in srgb, ${GOLD_TINT} 16%, transparent)` : "transparent",
|
|
1083
|
+
color: turbo ? C.label2 : C.label3,
|
|
1084
|
+
cursor: "pointer",
|
|
1085
|
+
...NUM
|
|
1086
|
+
}
|
|
1087
|
+
}, [
|
|
1088
|
+
import_react.default.createElement("input", {
|
|
1089
|
+
key: "i",
|
|
1090
|
+
type: "checkbox",
|
|
1091
|
+
checked: turbo,
|
|
1092
|
+
onChange: (event) => onTurboChange && onTurboChange(event.target.checked),
|
|
1093
|
+
style: { accentColor: GOLD_TINT, width: 12, height: 12, margin: 0, cursor: "inherit" }
|
|
1094
|
+
}),
|
|
1095
|
+
import_react.default.createElement("span", { key: "l" }, t("turboLabel"))
|
|
1096
|
+
])
|
|
1097
|
+
])
|
|
1098
|
+
])
|
|
1091
1099
|
]),
|
|
1092
1100
|
import_react.default.createElement("div", {
|
|
1093
1101
|
key: "amt",
|
|
@@ -1101,7 +1109,7 @@ function HeroCard(props) {
|
|
|
1101
1109
|
fontSize: 46,
|
|
1102
1110
|
lineHeight: 1.12,
|
|
1103
1111
|
fontWeight: 800,
|
|
1104
|
-
|
|
1112
|
+
color: "#D9A441",
|
|
1105
1113
|
...NUM,
|
|
1106
1114
|
...rest ? { opacity: 0.62 } : {}
|
|
1107
1115
|
}
|
|
@@ -1109,67 +1117,7 @@ function HeroCard(props) {
|
|
|
1109
1117
|
import_react.default.createElement("span", {
|
|
1110
1118
|
key: "unit",
|
|
1111
1119
|
style: { fontSize: 18, fontWeight: 700, color: C.label2, ...NUM }
|
|
1112
|
-
}, "\u5143")
|
|
1113
|
-
import_react.default.createElement("label", {
|
|
1114
|
-
key: "dec",
|
|
1115
|
-
title: t("decimalsLabel"),
|
|
1116
|
-
style: {
|
|
1117
|
-
marginLeft: "auto",
|
|
1118
|
-
display: "inline-flex",
|
|
1119
|
-
alignItems: "center",
|
|
1120
|
-
gap: 3,
|
|
1121
|
-
fontSize: 10,
|
|
1122
|
-
color: C.label3,
|
|
1123
|
-
...NUM
|
|
1124
|
-
}
|
|
1125
|
-
}, [
|
|
1126
|
-
import_react.default.createElement("span", { key: "l" }, t("decimalsLabel")),
|
|
1127
|
-
import_react.default.createElement("select", {
|
|
1128
|
-
key: "s",
|
|
1129
|
-
value: String(decimals),
|
|
1130
|
-
"aria-label": t("decimalsLabel"),
|
|
1131
|
-
onChange: (event) => onDecimalsChange && onDecimalsChange(Number(event.target.value)),
|
|
1132
|
-
style: {
|
|
1133
|
-
height: 22,
|
|
1134
|
-
padding: "0 2px",
|
|
1135
|
-
borderRadius: 6,
|
|
1136
|
-
border: `1px solid ${C.border1}`,
|
|
1137
|
-
background: C.layer2,
|
|
1138
|
-
color: C.label2,
|
|
1139
|
-
fontSize: 10.5,
|
|
1140
|
-
fontVariantNumeric: "tabular-nums",
|
|
1141
|
-
outline: "none",
|
|
1142
|
-
cursor: "pointer"
|
|
1143
|
-
}
|
|
1144
|
-
}, [0, 1, 2, 3, 4, 5, 6].map((n) => import_react.default.createElement("option", { key: n, value: String(n) }, String(n)))),
|
|
1145
|
-
import_react.default.createElement("span", { key: "u" }, t("decimalsUnit"))
|
|
1146
|
-
]),
|
|
1147
|
-
import_react.default.createElement("label", {
|
|
1148
|
-
key: "turbo",
|
|
1149
|
-
title: t("turboLabel"),
|
|
1150
|
-
style: {
|
|
1151
|
-
display: "inline-flex",
|
|
1152
|
-
alignItems: "center",
|
|
1153
|
-
gap: 3,
|
|
1154
|
-
fontSize: 10,
|
|
1155
|
-
padding: "1px 6px",
|
|
1156
|
-
borderRadius: 999,
|
|
1157
|
-
border: `1px solid ${turbo ? `color-mix(in srgb, ${GOLD_TINT} 60%, ${C.border1})` : C.border1}`,
|
|
1158
|
-
background: turbo ? `color-mix(in srgb, ${GOLD_TINT} 16%, transparent)` : "transparent",
|
|
1159
|
-
color: turbo ? C.label2 : C.label3,
|
|
1160
|
-
cursor: "pointer",
|
|
1161
|
-
...NUM
|
|
1162
|
-
}
|
|
1163
|
-
}, [
|
|
1164
|
-
import_react.default.createElement("input", {
|
|
1165
|
-
key: "i",
|
|
1166
|
-
type: "checkbox",
|
|
1167
|
-
checked: turbo,
|
|
1168
|
-
onChange: (event) => onTurboChange && onTurboChange(event.target.checked),
|
|
1169
|
-
style: { accentColor: GOLD_TINT, width: 12, height: 12, margin: 0, cursor: "inherit" }
|
|
1170
|
-
}),
|
|
1171
|
-
import_react.default.createElement("span", { key: "l" }, t("turboLabel"))
|
|
1172
|
-
])
|
|
1120
|
+
}, "\u5143")
|
|
1173
1121
|
]),
|
|
1174
1122
|
import_react.default.createElement("div", {
|
|
1175
1123
|
key: "chips",
|
|
@@ -1715,6 +1663,7 @@ function SettingsSection(props) {
|
|
|
1715
1663
|
function NiumaPanel(props) {
|
|
1716
1664
|
const t = props && typeof props.t === "function" ? props.t : fallbackTranslate;
|
|
1717
1665
|
const remote = useRemoteConfig();
|
|
1666
|
+
const update = useUpdateInfo();
|
|
1718
1667
|
const cfg = import_react.default.useMemo(() => {
|
|
1719
1668
|
const raw = remote.data && remote.data.config ? remote.data.config : null;
|
|
1720
1669
|
if (!raw) return DEFAULTS;
|
|
@@ -1839,6 +1788,7 @@ function NiumaPanel(props) {
|
|
|
1839
1788
|
const onDecimalsChange = (value) => postConfig({ decimals: value });
|
|
1840
1789
|
const onTurboChange = (checked) => postConfig({ turbo: Boolean(checked) });
|
|
1841
1790
|
const holidaySource = remote.data && remote.data.holidaySource || HOLIDAY_SOURCE;
|
|
1791
|
+
const versionText = remote.data && remote.data.version || update.data && update.data.currentVersion || "";
|
|
1842
1792
|
const banner = remote.status === "failed" ? {
|
|
1843
1793
|
color: C.warn,
|
|
1844
1794
|
text: `${t("configFailed")}${remote.error ? `\uFF08${remote.error}\uFF09` : ""}`,
|
|
@@ -1940,6 +1890,67 @@ function NiumaPanel(props) {
|
|
|
1940
1890
|
}
|
|
1941
1891
|
}, t("retry")) : null
|
|
1942
1892
|
]) : null,
|
|
1893
|
+
// 版本 / 自动更新提示:已下载→提示重启;发现新版→一键更新
|
|
1894
|
+
update.data && update.data.staged ? import_react.default.createElement("div", {
|
|
1895
|
+
key: "update",
|
|
1896
|
+
style: {
|
|
1897
|
+
display: "flex",
|
|
1898
|
+
alignItems: "center",
|
|
1899
|
+
gap: 8,
|
|
1900
|
+
flexWrap: "wrap",
|
|
1901
|
+
fontSize: 11.5,
|
|
1902
|
+
color: C.label2,
|
|
1903
|
+
padding: "6px 10px",
|
|
1904
|
+
borderRadius: 9,
|
|
1905
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 45%, transparent)`,
|
|
1906
|
+
background: `color-mix(in srgb, ${GOLD_TINT} 10%, transparent)`
|
|
1907
|
+
}
|
|
1908
|
+
}, [
|
|
1909
|
+
import_react.default.createElement("span", { key: "dot", "aria-hidden": "true", style: { width: 6, height: 6, borderRadius: "50%", background: GOLD_TINT } }),
|
|
1910
|
+
import_react.default.createElement(
|
|
1911
|
+
"span",
|
|
1912
|
+
{ key: "txt", style: { flex: "1 1 160px" } },
|
|
1913
|
+
t("updateStaged").replace("{version}", String(update.data.stagedVersion || update.data.latestVersion || ""))
|
|
1914
|
+
)
|
|
1915
|
+
]) : update.status === "updating" ? import_react.default.createElement("div", {
|
|
1916
|
+
key: "update",
|
|
1917
|
+
style: { fontSize: 11.5, color: C.label3, padding: "2px 2px" }
|
|
1918
|
+
}, t("updating")) : update.data && update.data.hasUpdate ? import_react.default.createElement("div", {
|
|
1919
|
+
key: "update",
|
|
1920
|
+
style: {
|
|
1921
|
+
display: "flex",
|
|
1922
|
+
alignItems: "center",
|
|
1923
|
+
gap: 8,
|
|
1924
|
+
flexWrap: "wrap",
|
|
1925
|
+
fontSize: 11.5,
|
|
1926
|
+
color: C.label2,
|
|
1927
|
+
padding: "6px 10px",
|
|
1928
|
+
borderRadius: 9,
|
|
1929
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 45%, transparent)`,
|
|
1930
|
+
background: `color-mix(in srgb, ${GOLD_TINT} 10%, transparent)`
|
|
1931
|
+
}
|
|
1932
|
+
}, [
|
|
1933
|
+
import_react.default.createElement(
|
|
1934
|
+
"span",
|
|
1935
|
+
{ key: "txt", style: { flex: "1 1 160px" } },
|
|
1936
|
+
t("updateAvailable").replace("{version}", String(update.data.latestVersion || ""))
|
|
1937
|
+
),
|
|
1938
|
+
import_react.default.createElement("button", {
|
|
1939
|
+
key: "go",
|
|
1940
|
+
type: "button",
|
|
1941
|
+
onClick: update.download,
|
|
1942
|
+
style: {
|
|
1943
|
+
border: `1px solid color-mix(in srgb, ${GOLD_TINT} 70%, rgba(0,0,0,.15))`,
|
|
1944
|
+
color: "#3A2A05",
|
|
1945
|
+
background: "linear-gradient(180deg, #F8DC86 0%, #EFC258 52%, #D99D2C 100%)",
|
|
1946
|
+
borderRadius: 7,
|
|
1947
|
+
padding: "3px 12px",
|
|
1948
|
+
fontSize: 11.5,
|
|
1949
|
+
fontWeight: 700,
|
|
1950
|
+
cursor: "pointer"
|
|
1951
|
+
}
|
|
1952
|
+
}, t("updateNow"))
|
|
1953
|
+
]) : null,
|
|
1943
1954
|
import_react.default.createElement(HeroCard, { key: "hero", t, snap, decimals: cfg.decimals, onDecimalsChange, turbo: cfg.turbo, onTurboChange }),
|
|
1944
1955
|
import_react.default.createElement(CountdownRow, { key: "countdown", t, snap }),
|
|
1945
1956
|
import_react.default.createElement("div", {
|
|
@@ -2004,7 +2015,28 @@ function NiumaPanel(props) {
|
|
|
2004
2015
|
setCheck,
|
|
2005
2016
|
save,
|
|
2006
2017
|
onSave
|
|
2007
|
-
})
|
|
2018
|
+
}),
|
|
2019
|
+
// 版本信息固定放在面板最底部
|
|
2020
|
+
import_react.default.createElement("div", {
|
|
2021
|
+
key: "version",
|
|
2022
|
+
style: {
|
|
2023
|
+
display: "flex",
|
|
2024
|
+
alignItems: "center",
|
|
2025
|
+
justifyContent: "center",
|
|
2026
|
+
gap: 6,
|
|
2027
|
+
padding: "4px 0 0",
|
|
2028
|
+
fontSize: 10.5,
|
|
2029
|
+
color: C.label3,
|
|
2030
|
+
...NUM
|
|
2031
|
+
}
|
|
2032
|
+
}, [
|
|
2033
|
+
versionText ? import_react.default.createElement("span", { key: "v" }, `\u725B\u9A6C\u52A0\u901F\u5668 v${versionText}`) : null,
|
|
2034
|
+
update.data && update.data.staged ? import_react.default.createElement(
|
|
2035
|
+
"span",
|
|
2036
|
+
{ key: "s", style: { color: C.label3 } },
|
|
2037
|
+
`\xB7 ${t("updateStaged").replace("{version}", String(update.data.stagedVersion || update.data.latestVersion || ""))}`
|
|
2038
|
+
) : null
|
|
2039
|
+
])
|
|
2008
2040
|
])
|
|
2009
2041
|
]);
|
|
2010
2042
|
}
|