dsh-pocket 1.16.1 → 2.0.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/client/client.js +177 -149
- package/client/index.jsx +129 -129
- package/client/pocket-locales.js +10 -0
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -1365,6 +1365,11 @@ var zh2 = {
|
|
|
1365
1365
|
"updatedRestartDetail": "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u91CD\u542F dsh web \u751F\u6548",
|
|
1366
1366
|
"updateFailed": "\u274C \u5931\u8D25\uFF1A{err}\uFF08\u624B\u52A8\u66F4\u65B0\uFF1Adsh plugin --profile web update dsh-pocket --latest -w\uFF09",
|
|
1367
1367
|
"versionRange": "\u5F53\u524D v{cur} \u2192 \u6700\u65B0 v{latest}",
|
|
1368
|
+
"wanAccess": "\u516C\u7F51\u8BBF\u95EE",
|
|
1369
|
+
"pinLabel": "\u8BBF\u95EE\u5BC6\u7801",
|
|
1370
|
+
"modeLabel": "\u5730\u5740\u6A21\u5F0F",
|
|
1371
|
+
"advAddress": "\u9AD8\u7EA7 \xB7 \u624B\u52A8\u9009\u5730\u5740",
|
|
1372
|
+
"wanOffHint": "\u5F00\u542F\u540E\u53EF\u4ECE\u4EFB\u4F55\u7F51\u7EDC\u8BBF\u95EE\uFF08\u6BCF\u6B21\u5F00\u542F\u9700\u786E\u8BA4\u514D\u8D23\u58F0\u660E\uFF09",
|
|
1368
1373
|
"lanTitle": "\u{1F4F6} \u5C40\u57DF\u7F51\uFF08\u540C\u4E00 WiFi\uFF09",
|
|
1369
1374
|
"lanHint": "\u624B\u673A\u8FDE\u63A5\u540C\u4E00 WiFi \u540E\u626B\u7801\u5373\u53EF\u6253\u5F00",
|
|
1370
1375
|
"lanAccess": "\u5C40\u57DF\u7F51\u8BBF\u95EE",
|
|
@@ -1447,6 +1452,11 @@ var en2 = {
|
|
|
1447
1452
|
"updatedRestartDetail": "\u2705 Updated \u2014 restart dsh web to apply",
|
|
1448
1453
|
"updateFailed": "\u274C Failed: {err} (manual update: dsh plugin --profile web update dsh-pocket --latest -w)",
|
|
1449
1454
|
"versionRange": "Current v{cur} \u2192 latest v{latest}",
|
|
1455
|
+
"wanAccess": "Public access",
|
|
1456
|
+
"pinLabel": "Access PIN",
|
|
1457
|
+
"modeLabel": "Address mode",
|
|
1458
|
+
"advAddress": "Advanced \xB7 Pick address",
|
|
1459
|
+
"wanOffHint": "Reachable from any network once enabled (a disclaimer is confirmed on each enable)",
|
|
1450
1460
|
"lanTitle": "\u{1F4F6} LAN (same Wi-Fi)",
|
|
1451
1461
|
"lanHint": "Scan to open once your phone is on the same Wi-Fi",
|
|
1452
1462
|
"lanAccess": "LAN access",
|
|
@@ -1781,6 +1791,31 @@ function PocketSettingsTab({ rpcCall, t }) {
|
|
|
1781
1791
|
background: active ? "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))" : "var(--dsw-alias-bg-layer-1,#fff)",
|
|
1782
1792
|
color: active ? "var(--dsw-alias-label-primary-foreground, #fff)" : "var(--dsw-alias-label-primary,inherit)"
|
|
1783
1793
|
});
|
|
1794
|
+
const Switch = (on, onClick) => (0, import_react2.createElement)("button", {
|
|
1795
|
+
role: "switch",
|
|
1796
|
+
"aria-checked": !!on,
|
|
1797
|
+
style: { flexShrink: 0, width: 40, height: 22, borderRadius: 11, border: "none", padding: 0, position: "relative", cursor: "pointer", font: "inherit", background: on ? "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))" : "var(--dsw-alias-border-l2,#d1d5db)" },
|
|
1798
|
+
onClick
|
|
1799
|
+
}, (0, import_react2.createElement)("span", { style: { position: "absolute", top: 2, left: on ? 20 : 2, width: 18, height: 18, borderRadius: "50%", background: "#fff" } }));
|
|
1800
|
+
const qrArea = (src, url, hint) => (0, import_react2.createElement)(
|
|
1801
|
+
"div",
|
|
1802
|
+
{ style: { background: "var(--dsw-alias-bg-layer-2,#f3f4f6)", borderRadius: 10, padding: "10px 12px", textAlign: "center", margin: "10px 0" } },
|
|
1803
|
+
(0, import_react2.createElement)("img", { src, alt: "QR", style: styles.qr }),
|
|
1804
|
+
(0, import_react2.createElement)("div", { style: styles.code }, url),
|
|
1805
|
+
(0, import_react2.createElement)("div", { style: styles.muted }, hint)
|
|
1806
|
+
);
|
|
1807
|
+
const row = (label, control, extra) => (0, import_react2.createElement)(
|
|
1808
|
+
"div",
|
|
1809
|
+
{ style: { borderTop: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", paddingTop: 9, marginTop: 9 } },
|
|
1810
|
+
(0, import_react2.createElement)(
|
|
1811
|
+
"div",
|
|
1812
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } },
|
|
1813
|
+
(0, import_react2.createElement)("span", { style: { fontSize: 13 } }, label),
|
|
1814
|
+
control
|
|
1815
|
+
),
|
|
1816
|
+
extra ?? null
|
|
1817
|
+
);
|
|
1818
|
+
const [advOpen, setAdvOpen] = (0, import_react2.useState)(false);
|
|
1784
1819
|
return (0, import_react2.createElement)(
|
|
1785
1820
|
"div",
|
|
1786
1821
|
{ style: styles.card },
|
|
@@ -1839,181 +1874,174 @@ function PocketSettingsTab({ rpcCall, t }) {
|
|
|
1839
1874
|
updateInfo.updating ? fmt(t, "updatingDetail", { s: elapsed(updateInfo.startedAt) }) : updateInfo.restarting ? fmt(t, "restartingDetail", { s: elapsed(updateInfo.startedAt) }) : updateInfo.result === "ok" ? updateInfo.autoRestart ? t("updatedAutoDetail") : t("updatedRestartDetail") : updateInfo.result === "fail" ? fmt(t, "updateFailed", { err: updateInfo.output || t("unknownError") }) : fmt(t, "versionRange", { cur: updateInfo.current, latest: updateInfo.latest })
|
|
1840
1875
|
)
|
|
1841
1876
|
) : null,
|
|
1842
|
-
//
|
|
1877
|
+
// 局域网:标题行自带总开关 → 二维码+地址 → 设置行(访问密码 / 高级·手动选地址)
|
|
1843
1878
|
(0, import_react2.createElement)(
|
|
1844
1879
|
"div",
|
|
1845
1880
|
{ style: styles.block },
|
|
1846
|
-
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, t("lanTitle")),
|
|
1847
|
-
// 局域网访问总开关:关闭后扫码/链接直接失效(公网不受影响)
|
|
1848
1881
|
(0, import_react2.createElement)(
|
|
1849
1882
|
"div",
|
|
1850
|
-
{ style: { display: "flex", alignItems: "center",
|
|
1851
|
-
(0, import_react2.createElement)("span", { style: {
|
|
1852
|
-
(
|
|
1853
|
-
style: { ...styles.btn, height: 28, padding: "0 12px", fontSize: 12, fontWeight: status?.lanEnabled !== false ? 600 : 400, background: status?.lanEnabled !== false ? "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))" : "var(--dsw-alias-bg-layer-1,#fff)", color: status?.lanEnabled !== false ? "var(--dsw-alias-label-primary-foreground, #fff)" : "var(--dsw-alias-label-primary,inherit)" },
|
|
1854
|
-
onClick: () => requestLanToggle(true)
|
|
1855
|
-
}, t("on")),
|
|
1856
|
-
(0, import_react2.createElement)("button", {
|
|
1857
|
-
style: { ...styles.btn, height: 28, padding: "0 12px", fontSize: 12, fontWeight: status?.lanEnabled === false ? 600 : 400, background: status?.lanEnabled === false ? "var(--dsw-alias-state-error-primary,#dc2626)" : "var(--dsw-alias-bg-layer-1,#fff)", color: status?.lanEnabled === false ? "#fff" : "var(--dsw-alias-label-primary,inherit)" },
|
|
1858
|
-
onClick: () => requestLanToggle(false)
|
|
1859
|
-
}, t("off"))
|
|
1883
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between" } },
|
|
1884
|
+
(0, import_react2.createElement)("span", { style: { fontWeight: 600, fontSize: 13 } }, t("lanAccess")),
|
|
1885
|
+
Switch(status?.lanEnabled !== false, () => requestLanToggle(status?.lanEnabled === false))
|
|
1860
1886
|
),
|
|
1861
1887
|
status?.lanEnabled === false ? (0, import_react2.createElement)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsw-alias-state-warn-primary,#b45309)", lineHeight: 1.5 } }, t("lanDisabledHint")) : lanUrl ? (0, import_react2.createElement)(
|
|
1862
1888
|
"div",
|
|
1863
1889
|
null,
|
|
1864
|
-
(
|
|
1865
|
-
|
|
1866
|
-
(
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
"
|
|
1873
|
-
{
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
style: { font: "inherit", height: 30, padding: "0 8px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-1,#fff)", color: "var(--dsw-alias-label-primary,inherit)" }
|
|
1877
|
-
},
|
|
1878
|
-
(0, import_react2.createElement)("option", { value: "" }, t("lanAddressAuto")),
|
|
1879
|
-
(status?.lanCandidates || []).map((ip) => (0, import_react2.createElement)("option", { key: ip, value: ip }, ip))
|
|
1890
|
+
qrArea(status.lanQr, lanUrl, t("lanHint")),
|
|
1891
|
+
// 访问密码行:开关 + 值(关闭时提示直连)
|
|
1892
|
+
row(
|
|
1893
|
+
t("lanPin"),
|
|
1894
|
+
Switch(status?.lanAuthEnabled !== false, () => setLanAuth(status?.lanAuthEnabled === false)),
|
|
1895
|
+
status?.lanAuthEnabled === false ? (0, import_react2.createElement)("div", { style: { ...styles.muted, marginTop: 6 } }, t("lanPinOff")) : customPin?.which === "lan" ? customPinRow("lan") : (0, import_react2.createElement)(
|
|
1896
|
+
"div",
|
|
1897
|
+
{ style: { marginTop: 6, display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" } },
|
|
1898
|
+
(0, import_react2.createElement)("span", { style: { fontFamily: "ui-monospace,Menlo,monospace", fontSize: 13, letterSpacing: 1 } }, status.lanToken),
|
|
1899
|
+
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12 }, onClick: refreshLanPin }, t("refresh")),
|
|
1900
|
+
customBtn("lan"),
|
|
1901
|
+
status?.lanPinCustom ? (0, import_react2.createElement)("span", { style: { fontSize: 11, color: "var(--dsw-alias-state-warn-primary,#b45309)" } }, t("pinCustomHint")) : null
|
|
1880
1902
|
)
|
|
1881
1903
|
),
|
|
1882
|
-
//
|
|
1883
|
-
(
|
|
1884
|
-
"
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
style: {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1904
|
+
// 高级:手动选地址(默认收起)
|
|
1905
|
+
row(
|
|
1906
|
+
t("advAddress"),
|
|
1907
|
+
(0, import_react2.createElement)(
|
|
1908
|
+
"button",
|
|
1909
|
+
{ style: { border: "none", background: "none", font: "inherit", cursor: "pointer", fontSize: 12, color: "var(--dsw-alias-label-tertiary,#8b93a1)", padding: 0 }, onClick: () => setAdvOpen((v) => !v) },
|
|
1910
|
+
(status?.lanIpOverride || t("lanAddressAuto")) + " \u203A"
|
|
1911
|
+
),
|
|
1912
|
+
advOpen ? (0, import_react2.createElement)(
|
|
1913
|
+
"div",
|
|
1914
|
+
{ style: { marginTop: 8 } },
|
|
1915
|
+
(0, import_react2.createElement)(
|
|
1916
|
+
"label",
|
|
1917
|
+
{ style: { display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } },
|
|
1918
|
+
t("lanAddress"),
|
|
1919
|
+
(0, import_react2.createElement)(
|
|
1920
|
+
"select",
|
|
1921
|
+
{
|
|
1922
|
+
value: status?.lanIpOverride || "",
|
|
1923
|
+
onChange: (e) => setLanAddress(e.target.value),
|
|
1924
|
+
style: { font: "inherit", height: 30, padding: "0 8px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-1,#fff)", color: "var(--dsw-alias-label-primary,inherit)" }
|
|
1925
|
+
},
|
|
1926
|
+
(0, import_react2.createElement)("option", { value: "" }, t("lanAddressAuto")),
|
|
1927
|
+
(status?.lanCandidates || []).map((ip) => (0, import_react2.createElement)("option", { key: ip, value: ip }, ip))
|
|
1928
|
+
)
|
|
1929
|
+
)
|
|
1930
|
+
) : null
|
|
1906
1931
|
)
|
|
1907
1932
|
) : (0, import_react2.createElement)("div", { style: styles.muted }, t("lanStarting"))
|
|
1908
1933
|
),
|
|
1909
|
-
//
|
|
1934
|
+
// 公网:标题行自带 开启/关闭 → 开启后:二维码+地址、地址模式行、访问密码行
|
|
1910
1935
|
(0, import_react2.createElement)(
|
|
1911
1936
|
"div",
|
|
1912
1937
|
{ style: styles.block },
|
|
1913
|
-
(0, import_react2.createElement)(
|
|
1938
|
+
(0, import_react2.createElement)(
|
|
1939
|
+
"div",
|
|
1940
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between" } },
|
|
1941
|
+
(0, import_react2.createElement)("span", { style: { fontWeight: 600, fontSize: 13 } }, t("wanAccess")),
|
|
1942
|
+
tunnelUrl ? (0, import_react2.createElement)("button", { style: { ...styles.btn, height: 28, padding: "0 12px", fontSize: 12, color: "var(--dsw-alias-state-error-primary,#dc2626)" }, onClick: stopTunnel }, t("stopTunnel")) : (0, import_react2.createElement)("button", { style: { ...styles.primary, height: 28, padding: "0 14px", fontSize: 12 }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy || tunnelStarting ? t("opening") : t("enable"))
|
|
1943
|
+
),
|
|
1944
|
+
tunnelStarting ? (0, import_react2.createElement)(
|
|
1945
|
+
"div",
|
|
1946
|
+
{ style: { marginTop: 8, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } },
|
|
1947
|
+
tunnelPhase === "downloading" ? fmt(t, "downloading", { s: elapsed(tunnelStateStarted) }) : fmt(t, "connecting", { s: elapsed(tunnelStateStarted), suffix: elapsed(tunnelStateStarted) > 30 ? t("slowHint") : "" })
|
|
1948
|
+
) : tunnelPhase === "error" ? (0, import_react2.createElement)(
|
|
1949
|
+
"div",
|
|
1950
|
+
{ style: { marginTop: 8, fontSize: 12, color: "var(--dsw-alias-state-error-primary,#dc2626)" } },
|
|
1951
|
+
fmt(t, "error", { detail: tunnelStateDetail || t("unknownError") })
|
|
1952
|
+
) : !tunnelUrl && !isDesktop ? (0, import_react2.createElement)("div", { style: { ...styles.muted, marginTop: 8 } }, t("wanOffHint")) : null,
|
|
1914
1953
|
tunnelUrl ? (0, import_react2.createElement)(
|
|
1915
1954
|
"div",
|
|
1916
1955
|
null,
|
|
1917
|
-
(
|
|
1918
|
-
|
|
1919
|
-
(
|
|
1920
|
-
|
|
1921
|
-
"div",
|
|
1922
|
-
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.5 } },
|
|
1923
|
-
fmt(t, status?.publicPinCustom ? "wanPinCustom" : "wanPin", { pin: status.accessToken }),
|
|
1924
|
-
customBtn("public"),
|
|
1925
|
-
status?.publicPinCustom ? (0, import_react2.createElement)("div", { style: { marginTop: 2, fontSize: 11, color: "var(--dsw-alias-state-warn-primary,#b45309)" } }, t("pinCustomHint")) : null,
|
|
1926
|
-
namedMode ? (0, import_react2.createElement)("div", { style: { marginTop: 2, fontSize: 11, color: "var(--dsw-alias-state-warn-primary,#b45309)" } }, t("namedSecurity")) : null
|
|
1927
|
-
) : null,
|
|
1928
|
-
(0, import_react2.createElement)("button", { style: styles.btn, onClick: stopTunnel }, t("stopTunnel")),
|
|
1929
|
-
// 公网模式(issue #66):仅在公网开启后才显示/可选
|
|
1930
|
-
(0, import_react2.createElement)(
|
|
1931
|
-
"div",
|
|
1932
|
-
{ style: { marginTop: 10 } },
|
|
1956
|
+
qrArea(status.tunnelQr, tunnelUrl, namedMode ? t("namedRunningHint") : t("wanHint")),
|
|
1957
|
+
// 地址模式行(随机/固定;固定域名选中或编辑时高亮)
|
|
1958
|
+
row(
|
|
1959
|
+
t("modeLabel"),
|
|
1933
1960
|
(0, import_react2.createElement)(
|
|
1934
|
-
"
|
|
1935
|
-
{ style: { display: "flex",
|
|
1936
|
-
(0, import_react2.createElement)("
|
|
1937
|
-
(0, import_react2.createElement)("button", {
|
|
1938
|
-
style: modeBtnStyle(!namedActive),
|
|
1939
|
-
onClick: namedMode ? switchToQuick : tunnelCfg ? () => setTunnelCfg(null) : void 0
|
|
1940
|
-
}, t("modeQuick")),
|
|
1941
|
-
(0, import_react2.createElement)("button", {
|
|
1942
|
-
style: modeBtnStyle(namedActive),
|
|
1943
|
-
onClick: () => setTunnelCfg(tunnelCfg ? null : { hostname: tunnelModeView.hostname ?? "", token: "", err: null })
|
|
1944
|
-
}, t("modeNamed"))
|
|
1961
|
+
"span",
|
|
1962
|
+
{ style: { display: "inline-flex", gap: 6 } },
|
|
1963
|
+
(0, import_react2.createElement)("button", { style: modeBtnStyle(!namedActive), onClick: namedMode ? switchToQuick : tunnelCfg ? () => setTunnelCfg(null) : void 0 }, t("modeQuick")),
|
|
1964
|
+
(0, import_react2.createElement)("button", { style: modeBtnStyle(namedActive), onClick: () => setTunnelCfg(tunnelCfg ? null : { hostname: tunnelModeView.hostname ?? "", token: "", err: null }) }, t("modeNamed"))
|
|
1945
1965
|
),
|
|
1946
|
-
|
|
1947
|
-
namedMode && /trycloudflare\.com/i.test(tunnelUrl ?? "") ? (0, import_react2.createElement)("div", { style: { marginTop: 4, fontSize: 11, color: "var(--dsw-alias-state-warn-primary,#b45309)" } }, t("namedTakeEffect")) : null,
|
|
1948
|
-
// 固定域名:已保存的摘要 + 「修改」入口(非编辑态)
|
|
1949
|
-
namedMode && !tunnelCfg ? (0, import_react2.createElement)(
|
|
1950
|
-
"div",
|
|
1951
|
-
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.5 } },
|
|
1952
|
-
fmt(t, "namedSummary", { host: tunnelModeView.hostname || "\u2014", token: tunnelModeView.tokenSet ? t("namedTokenSet") : t("namedTokenMissing") }),
|
|
1953
|
-
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12, marginLeft: 8 }, onClick: () => setTunnelCfg({ hostname: tunnelModeView.hostname ?? "", token: "", err: null }) }, t("namedEdit")),
|
|
1954
|
-
(0, import_react2.createElement)("div", { style: { ...styles.muted, marginTop: 4 } }, t("namedHow")),
|
|
1955
|
-
!tunnelModeView.tokenSet || !tunnelModeView.hostname ? (0, import_react2.createElement)("div", { style: { marginTop: 2, fontSize: 12, color: "var(--dsw-alias-state-error-primary,#dc2626)" } }, t("namedNeedCfg")) : null
|
|
1956
|
-
) : null,
|
|
1957
|
-
// 固定域名:编辑表单(域名 + Tunnel Token,Token 留空保持不变)
|
|
1958
|
-
tunnelCfg ? (0, import_react2.createElement)(
|
|
1966
|
+
(0, import_react2.createElement)(
|
|
1959
1967
|
"div",
|
|
1960
|
-
{ style: { marginTop:
|
|
1961
|
-
|
|
1968
|
+
{ style: { marginTop: 6 } },
|
|
1969
|
+
// 刚保存固定域名但当前连接仍是随机域名:需关闭后重新开启才生效
|
|
1970
|
+
namedMode && /trycloudflare\.com/i.test(tunnelUrl ?? "") ? (0, import_react2.createElement)("div", { style: { ...styles.warn } }, t("namedTakeEffect")) : null,
|
|
1971
|
+
// 固定域名:已保存摘要 + 修改入口(非编辑态)
|
|
1972
|
+
namedMode && !tunnelCfg ? (0, import_react2.createElement)(
|
|
1962
1973
|
"div",
|
|
1963
|
-
|
|
1964
|
-
t("
|
|
1965
|
-
(0, import_react2.createElement)("
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
onKeyDown: (e) => {
|
|
1972
|
-
if (e.key === "Enter") saveNamedTunnel();
|
|
1973
|
-
if (e.key === "Escape") setTunnelCfg(null);
|
|
1974
|
-
}
|
|
1975
|
-
})
|
|
1976
|
-
),
|
|
1977
|
-
(0, import_react2.createElement)(
|
|
1978
|
-
"div",
|
|
1979
|
-
{ style: { marginTop: 6 } },
|
|
1980
|
-
t("namedTokenLabel"),
|
|
1981
|
-
(0, import_react2.createElement)("input", {
|
|
1982
|
-
style: { margin: "4px 0 0 6px", padding: "4px 8px", fontSize: 13, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", borderRadius: 6, outline: "none", width: 240, fontFamily: "ui-monospace,Menlo,monospace" },
|
|
1983
|
-
type: "password",
|
|
1984
|
-
value: tunnelCfg.token ?? "",
|
|
1985
|
-
onChange: (e) => setTunnelCfg((c) => ({ ...c, token: e.target.value.trim(), err: null })),
|
|
1986
|
-
onKeyDown: (e) => {
|
|
1987
|
-
if (e.key === "Enter") saveNamedTunnel();
|
|
1988
|
-
if (e.key === "Escape") setTunnelCfg(null);
|
|
1989
|
-
}
|
|
1990
|
-
})
|
|
1991
|
-
),
|
|
1992
|
-
(0, import_react2.createElement)(
|
|
1974
|
+
{ style: { ...styles.muted } },
|
|
1975
|
+
fmt(t, "namedSummary", { host: tunnelModeView.hostname || "\u2014", token: tunnelModeView.tokenSet ? t("namedTokenSet") : t("namedTokenMissing") }),
|
|
1976
|
+
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12, marginLeft: 8 }, onClick: () => setTunnelCfg({ hostname: tunnelModeView.hostname ?? "", token: "", err: null }) }, t("namedEdit")),
|
|
1977
|
+
(0, import_react2.createElement)("div", { style: { ...styles.muted, marginTop: 4 } }, t("namedHow")),
|
|
1978
|
+
!tunnelModeView.tokenSet || !tunnelModeView.hostname ? (0, import_react2.createElement)("div", { style: { marginTop: 2, color: "var(--dsw-alias-state-error-primary,#dc2626)" } }, t("namedNeedCfg")) : null
|
|
1979
|
+
) : null,
|
|
1980
|
+
// 固定域名:编辑表单(域名 + Tunnel Token,Token 留空保持不变)
|
|
1981
|
+
tunnelCfg ? (0, import_react2.createElement)(
|
|
1993
1982
|
"div",
|
|
1994
|
-
{ style: { marginTop: 6,
|
|
1995
|
-
(0, import_react2.createElement)(
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
1983
|
+
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.6 } },
|
|
1984
|
+
(0, import_react2.createElement)(
|
|
1985
|
+
"div",
|
|
1986
|
+
null,
|
|
1987
|
+
t("namedHostnameLabel"),
|
|
1988
|
+
(0, import_react2.createElement)("input", {
|
|
1989
|
+
style: { margin: "4px 0 0 6px", padding: "4px 8px", fontSize: 13, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", borderRadius: 6, outline: "none", width: 200 },
|
|
1990
|
+
placeholder: "pocket.example.com",
|
|
1991
|
+
value: tunnelCfg.hostname ?? "",
|
|
1992
|
+
autoFocus: true,
|
|
1993
|
+
onChange: (e) => setTunnelCfg((c) => ({ ...c, hostname: e.target.value.trim(), err: null })),
|
|
1994
|
+
onKeyDown: (e) => {
|
|
1995
|
+
if (e.key === "Enter") saveNamedTunnel();
|
|
1996
|
+
if (e.key === "Escape") setTunnelCfg(null);
|
|
1997
|
+
}
|
|
1998
|
+
})
|
|
1999
|
+
),
|
|
2000
|
+
(0, import_react2.createElement)(
|
|
2001
|
+
"div",
|
|
2002
|
+
{ style: { marginTop: 6 } },
|
|
2003
|
+
t("namedTokenLabel"),
|
|
2004
|
+
(0, import_react2.createElement)("input", {
|
|
2005
|
+
style: { margin: "4px 0 0 6px", padding: "4px 8px", fontSize: 13, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", borderRadius: 6, outline: "none", width: 240, fontFamily: "ui-monospace,Menlo,monospace" },
|
|
2006
|
+
type: "password",
|
|
2007
|
+
value: tunnelCfg.token ?? "",
|
|
2008
|
+
onChange: (e) => setTunnelCfg((c) => ({ ...c, token: e.target.value.trim(), err: null })),
|
|
2009
|
+
onKeyDown: (e) => {
|
|
2010
|
+
if (e.key === "Enter") saveNamedTunnel();
|
|
2011
|
+
if (e.key === "Escape") setTunnelCfg(null);
|
|
2012
|
+
}
|
|
2013
|
+
})
|
|
2014
|
+
),
|
|
2015
|
+
(0, import_react2.createElement)(
|
|
2016
|
+
"div",
|
|
2017
|
+
{ style: { marginTop: 6, display: "flex", gap: 8 } },
|
|
2018
|
+
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12 }, onClick: saveNamedTunnel }, t("save")),
|
|
2019
|
+
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12 }, onClick: () => setTunnelCfg(null) }, t("cancel"))
|
|
2020
|
+
),
|
|
2021
|
+
(0, import_react2.createElement)("div", { style: { ...styles.muted, marginTop: 6 } }, t("namedHow")),
|
|
2022
|
+
(0, import_react2.createElement)("div", { style: { marginTop: 2, fontSize: 11, color: "var(--dsw-alias-state-warn-primary,#b45309)", lineHeight: 1.5 } }, t("namedSecurity")),
|
|
2023
|
+
tunnelCfg.err ? (0, import_react2.createElement)("div", { style: { color: "var(--dsw-alias-state-error-primary,#dc2626)", marginTop: 4 } }, tunnelCfg.err) : null
|
|
2024
|
+
) : null
|
|
2025
|
+
)
|
|
2026
|
+
),
|
|
2027
|
+
// 访问密码行:值 + 自定义(自定义输入态整体替换)
|
|
2028
|
+
status.accessToken ? row(
|
|
2029
|
+
t("pinLabel"),
|
|
2030
|
+
customPin?.which === "public" ? null : (0, import_react2.createElement)(
|
|
2031
|
+
"span",
|
|
2032
|
+
{ style: { display: "inline-flex", alignItems: "center", gap: 8 } },
|
|
2033
|
+
(0, import_react2.createElement)("span", { style: { fontFamily: "ui-monospace,Menlo,monospace", fontSize: 13, letterSpacing: 1 } }, status.accessToken),
|
|
2034
|
+
customBtn("public")
|
|
2035
|
+
),
|
|
2036
|
+
(0, import_react2.createElement)(
|
|
2037
|
+
"div",
|
|
2038
|
+
{ style: { marginTop: 6 } },
|
|
2039
|
+
customPin?.which === "public" ? customPinRow("public") : null,
|
|
2040
|
+
status?.publicPinCustom ? (0, import_react2.createElement)("div", { style: { ...styles.warn } }, t("pinCustomHint")) : null,
|
|
2041
|
+
namedMode ? (0, import_react2.createElement)("div", { style: { ...styles.warn } }, t("namedSecurity")) : null
|
|
2042
|
+
)
|
|
2015
2043
|
) : null
|
|
2016
|
-
)
|
|
2044
|
+
) : null
|
|
2017
2045
|
),
|
|
2018
2046
|
error ? (0, import_react2.createElement)("div", { style: { color: "var(--dsw-alias-state-error-primary,#dc2626)", fontSize: 12, marginTop: 8 } }, `\u274C ${error}`) : null,
|
|
2019
2047
|
// 局域网访问开关确认弹框(关闭/打开时弹窗提醒)
|
package/client/index.jsx
CHANGED
|
@@ -315,6 +315,23 @@ function PocketSettingsTab({ rpcCall, t }) {
|
|
|
315
315
|
background: active ? 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))' : 'var(--dsw-alias-bg-layer-1,#fff)',
|
|
316
316
|
color: active ? 'var(--dsw-alias-label-primary-foreground, #fff)' : 'var(--dsw-alias-label-primary,inherit)',
|
|
317
317
|
});
|
|
318
|
+
// iOS 风格小开关(重排后统一用:局域网总开关 / 局域网密码开关)
|
|
319
|
+
const Switch = (on, onClick) => h('button', {
|
|
320
|
+
role: 'switch', 'aria-checked': !!on,
|
|
321
|
+
style: { flexShrink: 0, width: 40, height: 22, borderRadius: 11, border: 'none', padding: 0, position: 'relative', cursor: 'pointer', font: 'inherit', background: on ? 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))' : 'var(--dsw-alias-border-l2,#d1d5db)' },
|
|
322
|
+
onClick,
|
|
323
|
+
}, h('span', { style: { position: 'absolute', top: 2, left: on ? 20 : 2, width: 18, height: 18, borderRadius: '50%', background: '#fff' } }));
|
|
324
|
+
// 卡片内主内容:二维码 + 地址 + 提示
|
|
325
|
+
const qrArea = (src, url, hint) => h('div', { style: { background: 'var(--dsw-alias-bg-layer-2,#f3f4f6)', borderRadius: 10, padding: '10px 12px', textAlign: 'center', margin: '10px 0' } },
|
|
326
|
+
h('img', { src, alt: 'QR', style: styles.qr }),
|
|
327
|
+
h('div', { style: styles.code }, url),
|
|
328
|
+
h('div', { style: styles.muted }, hint));
|
|
329
|
+
// 设置行:上分隔线,内部第一行 = 左标签 + 右操作;extra 作为第二段渲染
|
|
330
|
+
const row = (label, control, extra) => h('div', { style: { borderTop: '1px solid var(--dsw-alias-border-l2,#e5e7eb)', paddingTop: 9, marginTop: 9 } },
|
|
331
|
+
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
|
|
332
|
+
h('span', { style: { fontSize: 13 } }, label), control), extra ?? null);
|
|
333
|
+
// 高级(手动选地址)展开态
|
|
334
|
+
const [advOpen, setAdvOpen] = useState(false);
|
|
318
335
|
|
|
319
336
|
return h('div', { style: styles.card },
|
|
320
337
|
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
|
|
@@ -369,151 +386,134 @@ function PocketSettingsTab({ rpcCall, t }) {
|
|
|
369
386
|
: fmt(t, 'versionRange', { cur: updateInfo.current, latest: updateInfo.latest })),
|
|
370
387
|
) : null,
|
|
371
388
|
|
|
372
|
-
//
|
|
389
|
+
// 局域网:标题行自带总开关 → 二维码+地址 → 设置行(访问密码 / 高级·手动选地址)
|
|
373
390
|
h('div', { style: styles.block },
|
|
374
|
-
h('div', { style: {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
h('span', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } }, t('lanAccess')),
|
|
378
|
-
h('button', {
|
|
379
|
-
style: { ...styles.btn, height: 28, padding: '0 12px', fontSize: 12, fontWeight: status?.lanEnabled !== false ? 600 : 400, background: status?.lanEnabled !== false ? 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))' : 'var(--dsw-alias-bg-layer-1,#fff)', color: status?.lanEnabled !== false ? 'var(--dsw-alias-label-primary-foreground, #fff)' : 'var(--dsw-alias-label-primary,inherit)' },
|
|
380
|
-
onClick: () => requestLanToggle(true),
|
|
381
|
-
}, t('on')),
|
|
382
|
-
h('button', {
|
|
383
|
-
style: { ...styles.btn, height: 28, padding: '0 12px', fontSize: 12, fontWeight: status?.lanEnabled === false ? 600 : 400, background: status?.lanEnabled === false ? 'var(--dsw-alias-state-error-primary,#dc2626)' : 'var(--dsw-alias-bg-layer-1,#fff)', color: status?.lanEnabled === false ? '#fff' : 'var(--dsw-alias-label-primary,inherit)' },
|
|
384
|
-
onClick: () => requestLanToggle(false),
|
|
385
|
-
}, t('off')),
|
|
391
|
+
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
|
|
392
|
+
h('span', { style: { fontWeight: 600, fontSize: 13 } }, t('lanAccess')),
|
|
393
|
+
Switch(status?.lanEnabled !== false, () => requestLanToggle(status?.lanEnabled === false)),
|
|
386
394
|
),
|
|
387
395
|
status?.lanEnabled === false
|
|
388
396
|
? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-state-warn-primary,#b45309)', lineHeight: 1.5 } }, t('lanDisabledHint'))
|
|
389
397
|
: (lanUrl
|
|
390
398
|
? h('div', null,
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
fmt(t, status?.lanPinCustom ? 'lanPinCustomValue' : 'lanPinValue', { pin: status.lanToken }),
|
|
422
|
-
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12, marginLeft: 8 }, onClick: refreshLanPin }, t('refresh')),
|
|
423
|
-
customBtn('lan'),
|
|
424
|
-
))
|
|
425
|
-
: h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-state-warn-primary,#b45309)', lineHeight: 1.5 } },
|
|
426
|
-
t('lanPinOff')),
|
|
399
|
+
qrArea(status.lanQr, lanUrl, t('lanHint')),
|
|
400
|
+
// 访问密码行:开关 + 值(关闭时提示直连)
|
|
401
|
+
row(t('lanPin'), Switch(status?.lanAuthEnabled !== false, () => setLanAuth(status?.lanAuthEnabled === false)),
|
|
402
|
+
status?.lanAuthEnabled === false
|
|
403
|
+
? h('div', { style: { ...styles.muted, marginTop: 6 } }, t('lanPinOff'))
|
|
404
|
+
: (customPin?.which === 'lan'
|
|
405
|
+
? customPinRow('lan')
|
|
406
|
+
: h('div', { style: { marginTop: 6, display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
|
|
407
|
+
h('span', { style: { fontFamily: 'ui-monospace,Menlo,monospace', fontSize: 13, letterSpacing: 1 } }, status.lanToken),
|
|
408
|
+
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12 }, onClick: refreshLanPin }, t('refresh')),
|
|
409
|
+
customBtn('lan'),
|
|
410
|
+
status?.lanPinCustom ? h('span', { style: { fontSize: 11, color: 'var(--dsw-alias-state-warn-primary,#b45309)' } }, t('pinCustomHint')) : null,
|
|
411
|
+
))),
|
|
412
|
+
// 高级:手动选地址(默认收起)
|
|
413
|
+
row(t('advAddress'),
|
|
414
|
+
h('button', { style: { border: 'none', background: 'none', font: 'inherit', cursor: 'pointer', fontSize: 12, color: 'var(--dsw-alias-label-tertiary,#8b93a1)', padding: 0 }, onClick: () => setAdvOpen((v) => !v) },
|
|
415
|
+
(status?.lanIpOverride || t('lanAddressAuto')) + ' ›'),
|
|
416
|
+
advOpen ? h('div', { style: { marginTop: 8 } },
|
|
417
|
+
h('label', { style: { display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } },
|
|
418
|
+
t('lanAddress'),
|
|
419
|
+
h('select', {
|
|
420
|
+
value: status?.lanIpOverride || '',
|
|
421
|
+
onChange: (e) => setLanAddress(e.target.value),
|
|
422
|
+
style: { font: 'inherit', height: 30, padding: '0 8px', borderRadius: 8, border: '1px solid var(--dsw-alias-border-l2,#d1d5db)', background: 'var(--dsw-alias-bg-layer-1,#fff)', color: 'var(--dsw-alias-label-primary,inherit)' },
|
|
423
|
+
},
|
|
424
|
+
h('option', { value: '' }, t('lanAddressAuto')),
|
|
425
|
+
(status?.lanCandidates || []).map((ip) => h('option', { key: ip, value: ip }, ip)),
|
|
426
|
+
),
|
|
427
|
+
),
|
|
428
|
+
) : null),
|
|
427
429
|
)
|
|
428
430
|
: h('div', { style: styles.muted }, t('lanStarting'))),
|
|
429
431
|
),
|
|
430
432
|
|
|
431
|
-
//
|
|
433
|
+
// 公网:标题行自带 开启/关闭 → 开启后:二维码+地址、地址模式行、访问密码行
|
|
432
434
|
h('div', { style: styles.block },
|
|
433
|
-
h('div', { style: {
|
|
435
|
+
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
|
|
436
|
+
h('span', { style: { fontWeight: 600, fontSize: 13 } }, t('wanAccess')),
|
|
437
|
+
tunnelUrl
|
|
438
|
+
? h('button', { style: { ...styles.btn, height: 28, padding: '0 12px', fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' }, onClick: stopTunnel }, t('stopTunnel'))
|
|
439
|
+
: h('button', { style: { ...styles.primary, height: 28, padding: '0 14px', fontSize: 12 }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy || tunnelStarting ? t('opening') : t('enable')),
|
|
440
|
+
),
|
|
441
|
+
tunnelStarting
|
|
442
|
+
? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } },
|
|
443
|
+
tunnelPhase === 'downloading'
|
|
444
|
+
? fmt(t, 'downloading', { s: elapsed(tunnelStateStarted) })
|
|
445
|
+
: fmt(t, 'connecting', { s: elapsed(tunnelStateStarted), suffix: elapsed(tunnelStateStarted) > 30 ? t('slowHint') : '' }))
|
|
446
|
+
: tunnelPhase === 'error'
|
|
447
|
+
? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } },
|
|
448
|
+
fmt(t, 'error', { detail: tunnelStateDetail || t('unknownError') }))
|
|
449
|
+
: (!tunnelUrl && !isDesktop ? h('div', { style: { ...styles.muted, marginTop: 8 } }, t('wanOffHint')) : null),
|
|
434
450
|
tunnelUrl
|
|
435
451
|
? h('div', null,
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
h('
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
452
|
+
qrArea(status.tunnelQr, tunnelUrl, namedMode ? t('namedRunningHint') : t('wanHint')),
|
|
453
|
+
// 地址模式行(随机/固定;固定域名选中或编辑时高亮)
|
|
454
|
+
row(t('modeLabel'),
|
|
455
|
+
h('span', { style: { display: 'inline-flex', gap: 6 } },
|
|
456
|
+
h('button', { style: modeBtnStyle(!namedActive), onClick: namedMode ? switchToQuick : (tunnelCfg ? () => setTunnelCfg(null) : undefined) }, t('modeQuick')),
|
|
457
|
+
h('button', { style: modeBtnStyle(namedActive), onClick: () => setTunnelCfg(tunnelCfg ? null : { hostname: tunnelModeView.hostname ?? '', token: '', err: null }) }, t('modeNamed')),
|
|
458
|
+
),
|
|
459
|
+
h('div', { style: { marginTop: 6 } },
|
|
460
|
+
// 刚保存固定域名但当前连接仍是随机域名:需关闭后重新开启才生效
|
|
461
|
+
namedMode && /trycloudflare\.com/i.test(tunnelUrl ?? '') ? h('div', { style: { ...styles.warn } }, t('namedTakeEffect')) : null,
|
|
462
|
+
// 固定域名:已保存摘要 + 修改入口(非编辑态)
|
|
463
|
+
namedMode && !tunnelCfg ? h('div', { style: { ...styles.muted } },
|
|
464
|
+
fmt(t, 'namedSummary', { host: tunnelModeView.hostname || '—', token: tunnelModeView.tokenSet ? t('namedTokenSet') : t('namedTokenMissing') }),
|
|
465
|
+
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12, marginLeft: 8 }, onClick: () => setTunnelCfg({ hostname: tunnelModeView.hostname ?? '', token: '', err: null }) }, t('namedEdit')),
|
|
466
|
+
h('div', { style: { ...styles.muted, marginTop: 4 } }, t('namedHow')),
|
|
467
|
+
!tunnelModeView.tokenSet || !tunnelModeView.hostname ? h('div', { style: { marginTop: 2, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } }, t('namedNeedCfg')) : null,
|
|
468
|
+
) : null,
|
|
469
|
+
// 固定域名:编辑表单(域名 + Tunnel Token,Token 留空保持不变)
|
|
470
|
+
tunnelCfg ? h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.6 } },
|
|
471
|
+
h('div', null,
|
|
472
|
+
t('namedHostnameLabel'),
|
|
473
|
+
h('input', {
|
|
474
|
+
style: { margin: '4px 0 0 6px', padding: '4px 8px', fontSize: 13, border: '1px solid var(--dsw-alias-border-l2,#d1d5db)', borderRadius: 6, outline: 'none', width: 200 },
|
|
475
|
+
placeholder: 'pocket.example.com',
|
|
476
|
+
value: tunnelCfg.hostname ?? '',
|
|
477
|
+
autoFocus: true,
|
|
478
|
+
onChange: (e) => setTunnelCfg((c) => ({ ...c, hostname: e.target.value.trim(), err: null })),
|
|
479
|
+
onKeyDown: (e) => { if (e.key === 'Enter') saveNamedTunnel(); if (e.key === 'Escape') setTunnelCfg(null); },
|
|
480
|
+
}),
|
|
481
|
+
),
|
|
482
|
+
h('div', { style: { marginTop: 6 } },
|
|
483
|
+
t('namedTokenLabel'),
|
|
484
|
+
h('input', {
|
|
485
|
+
style: { margin: '4px 0 0 6px', padding: '4px 8px', fontSize: 13, border: '1px solid var(--dsw-alias-border-l2,#d1d5db)', borderRadius: 6, outline: 'none', width: 240, fontFamily: 'ui-monospace,Menlo,monospace' },
|
|
486
|
+
type: 'password',
|
|
487
|
+
value: tunnelCfg.token ?? '',
|
|
488
|
+
onChange: (e) => setTunnelCfg((c) => ({ ...c, token: e.target.value.trim(), err: null })),
|
|
489
|
+
onKeyDown: (e) => { if (e.key === 'Enter') saveNamedTunnel(); if (e.key === 'Escape') setTunnelCfg(null); },
|
|
490
|
+
}),
|
|
491
|
+
),
|
|
492
|
+
h('div', { style: { marginTop: 6, display: 'flex', gap: 8 } },
|
|
493
|
+
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12 }, onClick: saveNamedTunnel }, t('save')),
|
|
494
|
+
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12 }, onClick: () => setTunnelCfg(null) }, t('cancel')),
|
|
495
|
+
),
|
|
496
|
+
h('div', { style: { ...styles.muted, marginTop: 6 } }, t('namedHow')),
|
|
497
|
+
h('div', { style: { marginTop: 2, fontSize: 11, color: 'var(--dsw-alias-state-warn-primary,#b45309)', lineHeight: 1.5 } }, t('namedSecurity')),
|
|
498
|
+
tunnelCfg.err ? h('div', { style: { color: 'var(--dsw-alias-state-error-primary,#dc2626)', marginTop: 4 } }, tunnelCfg.err) : null,
|
|
499
|
+
) : null,
|
|
462
500
|
),
|
|
463
|
-
// 刚保存固定域名但当前连接仍是随机域名:需关闭后重新开启才生效
|
|
464
|
-
namedMode && /trycloudflare\.com/i.test(tunnelUrl ?? '') ? h('div', { style: { marginTop: 4, fontSize: 11, color: 'var(--dsw-alias-state-warn-primary,#b45309)' } }, t('namedTakeEffect')) : null,
|
|
465
|
-
// 固定域名:已保存的摘要 + 「修改」入口(非编辑态)
|
|
466
|
-
namedMode && !tunnelCfg ? h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.5 } },
|
|
467
|
-
fmt(t, 'namedSummary', { host: tunnelModeView.hostname || '—', token: tunnelModeView.tokenSet ? t('namedTokenSet') : t('namedTokenMissing') }),
|
|
468
|
-
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12, marginLeft: 8 }, onClick: () => setTunnelCfg({ hostname: tunnelModeView.hostname ?? '', token: '', err: null }) }, t('namedEdit')),
|
|
469
|
-
h('div', { style: { ...styles.muted, marginTop: 4 } }, t('namedHow')),
|
|
470
|
-
!tunnelModeView.tokenSet || !tunnelModeView.hostname ? h('div', { style: { marginTop: 2, fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } }, t('namedNeedCfg')) : null,
|
|
471
|
-
) : null,
|
|
472
|
-
// 固定域名:编辑表单(域名 + Tunnel Token,Token 留空保持不变)
|
|
473
|
-
tunnelCfg ? h('div', { style: { marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.6 } },
|
|
474
|
-
h('div', null,
|
|
475
|
-
t('namedHostnameLabel'),
|
|
476
|
-
h('input', {
|
|
477
|
-
style: { margin: '4px 0 0 6px', padding: '4px 8px', fontSize: 13, border: '1px solid var(--dsw-alias-border-l2,#d1d5db)', borderRadius: 6, outline: 'none', width: 200 },
|
|
478
|
-
placeholder: 'pocket.example.com',
|
|
479
|
-
value: tunnelCfg.hostname ?? '',
|
|
480
|
-
autoFocus: true,
|
|
481
|
-
onChange: (e) => setTunnelCfg((c) => ({ ...c, hostname: e.target.value.trim(), err: null })),
|
|
482
|
-
onKeyDown: (e) => { if (e.key === 'Enter') saveNamedTunnel(); if (e.key === 'Escape') setTunnelCfg(null); },
|
|
483
|
-
}),
|
|
484
|
-
),
|
|
485
|
-
h('div', { style: { marginTop: 6 } },
|
|
486
|
-
t('namedTokenLabel'),
|
|
487
|
-
h('input', {
|
|
488
|
-
style: { margin: '4px 0 0 6px', padding: '4px 8px', fontSize: 13, border: '1px solid var(--dsw-alias-border-l2,#d1d5db)', borderRadius: 6, outline: 'none', width: 240, fontFamily: 'ui-monospace,Menlo,monospace' },
|
|
489
|
-
type: 'password',
|
|
490
|
-
value: tunnelCfg.token ?? '',
|
|
491
|
-
onChange: (e) => setTunnelCfg((c) => ({ ...c, token: e.target.value.trim(), err: null })),
|
|
492
|
-
onKeyDown: (e) => { if (e.key === 'Enter') saveNamedTunnel(); if (e.key === 'Escape') setTunnelCfg(null); },
|
|
493
|
-
}),
|
|
494
|
-
),
|
|
495
|
-
h('div', { style: { marginTop: 6, display: 'flex', gap: 8 } },
|
|
496
|
-
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12 }, onClick: saveNamedTunnel }, t('save')),
|
|
497
|
-
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12 }, onClick: () => setTunnelCfg(null) }, t('cancel')),
|
|
498
|
-
),
|
|
499
|
-
h('div', { style: { ...styles.muted, marginTop: 6 } }, t('namedHow')),
|
|
500
|
-
h('div', { style: { marginTop: 2, fontSize: 11, color: 'var(--dsw-alias-state-warn-primary,#b45309)', lineHeight: 1.5 } }, t('namedSecurity')),
|
|
501
|
-
tunnelCfg.err ? h('div', { style: { color: 'var(--dsw-alias-state-error-primary,#dc2626)', marginTop: 4 } }, tunnelCfg.err) : null,
|
|
502
|
-
) : null,
|
|
503
501
|
),
|
|
502
|
+
// 访问密码行:值 + 自定义(自定义输入态整体替换)
|
|
503
|
+
status.accessToken
|
|
504
|
+
? row(t('pinLabel'),
|
|
505
|
+
customPin?.which === 'public'
|
|
506
|
+
? null
|
|
507
|
+
: h('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 8 } },
|
|
508
|
+
h('span', { style: { fontFamily: 'ui-monospace,Menlo,monospace', fontSize: 13, letterSpacing: 1 } }, status.accessToken),
|
|
509
|
+
customBtn('public')),
|
|
510
|
+
h('div', { style: { marginTop: 6 } },
|
|
511
|
+
customPin?.which === 'public' ? customPinRow('public') : null,
|
|
512
|
+
status?.publicPinCustom ? h('div', { style: { ...styles.warn } }, t('pinCustomHint')) : null,
|
|
513
|
+
namedMode ? h('div', { style: { ...styles.warn } }, t('namedSecurity')) : null))
|
|
514
|
+
: null,
|
|
504
515
|
)
|
|
505
|
-
:
|
|
506
|
-
h('button', { style: { ...styles.primary, margin: '8px 0' }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? t('opening') : t('enable')),
|
|
507
|
-
tunnelStarting
|
|
508
|
-
? h('div', { style: { marginTop: 4, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } },
|
|
509
|
-
tunnelPhase === 'downloading'
|
|
510
|
-
? fmt(t, 'downloading', { s: elapsed(tunnelStateStarted) })
|
|
511
|
-
: fmt(t, 'connecting', { s: elapsed(tunnelStateStarted), suffix: elapsed(tunnelStateStarted) > 30 ? t('slowHint') : '' }))
|
|
512
|
-
: tunnelPhase === 'error'
|
|
513
|
-
? h('div', { style: { marginTop: 4, fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } },
|
|
514
|
-
fmt(t, 'error', { detail: tunnelStateDetail || t('unknownError') }))
|
|
515
|
-
: null,
|
|
516
|
-
),
|
|
516
|
+
: null,
|
|
517
517
|
),
|
|
518
518
|
|
|
519
519
|
error ? h('div', { style: { color: 'var(--dsw-alias-state-error-primary,#dc2626)', fontSize: 12, marginTop: 8 } }, `❌ ${error}`) : null,
|
package/client/pocket-locales.js
CHANGED
|
@@ -28,6 +28,11 @@ export const zh = {
|
|
|
28
28
|
'updatedRestartDetail': '✅ 已更新,重启 dsh web 生效',
|
|
29
29
|
'updateFailed': '❌ 失败:{err}(手动更新:dsh plugin --profile web update dsh-pocket --latest -w)',
|
|
30
30
|
'versionRange': '当前 v{cur} → 最新 v{latest}',
|
|
31
|
+
'wanAccess': '公网访问',
|
|
32
|
+
'pinLabel': '访问密码',
|
|
33
|
+
'modeLabel': '地址模式',
|
|
34
|
+
'advAddress': '高级 · 手动选地址',
|
|
35
|
+
'wanOffHint': '开启后可从任何网络访问(每次开启需确认免责声明)',
|
|
31
36
|
'lanTitle': '📶 局域网(同一 WiFi)',
|
|
32
37
|
'lanHint': '手机连接同一 WiFi 后扫码即可打开',
|
|
33
38
|
'lanAccess': '局域网访问',
|
|
@@ -112,6 +117,11 @@ export const en = {
|
|
|
112
117
|
'updatedRestartDetail': '✅ Updated — restart dsh web to apply',
|
|
113
118
|
'updateFailed': '❌ Failed: {err} (manual update: dsh plugin --profile web update dsh-pocket --latest -w)',
|
|
114
119
|
'versionRange': 'Current v{cur} → latest v{latest}',
|
|
120
|
+
'wanAccess': 'Public access',
|
|
121
|
+
'pinLabel': 'Access PIN',
|
|
122
|
+
'modeLabel': 'Address mode',
|
|
123
|
+
'advAddress': 'Advanced · Pick address',
|
|
124
|
+
'wanOffHint': 'Reachable from any network once enabled (a disclaimer is confirmed on each enable)',
|
|
115
125
|
'lanTitle': '📶 LAN (same Wi-Fi)',
|
|
116
126
|
'lanHint': 'Scan to open once your phone is on the same Wi-Fi',
|
|
117
127
|
'lanAccess': 'LAN access',
|
package/package.json
CHANGED