@iasiv5/dsh-skins 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +8 -20
- package/README.i18n.yaml +2 -2
- package/README.md +8 -20
- package/lib/client.js +44 -408
- package/lib/index.js +112 -891
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -808,294 +808,6 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
808
808
|
};
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
// src/client/host-errors.js
|
|
812
|
-
var HOST_ERROR_KEYS = {
|
|
813
|
-
RESTART_UNAVAILABLE: "host.restart.unavailable",
|
|
814
|
-
NO_PENDING_UPDATE: "host.restart.noPending",
|
|
815
|
-
RESTART_SAFETY_UNKNOWN: "update.restart.unknown",
|
|
816
|
-
AGENTS_RUNNING: "update.restart.blocked",
|
|
817
|
-
UPDATE_LINK_PROTECTED: "host.update.linkProtected",
|
|
818
|
-
UPDATE_SOURCE_UNSUPPORTED: "host.update.sourceUnsupported",
|
|
819
|
-
UPDATE_ALREADY_LATEST: "host.update.alreadyLatest",
|
|
820
|
-
UPDATE_SOURCE_CHANGED: "host.update.sourceChanged",
|
|
821
|
-
UPDATE_COMMAND_FAILED: "host.update.commandFailed",
|
|
822
|
-
UPDATE_COMMAND_TIMEOUT: "host.update.commandTimeout",
|
|
823
|
-
REGISTRY_CHECK_FAILED: "host.registry.checkFailed",
|
|
824
|
-
REGISTRY_NAME_MISMATCH: "host.registry.nameMismatch",
|
|
825
|
-
REGISTRY_VERSION_INVALID: "host.registry.versionInvalid",
|
|
826
|
-
REGISTRY_INTEGRITY_MISSING: "host.registry.integrityMissing",
|
|
827
|
-
RELEASE_MANIFEST_MISSING: "host.release.manifestMissing",
|
|
828
|
-
RELEASE_NAME_MISMATCH: "host.release.nameMismatch",
|
|
829
|
-
RELEASE_VERSION_MISMATCH: "host.release.versionMismatch",
|
|
830
|
-
RELEASE_REPOSITORY_MISMATCH: "host.release.repoMismatch",
|
|
831
|
-
RELEASE_NOT_WEB_PLUGIN: "host.release.notWebPlugin",
|
|
832
|
-
RELEASE_NO_BUNDLE_PATCH: "host.release.noBundlePatch",
|
|
833
|
-
PROFILE_NOT_PINNED: "host.profile.notPinned",
|
|
834
|
-
PROFILE_BUNDLE_MISSING: "host.profile.bundleMissing",
|
|
835
|
-
ROLLBACK_LOCKFILE_MISMATCH: "host.rollback.lockfileMismatch",
|
|
836
|
-
ROLLBACK_BUNDLE_MISSING: "host.rollback.bundleMissing",
|
|
837
|
-
UPLOAD_TOO_LARGE: "host.personalization.tooLarge",
|
|
838
|
-
// UPLOAD_TIMEOUT: client-side fetch abort (config-client uploadImage).
|
|
839
|
-
// UPLOAD_FAILED (any other rejected upload fetch) is intentionally unmapped —
|
|
840
|
-
// resolveHostErrorText falls back to the panel's generic uploadFailed copy.
|
|
841
|
-
UPLOAD_TIMEOUT: "host.personalization.uploadTimeout",
|
|
842
|
-
UNSUPPORTED_IMAGE: "host.personalization.unsupportedImage",
|
|
843
|
-
ANIMATION_UNSUPPORTED: "host.personalization.animatedWebp",
|
|
844
|
-
DISK_FULL: "host.personalization.diskFull",
|
|
845
|
-
FILENAME_INVALID: "host.personalization.invalidFilename",
|
|
846
|
-
ASSET_NOT_FOUND: "host.personalization.assetMissing",
|
|
847
|
-
INVALID_CONFIG: "host.personalization.invalidConfig",
|
|
848
|
-
STORE_READONLY: "host.personalization.readonly",
|
|
849
|
-
STORE_RECOVERY_REQUIRED: "host.personalization.recoveryRequired",
|
|
850
|
-
UNKNOWN_SKIN: "host.personalization.unknownSkin"
|
|
851
|
-
};
|
|
852
|
-
function safeTr(tr, key, params) {
|
|
853
|
-
if (typeof tr !== "function") return key;
|
|
854
|
-
const text = tr(key, params);
|
|
855
|
-
return typeof text === "string" ? text : key;
|
|
856
|
-
}
|
|
857
|
-
function resolveHostErrorText(value, tr) {
|
|
858
|
-
if (value === null || value === void 0 || value === "") return "";
|
|
859
|
-
if (typeof value === "string") return value;
|
|
860
|
-
const key = value.code === void 0 ? void 0 : HOST_ERROR_KEYS[value.code];
|
|
861
|
-
if (key !== void 0) {
|
|
862
|
-
const text = safeTr(tr, key, value.params ?? {});
|
|
863
|
-
if (text !== key) return text;
|
|
864
|
-
}
|
|
865
|
-
return value.text ?? value.message ?? String(value);
|
|
866
|
-
}
|
|
867
|
-
function resolveFailedOperationText(operation, tr) {
|
|
868
|
-
if (operation === null || operation === void 0) return "";
|
|
869
|
-
const base = resolveHostErrorText({ code: operation.code, params: operation.params, text: operation.message }, tr);
|
|
870
|
-
const rollback = operation.rollbackError;
|
|
871
|
-
if (rollback === null || rollback === void 0) return base;
|
|
872
|
-
const reason = resolveHostErrorText(rollback, tr);
|
|
873
|
-
const suffix = safeTr(tr, "host.update.rollbackSuffix", { reason });
|
|
874
|
-
return suffix === "host.update.rollbackSuffix" ? `${base};自动回滚失败:${reason}` : base + suffix;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
// src/client/update-panel.js
|
|
878
|
-
var UPDATE_ENDPOINT = "/dsh-skins/update";
|
|
879
|
-
var RESTART_ENDPOINT = "/dsh-skins/restart";
|
|
880
|
-
var TERMINAL_PHASES = /* @__PURE__ */ new Set(["done", "failed"]);
|
|
881
|
-
var UPDATE_CSS = [
|
|
882
|
-
".dsh-skins-update-row{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:4px;padding:12px 4px 0;border-top:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:17px}",
|
|
883
|
-
".dsh-skins-update-row-muted{display:block;min-width:0;color:var(--dsw-alias-label-secondary,#5f6368);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",
|
|
884
|
-
".dsh-skins-update-copy{display:flex;min-width:0;flex:1;flex-direction:column;align-items:flex-start;gap:2px;color:var(--dsw-alias-label-secondary)}",
|
|
885
|
-
".dsh-skins-update-copy strong{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}",
|
|
886
|
-
".dsh-skins-update-copy a{color:var(--dsw-alias-brand-text);text-decoration:none}",
|
|
887
|
-
".dsh-skins-update-copy a:hover{text-decoration:underline}",
|
|
888
|
-
".dsh-skins-update-actions{display:flex;flex:none;align-items:center;gap:6px}",
|
|
889
|
-
".dsh-skins-update-actions button,.dsh-skins-update-error>button{height:30px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer}",
|
|
890
|
-
".dsh-skins-update-actions button:hover,.dsh-skins-update-error>button:hover{background:var(--dsw-alias-interactive-bg-hover)}",
|
|
891
|
-
".dsh-skins-update-actions button:disabled{opacity:.55;cursor:default}",
|
|
892
|
-
".dsh-skins-update-error,.dsh-skins-update-error-text{color:var(--dsw-alias-error-text,var(--dsw-static-red-500,#d33))}"
|
|
893
|
-
].join("\n");
|
|
894
|
-
function toPanelError(error) {
|
|
895
|
-
return {
|
|
896
|
-
text: error instanceof Error ? error.message : String(error),
|
|
897
|
-
...error?.code === void 0 ? {} : { code: error.code },
|
|
898
|
-
...error?.params === void 0 ? {} : { params: error.params }
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
|
-
async function json(url, options) {
|
|
902
|
-
const response = await fetch(url, options);
|
|
903
|
-
const value = await response.json().catch(() => ({}));
|
|
904
|
-
if (!response.ok) {
|
|
905
|
-
const error = new Error(value.error || `HTTP ${response.status}`);
|
|
906
|
-
if (value.code !== void 0) error.code = value.code;
|
|
907
|
-
if (value.params !== void 0 && value.params !== null) error.params = value.params;
|
|
908
|
-
throw error;
|
|
909
|
-
}
|
|
910
|
-
return value;
|
|
911
|
-
}
|
|
912
|
-
function createOperationPoller(options) {
|
|
913
|
-
const schedule = options.schedule ?? setTimeout;
|
|
914
|
-
const cancel = options.cancel ?? clearTimeout;
|
|
915
|
-
const delay = options.delay ?? 450;
|
|
916
|
-
let active = false;
|
|
917
|
-
let timer;
|
|
918
|
-
const tick = async () => {
|
|
919
|
-
if (!active) return;
|
|
920
|
-
const status = await options.loadStatus();
|
|
921
|
-
const phase = status?.operation?.phase;
|
|
922
|
-
if (active && phase && !TERMINAL_PHASES.has(phase)) timer = schedule(tick, delay);
|
|
923
|
-
};
|
|
924
|
-
return {
|
|
925
|
-
start() {
|
|
926
|
-
if (active) return;
|
|
927
|
-
active = true;
|
|
928
|
-
timer = schedule(tick, delay);
|
|
929
|
-
},
|
|
930
|
-
stop() {
|
|
931
|
-
active = false;
|
|
932
|
-
if (timer !== void 0) cancel(timer);
|
|
933
|
-
timer = void 0;
|
|
934
|
-
}
|
|
935
|
-
};
|
|
936
|
-
}
|
|
937
|
-
function createUpdatePanel({ jsx, react }) {
|
|
938
|
-
const phaseKey = (phase) => `update.phase.${phase ?? "checking"}`;
|
|
939
|
-
function UpdatePanel({ open, tr }) {
|
|
940
|
-
const [view, setView] = react.useState({ kind: "idle", status: null, error: null });
|
|
941
|
-
const [restartConfirm, setRestartConfirm] = react.useState(false);
|
|
942
|
-
const [confirmUnknown, setConfirmUnknown] = react.useState(false);
|
|
943
|
-
const [restarting, setRestarting] = react.useState(false);
|
|
944
|
-
const [restartDeferred, setRestartDeferred] = react.useState(false);
|
|
945
|
-
const loadStatus = react.useCallback(async (force = false, quiet = false) => {
|
|
946
|
-
if (!quiet) setView((current) => ({ ...current, kind: "checking", error: null }));
|
|
947
|
-
try {
|
|
948
|
-
const status2 = await json(`${UPDATE_ENDPOINT}${force ? "?force=1" : ""}`, force ? {
|
|
949
|
-
headers: { "x-dsh-skins-force": "1" }
|
|
950
|
-
} : void 0);
|
|
951
|
-
setView({ kind: "ready", status: status2, error: null });
|
|
952
|
-
return status2;
|
|
953
|
-
} catch (error) {
|
|
954
|
-
setView({ kind: "error", status: null, error: toPanelError(error) });
|
|
955
|
-
return null;
|
|
956
|
-
}
|
|
957
|
-
}, []);
|
|
958
|
-
react.useEffect(() => {
|
|
959
|
-
if (!open) return void 0;
|
|
960
|
-
void loadStatus(false);
|
|
961
|
-
return void 0;
|
|
962
|
-
}, [open, loadStatus]);
|
|
963
|
-
const operationPhase = view.status?.operation?.phase;
|
|
964
|
-
react.useEffect(() => {
|
|
965
|
-
if (!open || !operationPhase || TERMINAL_PHASES.has(operationPhase)) return void 0;
|
|
966
|
-
const poller = createOperationPoller({ loadStatus: () => loadStatus(false, true) });
|
|
967
|
-
poller.start();
|
|
968
|
-
return poller.stop;
|
|
969
|
-
}, [open, operationPhase, loadStatus]);
|
|
970
|
-
const startUpdate = async () => {
|
|
971
|
-
setView((current) => ({ ...current, kind: "updating", error: null }));
|
|
972
|
-
try {
|
|
973
|
-
const started = await json(UPDATE_ENDPOINT, {
|
|
974
|
-
method: "POST",
|
|
975
|
-
headers: { "content-type": "application/json" },
|
|
976
|
-
body: "{}"
|
|
977
|
-
});
|
|
978
|
-
setView((current) => ({
|
|
979
|
-
...current,
|
|
980
|
-
kind: "updating",
|
|
981
|
-
status: current.status === null ? { operation: started.operation } : { ...current.status, operation: started.operation }
|
|
982
|
-
}));
|
|
983
|
-
} catch (error) {
|
|
984
|
-
setView((current) => ({ ...current, kind: "error", error: toPanelError(error) }));
|
|
985
|
-
}
|
|
986
|
-
};
|
|
987
|
-
const waitForReplacement = () => {
|
|
988
|
-
const startedAt = Date.now();
|
|
989
|
-
const probe = async () => {
|
|
990
|
-
try {
|
|
991
|
-
const response = await fetch(`/?dsh-skins-restart=${Date.now()}`, { cache: "no-store" });
|
|
992
|
-
if (response.ok && Date.now() - startedAt > 1e3) {
|
|
993
|
-
window.location.reload();
|
|
994
|
-
return;
|
|
995
|
-
}
|
|
996
|
-
} catch {
|
|
997
|
-
}
|
|
998
|
-
if (Date.now() - startedAt < 3e4) setTimeout(probe, 700);
|
|
999
|
-
};
|
|
1000
|
-
setTimeout(probe, 900);
|
|
1001
|
-
};
|
|
1002
|
-
const restartNow = async () => {
|
|
1003
|
-
const safety = view.status?.restartSafety;
|
|
1004
|
-
if (safety?.state === "blocked") {
|
|
1005
|
-
setView((current) => ({ ...current, error: tr("update.restart.blocked", { count: safety.running ?? 1 }) }));
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
|
-
if (safety?.state === "unknown" && !confirmUnknown) {
|
|
1009
|
-
setConfirmUnknown(true);
|
|
1010
|
-
setView((current) => ({ ...current, error: tr("update.restart.unknown") }));
|
|
1011
|
-
return;
|
|
1012
|
-
}
|
|
1013
|
-
setRestarting(true);
|
|
1014
|
-
try {
|
|
1015
|
-
await json(RESTART_ENDPOINT, {
|
|
1016
|
-
method: "POST",
|
|
1017
|
-
headers: { "content-type": "application/json" },
|
|
1018
|
-
body: JSON.stringify({ confirmUnknown })
|
|
1019
|
-
});
|
|
1020
|
-
waitForReplacement();
|
|
1021
|
-
} catch (error) {
|
|
1022
|
-
setRestarting(false);
|
|
1023
|
-
setView((current) => ({ ...current, error: toPanelError(error) }));
|
|
1024
|
-
}
|
|
1025
|
-
};
|
|
1026
|
-
const status = view.status;
|
|
1027
|
-
const operation = status?.operation;
|
|
1028
|
-
const sourceKind = status?.source?.kind;
|
|
1029
|
-
const showDevelopment = sourceKind === "link";
|
|
1030
|
-
const showUnsupported = sourceKind === "file" || sourceKind === "github" || sourceKind === "unknown";
|
|
1031
|
-
const showOperation = operation !== null && operation !== void 0;
|
|
1032
|
-
const showAvailable = status?.updateAvailable === true;
|
|
1033
|
-
const showRestart = status?.restartRequired === true || operation?.phase === "done";
|
|
1034
|
-
if (view.kind === "idle") return null;
|
|
1035
|
-
if (view.kind === "checking" && status === null) {
|
|
1036
|
-
return jsx("div", { className: "dsh-skins-update-row", children: tr("update.checking") });
|
|
1037
|
-
}
|
|
1038
|
-
if (view.kind === "error" && status === null) {
|
|
1039
|
-
return jsx("div", { className: "dsh-skins-update-row dsh-skins-update-error", children: [
|
|
1040
|
-
jsx("span", { children: resolveHostErrorText(view.error, tr) || tr("update.checkFailed") }),
|
|
1041
|
-
jsx("button", { type: "button", onClick: () => void loadStatus(true), children: tr("update.retry") })
|
|
1042
|
-
] });
|
|
1043
|
-
}
|
|
1044
|
-
if (showDevelopment) {
|
|
1045
|
-
const line = tr(showAvailable ? "update.developmentNewer" : "update.developmentCurrent", {
|
|
1046
|
-
current: status.currentVersion,
|
|
1047
|
-
latest: status.latest?.version ?? "—"
|
|
1048
|
-
});
|
|
1049
|
-
return jsx("div", {
|
|
1050
|
-
className: "dsh-skins-update-row dsh-skins-update-row-muted",
|
|
1051
|
-
title: line,
|
|
1052
|
-
children: line
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
if (showUnsupported) {
|
|
1056
|
-
return jsx("div", { className: "dsh-skins-update-row", children: [
|
|
1057
|
-
jsx("div", { className: "dsh-skins-update-copy", children: [
|
|
1058
|
-
jsx("strong", { children: tr("update.unsupported") }),
|
|
1059
|
-
jsx("span", { children: tr("update.unsupportedHint") })
|
|
1060
|
-
] })
|
|
1061
|
-
] });
|
|
1062
|
-
}
|
|
1063
|
-
if (!showAvailable && !showOperation && !showRestart && view.error === null) return null;
|
|
1064
|
-
const running = showOperation && !TERMINAL_PHASES.has(operation.phase);
|
|
1065
|
-
const failed = operation?.phase === "failed";
|
|
1066
|
-
const release = operation?.release ?? status?.latest;
|
|
1067
|
-
const phaseLabel = running ? tr(phaseKey(operation.phase)) : null;
|
|
1068
|
-
return jsx("div", { className: `dsh-skins-update-row${failed || view.error ? " dsh-skins-update-error" : ""}`, children: [
|
|
1069
|
-
jsx("div", { className: "dsh-skins-update-copy", children: [
|
|
1070
|
-
jsx("strong", { children: showRestart ? tr("update.installed") : failed ? tr("update.failed") : tr("update.available") }),
|
|
1071
|
-
jsx("span", { children: running ? phaseLabel : showRestart ? tr("update.restartRequired", { version: release?.version ?? status?.latest?.version ?? "" }) : failed ? resolveFailedOperationText(operation, tr) : tr("update.versions", { current: status?.currentVersion ?? "", latest: status?.latest?.version ?? "" }) }),
|
|
1072
|
-
view.error ? jsx("span", { className: "dsh-skins-update-error-text", children: resolveHostErrorText(view.error, tr) }) : null,
|
|
1073
|
-
release?.htmlUrl ? jsx("a", {
|
|
1074
|
-
href: release.htmlUrl,
|
|
1075
|
-
target: "_blank",
|
|
1076
|
-
rel: "noreferrer",
|
|
1077
|
-
children: tr("update.releaseNotes")
|
|
1078
|
-
}) : null
|
|
1079
|
-
] }),
|
|
1080
|
-
jsx("div", {
|
|
1081
|
-
className: "dsh-skins-update-actions",
|
|
1082
|
-
children: running ? jsx("span", { className: "dsh-skins-update-spinner", "aria-hidden": "true" }) : showRestart ? restartDeferred ? jsx("span", { children: tr("update.deferred") }) : restartConfirm ? [
|
|
1083
|
-
jsx("button", { type: "button", disabled: restarting, onClick: () => void restartNow(), children: restarting ? tr("update.restarting") : confirmUnknown ? tr("update.confirmUnknown") : tr("update.confirmRestart") }),
|
|
1084
|
-
jsx("button", { type: "button", disabled: restarting, onClick: () => {
|
|
1085
|
-
setRestartConfirm(false);
|
|
1086
|
-
setConfirmUnknown(false);
|
|
1087
|
-
setRestartDeferred(true);
|
|
1088
|
-
}, children: tr("update.later") })
|
|
1089
|
-
] : status?.restartAvailable === true ? [
|
|
1090
|
-
jsx("button", { type: "button", onClick: () => setRestartConfirm(true), children: tr("update.restartNow") }),
|
|
1091
|
-
jsx("button", { type: "button", onClick: () => setRestartDeferred(true), children: tr("update.later") })
|
|
1092
|
-
] : jsx("span", { children: tr("update.restartManual") }) : jsx("button", { type: "button", onClick: () => void startUpdate(), disabled: status?.canUpdate !== true && !failed, children: failed ? tr("update.retry") : tr("update.action") })
|
|
1093
|
-
})
|
|
1094
|
-
] });
|
|
1095
|
-
}
|
|
1096
|
-
return UpdatePanel;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
811
|
// src/client/dicts.js
|
|
1100
812
|
var NS = "dsh-skins.ui";
|
|
1101
813
|
var DICTS = {
|
|
@@ -1108,35 +820,6 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1108
820
|
"appearance.light": "浅色",
|
|
1109
821
|
"appearance.dark": "深色",
|
|
1110
822
|
"appearance.system": "跟随系统",
|
|
1111
|
-
"update.checking": "正在检查更新…",
|
|
1112
|
-
"update.checkFailed": "暂时无法检查更新",
|
|
1113
|
-
"update.retry": "重试",
|
|
1114
|
-
"update.developmentCurrent": "本地开发模式 - v{current}(最新正式版 v{latest})",
|
|
1115
|
-
"update.developmentNewer": "本地开发模式 - v{current}(可更新至 v{latest})",
|
|
1116
|
-
"update.unsupported": "当前安装来源不支持在线更新",
|
|
1117
|
-
"update.unsupportedHint": "仅 npm 安装的 @iasiv5/dsh-skins 支持一键更新",
|
|
1118
|
-
"update.available": "发现插件更新",
|
|
1119
|
-
"update.versions": "v{current} → v{latest}",
|
|
1120
|
-
"update.releaseNotes": "查看版本说明",
|
|
1121
|
-
"update.action": "更新",
|
|
1122
|
-
"update.failed": "更新失败",
|
|
1123
|
-
"update.installed": "更新已安装",
|
|
1124
|
-
"update.restartRequired": "v{version} 将在重启 DSH Web 后生效",
|
|
1125
|
-
"update.restartNow": "立即重启",
|
|
1126
|
-
"update.confirmRestart": "确认重启",
|
|
1127
|
-
"update.confirmUnknown": "仍要重启",
|
|
1128
|
-
"update.later": "稍后",
|
|
1129
|
-
"update.deferred": "已选择稍后重启",
|
|
1130
|
-
"update.restartManual": "请手动重启 DSH Web",
|
|
1131
|
-
"update.restarting": "正在重启…",
|
|
1132
|
-
"update.restart.blocked": "检测到 {count} 个 Agent 正在运行,请稍后重试",
|
|
1133
|
-
"update.restart.unknown": "无法确认 Agent 状态;再次点击“仍要重启”表示你确认继续",
|
|
1134
|
-
"update.phase.queued": "更新已排队",
|
|
1135
|
-
"update.phase.checking": "正在检查最新正式版本…",
|
|
1136
|
-
"update.phase.preparing": "正在验证 npm 版本元数据…",
|
|
1137
|
-
"update.phase.installing": "正在下载安装…",
|
|
1138
|
-
"update.phase.validating": "正在校验安装结果…",
|
|
1139
|
-
"update.phase.rollback": "更新失败,正在恢复原版本…",
|
|
1140
823
|
// Personalization surface (1.0.0)
|
|
1141
824
|
"personalization.title": "个性化",
|
|
1142
825
|
"personalization.collapse": "收起个性化面板",
|
|
@@ -1197,33 +880,7 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1197
880
|
"host.personalization.readonly": "配置为更高版本创建,当前只读",
|
|
1198
881
|
"host.personalization.recoveryRequired": "配置状态待恢复,请先在个性化面板确认恢复",
|
|
1199
882
|
"host.personalization.unknownSkin": "皮肤不存在",
|
|
1200
|
-
"host.personalization.uploadTimeout": "上传超时,请检查网络后重试"
|
|
1201
|
-
// Host-reported errors, keyed by the stable `code` the Host attaches to
|
|
1202
|
-
// every user-facing error (see host-errors.js HOST_ERROR_KEYS). The Host keeps a zh
|
|
1203
|
-
// fallback message; the client renders the localized template instead.
|
|
1204
|
-
"host.restart.unavailable": "当前 DSH Host 不支持自重启",
|
|
1205
|
-
"host.restart.noPending": "当前没有等待重启应用的更新",
|
|
1206
|
-
"host.update.linkProtected": "本地 link 开发模式不会被在线更新覆盖",
|
|
1207
|
-
"host.update.sourceUnsupported": "当前安装来源不支持一键更新",
|
|
1208
|
-
"host.update.alreadyLatest": "已经是最新正式版本",
|
|
1209
|
-
"host.update.sourceChanged": "更新开始前安装来源已变化,请重新打开主题切换器",
|
|
1210
|
-
"host.update.commandFailed": "DSH 插件更新失败(exit {exitCode}):{output}",
|
|
1211
|
-
"host.update.commandTimeout": "DSH 插件更新超时",
|
|
1212
|
-
"host.update.rollbackSuffix": ";自动回滚失败:{reason}",
|
|
1213
|
-
"host.registry.checkFailed": "npm registry 更新检查失败(HTTP {status})",
|
|
1214
|
-
"host.registry.nameMismatch": "npm registry 返回的包名异常,应是 {expected}",
|
|
1215
|
-
"host.registry.versionInvalid": "npm registry latest 不是严格 X.Y.Z 版本:{version}",
|
|
1216
|
-
"host.registry.integrityMissing": "npm registry 版本元数据缺少完整性校验(dist.integrity)",
|
|
1217
|
-
"host.release.manifestMissing": "发布的包缺少 package.json",
|
|
1218
|
-
"host.release.nameMismatch": "发布的包名必须是 {expected}",
|
|
1219
|
-
"host.release.versionMismatch": "发布版本 v{tag} 与包版本 {version} 不一致",
|
|
1220
|
-
"host.release.repoMismatch": "发布的包仓库必须是 {repository}",
|
|
1221
|
-
"host.release.notWebPlugin": "发布的包不是 DSH Web 客户端插件",
|
|
1222
|
-
"host.release.noBundlePatch": "发布的包未声明 DSH bundle patch",
|
|
1223
|
-
"host.profile.notPinned": "profile 未固定到已验证的精确版本",
|
|
1224
|
-
"host.profile.bundleMissing": "profile 未注册 dsh-skins bundle",
|
|
1225
|
-
"host.rollback.lockfileMismatch": "恢复后的版本锁定校验失败",
|
|
1226
|
-
"host.rollback.bundleMissing": "恢复后的 bundle 注册校验失败"
|
|
883
|
+
"host.personalization.uploadTimeout": "上传超时,请检查网络后重试"
|
|
1227
884
|
},
|
|
1228
885
|
en: {
|
|
1229
886
|
"skins.switch": "Theme Switcher",
|
|
@@ -1234,35 +891,6 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1234
891
|
"appearance.light": "Light",
|
|
1235
892
|
"appearance.dark": "Dark",
|
|
1236
893
|
"appearance.system": "System",
|
|
1237
|
-
"update.checking": "Checking for updates…",
|
|
1238
|
-
"update.checkFailed": "Unable to check for updates",
|
|
1239
|
-
"update.retry": "Retry",
|
|
1240
|
-
"update.developmentCurrent": "Local development mode - v{current} (latest release v{latest})",
|
|
1241
|
-
"update.developmentNewer": "Local development mode - v{current} (update available: v{latest})",
|
|
1242
|
-
"update.unsupported": "This install source cannot update online",
|
|
1243
|
-
"update.unsupportedHint": "One-click update is available only for npm installs of @iasiv5/dsh-skins",
|
|
1244
|
-
"update.available": "Plugin update available",
|
|
1245
|
-
"update.versions": "v{current} → v{latest}",
|
|
1246
|
-
"update.releaseNotes": "Release notes",
|
|
1247
|
-
"update.action": "Update",
|
|
1248
|
-
"update.failed": "Update failed",
|
|
1249
|
-
"update.installed": "Update installed",
|
|
1250
|
-
"update.restartRequired": "v{version} will take effect after DSH Web restarts",
|
|
1251
|
-
"update.restartNow": "Restart now",
|
|
1252
|
-
"update.confirmRestart": "Confirm restart",
|
|
1253
|
-
"update.confirmUnknown": "Restart anyway",
|
|
1254
|
-
"update.later": "Later",
|
|
1255
|
-
"update.deferred": "Restart deferred",
|
|
1256
|
-
"update.restartManual": "Restart DSH Web manually",
|
|
1257
|
-
"update.restarting": "Restarting…",
|
|
1258
|
-
"update.restart.blocked": "{count} Agent(s) are running; try again later",
|
|
1259
|
-
"update.restart.unknown": "Agent status is unavailable; click Restart anyway again to confirm",
|
|
1260
|
-
"update.phase.queued": "Update queued",
|
|
1261
|
-
"update.phase.checking": "Checking the latest stable release…",
|
|
1262
|
-
"update.phase.preparing": "Verifying npm version metadata…",
|
|
1263
|
-
"update.phase.installing": "Downloading and installing…",
|
|
1264
|
-
"update.phase.validating": "Validating the installation…",
|
|
1265
|
-
"update.phase.rollback": "Update failed; restoring the previous version…",
|
|
1266
894
|
// Personalization surface (1.0.0)
|
|
1267
895
|
"personalization.title": "Personalize",
|
|
1268
896
|
"personalization.collapse": "Collapse personalization panel",
|
|
@@ -1323,30 +951,7 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1323
951
|
"host.personalization.readonly": "Created by a newer config version; read-only",
|
|
1324
952
|
"host.personalization.recoveryRequired": "Configuration needs recovery; confirm it in the personalization panel first",
|
|
1325
953
|
"host.personalization.unknownSkin": "Skin not found",
|
|
1326
|
-
"host.personalization.uploadTimeout": "Upload timed out; check your connection and retry"
|
|
1327
|
-
"host.restart.unavailable": "This DSH Host cannot restart itself",
|
|
1328
|
-
"host.restart.noPending": "No update is waiting to be applied by a restart",
|
|
1329
|
-
"host.update.linkProtected": "Local link development installs are never overwritten by online updates",
|
|
1330
|
-
"host.update.sourceUnsupported": "The current install source does not support one-click updates",
|
|
1331
|
-
"host.update.alreadyLatest": "Already on the latest stable release",
|
|
1332
|
-
"host.update.sourceChanged": "The install source changed before the update started; reopen the theme switcher",
|
|
1333
|
-
"host.update.commandFailed": "DSH plugin update failed (exit {exitCode}): {output}",
|
|
1334
|
-
"host.update.commandTimeout": "DSH plugin update timed out",
|
|
1335
|
-
"host.update.rollbackSuffix": "; automatic rollback failed: {reason}",
|
|
1336
|
-
"host.registry.checkFailed": "npm registry update check failed (HTTP {status})",
|
|
1337
|
-
"host.registry.nameMismatch": "npm registry returned an unexpected package name; expected {expected}",
|
|
1338
|
-
"host.registry.versionInvalid": "npm registry latest is not a strict X.Y.Z version: {version}",
|
|
1339
|
-
"host.registry.integrityMissing": "npm registry version metadata lacks a dist.integrity digest",
|
|
1340
|
-
"host.release.manifestMissing": "The published package is missing package.json",
|
|
1341
|
-
"host.release.nameMismatch": "The published package name must be {expected}",
|
|
1342
|
-
"host.release.versionMismatch": "Published version v{tag} does not match package version {version}",
|
|
1343
|
-
"host.release.repoMismatch": "The published package repository must be {repository}",
|
|
1344
|
-
"host.release.notWebPlugin": "The published package is not a DSH Web client plugin",
|
|
1345
|
-
"host.release.noBundlePatch": "The published package does not declare a DSH bundle patch",
|
|
1346
|
-
"host.profile.notPinned": "Profile is not pinned to the verified exact version",
|
|
1347
|
-
"host.profile.bundleMissing": "Profile does not register the dsh-skins bundle",
|
|
1348
|
-
"host.rollback.lockfileMismatch": "Restored profile failed exact-version verification",
|
|
1349
|
-
"host.rollback.bundleMissing": "Restored profile failed bundle registration verification"
|
|
954
|
+
"host.personalization.uploadTimeout": "Upload timed out; check your connection and retry"
|
|
1350
955
|
}
|
|
1351
956
|
};
|
|
1352
957
|
function formatTemplate(template, params = {}) {
|
|
@@ -1356,6 +961,39 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1356
961
|
);
|
|
1357
962
|
}
|
|
1358
963
|
|
|
964
|
+
// src/client/host-errors.js
|
|
965
|
+
var HOST_ERROR_KEYS = {
|
|
966
|
+
UPLOAD_TOO_LARGE: "host.personalization.tooLarge",
|
|
967
|
+
// UPLOAD_TIMEOUT: client-side fetch abort (config-client uploadImage).
|
|
968
|
+
// UPLOAD_FAILED (any other rejected upload fetch) is intentionally unmapped —
|
|
969
|
+
// resolveHostErrorText falls back to the panel's generic uploadFailed copy.
|
|
970
|
+
UPLOAD_TIMEOUT: "host.personalization.uploadTimeout",
|
|
971
|
+
UNSUPPORTED_IMAGE: "host.personalization.unsupportedImage",
|
|
972
|
+
ANIMATION_UNSUPPORTED: "host.personalization.animatedWebp",
|
|
973
|
+
DISK_FULL: "host.personalization.diskFull",
|
|
974
|
+
FILENAME_INVALID: "host.personalization.invalidFilename",
|
|
975
|
+
ASSET_NOT_FOUND: "host.personalization.assetMissing",
|
|
976
|
+
INVALID_CONFIG: "host.personalization.invalidConfig",
|
|
977
|
+
STORE_READONLY: "host.personalization.readonly",
|
|
978
|
+
STORE_RECOVERY_REQUIRED: "host.personalization.recoveryRequired",
|
|
979
|
+
UNKNOWN_SKIN: "host.personalization.unknownSkin"
|
|
980
|
+
};
|
|
981
|
+
function safeTr(tr, key, params) {
|
|
982
|
+
if (typeof tr !== "function") return key;
|
|
983
|
+
const text = tr(key, params);
|
|
984
|
+
return typeof text === "string" ? text : key;
|
|
985
|
+
}
|
|
986
|
+
function resolveHostErrorText(value, tr) {
|
|
987
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
988
|
+
if (typeof value === "string") return value;
|
|
989
|
+
const key = value.code === void 0 ? void 0 : HOST_ERROR_KEYS[value.code];
|
|
990
|
+
if (key !== void 0) {
|
|
991
|
+
const text = safeTr(tr, key, value.params ?? {});
|
|
992
|
+
if (text !== key) return text;
|
|
993
|
+
}
|
|
994
|
+
return value.text ?? value.message ?? String(value);
|
|
995
|
+
}
|
|
996
|
+
|
|
1359
997
|
// src/client/personalization/panel.js
|
|
1360
998
|
var PANEL_CSS = [
|
|
1361
999
|
// Panel header collapse control (v1.0.0 ruling): ghost icon button in the
|
|
@@ -1414,7 +1052,7 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1414
1052
|
".dsh-skins-pz-del{position:absolute;top:4px;right:4px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;padding:0;border:0;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;font:inherit;font-size:14px;line-height:1;cursor:pointer}",
|
|
1415
1053
|
".dsh-skins-pz-del:hover{background:rgba(0,0,0,.78)}",
|
|
1416
1054
|
".dsh-skins-pz-del:disabled{opacity:.55;cursor:default}",
|
|
1417
|
-
".dsh-skins-pz-del .dsh-skins-
|
|
1055
|
+
".dsh-skins-pz-del .dsh-skins-spinner{width:12px;height:12px;border-width:2px}",
|
|
1418
1056
|
".dsh-skins-pz-rowbtns{display:flex;gap:6px;flex-wrap:wrap}",
|
|
1419
1057
|
".dsh-skins-pz-actions{position:sticky;bottom:0;z-index:1;display:flex;align-items:flex-end;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-top:2px;padding:10px 2px 2px;background:var(--dsw-alias-bg-overlay);border-top:1px solid var(--dsw-alias-border-l2)}",
|
|
1420
1058
|
".dsh-skins-pz-cluster{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}",
|
|
@@ -1587,7 +1225,7 @@ ${names}`);
|
|
|
1587
1225
|
disabled: disabled || deletingId !== null,
|
|
1588
1226
|
"aria-label": `${tr("personalization.library.delete")}: ${asset.displayName}`,
|
|
1589
1227
|
onClick: () => removeAsset(asset),
|
|
1590
|
-
children: deletingId === asset.id ? jsx("span", { className: "dsh-skins-
|
|
1228
|
+
children: deletingId === asset.id ? jsx("span", { className: "dsh-skins-spinner", "aria-hidden": "true" }) : "×"
|
|
1591
1229
|
}, `${asset.id}-del`)
|
|
1592
1230
|
]
|
|
1593
1231
|
})),
|
|
@@ -1919,12 +1557,12 @@ ${names}`);
|
|
|
1919
1557
|
".dsh-skins-pop-card-on,.dsh-skins-pop-card-on:hover{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-module-platform)}",
|
|
1920
1558
|
".dsh-skins-pop-card-label{font-size:14px;line-height:20px;font-weight:500}",
|
|
1921
1559
|
".dsh-skins-pop-card-desc{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}",
|
|
1922
|
-
// 【共享原子】.dsh-skins-
|
|
1923
|
-
// reduced-motion opt-out) is
|
|
1924
|
-
//
|
|
1925
|
-
".dsh-skins-
|
|
1560
|
+
// 【共享原子】.dsh-skins-spinner (+ its keyframes and the
|
|
1561
|
+
// reduced-motion opt-out) is the personalization panel's delete-badge
|
|
1562
|
+
// loading indicator, styled here with the shell's base atoms.
|
|
1563
|
+
".dsh-skins-spinner{width:16px;height:16px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-brand-primary);border-radius:50%;animation:dsh-skins-spin .8s linear infinite}",
|
|
1926
1564
|
"@keyframes dsh-skins-spin{to{transform:rotate(360deg)}}",
|
|
1927
|
-
"@media (prefers-reduced-motion:reduce){.dsh-skins-
|
|
1565
|
+
"@media (prefers-reduced-motion:reduce){.dsh-skins-spinner{animation:none}}",
|
|
1928
1566
|
// -- personalization gear + panel -------------------------------------------
|
|
1929
1567
|
".dsh-skins-pop-card-row{display:flex;width:100%;min-width:0;gap:6px;align-items:stretch}",
|
|
1930
1568
|
".dsh-skins-pop-card-row .dsh-skins-pop-card{flex:1;min-width:0}",
|
|
@@ -1991,9 +1629,8 @@ ${names}`);
|
|
|
1991
1629
|
// be a HEIGHT, and the stacked panel never reflows horizontally anyway.
|
|
1992
1630
|
"@media (min-width:905px){.dsh-skins-sweeping.dsh-skins-wide .dsh-skins-pz-panel{flex:0 0 var(--dsh-skins-sweep-panel-basis,700px)}}"
|
|
1993
1631
|
].join("\n");
|
|
1994
|
-
var CSS = [SHELL_CSS, PANEL_CSS
|
|
1632
|
+
var CSS = [SHELL_CSS, PANEL_CSS].join("\n");
|
|
1995
1633
|
function installSidebarSwitcher(ctx, { runtime, jsx, react, reactDom, configClient, skinsById }) {
|
|
1996
|
-
const UpdatePanel = createUpdatePanel({ jsx, react });
|
|
1997
1634
|
function fallbackTranslate(key, params = {}) {
|
|
1998
1635
|
return formatTemplate(DICTS.zh[key] ?? key, params);
|
|
1999
1636
|
}
|
|
@@ -2222,8 +1859,7 @@ ${names}`);
|
|
|
2222
1859
|
jsx("div", { key: "grid", className: "dsh-skins-theme-grid", children: themeCards }),
|
|
2223
1860
|
jsx("div", { key: "d1", className: "dsh-skins-pop-divider", "aria-hidden": "true" }),
|
|
2224
1861
|
jsx("div", { key: "skins", className: "dsh-skins-pop-title", children: tr("skins.title") }),
|
|
2225
|
-
...skinCards
|
|
2226
|
-
jsx(UpdatePanel, { key: "update", open, tr })
|
|
1862
|
+
...skinCards
|
|
2227
1863
|
] }),
|
|
2228
1864
|
showPersonalization ? jsx("div", {
|
|
2229
1865
|
key: "panel",
|