dsh-remote-mobile 1.2.1 → 1.4.1
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 +82 -0
- package/README.md +94 -13
- package/README_EN.md +93 -13
- package/lib/auth/crypto.js +2 -2
- package/lib/auth/gate.d.ts +15 -0
- package/lib/auth/gate.js +49 -0
- package/lib/auth/token.js +9 -4
- package/lib/bridge/compat.d.ts +79 -9
- package/lib/bridge/compat.js +562 -51
- package/lib/client.js +1114 -303
- package/lib/index.d.ts +1 -0
- package/lib/index.js +9 -6
- package/lib/routes/api.d.ts +6 -1
- package/lib/routes/api.js +85 -2
- package/lib/styles/style-snippets.d.ts +133 -0
- package/lib/styles/style-snippets.js +932 -0
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -47,10 +47,10 @@ __export(index_exports, {
|
|
|
47
47
|
inject: () => inject
|
|
48
48
|
});
|
|
49
49
|
module.exports = __toCommonJS(index_exports);
|
|
50
|
-
var
|
|
50
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
51
51
|
|
|
52
52
|
// src/client/components/MainSection.jsx
|
|
53
|
-
var
|
|
53
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
54
54
|
|
|
55
55
|
// src/client/api.js
|
|
56
56
|
function fetchStatus() {
|
|
@@ -132,6 +132,46 @@ function clearIpStatsApi() {
|
|
|
132
132
|
return res.json();
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
|
+
function fetchStyles() {
|
|
136
|
+
return fetch("/api/remote-mobile/styles?_t=" + Date.now()).then(function(res) {
|
|
137
|
+
return res.json();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function saveStyleSnippet(payload) {
|
|
141
|
+
return fetch("/api/remote-mobile/styles", {
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: { "Content-Type": "application/json" },
|
|
144
|
+
body: JSON.stringify(payload)
|
|
145
|
+
}).then(function(res) {
|
|
146
|
+
return res.json();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function toggleStyleApi(id, scope, enabled) {
|
|
150
|
+
return fetch("/api/remote-mobile/styles/toggle", {
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: { "Content-Type": "application/json" },
|
|
153
|
+
body: JSON.stringify({ id, scope, enabled })
|
|
154
|
+
}).then(function(res) {
|
|
155
|
+
return res.json();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function deleteStyleSnippetApi(id) {
|
|
159
|
+
return fetch("/api/remote-mobile/styles/delete", {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
162
|
+
body: JSON.stringify({ id })
|
|
163
|
+
}).then(function(res) {
|
|
164
|
+
return res.json();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function resetStylesApi() {
|
|
168
|
+
return fetch("/api/remote-mobile/styles/reset", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: { "Content-Type": "application/json" }
|
|
171
|
+
}).then(function(res) {
|
|
172
|
+
return res.json();
|
|
173
|
+
});
|
|
174
|
+
}
|
|
135
175
|
|
|
136
176
|
// src/client/qrcode.js
|
|
137
177
|
var generateQrSvg = (function() {
|
|
@@ -739,7 +779,7 @@ var translations = {
|
|
|
739
779
|
storageCardDesc: "\u6240\u6709\u654F\u611F\u51ED\u8BC1\u5747\u5728\u672C\u5730\u7ECF\u8FC7\u52A0\u76D0\u54C8\u5E0C\u6216\u975E\u5BF9\u79F0\u52A0\u5BC6\u4FDD\u62A4\uFF0C\u4E0D\u4F9D\u8D56\u4EFB\u4F55\u7B2C\u4E09\u65B9\u4E91\u7AEF\u9274\u6743\u4E2D\u5FC3\u3002",
|
|
740
780
|
storageDeviceFile: "\u5DF2\u6388\u6743\u8BBE\u5907\u4E0E\u4F1A\u8BDD\u7F13\u5B58\u6587\u4EF6\uFF1A",
|
|
741
781
|
storageRsaFile: "\u670D\u52A1\u7AEF RSA \u79C1\u94A5\u6587\u4EF6 (0o600 \u6743\u9650\u4FDD\u62A4)\uFF1A",
|
|
742
|
-
|
|
782
|
+
storageStylesFile: "\u79FB\u52A8\u7AEF\u6837\u5F0F\u7247\u6BB5\u6587\u4EF6 (\u53EF\u72EC\u7ACB\u542F\u505C\u7684 CSS \u5C0F\u63D2\u4EF6)\uFF1A",
|
|
743
783
|
// 卡片 7: 全局高级配置
|
|
744
784
|
configCardTitle: "\u5168\u5C40\u9AD8\u7EA7\u5B89\u5168\u53C2\u6570\u914D\u7F6E",
|
|
745
785
|
configCardDesc: "\u8C03\u6574\u5355 IP \u8BBF\u95EE\u9891\u7387\u9650\u5236\u3001\u8F93\u9519\u5C01\u7981\u9608\u503C\u4E0E\u9501\u5B9A\u6301\u7EED\u65F6\u95F4\u3002\u70B9\u51FB\u4FDD\u5B58\u5C06\u7ACB\u5373\u751F\u6548\u5E76\u81EA\u52A8\u540C\u6B65\u5199\u56DE ~/.dsh/settings.yaml \u914D\u7F6E\u6587\u4EF6\u3002",
|
|
@@ -758,6 +798,49 @@ var translations = {
|
|
|
758
798
|
saveConfigSuccessToast: "\u9AD8\u7EA7\u5B89\u5168\u53C2\u6570\u5DF2\u6210\u529F\u4FDD\u5B58\u5E76\u540C\u6B65\u5230 settings.yaml\uFF01",
|
|
759
799
|
restoreDefaultsSuccessToast: "\u5DF2\u6210\u529F\u6062\u590D\u9ED8\u8BA4\u5B89\u5168\u53C2\u6570\u5E76\u7ACB\u5373\u751F\u6548\uFF01",
|
|
760
800
|
saveConfigFailTip: "\u53C2\u6570\u5FC5\u987B\u4E3A\u5927\u4E8E 0 \u7684\u6709\u6548\u6574\u6570",
|
|
801
|
+
// 卡片 8: 移动端样式片段(样式小插件)
|
|
802
|
+
tabAccess: "\u63A5\u5165",
|
|
803
|
+
tabDevices: "\u8BBE\u5907\u4E0E\u5B89\u5168",
|
|
804
|
+
tabStyle: "\u6837\u5F0F\u8986\u5199",
|
|
805
|
+
tabStorage: "\u672C\u5730\u6570\u636E",
|
|
806
|
+
stylesCardTitle: "\u79FB\u52A8\u7AEF\u6837\u5F0F\u7247\u6BB5\uFF08\u6837\u5F0F\u5C0F\u63D2\u4EF6\uFF09",
|
|
807
|
+
stylesCardDesc: "\u4EE5\u53EF\u72EC\u7ACB\u542F\u505C\u7684 CSS \u7247\u6BB5\u65B9\u5F0F\u9002\u914D DSH Web \u754C\u9762\u3002\u5185\u7F6E\u9884\u8BBE\u6309\u754C\u9762\u533A\u57DF\u5206\u4E3A\u4FA7\u8FB9\u680F\u3001\u8BBE\u7F6E\u9762\u677F\u4E0E\u6B63\u6587\u4E09\u6BB5\uFF0C\u6BCF\u6BB5\u5747\u53EF\u5206\u522B\u8BBE\u7F6E PC / \u79FB\u52A8\u7AEF\u662F\u5426\u542F\u7528\uFF1B\u4F60\u4E5F\u53EF\u4EE5\u7C98\u8D34\u81EA\u5DF1\u7684 CSS \u5C0F\u63D2\u4EF6\uFF0C\u4FDD\u5B58\u540E\u4E0B\u4E00\u6B21\u9875\u9762\u52A0\u8F7D\u7ACB\u5373\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002",
|
|
808
|
+
stylesPresetsTitle: "\u{1F9E9} \u5185\u7F6E\u9884\u8BBE\u7247\u6BB5",
|
|
809
|
+
stylesCustomTitle: "\u270D\uFE0F \u81EA\u5B9A\u4E49\u7247\u6BB5",
|
|
810
|
+
stylesPcShort: "PC",
|
|
811
|
+
stylesMobileShort: "\u79FB\u52A8\u7AEF",
|
|
812
|
+
stylesBothDevices: "PC + \u79FB\u52A8\u7AEF",
|
|
813
|
+
stylesMobileOnlyBadge: "\u4EC5\u79FB\u52A8\u7AEF",
|
|
814
|
+
stylesPcOnlyBadge: "\u4EC5 PC",
|
|
815
|
+
stylesDisabled: "\u5DF2\u505C\u7528",
|
|
816
|
+
stylesViewCss: "\u67E5\u770B CSS",
|
|
817
|
+
stylesHideCss: "\u6536\u8D77 CSS",
|
|
818
|
+
stylesCopyCss: "\u{1F4CB} \u590D\u5236\u6837\u5F0F",
|
|
819
|
+
stylesCopyCssDone: "\u6837\u5F0F\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\uFF01",
|
|
820
|
+
stylesNamePlaceholder: "\u7247\u6BB5\u540D\u79F0\uFF08\u5FC5\u586B\uFF09",
|
|
821
|
+
stylesCssPlaceholder: "\u7C98\u8D34\u6216\u7F16\u5199 CSS \u4EE3\u7801\u7247\u6BB5\u2026\uFF08\u79FB\u52A8\u7AEF\u53EF\u7528 html[data-dsh-mobile] \u4F5C\u4E3A\u4F5C\u7528\u57DF\u9009\u62E9\u5668\uFF09",
|
|
822
|
+
stylesAddNew: "\uFF0B \u65B0\u589E\u81EA\u5B9A\u4E49\u7247\u6BB5",
|
|
823
|
+
stylesSave: "\u{1F4BE} \u4FDD\u5B58\u7247\u6BB5",
|
|
824
|
+
stylesCancelEdit: "\u53D6\u6D88",
|
|
825
|
+
stylesEditBtn: "\u7F16\u8F91",
|
|
826
|
+
stylesDeleteBtn: "\u5220\u9664",
|
|
827
|
+
stylesResetAll: "\u{1F504} \u6062\u590D\u9ED8\u8BA4\u542F\u505C",
|
|
828
|
+
stylesEmptyCustom: "\u6682\u65E0\u81EA\u5B9A\u4E49\u7247\u6BB5\uFF0C\u70B9\u51FB\u300C\u65B0\u589E\u81EA\u5B9A\u4E49\u7247\u6BB5\u300D\u5F00\u59CB\u3002",
|
|
829
|
+
stylesLoadFail: "\u52A0\u8F7D\u6837\u5F0F\u7247\u6BB5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
|
|
830
|
+
stylesSaveSuccess: "\u6837\u5F0F\u7247\u6BB5\u5DF2\u4FDD\u5B58\uFF0C\u5237\u65B0\u9875\u9762\u5373\u53EF\u770B\u5230\u6548\u679C",
|
|
831
|
+
stylesDeleteConfirm: "\u786E\u5B9A\u8981\u5220\u9664\u8BE5\u81EA\u5B9A\u4E49\u6837\u5F0F\u7247\u6BB5\u5417\uFF1F",
|
|
832
|
+
stylesResetConfirm: "\u786E\u5B9A\u8981\u6062\u590D\u6240\u6709\u7247\u6BB5\u7684\u9ED8\u8BA4\u542F\u505C\u72B6\u6001\u5417\uFF1F\uFF08\u5185\u7F6E\u9884\u8BBE\uFF1APC \u5173\u95ED\u3001\u79FB\u52A8\u7AEF\u542F\u7528\uFF1B\u81EA\u5B9A\u4E49\u7247\u6BB5\uFF1APC \u5173\u95ED\u3001\u79FB\u52A8\u7AEF\u542F\u7528\uFF09",
|
|
833
|
+
stylesFieldsRequired: "\u8BF7\u586B\u5199\u7247\u6BB5\u540D\u79F0\u4E0E CSS \u5185\u5BB9",
|
|
834
|
+
stylesHint: "\u{1F4A1} \u63D0\u793A\uFF1A\u6BCF\u6BB5\u9884\u8BBE\u4E0E\u81EA\u5B9A\u4E49\u7247\u6BB5\u90FD\u652F\u6301 PC / \u79FB\u52A8\u7AEF\u5206\u522B\u542F\u7528\u3002\u79FB\u52A8\u7AEF\u8BF7\u6C42\u4F1A\u7ED9 <html> \u6253\u4E0A data-dsh-mobile \u6807\u8BB0\uFF1B\u5185\u7F6E\u9884\u8BBE\u9762\u5411\u79FB\u52A8\u7AEF\u4F18\u5316\uFF08\u9ED8\u8BA4 PC \u5173\u95ED\uFF09\uFF0C\u5728 PC \u4E0A\u542F\u7528\u65F6\u8BF7\u786E\u4FDD\u7247\u6BB5\u4E0D\u4F9D\u8D56 data-dsh-mobile \u4F5C\u7528\u57DF\u3002",
|
|
835
|
+
// 插件共存警示横幅
|
|
836
|
+
conflictBannerTitle: "\u68C0\u6D4B\u5230\u5176\u4ED6\u8FDC\u7A0B\u63A5\u5165\u63D2\u4EF6",
|
|
837
|
+
conflictUnknownPlugin: "\u53E6\u4E00\u6B3E\u8FDC\u7A0B\u63A5\u5165\u7C7B\u63D2\u4EF6",
|
|
838
|
+
conflictBannerBody: "\u68C0\u6D4B\u5230 {plugin} \u5DF2\u5360\u7528\u914D\u5BF9\u5171\u4EAB\u670D\u52A1\uFF08remoteWebUiPairing\uFF09\uFF0C\u672C\u63D2\u4EF6\u5DF2\u81EA\u52A8\u8BA9\u51FA\u4EE5\u4FDD\u8BC1\u6B63\u5E38\u542F\u52A8\u3002\u4E24\u5957\u8FDC\u7A0B\u63A5\u5165\u529F\u80FD\u5E76\u5B58\u53EF\u80FD\u51FA\u73B0\u91CD\u590D\u5165\u53E3\u4E0E\u72B6\u6001\u4E0D\u4E00\u81F4\uFF0C\u5EFA\u8BAE\u53EA\u4FDD\u7559\u5176\u4E00\u3002\u53EF\u590D\u5236\u4E0B\u65B9\u8BCA\u65AD\u4FE1\u606F\uFF0C\u7C98\u8D34\u7ED9 AI \u52A9\u624B\u6309\u6B65\u9AA4\u5904\u7406\u3002",
|
|
839
|
+
conflictCopyBtn: "\u{1F4CB} \u590D\u5236\u8BCA\u65AD\u4E0E\u4FEE\u590D\u4FE1\u606F",
|
|
840
|
+
conflictCopiedTip: "\u8BCA\u65AD\u4FE1\u606F\u5DF2\u590D\u5236\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34\u7ED9 AI \u52A9\u624B\u534F\u52A9\u5904\u7406",
|
|
841
|
+
conflictReportText: "[DSH \u63D2\u4EF6\u51B2\u7A81\u8BCA\u65AD\u62A5\u544A]\n\u73B0\u8C61\uFF1Adsh-remote-mobile \u8BBE\u7F6E\u9762\u677F\u63D0\u793A\u300C\u68C0\u6D4B\u5230\u5176\u4ED6\u8FDC\u7A0B\u63A5\u5165\u63D2\u4EF6\u300D\u3002\n\u539F\u56E0\uFF1A\u53E6\u4E00\u6B3E\u8FDC\u7A0B/Web \u63A5\u5165\u7C7B\u63D2\u4EF6\u5360\u7528\u4E86 Cordis \u5171\u4EAB\u670D\u52A1 remoteWebUiPairing\uFF0Cdsh-remote-mobile \u4E3A\u4FDD\u8BC1\u6B63\u5E38\u542F\u52A8\u5DF2\u81EA\u52A8\u8BA9\u51FA\u8BE5\u670D\u52A1\uFF0C\u5F53\u524D\u4E24\u5957\u8FDC\u7A0B\u63A5\u5165\u529F\u80FD\u5E76\u5B58\u3002\n\u5360\u7528\u65B9\u63D2\u4EF6\u5305\u540D\uFF1A{plugin}\n\u5360\u7528\u65B9 loader entry id\uFF1A{entryId}\n\u5904\u7406\u65B9\u6848\uFF08\u4E8C\u9009\u4E00\uFF09\uFF1A\n\u65B9\u6848 A\uFF08\u4FDD\u7559 dsh-remote-mobile\uFF0C\u7981\u7528\u5360\u7528\u65B9\uFF09\uFF1A\n1. \u6253\u5F00\u914D\u7F6E\u6587\u4EF6 ~/.dsh/profiles/web/cordis.patch.yml\n2. \u5728\u6587\u4EF6\u672B\u5C3E\u8FFD\u52A0\u4EE5\u4E0B\u4E24\u884C\uFF08\u6CE8\u610F YAML \u7F29\u8FDB\uFF0C\u7B2C\u4E8C\u884C\u524D\u6709\u4E24\u4E2A\u7A7A\u683C\uFF09\uFF1A\n- id: {entryId}\n disabled: true\n3. \u7ED3\u675F\u5F53\u524D\u6B63\u5728\u8FD0\u884C\u7684 dsh web \u8FDB\u7A0B\uFF0C\u91CD\u65B0\u6267\u884C dsh web --no-open\n\u65B9\u6848 B\uFF08\u4FDD\u7559\u5360\u7528\u65B9\uFF0C\u5378\u8F7D dsh-remote-mobile\uFF09\uFF1A\n\u6267\u884C\u547D\u4EE4 dsh plugin --profile web remove dsh-remote-mobile \u540E\u91CD\u542F dsh web",
|
|
842
|
+
conflictReportNoEntryIdText: "[DSH \u63D2\u4EF6\u51B2\u7A81\u8BCA\u65AD\u62A5\u544A]\n\u73B0\u8C61\uFF1Adsh-remote-mobile \u8BBE\u7F6E\u9762\u677F\u63D0\u793A\u300C\u68C0\u6D4B\u5230\u5176\u4ED6\u8FDC\u7A0B\u63A5\u5165\u63D2\u4EF6\u300D\u3002\n\u539F\u56E0\uFF1A\u53E6\u4E00\u6B3E\u8FDC\u7A0B/Web \u63A5\u5165\u7C7B\u63D2\u4EF6\u5360\u7528\u4E86 Cordis \u5171\u4EAB\u670D\u52A1 remoteWebUiPairing\uFF0Cdsh-remote-mobile \u4E3A\u4FDD\u8BC1\u6B63\u5E38\u542F\u52A8\u5DF2\u81EA\u52A8\u8BA9\u51FA\u8BE5\u670D\u52A1\uFF0C\u5F53\u524D\u4E24\u5957\u8FDC\u7A0B\u63A5\u5165\u529F\u80FD\u5E76\u5B58\u3002\n\u5360\u7528\u65B9\u63D2\u4EF6\u5305\u540D\uFF1A{plugin}\n\u5360\u7528\u65B9 loader entry id\uFF1A\u672A\u80FD\u81EA\u52A8\u8BC6\u522B\n\u5904\u7406\u65B9\u6848\uFF08\u4E8C\u9009\u4E00\uFF09\uFF1A\n\u65B9\u6848 A\uFF08\u4FDD\u7559 dsh-remote-mobile\uFF0C\u7981\u7528\u5360\u7528\u65B9\uFF09\uFF1A\n1. \u6267\u884C dsh --dump-config \u67E5\u770B\u5168\u90E8 loader entry\uFF0C\u627E\u5230\u5360\u7528\u65B9\u63D2\u4EF6\u5BF9\u5E94\u7684\u6761\u76EE id\n2. \u6253\u5F00\u914D\u7F6E\u6587\u4EF6 ~/.dsh/profiles/web/cordis.patch.yml\uFF0C\u5728\u6587\u4EF6\u672B\u5C3E\u8FFD\u52A0\uFF08\u6CE8\u610F YAML \u7F29\u8FDB\uFF09\uFF1A\n- id: <\u5360\u7528\u65B9\u6761\u76EEid>\n disabled: true\n3. \u7ED3\u675F\u5F53\u524D\u6B63\u5728\u8FD0\u884C\u7684 dsh web \u8FDB\u7A0B\uFF0C\u91CD\u65B0\u6267\u884C dsh web --no-open\n\u65B9\u6848 B\uFF08\u4FDD\u7559\u5360\u7528\u65B9\uFF0C\u5378\u8F7D dsh-remote-mobile\uFF09\uFF1A\n\u6267\u884C\u547D\u4EE4 dsh plugin --profile web remove dsh-remote-mobile \u540E\u91CD\u542F dsh web",
|
|
843
|
+
conflictBannerDismiss: "\u77E5\u9053\u4E86",
|
|
761
844
|
// Toast 提示
|
|
762
845
|
toastDeviceConnected: "\u{1F389} \u65B0\u8BBE\u5907\u63A5\u5165\u6210\u529F\uFF1A{name} ({ip})",
|
|
763
846
|
toastDeviceOnline: "\u{1F4F6} \u8BBE\u5907\u91CD\u65B0\u4E0A\u7EBF\uFF1A{name} ({ip})",
|
|
@@ -850,7 +933,7 @@ var translations = {
|
|
|
850
933
|
storageCardDesc: "All sensitive credentials are protected locally via slow salt hashing and asymmetric RSA cryptography, without cloud dependencies.",
|
|
851
934
|
storageDeviceFile: "Authorized devices & session cache:",
|
|
852
935
|
storageRsaFile: "Server RSA private key (0o600 protected):",
|
|
853
|
-
|
|
936
|
+
storageStylesFile: "Mobile style snippets file (toggleable CSS mini-plugins):",
|
|
854
937
|
// Card 7: Advanced Security Config
|
|
855
938
|
configCardTitle: "Global Security Policy Configuration",
|
|
856
939
|
configCardDesc: "Configure per-IP rate limits, brute-force failure thresholds, and lockout durations. Changes take effect immediately and sync to ~/.dsh/settings.yaml.",
|
|
@@ -869,6 +952,49 @@ var translations = {
|
|
|
869
952
|
saveConfigSuccessToast: "Security policy successfully saved and synced to settings.yaml!",
|
|
870
953
|
restoreDefaultsSuccessToast: "Default security policies restored and applied immediately!",
|
|
871
954
|
saveConfigFailTip: "Parameters must be valid integers greater than 0",
|
|
955
|
+
// Card 8: Mobile Style Snippets (style mini-plugin)
|
|
956
|
+
tabAccess: "Access",
|
|
957
|
+
tabDevices: "Devices & Security",
|
|
958
|
+
tabStyle: "Style Overrides",
|
|
959
|
+
tabStorage: "Local Data",
|
|
960
|
+
stylesCardTitle: "Mobile Style Snippets",
|
|
961
|
+
stylesCardDesc: "Adapt the DSH web UI via toggleable CSS snippets. Built-in presets are split by UI area: sidebar, settings panel and conversation. Each can be enabled per device (PC / Mobile). You can also add your own CSS mini-plugins; changes take effect on the next page load without restart.",
|
|
962
|
+
stylesPresetsTitle: "\u{1F9E9} Built-in Presets",
|
|
963
|
+
stylesCustomTitle: "\u270D\uFE0F Custom Snippets",
|
|
964
|
+
stylesPcShort: "PC",
|
|
965
|
+
stylesMobileShort: "Mobile",
|
|
966
|
+
stylesBothDevices: "PC + Mobile",
|
|
967
|
+
stylesMobileOnlyBadge: "Mobile only",
|
|
968
|
+
stylesPcOnlyBadge: "PC only",
|
|
969
|
+
stylesDisabled: "Disabled",
|
|
970
|
+
stylesViewCss: "View CSS",
|
|
971
|
+
stylesHideCss: "Hide CSS",
|
|
972
|
+
stylesCopyCss: "\u{1F4CB} Copy CSS",
|
|
973
|
+
stylesCopyCssDone: "CSS copied to clipboard!",
|
|
974
|
+
stylesNamePlaceholder: "Snippet name (required)",
|
|
975
|
+
stylesCssPlaceholder: "Paste or write CSS here\u2026 (html[data-dsh-mobile] can be used as a mobile scope selector)",
|
|
976
|
+
stylesAddNew: "\uFF0B Add Custom Snippet",
|
|
977
|
+
stylesSave: "\u{1F4BE} Save Snippet",
|
|
978
|
+
stylesCancelEdit: "Cancel",
|
|
979
|
+
stylesEditBtn: "Edit",
|
|
980
|
+
stylesDeleteBtn: "Delete",
|
|
981
|
+
stylesResetAll: "\u{1F504} Reset Defaults",
|
|
982
|
+
stylesEmptyCustom: 'No custom snippets yet. Click "Add Custom Snippet" to start.',
|
|
983
|
+
stylesLoadFail: "Failed to load style snippets, please try again later",
|
|
984
|
+
stylesSaveSuccess: "Style snippet saved. Refresh to see the effect.",
|
|
985
|
+
stylesDeleteConfirm: "Are you sure you want to delete this custom style snippet?",
|
|
986
|
+
stylesResetConfirm: "Reset all snippets to default states? (Built-ins: PC off / Mobile on. Custom: PC off / Mobile on.)",
|
|
987
|
+
stylesFieldsRequired: "Please fill in both the snippet name and CSS content",
|
|
988
|
+
stylesHint: "\u{1F4A1} Tip: every preset and custom snippet has separate PC / Mobile toggles. Mobile requests add a data-dsh-mobile attribute to <html>. Built-ins target mobile (PC off by default); when enabling them on PC, make sure they do not depend on the data-dsh-mobile scope.",
|
|
989
|
+
// Plugin coexistence banner
|
|
990
|
+
conflictBannerTitle: "Another remote-access plugin detected",
|
|
991
|
+
conflictUnknownPlugin: "another remote-access plugin",
|
|
992
|
+
conflictBannerBody: "{plugin} has already registered the shared pairing service (remoteWebUiPairing); this plugin has automatically yielded it to keep startup safe. Running two remote-access features side by side may cause duplicated entries and inconsistent state \u2014 keeping only one is recommended. Copy the diagnosis below and paste it to an AI assistant for step-by-step help.",
|
|
993
|
+
conflictCopyBtn: "\u{1F4CB} Copy diagnosis & fix",
|
|
994
|
+
conflictCopiedTip: "Diagnosis copied! Paste it to your AI assistant",
|
|
995
|
+
conflictReportText: '[DSH plugin conflict diagnosis]\nSymptom: the dsh-remote-mobile settings panel shows "Another remote-access plugin detected".\nCause: another remote/Web access plugin registered the shared Cordis service remoteWebUiPairing first; dsh-remote-mobile yielded it to keep startup safe, so both remote features now run in parallel.\nConflicting plugin package: {plugin}\nConflicting loader entry id: {entryId}\nFix (choose ONE):\nOption A (keep dsh-remote-mobile, disable the other):\n1. Open ~/.dsh/profiles/web/cordis.patch.yml\n2. Append these two lines at the end (mind YAML indentation, two spaces before disabled):\n- id: {entryId}\n disabled: true\n3. Stop the running dsh web process, then run dsh web --no-open again\nOption B (keep the other, remove dsh-remote-mobile):\nRun dsh plugin --profile web remove dsh-remote-mobile and restart dsh web',
|
|
996
|
+
conflictReportNoEntryIdText: '[DSH plugin conflict diagnosis]\nSymptom: the dsh-remote-mobile settings panel shows "Another remote-access plugin detected".\nCause: another remote/Web access plugin registered the shared Cordis service remoteWebUiPairing first; dsh-remote-mobile yielded it to keep startup safe, so both remote features now run in parallel.\nConflicting plugin package: {plugin}\nConflicting loader entry id: could not be detected automatically\nFix (choose ONE):\nOption A (keep dsh-remote-mobile, disable the other):\n1. Run dsh --dump-config to list all loader entries and find the entry id of the conflicting plugin\n2. Open ~/.dsh/profiles/web/cordis.patch.yml and append at the end (mind YAML indentation):\n- id: <the conflicting entry id>\n disabled: true\n3. Stop the running dsh web process, then run dsh web --no-open again\nOption B (keep the other, remove dsh-remote-mobile):\nRun dsh plugin --profile web remove dsh-remote-mobile and restart dsh web',
|
|
997
|
+
conflictBannerDismiss: "Got it",
|
|
872
998
|
// Toast
|
|
873
999
|
toastDeviceConnected: "\u{1F389} New device connected: {name} ({ip})",
|
|
874
1000
|
toastDeviceOnline: "\u{1F4F6} Device reconnected: {name} ({ip})",
|
|
@@ -2430,8 +2556,42 @@ function SecurityCard({ status, unlockIp, clearIpStats, lang }) {
|
|
|
2430
2556
|
// src/client/components/StorageCard.jsx
|
|
2431
2557
|
var import_react6 = __toESM(require("react"), 1);
|
|
2432
2558
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2433
|
-
function StorageCard({ status, lang }) {
|
|
2434
|
-
|
|
2559
|
+
function StorageCard({ status, lang, copyText }) {
|
|
2560
|
+
const handleCopy = (path, tip) => {
|
|
2561
|
+
if (!path) return;
|
|
2562
|
+
if (typeof copyText === "function") {
|
|
2563
|
+
copyText(path, tip);
|
|
2564
|
+
return;
|
|
2565
|
+
}
|
|
2566
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
|
|
2567
|
+
navigator.clipboard.writeText(path).catch(() => {
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
const devicesPath = status.persistPath || "";
|
|
2572
|
+
const rsaPath = status.rsaKeyPath || "";
|
|
2573
|
+
const stylesPath = status.styleSnippetsPath || "";
|
|
2574
|
+
const items = [
|
|
2575
|
+
{
|
|
2576
|
+
icon: "\u{1F4C1}",
|
|
2577
|
+
title: t("storageDeviceFile", lang),
|
|
2578
|
+
path: devicesPath,
|
|
2579
|
+
tip: lang === "en" ? "Devices storage path copied!" : "\u5DF2\u6210\u529F\u590D\u5236\u8BBE\u5907\u5B58\u50A8\u6587\u4EF6\u8DEF\u5F84\uFF01"
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
icon: "\u{1F511}",
|
|
2583
|
+
title: t("storageRsaFile", lang),
|
|
2584
|
+
path: rsaPath,
|
|
2585
|
+
tip: lang === "en" ? "RSA key path copied!" : "\u5DF2\u6210\u529F\u590D\u5236 RSA \u5BC6\u94A5\u6587\u4EF6\u8DEF\u5F84\uFF01"
|
|
2586
|
+
},
|
|
2587
|
+
{
|
|
2588
|
+
icon: "\u{1F3A8}",
|
|
2589
|
+
title: t("storageStylesFile", lang),
|
|
2590
|
+
path: stylesPath,
|
|
2591
|
+
tip: lang === "en" ? "Style snippets path copied!" : "\u5DF2\u6210\u529F\u590D\u5236\u6837\u5F0F\u7247\u6BB5\u6587\u4EF6\u8DEF\u5F84\uFF01"
|
|
2592
|
+
}
|
|
2593
|
+
];
|
|
2594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2435
2595
|
"div",
|
|
2436
2596
|
{
|
|
2437
2597
|
style: {
|
|
@@ -2443,138 +2603,69 @@ function StorageCard({ status, lang }) {
|
|
|
2443
2603
|
flexDirection: "column",
|
|
2444
2604
|
gap: "10px"
|
|
2445
2605
|
},
|
|
2446
|
-
children:
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
{
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
] })
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
}
|
|
2510
|
-
),
|
|
2511
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2512
|
-
"div",
|
|
2513
|
-
{
|
|
2514
|
-
style: {
|
|
2515
|
-
display: "flex",
|
|
2516
|
-
alignItems: "center",
|
|
2517
|
-
justifyContent: "space-between",
|
|
2518
|
-
gap: "12px",
|
|
2519
|
-
paddingTop: "8px",
|
|
2520
|
-
borderTop: "1px dashed var(--dsw-alias-border-l2, rgba(128,128,128,0.15))"
|
|
2521
|
-
},
|
|
2522
|
-
children: [
|
|
2523
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "10px", minWidth: 0 }, children: [
|
|
2524
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "18px" }, children: "\u{1F511}" }),
|
|
2525
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px", minWidth: 0 }, children: [
|
|
2526
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2527
|
-
"div",
|
|
2528
|
-
{
|
|
2529
|
-
style: {
|
|
2530
|
-
fontSize: "12px",
|
|
2531
|
-
fontWeight: "600",
|
|
2532
|
-
color: "var(--dsw-alias-label-primary, inherit)"
|
|
2533
|
-
},
|
|
2534
|
-
children: t("storageRsaFile", lang)
|
|
2535
|
-
}
|
|
2536
|
-
),
|
|
2537
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2538
|
-
"code",
|
|
2539
|
-
{
|
|
2540
|
-
style: {
|
|
2541
|
-
fontSize: "11px",
|
|
2542
|
-
color: "var(--dsw-alias-brand-primary, #3b82f6)",
|
|
2543
|
-
fontFamily: "monospace",
|
|
2544
|
-
wordBreak: "break-all"
|
|
2545
|
-
},
|
|
2546
|
-
children: status.rsaKeyPath || "~/.dsh/remote-mobile/rsa-keys.json"
|
|
2547
|
-
}
|
|
2548
|
-
)
|
|
2549
|
-
] })
|
|
2550
|
-
] }),
|
|
2551
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2552
|
-
"button",
|
|
2553
|
-
{
|
|
2554
|
-
type: "button",
|
|
2555
|
-
onClick: () => {
|
|
2556
|
-
const p = status.rsaKeyPath || "~/.dsh/remote-mobile/rsa-keys.json";
|
|
2557
|
-
navigator.clipboard.writeText(p).then(() => {
|
|
2558
|
-
alert((lang === "en" ? "Copied RSA path:\n" : "RSA \u5BC6\u94A5\u6587\u4EF6\u8DEF\u5F84\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\uFF01\n") + p);
|
|
2559
|
-
});
|
|
2560
|
-
},
|
|
2561
|
-
style: {
|
|
2562
|
-
padding: "4px 10px",
|
|
2563
|
-
background: "var(--dsw-alias-bg-layer-3, rgba(128,128,128,0.1))",
|
|
2564
|
-
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.2))",
|
|
2565
|
-
color: "var(--dsw-alias-label-secondary, inherit)",
|
|
2566
|
-
borderRadius: "6px",
|
|
2567
|
-
fontSize: "11px",
|
|
2568
|
-
cursor: "pointer",
|
|
2569
|
-
whiteSpace: "nowrap"
|
|
2570
|
-
},
|
|
2571
|
-
children: t("copyUrlBtn", lang)
|
|
2572
|
-
}
|
|
2573
|
-
)
|
|
2574
|
-
]
|
|
2575
|
-
}
|
|
2576
|
-
)
|
|
2577
|
-
]
|
|
2606
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2607
|
+
"div",
|
|
2608
|
+
{
|
|
2609
|
+
style: {
|
|
2610
|
+
display: "flex",
|
|
2611
|
+
alignItems: "center",
|
|
2612
|
+
justifyContent: "space-between",
|
|
2613
|
+
gap: "12px",
|
|
2614
|
+
paddingTop: index > 0 ? "8px" : "0",
|
|
2615
|
+
borderTop: index > 0 ? "1px dashed var(--dsw-alias-border-l2, rgba(128,128,128,0.15))" : "none"
|
|
2616
|
+
},
|
|
2617
|
+
children: [
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "10px", minWidth: 0, flex: 1 }, children: [
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "18px", flexShrink: 0 }, children: item.icon }),
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px", minWidth: 0 }, children: [
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2622
|
+
"div",
|
|
2623
|
+
{
|
|
2624
|
+
style: {
|
|
2625
|
+
fontSize: "12px",
|
|
2626
|
+
fontWeight: "600",
|
|
2627
|
+
color: "var(--dsw-alias-label-primary, inherit)"
|
|
2628
|
+
},
|
|
2629
|
+
children: item.title
|
|
2630
|
+
}
|
|
2631
|
+
),
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2633
|
+
"code",
|
|
2634
|
+
{
|
|
2635
|
+
style: {
|
|
2636
|
+
fontSize: "11px",
|
|
2637
|
+
color: "var(--dsw-alias-brand-primary, #3b82f6)",
|
|
2638
|
+
fontFamily: "monospace",
|
|
2639
|
+
wordBreak: "break-all"
|
|
2640
|
+
},
|
|
2641
|
+
children: item.path || "..."
|
|
2642
|
+
}
|
|
2643
|
+
)
|
|
2644
|
+
] })
|
|
2645
|
+
] }),
|
|
2646
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2647
|
+
"button",
|
|
2648
|
+
{
|
|
2649
|
+
type: "button",
|
|
2650
|
+
onClick: () => handleCopy(item.path, item.tip),
|
|
2651
|
+
style: {
|
|
2652
|
+
padding: "4px 10px",
|
|
2653
|
+
background: "var(--dsw-alias-bg-layer-3, rgba(128,128,128,0.1))",
|
|
2654
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.2))",
|
|
2655
|
+
color: "var(--dsw-alias-label-secondary, inherit)",
|
|
2656
|
+
borderRadius: "6px",
|
|
2657
|
+
fontSize: "11px",
|
|
2658
|
+
cursor: "pointer",
|
|
2659
|
+
whiteSpace: "nowrap",
|
|
2660
|
+
flexShrink: 0
|
|
2661
|
+
},
|
|
2662
|
+
children: t("copyUrlBtn", lang)
|
|
2663
|
+
}
|
|
2664
|
+
)
|
|
2665
|
+
]
|
|
2666
|
+
},
|
|
2667
|
+
index
|
|
2668
|
+
))
|
|
2578
2669
|
}
|
|
2579
2670
|
);
|
|
2580
2671
|
}
|
|
@@ -2592,7 +2683,8 @@ function ConfigCard({
|
|
|
2592
2683
|
saveAdvancedConfig,
|
|
2593
2684
|
resetAdvancedConfigDefaults,
|
|
2594
2685
|
isSaving,
|
|
2595
|
-
lang
|
|
2686
|
+
lang,
|
|
2687
|
+
copyText
|
|
2596
2688
|
}) {
|
|
2597
2689
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2598
2690
|
"div",
|
|
@@ -2636,11 +2728,12 @@ function ConfigCard({
|
|
|
2636
2728
|
{
|
|
2637
2729
|
type: "button",
|
|
2638
2730
|
onClick: () => {
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2731
|
+
if (typeof copyText === "function") {
|
|
2732
|
+
copyText(
|
|
2733
|
+
"~/.dsh/settings.yaml",
|
|
2734
|
+
lang === "en" ? "Settings path copied (~/.dsh/settings.yaml)" : "\u5DF2\u590D\u5236\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08~/.dsh/settings.yaml\uFF09"
|
|
2642
2735
|
);
|
|
2643
|
-
}
|
|
2736
|
+
}
|
|
2644
2737
|
},
|
|
2645
2738
|
style: {
|
|
2646
2739
|
padding: "4px 10px",
|
|
@@ -2890,15 +2983,495 @@ function ConfigCard({
|
|
|
2890
2983
|
);
|
|
2891
2984
|
}
|
|
2892
2985
|
|
|
2986
|
+
// src/client/components/StylesCard.jsx
|
|
2987
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
2988
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2989
|
+
function StylesCard({ lang, showToast }) {
|
|
2990
|
+
const [snippets, setSnippets] = (0, import_react8.useState)([]);
|
|
2991
|
+
const [loading, setLoading] = (0, import_react8.useState)(true);
|
|
2992
|
+
const [editingId, setEditingId] = (0, import_react8.useState)(null);
|
|
2993
|
+
const [showForm, setShowForm] = (0, import_react8.useState)(false);
|
|
2994
|
+
const [name, setName] = (0, import_react8.useState)("");
|
|
2995
|
+
const [css, setCss] = (0, import_react8.useState)("");
|
|
2996
|
+
const [pcEnabled, setPcEnabled] = (0, import_react8.useState)(false);
|
|
2997
|
+
const [mobileEnabled, setMobileEnabled] = (0, import_react8.useState)(true);
|
|
2998
|
+
const [expanded, setExpanded] = (0, import_react8.useState)({});
|
|
2999
|
+
const [feedback, setFeedback] = (0, import_react8.useState)("");
|
|
3000
|
+
const showFeedback = (0, import_react8.useCallback)((msg, type = "success") => {
|
|
3001
|
+
if (typeof showToast === "function") {
|
|
3002
|
+
showToast(msg, type);
|
|
3003
|
+
} else {
|
|
3004
|
+
setFeedback(msg);
|
|
3005
|
+
setTimeout(() => setFeedback(""), 3500);
|
|
3006
|
+
}
|
|
3007
|
+
}, [showToast]);
|
|
3008
|
+
const load = (0, import_react8.useCallback)(() => {
|
|
3009
|
+
fetchStyles().then((data) => {
|
|
3010
|
+
setSnippets(data.snippets || []);
|
|
3011
|
+
setLoading(false);
|
|
3012
|
+
}).catch(() => {
|
|
3013
|
+
setLoading(false);
|
|
3014
|
+
showFeedback(t("stylesLoadFail", lang), "danger");
|
|
3015
|
+
});
|
|
3016
|
+
}, [lang, showFeedback]);
|
|
3017
|
+
(0, import_react8.useEffect)(() => {
|
|
3018
|
+
load();
|
|
3019
|
+
}, [load]);
|
|
3020
|
+
const toggle = (id, scope, enabled) => {
|
|
3021
|
+
toggleStyleApi(id, scope, enabled).then((data) => {
|
|
3022
|
+
if (data.success) {
|
|
3023
|
+
load();
|
|
3024
|
+
const scopeLabel = scope === "pc" ? lang === "en" ? "PC" : "PC \u7AEF" : lang === "en" ? "Mobile" : "\u79FB\u52A8\u7AEF";
|
|
3025
|
+
showFeedback(
|
|
3026
|
+
enabled ? lang === "en" ? scopeLabel + " enabled!" : scopeLabel + " \u5DF2\u542F\u7528\uFF01" : lang === "en" ? scopeLabel + " disabled!" : scopeLabel + " \u5DF2\u505C\u7528\uFF01",
|
|
3027
|
+
"success"
|
|
3028
|
+
);
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
};
|
|
3032
|
+
const startEdit = (s) => {
|
|
3033
|
+
setEditingId(s.id);
|
|
3034
|
+
setShowForm(true);
|
|
3035
|
+
setName(s.name);
|
|
3036
|
+
setCss(s.css);
|
|
3037
|
+
setPcEnabled(s.pcEnabled !== false);
|
|
3038
|
+
setMobileEnabled(s.mobileEnabled !== false);
|
|
3039
|
+
setFeedback("");
|
|
3040
|
+
};
|
|
3041
|
+
const cancelEdit = () => {
|
|
3042
|
+
setEditingId(null);
|
|
3043
|
+
setShowForm(false);
|
|
3044
|
+
setName("");
|
|
3045
|
+
setCss("");
|
|
3046
|
+
setPcEnabled(false);
|
|
3047
|
+
setMobileEnabled(true);
|
|
3048
|
+
setFeedback("");
|
|
3049
|
+
};
|
|
3050
|
+
const save = () => {
|
|
3051
|
+
if (!name.trim() || !css.trim()) {
|
|
3052
|
+
alert(t("stylesFieldsRequired", lang));
|
|
3053
|
+
return;
|
|
3054
|
+
}
|
|
3055
|
+
saveStyleSnippet({
|
|
3056
|
+
id: editingId || void 0,
|
|
3057
|
+
name: name.trim(),
|
|
3058
|
+
css,
|
|
3059
|
+
pcEnabled,
|
|
3060
|
+
mobileEnabled
|
|
3061
|
+
}).then((data) => {
|
|
3062
|
+
if (data.success) {
|
|
3063
|
+
load();
|
|
3064
|
+
cancelEdit();
|
|
3065
|
+
showFeedback(t("stylesSaveSuccess", lang));
|
|
3066
|
+
} else {
|
|
3067
|
+
alert((lang === "en" ? "Save failed: " : "\u4FDD\u5B58\u5931\u8D25\uFF1A") + (data.reason || ""));
|
|
3068
|
+
}
|
|
3069
|
+
}).catch(() => {
|
|
3070
|
+
alert(lang === "en" ? "Network request failed, please try again." : "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
|
|
3071
|
+
});
|
|
3072
|
+
};
|
|
3073
|
+
const remove = (s) => {
|
|
3074
|
+
if (s.builtin) return;
|
|
3075
|
+
if (confirm(t("stylesDeleteConfirm", lang))) {
|
|
3076
|
+
deleteStyleSnippetApi(s.id).then((data) => {
|
|
3077
|
+
if (data.success) {
|
|
3078
|
+
if (editingId === s.id) cancelEdit();
|
|
3079
|
+
load();
|
|
3080
|
+
showFeedback(lang === "en" ? "Style snippet deleted!" : "\u81EA\u5B9A\u4E49\u6837\u5F0F\u7247\u6BB5\u5DF2\u5220\u9664\uFF01");
|
|
3081
|
+
}
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
};
|
|
3085
|
+
const resetAll = () => {
|
|
3086
|
+
if (!confirm(t("stylesResetConfirm", lang))) return;
|
|
3087
|
+
resetStylesApi().then((data) => {
|
|
3088
|
+
if (data.success) {
|
|
3089
|
+
load();
|
|
3090
|
+
showFeedback(lang === "en" ? "Style snippets reset to defaults!" : "\u5DF2\u6062\u590D\u6240\u6709\u7247\u6BB5\u7684\u9ED8\u8BA4\u542F\u505C\u72B6\u6001\uFF01");
|
|
3091
|
+
}
|
|
3092
|
+
});
|
|
3093
|
+
};
|
|
3094
|
+
const toggleExpand = (id) => {
|
|
3095
|
+
setExpanded((prev) => ({ ...prev, [id]: !prev[id] }));
|
|
3096
|
+
};
|
|
3097
|
+
const copyCss = (cssText) => {
|
|
3098
|
+
navigator.clipboard.writeText(cssText).then(() => showFeedback(t("stylesCopyCssDone", lang))).catch(() => {
|
|
3099
|
+
const ta = document.createElement("textarea");
|
|
3100
|
+
ta.value = cssText;
|
|
3101
|
+
document.body.appendChild(ta);
|
|
3102
|
+
ta.select();
|
|
3103
|
+
try {
|
|
3104
|
+
document.execCommand("copy");
|
|
3105
|
+
showFeedback(t("stylesCopyCssDone", lang));
|
|
3106
|
+
} catch {
|
|
3107
|
+
showFeedback(lang === "en" ? "Copy failed, please copy manually." : "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u3002", "danger");
|
|
3108
|
+
}
|
|
3109
|
+
document.body.removeChild(ta);
|
|
3110
|
+
});
|
|
3111
|
+
};
|
|
3112
|
+
const scopeBadge = (s) => {
|
|
3113
|
+
if (s.pcEnabled && s.mobileEnabled) return t("stylesBothDevices", lang);
|
|
3114
|
+
if (s.mobileEnabled) return "\u{1F4F1} " + t("stylesMobileOnlyBadge", lang);
|
|
3115
|
+
if (s.pcEnabled) return "\u{1F5A5}\uFE0F " + t("stylesPcOnlyBadge", lang);
|
|
3116
|
+
return t("stylesDisabled", lang);
|
|
3117
|
+
};
|
|
3118
|
+
const rowStyle = {
|
|
3119
|
+
display: "flex",
|
|
3120
|
+
flexDirection: "column",
|
|
3121
|
+
gap: "8px",
|
|
3122
|
+
background: "var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.06))",
|
|
3123
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.12))",
|
|
3124
|
+
borderRadius: "8px",
|
|
3125
|
+
padding: "10px 12px"
|
|
3126
|
+
};
|
|
3127
|
+
const miniBtnStyle = {
|
|
3128
|
+
padding: "4px 10px",
|
|
3129
|
+
background: "var(--dsw-alias-bg-layer-3, rgba(128,128,128,0.1))",
|
|
3130
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.2))",
|
|
3131
|
+
color: "var(--dsw-alias-label-secondary, inherit)",
|
|
3132
|
+
borderRadius: "6px",
|
|
3133
|
+
fontSize: "11px",
|
|
3134
|
+
cursor: "pointer",
|
|
3135
|
+
whiteSpace: "nowrap"
|
|
3136
|
+
};
|
|
3137
|
+
const primaryBtnStyle = {
|
|
3138
|
+
...miniBtnStyle,
|
|
3139
|
+
background: "rgba(59,130,246,0.15)",
|
|
3140
|
+
color: "var(--dsw-alias-brand-primary, #3b82f6)",
|
|
3141
|
+
border: "1px solid rgba(59,130,246,0.3)"
|
|
3142
|
+
};
|
|
3143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3144
|
+
"div",
|
|
3145
|
+
{
|
|
3146
|
+
style: {
|
|
3147
|
+
background: "var(--dsw-alias-bg-layer-3, rgba(128,128,128,0.06))",
|
|
3148
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.15))",
|
|
3149
|
+
borderRadius: "12px",
|
|
3150
|
+
padding: "18px 20px",
|
|
3151
|
+
display: "flex",
|
|
3152
|
+
flexDirection: "column",
|
|
3153
|
+
gap: "14px"
|
|
3154
|
+
},
|
|
3155
|
+
children: [
|
|
3156
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "10px", flexWrap: "wrap" }, children: [
|
|
3157
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
3158
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: "16px" }, children: "\u{1F3A8}" }),
|
|
3159
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: "15px", fontWeight: "600", color: "var(--dsw-alias-label-primary, inherit)" }, children: t("stylesCardTitle", lang) })
|
|
3160
|
+
] }),
|
|
3161
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: resetAll, style: miniBtnStyle, children: t("stylesResetAll", lang) })
|
|
3162
|
+
] }),
|
|
3163
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "12px", color: "var(--dsw-alias-label-tertiary, #888)", lineHeight: "1.5" }, children: t("stylesCardDesc", lang) }),
|
|
3164
|
+
feedback && typeof showToast !== "function" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3165
|
+
"div",
|
|
3166
|
+
{
|
|
3167
|
+
style: {
|
|
3168
|
+
fontSize: "12px",
|
|
3169
|
+
padding: "8px 12px",
|
|
3170
|
+
borderRadius: "8px",
|
|
3171
|
+
background: "rgba(16,185,129,0.12)",
|
|
3172
|
+
color: "var(--dsw-alias-success, #10b981)",
|
|
3173
|
+
border: "1px solid rgba(16,185,129,0.25)"
|
|
3174
|
+
},
|
|
3175
|
+
children: feedback
|
|
3176
|
+
}
|
|
3177
|
+
) : null,
|
|
3178
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "12px", color: "var(--dsw-alias-label-tertiary, #888)" }, children: lang === "en" ? "Loading style snippets..." : "\u6B63\u5728\u52A0\u8F7D\u6837\u5F0F\u7247\u6BB5..." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
3179
|
+
snippets.some((s) => s.builtin) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
3180
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "13px", fontWeight: "600", color: "var(--dsw-alias-label-secondary, inherit)" }, children: t("stylesPresetsTitle", lang) }),
|
|
3181
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: snippets.filter((s) => s.builtin).map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: rowStyle, children: [
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", gap: "8px", flexWrap: "wrap" }, children: [
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, minWidth: "180px" }, children: [
|
|
3184
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }, children: [
|
|
3185
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: "12px", fontWeight: "600", color: "var(--dsw-alias-label-primary, inherit)" }, children: s.name }),
|
|
3186
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3187
|
+
"span",
|
|
3188
|
+
{
|
|
3189
|
+
style: {
|
|
3190
|
+
fontSize: "10px",
|
|
3191
|
+
padding: "1px 6px",
|
|
3192
|
+
borderRadius: "8px",
|
|
3193
|
+
background: "rgba(139,92,246,0.15)",
|
|
3194
|
+
color: "#8b5cf6",
|
|
3195
|
+
fontWeight: "600"
|
|
3196
|
+
},
|
|
3197
|
+
children: "Preset"
|
|
3198
|
+
}
|
|
3199
|
+
),
|
|
3200
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3201
|
+
"span",
|
|
3202
|
+
{
|
|
3203
|
+
style: {
|
|
3204
|
+
fontSize: "10px",
|
|
3205
|
+
padding: "1px 6px",
|
|
3206
|
+
borderRadius: "8px",
|
|
3207
|
+
background: "rgba(59,130,246,0.12)",
|
|
3208
|
+
color: "#3b82f6",
|
|
3209
|
+
fontWeight: "600"
|
|
3210
|
+
},
|
|
3211
|
+
children: scopeBadge(s)
|
|
3212
|
+
}
|
|
3213
|
+
)
|
|
3214
|
+
] }),
|
|
3215
|
+
s.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary, #888)", marginTop: "3px" }, children: s.description }) : null
|
|
3216
|
+
] }),
|
|
3217
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px", flexShrink: 0, flexWrap: "wrap" }, children: [
|
|
3218
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer" }, children: [
|
|
3219
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3220
|
+
"input",
|
|
3221
|
+
{
|
|
3222
|
+
type: "checkbox",
|
|
3223
|
+
checked: s.pcEnabled,
|
|
3224
|
+
onChange: (e) => toggle(s.id, "pc", e.target.checked),
|
|
3225
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3226
|
+
}
|
|
3227
|
+
),
|
|
3228
|
+
"\u{1F5A5}\uFE0F ",
|
|
3229
|
+
t("stylesPcShort", lang)
|
|
3230
|
+
] }),
|
|
3231
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer" }, children: [
|
|
3232
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3233
|
+
"input",
|
|
3234
|
+
{
|
|
3235
|
+
type: "checkbox",
|
|
3236
|
+
checked: s.mobileEnabled,
|
|
3237
|
+
onChange: (e) => toggle(s.id, "mobile", e.target.checked),
|
|
3238
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3239
|
+
}
|
|
3240
|
+
),
|
|
3241
|
+
"\u{1F4F1} ",
|
|
3242
|
+
t("stylesMobileShort", lang)
|
|
3243
|
+
] }),
|
|
3244
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => toggleExpand(s.id), style: miniBtnStyle, children: expanded[s.id] ? t("stylesHideCss", lang) : t("stylesViewCss", lang) }),
|
|
3245
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => copyCss(s.css), style: miniBtnStyle, children: t("stylesCopyCss", lang) })
|
|
3246
|
+
] })
|
|
3247
|
+
] }),
|
|
3248
|
+
expanded[s.id] ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3249
|
+
"pre",
|
|
3250
|
+
{
|
|
3251
|
+
style: {
|
|
3252
|
+
maxHeight: "180px",
|
|
3253
|
+
overflow: "auto",
|
|
3254
|
+
fontSize: "11px",
|
|
3255
|
+
lineHeight: "1.5",
|
|
3256
|
+
margin: 0,
|
|
3257
|
+
padding: "8px 10px",
|
|
3258
|
+
background: "var(--dsw-alias-bg-layer-1, rgba(0,0,0,0.25))",
|
|
3259
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.15))",
|
|
3260
|
+
borderRadius: "6px",
|
|
3261
|
+
color: "var(--dsw-alias-label-secondary, inherit)",
|
|
3262
|
+
whiteSpace: "pre-wrap",
|
|
3263
|
+
wordBreak: "break-word",
|
|
3264
|
+
fontFamily: "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)"
|
|
3265
|
+
},
|
|
3266
|
+
children: s.css
|
|
3267
|
+
}
|
|
3268
|
+
) : null
|
|
3269
|
+
] }, s.id)) })
|
|
3270
|
+
] }) : null,
|
|
3271
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "13px", fontWeight: "600", color: "var(--dsw-alias-label-secondary, inherit)", marginTop: "4px" }, children: t("stylesCustomTitle", lang) }),
|
|
3272
|
+
!showForm ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3273
|
+
"button",
|
|
3274
|
+
{
|
|
3275
|
+
type: "button",
|
|
3276
|
+
onClick: () => setShowForm(true),
|
|
3277
|
+
style: {
|
|
3278
|
+
width: "100%",
|
|
3279
|
+
padding: "12px",
|
|
3280
|
+
background: "var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.06))",
|
|
3281
|
+
border: "1px dashed var(--dsw-alias-border-l2, rgba(128,128,128,0.25))",
|
|
3282
|
+
borderRadius: "8px",
|
|
3283
|
+
color: "var(--dsw-alias-brand-primary, #3b82f6)",
|
|
3284
|
+
fontSize: "12px",
|
|
3285
|
+
fontWeight: "600",
|
|
3286
|
+
cursor: "pointer"
|
|
3287
|
+
},
|
|
3288
|
+
children: t("stylesAddNew", lang)
|
|
3289
|
+
}
|
|
3290
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
3291
|
+
"div",
|
|
3292
|
+
{
|
|
3293
|
+
style: {
|
|
3294
|
+
display: "flex",
|
|
3295
|
+
flexDirection: "column",
|
|
3296
|
+
gap: "8px",
|
|
3297
|
+
background: "var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.06))",
|
|
3298
|
+
border: "1px dashed var(--dsw-alias-border-l2, rgba(128,128,128,0.25))",
|
|
3299
|
+
borderRadius: "8px",
|
|
3300
|
+
padding: "12px"
|
|
3301
|
+
},
|
|
3302
|
+
children: [
|
|
3303
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
|
|
3304
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3305
|
+
"input",
|
|
3306
|
+
{
|
|
3307
|
+
type: "text",
|
|
3308
|
+
value: name,
|
|
3309
|
+
onChange: (e) => setName(e.target.value),
|
|
3310
|
+
placeholder: t("stylesNamePlaceholder", lang),
|
|
3311
|
+
style: {
|
|
3312
|
+
flex: 1,
|
|
3313
|
+
minWidth: "160px",
|
|
3314
|
+
padding: "8px 10px",
|
|
3315
|
+
fontSize: "12px",
|
|
3316
|
+
borderRadius: "6px",
|
|
3317
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.25))",
|
|
3318
|
+
background: "var(--dsw-alias-bg-layer-1, rgba(0,0,0,0.2))",
|
|
3319
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
3320
|
+
outline: "none"
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
),
|
|
3324
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer", whiteSpace: "nowrap" }, children: [
|
|
3325
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3326
|
+
"input",
|
|
3327
|
+
{
|
|
3328
|
+
type: "checkbox",
|
|
3329
|
+
checked: pcEnabled,
|
|
3330
|
+
onChange: (e) => setPcEnabled(e.target.checked),
|
|
3331
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3332
|
+
}
|
|
3333
|
+
),
|
|
3334
|
+
"\u{1F5A5}\uFE0F ",
|
|
3335
|
+
t("stylesPcShort", lang)
|
|
3336
|
+
] }),
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer", whiteSpace: "nowrap" }, children: [
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3339
|
+
"input",
|
|
3340
|
+
{
|
|
3341
|
+
type: "checkbox",
|
|
3342
|
+
checked: mobileEnabled,
|
|
3343
|
+
onChange: (e) => setMobileEnabled(e.target.checked),
|
|
3344
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3345
|
+
}
|
|
3346
|
+
),
|
|
3347
|
+
"\u{1F4F1} ",
|
|
3348
|
+
t("stylesMobileShort", lang)
|
|
3349
|
+
] })
|
|
3350
|
+
] }),
|
|
3351
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3352
|
+
"textarea",
|
|
3353
|
+
{
|
|
3354
|
+
value: css,
|
|
3355
|
+
onChange: (e) => setCss(e.target.value),
|
|
3356
|
+
placeholder: t("stylesCssPlaceholder", lang),
|
|
3357
|
+
rows: 5,
|
|
3358
|
+
style: {
|
|
3359
|
+
width: "100%",
|
|
3360
|
+
boxSizing: "border-box",
|
|
3361
|
+
padding: "8px 10px",
|
|
3362
|
+
fontSize: "12px",
|
|
3363
|
+
lineHeight: "1.5",
|
|
3364
|
+
borderRadius: "6px",
|
|
3365
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.25))",
|
|
3366
|
+
background: "var(--dsw-alias-bg-layer-1, rgba(0,0,0,0.2))",
|
|
3367
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
3368
|
+
fontFamily: "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)",
|
|
3369
|
+
outline: "none",
|
|
3370
|
+
resize: "vertical"
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
),
|
|
3374
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
|
|
3375
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: save, style: primaryBtnStyle, children: t("stylesSave", lang) }),
|
|
3376
|
+
editingId !== null ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: cancelEdit, style: miniBtnStyle, children: t("stylesCancelEdit", lang) }) : null,
|
|
3377
|
+
showForm && !editingId ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: cancelEdit, style: miniBtnStyle, children: t("stylesCancelEdit", lang) }) : null
|
|
3378
|
+
] })
|
|
3379
|
+
]
|
|
3380
|
+
}
|
|
3381
|
+
),
|
|
3382
|
+
snippets.filter((s) => !s.builtin).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "12px", color: "var(--dsw-alias-label-tertiary, #888)" }, children: t("stylesEmptyCustom", lang) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: snippets.filter((s) => !s.builtin).map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: rowStyle, children: [
|
|
3383
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", gap: "8px", flexWrap: "wrap" }, children: [
|
|
3384
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, minWidth: "180px" }, children: [
|
|
3385
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }, children: [
|
|
3386
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: "12px", fontWeight: "600", color: "var(--dsw-alias-label-primary, inherit)" }, children: s.name }),
|
|
3387
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3388
|
+
"span",
|
|
3389
|
+
{
|
|
3390
|
+
style: {
|
|
3391
|
+
fontSize: "10px",
|
|
3392
|
+
padding: "1px 6px",
|
|
3393
|
+
borderRadius: "8px",
|
|
3394
|
+
background: "rgba(59,130,246,0.12)",
|
|
3395
|
+
color: "#3b82f6",
|
|
3396
|
+
fontWeight: "600"
|
|
3397
|
+
},
|
|
3398
|
+
children: scopeBadge(s)
|
|
3399
|
+
}
|
|
3400
|
+
)
|
|
3401
|
+
] }),
|
|
3402
|
+
s.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary, #888)", marginTop: "3px" }, children: s.description }) : null
|
|
3403
|
+
] }),
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px", flexShrink: 0, flexWrap: "wrap" }, children: [
|
|
3405
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer" }, children: [
|
|
3406
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3407
|
+
"input",
|
|
3408
|
+
{
|
|
3409
|
+
type: "checkbox",
|
|
3410
|
+
checked: s.pcEnabled,
|
|
3411
|
+
onChange: (e) => toggle(s.id, "pc", e.target.checked),
|
|
3412
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3413
|
+
}
|
|
3414
|
+
),
|
|
3415
|
+
"\u{1F5A5}\uFE0F ",
|
|
3416
|
+
t("stylesPcShort", lang)
|
|
3417
|
+
] }),
|
|
3418
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: "4px", fontSize: "11px", cursor: "pointer" }, children: [
|
|
3419
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3420
|
+
"input",
|
|
3421
|
+
{
|
|
3422
|
+
type: "checkbox",
|
|
3423
|
+
checked: s.mobileEnabled,
|
|
3424
|
+
onChange: (e) => toggle(s.id, "mobile", e.target.checked),
|
|
3425
|
+
style: { accentColor: "#3b82f6", width: "16px", height: "16px", cursor: "pointer" }
|
|
3426
|
+
}
|
|
3427
|
+
),
|
|
3428
|
+
"\u{1F4F1} ",
|
|
3429
|
+
t("stylesMobileShort", lang)
|
|
3430
|
+
] }),
|
|
3431
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => startEdit(s), style: miniBtnStyle, children: t("stylesEditBtn", lang) }),
|
|
3432
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => remove(s), style: { ...miniBtnStyle, color: "#ef4444" }, children: t("stylesDeleteBtn", lang) }),
|
|
3433
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => toggleExpand(s.id), style: miniBtnStyle, children: expanded[s.id] ? t("stylesHideCss", lang) : t("stylesViewCss", lang) }),
|
|
3434
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", onClick: () => copyCss(s.css), style: miniBtnStyle, children: t("stylesCopyCss", lang) })
|
|
3435
|
+
] })
|
|
3436
|
+
] }),
|
|
3437
|
+
expanded[s.id] ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3438
|
+
"pre",
|
|
3439
|
+
{
|
|
3440
|
+
style: {
|
|
3441
|
+
maxHeight: "180px",
|
|
3442
|
+
overflow: "auto",
|
|
3443
|
+
fontSize: "11px",
|
|
3444
|
+
lineHeight: "1.5",
|
|
3445
|
+
margin: 0,
|
|
3446
|
+
padding: "8px 10px",
|
|
3447
|
+
background: "var(--dsw-alias-bg-layer-1, rgba(0,0,0,0.25))",
|
|
3448
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.15))",
|
|
3449
|
+
borderRadius: "6px",
|
|
3450
|
+
color: "var(--dsw-alias-label-secondary, inherit)",
|
|
3451
|
+
whiteSpace: "pre-wrap",
|
|
3452
|
+
wordBreak: "break-word",
|
|
3453
|
+
fontFamily: "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)"
|
|
3454
|
+
},
|
|
3455
|
+
children: s.css
|
|
3456
|
+
}
|
|
3457
|
+
) : null
|
|
3458
|
+
] }, s.id)) }),
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary, #888)", lineHeight: "1.6" }, children: t("stylesHint", lang) })
|
|
3460
|
+
] })
|
|
3461
|
+
]
|
|
3462
|
+
}
|
|
3463
|
+
);
|
|
3464
|
+
}
|
|
3465
|
+
|
|
2893
3466
|
// src/client/version.js
|
|
2894
|
-
var PLUGIN_VERSION = "v1.
|
|
2895
|
-
var BUILD_TIME = "2026-08-23
|
|
3467
|
+
var PLUGIN_VERSION = "v1.4.1";
|
|
3468
|
+
var BUILD_TIME = "2026-08-26 23:00:00";
|
|
2896
3469
|
|
|
2897
3470
|
// src/client/components/MainSection.jsx
|
|
2898
|
-
var
|
|
3471
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2899
3472
|
function TailscaleMobileSection(props) {
|
|
2900
3473
|
const ctx = props && props.ctx || typeof window !== "undefined" && window.__DSH_CLIENT_CTX__ || null;
|
|
2901
|
-
const [status, setStatus] = (0,
|
|
3474
|
+
const [status, setStatus] = (0, import_react9.useState)({
|
|
2902
3475
|
tailscaleIp: "",
|
|
2903
3476
|
lanIp: "",
|
|
2904
3477
|
code: "",
|
|
@@ -2915,24 +3488,50 @@ function TailscaleMobileSection(props) {
|
|
|
2915
3488
|
copied: false,
|
|
2916
3489
|
loading: true,
|
|
2917
3490
|
persistPath: "",
|
|
2918
|
-
|
|
3491
|
+
rsaKeyPath: "",
|
|
3492
|
+
styleSnippetsPath: "",
|
|
3493
|
+
locale: "zh",
|
|
3494
|
+
pairingBridgeMode: "pending",
|
|
3495
|
+
pairingBridgeConflict: "",
|
|
3496
|
+
pairingBridgeConflictId: ""
|
|
2919
3497
|
});
|
|
2920
|
-
const [secretInput, setSecretInput] = (0,
|
|
2921
|
-
const [showSecret, setShowSecret] = (0,
|
|
2922
|
-
const [showCode, setShowCode] = (0,
|
|
2923
|
-
const [showQr, setShowQr] = (0,
|
|
2924
|
-
const [selectedTab, setSelectedTab] = (0,
|
|
2925
|
-
const [timeLeft, setTimeLeft] = (0,
|
|
2926
|
-
const [toast, setToast] = (0,
|
|
2927
|
-
const [maxVisitsInput, setMaxVisitsInput] = (0,
|
|
2928
|
-
const [maxFailedInput, setMaxFailedInput] = (0,
|
|
2929
|
-
const [lockDurationMinsInput, setLockDurationMinsInput] = (0,
|
|
2930
|
-
const [isSaving, setIsSaving] = (0,
|
|
2931
|
-
const [showVersionTip, setShowVersionTip] = (0,
|
|
2932
|
-
const [currentLang, setCurrentLang] = (0,
|
|
2933
|
-
const
|
|
3498
|
+
const [secretInput, setSecretInput] = (0, import_react9.useState)("");
|
|
3499
|
+
const [showSecret, setShowSecret] = (0, import_react9.useState)(false);
|
|
3500
|
+
const [showCode, setShowCode] = (0, import_react9.useState)(false);
|
|
3501
|
+
const [showQr, setShowQr] = (0, import_react9.useState)(false);
|
|
3502
|
+
const [selectedTab, setSelectedTab] = (0, import_react9.useState)("lan");
|
|
3503
|
+
const [timeLeft, setTimeLeft] = (0, import_react9.useState)(300);
|
|
3504
|
+
const [toast, setToast] = (0, import_react9.useState)(null);
|
|
3505
|
+
const [maxVisitsInput, setMaxVisitsInput] = (0, import_react9.useState)("60");
|
|
3506
|
+
const [maxFailedInput, setMaxFailedInput] = (0, import_react9.useState)("5");
|
|
3507
|
+
const [lockDurationMinsInput, setLockDurationMinsInput] = (0, import_react9.useState)("15");
|
|
3508
|
+
const [isSaving, setIsSaving] = (0, import_react9.useState)(false);
|
|
3509
|
+
const [showVersionTip, setShowVersionTip] = (0, import_react9.useState)(false);
|
|
3510
|
+
const [currentLang, setCurrentLang] = (0, import_react9.useState)(resolveLocale(ctx, status));
|
|
3511
|
+
const [conflictBannerDismissed, setConflictBannerDismissed] = (0, import_react9.useState)(false);
|
|
3512
|
+
const qrTabTouchedRef = (0, import_react9.useRef)(false);
|
|
3513
|
+
const updateQrTab = (0, import_react9.useCallback)((tab) => {
|
|
3514
|
+
qrTabTouchedRef.current = true;
|
|
3515
|
+
setSelectedTab(tab);
|
|
3516
|
+
}, []);
|
|
3517
|
+
const [activeTab, setActiveTab] = (0, import_react9.useState)(() => {
|
|
3518
|
+
try {
|
|
3519
|
+
const saved = localStorage.getItem("dsh-rm-settings-tab");
|
|
3520
|
+
if (saved === "access" || saved === "devices" || saved === "style" || saved === "storage") return saved;
|
|
3521
|
+
} catch (e) {
|
|
3522
|
+
}
|
|
3523
|
+
return "access";
|
|
3524
|
+
});
|
|
3525
|
+
const switchTab = (tab) => {
|
|
3526
|
+
setActiveTab(tab);
|
|
3527
|
+
try {
|
|
3528
|
+
localStorage.setItem("dsh-rm-settings-tab", tab);
|
|
3529
|
+
} catch (e) {
|
|
3530
|
+
}
|
|
3531
|
+
};
|
|
3532
|
+
const refreshStatusOnly = (0, import_react9.useCallback)(() => {
|
|
2934
3533
|
fetchStatus().then((data) => {
|
|
2935
|
-
if (data.tailscaleIp) {
|
|
3534
|
+
if (data.tailscaleIp && !qrTabTouchedRef.current) {
|
|
2936
3535
|
setSelectedTab("tailscale");
|
|
2937
3536
|
}
|
|
2938
3537
|
if (data.maxVisitsPerMinute) setMaxVisitsInput(String(data.maxVisitsPerMinute));
|
|
@@ -2957,13 +3556,17 @@ function TailscaleMobileSection(props) {
|
|
|
2957
3556
|
ipSecurityStats: data.ipSecurityStats || [],
|
|
2958
3557
|
persistPath: data.persistPath || "",
|
|
2959
3558
|
rsaKeyPath: data.rsaKeyPath || "",
|
|
3559
|
+
styleSnippetsPath: data.styleSnippetsPath || "",
|
|
2960
3560
|
locale: data.locale || "zh",
|
|
3561
|
+
pairingBridgeMode: data.pairingBridgeMode || "pending",
|
|
3562
|
+
pairingBridgeConflict: data.pairingBridgeConflict || "",
|
|
3563
|
+
pairingBridgeConflictId: data.pairingBridgeConflictId || "",
|
|
2961
3564
|
loading: false
|
|
2962
3565
|
}));
|
|
2963
3566
|
}).catch(() => {
|
|
2964
3567
|
});
|
|
2965
3568
|
}, [ctx]);
|
|
2966
|
-
const refreshStatusAndCode = (0,
|
|
3569
|
+
const refreshStatusAndCode = (0, import_react9.useCallback)(() => {
|
|
2967
3570
|
refreshStatusOnly();
|
|
2968
3571
|
generatePairCode().then((data) => {
|
|
2969
3572
|
if (data.success) {
|
|
@@ -2978,7 +3581,7 @@ function TailscaleMobileSection(props) {
|
|
|
2978
3581
|
}).catch(() => {
|
|
2979
3582
|
});
|
|
2980
3583
|
}, [refreshStatusOnly]);
|
|
2981
|
-
(0,
|
|
3584
|
+
(0, import_react9.useEffect)(() => {
|
|
2982
3585
|
refreshStatusAndCode();
|
|
2983
3586
|
const localeUnsubs = [];
|
|
2984
3587
|
try {
|
|
@@ -3015,8 +3618,7 @@ function TailscaleMobileSection(props) {
|
|
|
3015
3618
|
name: dev.deviceName || "Device",
|
|
3016
3619
|
ip: dev.ip
|
|
3017
3620
|
});
|
|
3018
|
-
|
|
3019
|
-
setTimeout(() => setToast(null), 4e3);
|
|
3621
|
+
showToast(msg, "info", 4e3);
|
|
3020
3622
|
}
|
|
3021
3623
|
if (detail.type === "device-revoked") {
|
|
3022
3624
|
setStatus((prev) => {
|
|
@@ -3031,8 +3633,7 @@ function TailscaleMobileSection(props) {
|
|
|
3031
3633
|
}
|
|
3032
3634
|
if (detail.type === "ip-security-alert") {
|
|
3033
3635
|
const alertMsg = t("toastIpLocked", currentLang, { ip: detail.ip });
|
|
3034
|
-
|
|
3035
|
-
setTimeout(() => setToast(null), 5e3);
|
|
3636
|
+
showToast(alertMsg, "danger", 5e3);
|
|
3036
3637
|
}
|
|
3037
3638
|
refreshStatusOnly();
|
|
3038
3639
|
};
|
|
@@ -3048,7 +3649,7 @@ function TailscaleMobileSection(props) {
|
|
|
3048
3649
|
}
|
|
3049
3650
|
};
|
|
3050
3651
|
}, [refreshStatusAndCode, refreshStatusOnly, currentLang, ctx]);
|
|
3051
|
-
(0,
|
|
3652
|
+
(0, import_react9.useEffect)(() => {
|
|
3052
3653
|
if (timeLeft <= 0) return;
|
|
3053
3654
|
const timer = setInterval(() => {
|
|
3054
3655
|
setTimeLeft((prev) => {
|
|
@@ -3093,11 +3694,11 @@ function TailscaleMobileSection(props) {
|
|
|
3093
3694
|
if (data.success) {
|
|
3094
3695
|
setStatus((prev) => ({ ...prev, hasSecret: true }));
|
|
3095
3696
|
setSecretInput("");
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3697
|
+
showToast(
|
|
3698
|
+
currentLang === "en" ? "Persistent password saved!" : "\u957F\u671F\u8BBF\u95EE\u5BC6\u7801\u5DF2\u6210\u529F\u4FDD\u5B58\u5E76\u542F\u7528\uFF01",
|
|
3699
|
+
"success",
|
|
3700
|
+
3e3
|
|
3701
|
+
);
|
|
3101
3702
|
} else {
|
|
3102
3703
|
alert((currentLang === "en" ? "Save failed: " : "\u4FDD\u5B58\u5931\u8D25\uFF1A") + (data.reason || ""));
|
|
3103
3704
|
}
|
|
@@ -3108,11 +3709,11 @@ function TailscaleMobileSection(props) {
|
|
|
3108
3709
|
clearSecretApi().then(() => {
|
|
3109
3710
|
setStatus((prev) => ({ ...prev, hasSecret: false }));
|
|
3110
3711
|
setSecretInput("");
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3712
|
+
showToast(
|
|
3713
|
+
currentLang === "en" ? "Password cleared!" : "\u5DF2\u6210\u529F\u6E05\u9664\u957F\u671F\u8BBF\u95EE\u5BC6\u7801\uFF01",
|
|
3714
|
+
"info",
|
|
3715
|
+
3e3
|
|
3716
|
+
);
|
|
3116
3717
|
});
|
|
3117
3718
|
}
|
|
3118
3719
|
};
|
|
@@ -3120,11 +3721,11 @@ function TailscaleMobileSection(props) {
|
|
|
3120
3721
|
if (confirm(t("revokeDeviceConfirm", currentLang))) {
|
|
3121
3722
|
revokeDeviceApi(token).then(() => {
|
|
3122
3723
|
refreshStatusAndCode();
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3724
|
+
showToast(
|
|
3725
|
+
currentLang === "en" ? "Device disconnected!" : "\u5DF2\u6210\u529F\u8E22\u51FA\u8BE5\u8BBE\u5907\uFF01",
|
|
3726
|
+
"info",
|
|
3727
|
+
2500
|
|
3728
|
+
);
|
|
3128
3729
|
});
|
|
3129
3730
|
}
|
|
3130
3731
|
};
|
|
@@ -3132,11 +3733,11 @@ function TailscaleMobileSection(props) {
|
|
|
3132
3733
|
if (confirm(t("revokeAllConfirm", currentLang))) {
|
|
3133
3734
|
revokeAllDevicesApi().then(() => {
|
|
3134
3735
|
refreshStatusAndCode();
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3736
|
+
showToast(
|
|
3737
|
+
currentLang === "en" ? "All devices disconnected!" : "\u5DF2\u6210\u529F\u6CE8\u9500\u5E76\u8E22\u4E0B\u7EBF\u6240\u6709\u8BBE\u5907\uFF01",
|
|
3738
|
+
"info",
|
|
3739
|
+
2500
|
|
3740
|
+
);
|
|
3140
3741
|
});
|
|
3141
3742
|
}
|
|
3142
3743
|
};
|
|
@@ -3144,11 +3745,11 @@ function TailscaleMobileSection(props) {
|
|
|
3144
3745
|
if (confirm(t("unlockIpConfirm", currentLang, { ip }))) {
|
|
3145
3746
|
unlockIpApi(ip).then(() => {
|
|
3146
3747
|
refreshStatusAndCode();
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3748
|
+
showToast(
|
|
3749
|
+
currentLang === "en" ? `IP ${ip} unlocked!` : `\u5DF2\u6210\u529F\u4E3A IP ${ip} \u89E3\u9664\u9501\u5B9A\uFF01`,
|
|
3750
|
+
"success",
|
|
3751
|
+
3e3
|
|
3752
|
+
);
|
|
3152
3753
|
}).catch(() => {
|
|
3153
3754
|
});
|
|
3154
3755
|
}
|
|
@@ -3157,11 +3758,11 @@ function TailscaleMobileSection(props) {
|
|
|
3157
3758
|
if (confirm(t("clearSecurityLogConfirm", currentLang))) {
|
|
3158
3759
|
clearIpStatsApi().then(() => {
|
|
3159
3760
|
refreshStatusAndCode();
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3761
|
+
showToast(
|
|
3762
|
+
currentLang === "en" ? "Audit logs cleared!" : "\u5DF2\u6210\u529F\u6E05\u7A7A\u6240\u6709\u5B89\u5168\u5BA1\u8BA1\u65E5\u5FD7\uFF01",
|
|
3763
|
+
"success",
|
|
3764
|
+
2500
|
|
3765
|
+
);
|
|
3165
3766
|
}).catch(() => {
|
|
3166
3767
|
});
|
|
3167
3768
|
}
|
|
@@ -3186,8 +3787,7 @@ function TailscaleMobileSection(props) {
|
|
|
3186
3787
|
setIsSaving(false);
|
|
3187
3788
|
if (data.success) {
|
|
3188
3789
|
refreshStatusAndCode();
|
|
3189
|
-
|
|
3190
|
-
setTimeout(() => setToast(null), 3e3);
|
|
3790
|
+
showToast(t("saveConfigSuccessToast", currentLang), "success", 3e3);
|
|
3191
3791
|
} else {
|
|
3192
3792
|
alert((currentLang === "en" ? "Save failed: " : "\u4FDD\u5B58\u5931\u8D25\uFF1A") + (data.reason || ""));
|
|
3193
3793
|
}
|
|
@@ -3212,8 +3812,7 @@ function TailscaleMobileSection(props) {
|
|
|
3212
3812
|
setIsSaving(false);
|
|
3213
3813
|
if (data.success) {
|
|
3214
3814
|
refreshStatusAndCode();
|
|
3215
|
-
|
|
3216
|
-
setTimeout(() => setToast(null), 3e3);
|
|
3815
|
+
showToast(t("restoreDefaultsSuccessToast", currentLang), "success", 3e3);
|
|
3217
3816
|
} else {
|
|
3218
3817
|
alert((currentLang === "en" ? "Reset failed: " : "\u91CD\u7F6E\u5931\u8D25\uFF1A") + (data.reason || ""));
|
|
3219
3818
|
}
|
|
@@ -3230,23 +3829,57 @@ function TailscaleMobileSection(props) {
|
|
|
3230
3829
|
const effectiveQrIp = selectedTab === "tailscale" && status.tailscaleIp ? status.tailscaleIp : status.lanIp || "127.0.0.1";
|
|
3231
3830
|
const port = typeof window !== "undefined" && window.location.port || "3080";
|
|
3232
3831
|
const directLink = `http://${effectiveQrIp}:${port}/auth?token=${status.code || ""}`;
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
});
|
|
3832
|
+
copyText(directLink, t("copiedTip", currentLang));
|
|
3833
|
+
setStatus((prev) => ({ ...prev, copied: true }));
|
|
3834
|
+
setTimeout(() => {
|
|
3835
|
+
setStatus((prev) => ({ ...prev, copied: false }));
|
|
3836
|
+
}, 2e3);
|
|
3239
3837
|
};
|
|
3838
|
+
const toastTimerRef = (0, import_react9.useRef)(null);
|
|
3839
|
+
const showToast = (0, import_react9.useCallback)((message, type = "success", duration = 2500) => {
|
|
3840
|
+
if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
|
|
3841
|
+
setToast({ message, type });
|
|
3842
|
+
toastTimerRef.current = setTimeout(() => setToast(null), duration);
|
|
3843
|
+
}, []);
|
|
3240
3844
|
const copyText = (text, successTip) => {
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3845
|
+
const triggerToast = () => {
|
|
3846
|
+
showToast(
|
|
3847
|
+
successTip || (currentLang === "en" ? "Copied to clipboard!" : "\u5DF2\u6210\u529F\u590D\u5236\u5230\u526A\u8D34\u677F\uFF01"),
|
|
3848
|
+
"success",
|
|
3849
|
+
2500
|
|
3850
|
+
);
|
|
3851
|
+
};
|
|
3852
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
|
|
3853
|
+
navigator.clipboard.writeText(text).then(triggerToast).catch(() => {
|
|
3854
|
+
try {
|
|
3855
|
+
const ta = document.createElement("textarea");
|
|
3856
|
+
ta.value = text;
|
|
3857
|
+
ta.style.position = "fixed";
|
|
3858
|
+
ta.style.opacity = "0";
|
|
3859
|
+
document.body.appendChild(ta);
|
|
3860
|
+
ta.select();
|
|
3861
|
+
document.execCommand("copy");
|
|
3862
|
+
document.body.removeChild(ta);
|
|
3863
|
+
triggerToast();
|
|
3864
|
+
} catch (e) {
|
|
3865
|
+
}
|
|
3245
3866
|
});
|
|
3246
|
-
|
|
3247
|
-
|
|
3867
|
+
} else {
|
|
3868
|
+
try {
|
|
3869
|
+
const ta = document.createElement("textarea");
|
|
3870
|
+
ta.value = text;
|
|
3871
|
+
ta.style.position = "fixed";
|
|
3872
|
+
ta.style.opacity = "0";
|
|
3873
|
+
document.body.appendChild(ta);
|
|
3874
|
+
ta.select();
|
|
3875
|
+
document.execCommand("copy");
|
|
3876
|
+
document.body.removeChild(ta);
|
|
3877
|
+
triggerToast();
|
|
3878
|
+
} catch (e) {
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3248
3881
|
};
|
|
3249
|
-
return /* @__PURE__ */ (0,
|
|
3882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3250
3883
|
"div",
|
|
3251
3884
|
{
|
|
3252
3885
|
style: {
|
|
@@ -3254,10 +3887,41 @@ function TailscaleMobileSection(props) {
|
|
|
3254
3887
|
color: "var(--dsw-alias-label-primary, inherit)",
|
|
3255
3888
|
display: "flex",
|
|
3256
3889
|
flexDirection: "column",
|
|
3257
|
-
gap: "16px"
|
|
3890
|
+
gap: "16px",
|
|
3891
|
+
position: "relative"
|
|
3258
3892
|
},
|
|
3259
3893
|
children: [
|
|
3260
|
-
/* @__PURE__ */ (0,
|
|
3894
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3895
|
+
"div",
|
|
3896
|
+
{
|
|
3897
|
+
style: {
|
|
3898
|
+
position: "fixed",
|
|
3899
|
+
top: "24px",
|
|
3900
|
+
left: "50%",
|
|
3901
|
+
transform: "translateX(-50%)",
|
|
3902
|
+
zIndex: 100010,
|
|
3903
|
+
background: toast.type === "danger" ? "linear-gradient(135deg, rgba(239, 68, 68, 0.95), rgba(185, 28, 28, 0.95))" : toast.type === "success" ? "linear-gradient(135deg, rgba(16, 185, 129, 0.95), rgba(5, 150, 105, 0.95))" : "linear-gradient(135deg, rgba(59, 130, 246, 0.95), rgba(37, 99, 235, 0.95))",
|
|
3904
|
+
color: "#ffffff",
|
|
3905
|
+
borderRadius: "10px",
|
|
3906
|
+
padding: "10px 18px",
|
|
3907
|
+
fontSize: "13px",
|
|
3908
|
+
fontWeight: "600",
|
|
3909
|
+
boxShadow: "0 12px 30px rgba(0, 0, 0, 0.35)",
|
|
3910
|
+
backdropFilter: "blur(10px)",
|
|
3911
|
+
WebkitBackdropFilter: "blur(10px)",
|
|
3912
|
+
border: "1px solid rgba(255, 255, 255, 0.25)",
|
|
3913
|
+
display: "flex",
|
|
3914
|
+
alignItems: "center",
|
|
3915
|
+
gap: "8px",
|
|
3916
|
+
pointerEvents: "none"
|
|
3917
|
+
},
|
|
3918
|
+
children: [
|
|
3919
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: toast.type === "danger" ? "\u{1F6A8}" : toast.type === "success" ? "\u2705" : "\u2139\uFE0F" }),
|
|
3920
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: toast.message })
|
|
3921
|
+
]
|
|
3922
|
+
}
|
|
3923
|
+
) : null,
|
|
3924
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3261
3925
|
"div",
|
|
3262
3926
|
{
|
|
3263
3927
|
style: {
|
|
@@ -3269,8 +3933,8 @@ function TailscaleMobileSection(props) {
|
|
|
3269
3933
|
marginBottom: "4px"
|
|
3270
3934
|
},
|
|
3271
3935
|
children: [
|
|
3272
|
-
/* @__PURE__ */ (0,
|
|
3273
|
-
/* @__PURE__ */ (0,
|
|
3936
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { minWidth: "220px", flex: 1 }, children: [
|
|
3937
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3274
3938
|
"div",
|
|
3275
3939
|
{
|
|
3276
3940
|
style: {
|
|
@@ -3281,7 +3945,7 @@ function TailscaleMobileSection(props) {
|
|
|
3281
3945
|
margin: "0 0 6px 0"
|
|
3282
3946
|
},
|
|
3283
3947
|
children: [
|
|
3284
|
-
/* @__PURE__ */ (0,
|
|
3948
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3285
3949
|
"h3",
|
|
3286
3950
|
{
|
|
3287
3951
|
style: {
|
|
@@ -3293,21 +3957,21 @@ function TailscaleMobileSection(props) {
|
|
|
3293
3957
|
children: t("title", currentLang)
|
|
3294
3958
|
}
|
|
3295
3959
|
),
|
|
3296
|
-
/* @__PURE__ */ (0,
|
|
3960
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3297
3961
|
"div",
|
|
3298
3962
|
{
|
|
3299
3963
|
style: { position: "relative", display: "inline-flex", alignItems: "center" },
|
|
3300
3964
|
onMouseEnter: () => setShowVersionTip(true),
|
|
3301
3965
|
onMouseLeave: () => setShowVersionTip(false),
|
|
3302
3966
|
onClick: () => {
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3967
|
+
showToast(
|
|
3968
|
+
`\u{1F4E6} dsh-remote-mobile ${PLUGIN_VERSION} (${currentLang === "en" ? "Build: " : "\u6784\u5EFA\u65F6\u95F4: "}${BUILD_TIME})`,
|
|
3969
|
+
"info",
|
|
3970
|
+
3e3
|
|
3971
|
+
);
|
|
3308
3972
|
},
|
|
3309
3973
|
children: [
|
|
3310
|
-
/* @__PURE__ */ (0,
|
|
3974
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3311
3975
|
"span",
|
|
3312
3976
|
{
|
|
3313
3977
|
style: {
|
|
@@ -3324,7 +3988,7 @@ function TailscaleMobileSection(props) {
|
|
|
3324
3988
|
children: PLUGIN_VERSION
|
|
3325
3989
|
}
|
|
3326
3990
|
),
|
|
3327
|
-
showVersionTip ? /* @__PURE__ */ (0,
|
|
3991
|
+
showVersionTip ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3328
3992
|
"div",
|
|
3329
3993
|
{
|
|
3330
3994
|
style: {
|
|
@@ -3355,7 +4019,7 @@ function TailscaleMobileSection(props) {
|
|
|
3355
4019
|
]
|
|
3356
4020
|
}
|
|
3357
4021
|
),
|
|
3358
|
-
/* @__PURE__ */ (0,
|
|
4022
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3359
4023
|
"div",
|
|
3360
4024
|
{
|
|
3361
4025
|
style: {
|
|
@@ -3366,7 +4030,7 @@ function TailscaleMobileSection(props) {
|
|
|
3366
4030
|
}
|
|
3367
4031
|
)
|
|
3368
4032
|
] }),
|
|
3369
|
-
/* @__PURE__ */ (0,
|
|
4033
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3370
4034
|
"a",
|
|
3371
4035
|
{
|
|
3372
4036
|
href: "https://github.com/IceApriler/dsh-remote-mobile",
|
|
@@ -3388,88 +4052,235 @@ function TailscaleMobileSection(props) {
|
|
|
3388
4052
|
cursor: "pointer"
|
|
3389
4053
|
},
|
|
3390
4054
|
children: [
|
|
3391
|
-
/* @__PURE__ */ (0,
|
|
3392
|
-
/* @__PURE__ */ (0,
|
|
4055
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { style: { width: "16px", height: "16px", fill: "currentColor" }, viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" }) }),
|
|
4056
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "dsh-remote-mobile" })
|
|
3393
4057
|
]
|
|
3394
4058
|
}
|
|
3395
4059
|
)
|
|
3396
4060
|
]
|
|
3397
4061
|
}
|
|
3398
4062
|
),
|
|
3399
|
-
/* @__PURE__ */ (0,
|
|
3400
|
-
|
|
3401
|
-
{
|
|
3402
|
-
status,
|
|
3403
|
-
toggleTailscale,
|
|
3404
|
-
toggleLan,
|
|
3405
|
-
copyText,
|
|
3406
|
-
lang: currentLang
|
|
3407
|
-
}
|
|
3408
|
-
),
|
|
3409
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3410
|
-
QrPairingCard,
|
|
3411
|
-
{
|
|
3412
|
-
status,
|
|
3413
|
-
showCode,
|
|
3414
|
-
setShowCode,
|
|
3415
|
-
timeLeft,
|
|
3416
|
-
showQr,
|
|
3417
|
-
setShowQr,
|
|
3418
|
-
selectedTab,
|
|
3419
|
-
setSelectedTab,
|
|
3420
|
-
generateQrSvg,
|
|
3421
|
-
refreshStatusAndCode,
|
|
3422
|
-
copyDirectLink,
|
|
3423
|
-
lang: currentLang
|
|
3424
|
-
}
|
|
3425
|
-
),
|
|
3426
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3427
|
-
SecretCard,
|
|
3428
|
-
{
|
|
3429
|
-
status,
|
|
3430
|
-
secretInput,
|
|
3431
|
-
setSecretInput,
|
|
3432
|
-
showSecret,
|
|
3433
|
-
setShowSecret,
|
|
3434
|
-
saveSecret,
|
|
3435
|
-
clearSecret,
|
|
3436
|
-
lang: currentLang
|
|
3437
|
-
}
|
|
3438
|
-
),
|
|
3439
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3440
|
-
DeviceListCard,
|
|
4063
|
+
status.pairingBridgeConflict && !conflictBannerDismissed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4064
|
+
"div",
|
|
3441
4065
|
{
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
4066
|
+
style: {
|
|
4067
|
+
display: "flex",
|
|
4068
|
+
alignItems: "flex-start",
|
|
4069
|
+
gap: "10px",
|
|
4070
|
+
padding: "12px 14px",
|
|
4071
|
+
borderRadius: "10px",
|
|
4072
|
+
border: "1px solid rgba(245, 158, 11, 0.45)",
|
|
4073
|
+
background: "rgba(245, 158, 11, 0.12)"
|
|
4074
|
+
},
|
|
4075
|
+
children: [
|
|
4076
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: "16px", lineHeight: "20px" }, children: "\u26A0\uFE0F" }),
|
|
4077
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
4078
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4079
|
+
"div",
|
|
4080
|
+
{
|
|
4081
|
+
style: {
|
|
4082
|
+
fontSize: "13px",
|
|
4083
|
+
fontWeight: "700",
|
|
4084
|
+
marginBottom: "4px",
|
|
4085
|
+
color: "var(--dsw-alias-label-primary, inherit)"
|
|
4086
|
+
},
|
|
4087
|
+
children: t("conflictBannerTitle", currentLang)
|
|
4088
|
+
}
|
|
4089
|
+
),
|
|
4090
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4091
|
+
"div",
|
|
4092
|
+
{
|
|
4093
|
+
style: {
|
|
4094
|
+
fontSize: "12px",
|
|
4095
|
+
lineHeight: 1.6,
|
|
4096
|
+
whiteSpace: "pre-line",
|
|
4097
|
+
color: "var(--dsw-alias-label-secondary, inherit)"
|
|
4098
|
+
},
|
|
4099
|
+
children: t("conflictBannerBody", currentLang, {
|
|
4100
|
+
plugin: status.pairingBridgeConflict || t("conflictUnknownPlugin", currentLang)
|
|
4101
|
+
})
|
|
4102
|
+
}
|
|
4103
|
+
),
|
|
4104
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4105
|
+
"button",
|
|
4106
|
+
{
|
|
4107
|
+
type: "button",
|
|
4108
|
+
onClick: () => {
|
|
4109
|
+
const plugin = status.pairingBridgeConflict || t("conflictUnknownPlugin", currentLang);
|
|
4110
|
+
const entryId = status.pairingBridgeConflictId || "";
|
|
4111
|
+
const report = t(
|
|
4112
|
+
entryId ? "conflictReportText" : "conflictReportNoEntryIdText",
|
|
4113
|
+
currentLang,
|
|
4114
|
+
{ plugin, entryId }
|
|
4115
|
+
);
|
|
4116
|
+
copyText(report, t("conflictCopiedTip", currentLang));
|
|
4117
|
+
},
|
|
4118
|
+
style: {
|
|
4119
|
+
marginTop: "8px",
|
|
4120
|
+
display: "inline-flex",
|
|
4121
|
+
alignItems: "center",
|
|
4122
|
+
gap: "6px",
|
|
4123
|
+
padding: "5px 10px",
|
|
4124
|
+
fontSize: "12px",
|
|
4125
|
+
fontWeight: "600",
|
|
4126
|
+
borderRadius: "7px",
|
|
4127
|
+
cursor: "pointer",
|
|
4128
|
+
border: "1px solid rgba(245, 158, 11, 0.55)",
|
|
4129
|
+
background: "rgba(245, 158, 11, 0.18)",
|
|
4130
|
+
color: "var(--dsw-alias-label-primary, inherit)"
|
|
4131
|
+
},
|
|
4132
|
+
children: t("conflictCopyBtn", currentLang)
|
|
4133
|
+
}
|
|
4134
|
+
)
|
|
4135
|
+
] }),
|
|
4136
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4137
|
+
"button",
|
|
4138
|
+
{
|
|
4139
|
+
type: "button",
|
|
4140
|
+
onClick: () => setConflictBannerDismissed(true),
|
|
4141
|
+
title: t("conflictBannerDismiss", currentLang),
|
|
4142
|
+
style: {
|
|
4143
|
+
flexShrink: 0,
|
|
4144
|
+
width: "24px",
|
|
4145
|
+
height: "24px",
|
|
4146
|
+
display: "inline-flex",
|
|
4147
|
+
alignItems: "center",
|
|
4148
|
+
justifyContent: "center",
|
|
4149
|
+
border: "none",
|
|
4150
|
+
borderRadius: "6px",
|
|
4151
|
+
cursor: "pointer",
|
|
4152
|
+
fontSize: "12px",
|
|
4153
|
+
background: "rgba(128, 128, 128, 0.15)",
|
|
4154
|
+
color: "var(--dsw-alias-label-secondary, inherit)"
|
|
4155
|
+
},
|
|
4156
|
+
children: "\u2715"
|
|
4157
|
+
}
|
|
4158
|
+
)
|
|
4159
|
+
]
|
|
3446
4160
|
}
|
|
3447
|
-
),
|
|
3448
|
-
/* @__PURE__ */ (0,
|
|
3449
|
-
|
|
4161
|
+
) : null,
|
|
4162
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4163
|
+
"div",
|
|
3450
4164
|
{
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
4165
|
+
style: {
|
|
4166
|
+
display: "flex",
|
|
4167
|
+
gap: "24px",
|
|
4168
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.2))",
|
|
4169
|
+
paddingBottom: "0",
|
|
4170
|
+
marginBottom: "6px"
|
|
4171
|
+
},
|
|
4172
|
+
children: [
|
|
4173
|
+
{ id: "access", label: t("tabAccess", currentLang) },
|
|
4174
|
+
{ id: "devices", label: t("tabDevices", currentLang) },
|
|
4175
|
+
{ id: "style", label: t("tabStyle", currentLang) },
|
|
4176
|
+
{ id: "storage", label: t("tabStorage", currentLang) }
|
|
4177
|
+
].map((item) => {
|
|
4178
|
+
const isActive = activeTab === item.id;
|
|
4179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4180
|
+
"button",
|
|
4181
|
+
{
|
|
4182
|
+
type: "button",
|
|
4183
|
+
onClick: () => switchTab(item.id),
|
|
4184
|
+
style: {
|
|
4185
|
+
background: "transparent",
|
|
4186
|
+
border: "none",
|
|
4187
|
+
outline: "none",
|
|
4188
|
+
padding: "8px 2px 10px 2px",
|
|
4189
|
+
fontSize: "14px",
|
|
4190
|
+
fontWeight: isActive ? "600" : "400",
|
|
4191
|
+
cursor: "pointer",
|
|
4192
|
+
color: isActive ? "var(--dsw-alias-label-primary, #111827)" : "var(--dsw-alias-label-tertiary, #8c8c8c)",
|
|
4193
|
+
borderBottom: isActive ? "2px solid var(--dsw-alias-label-primary, #111827)" : "2px solid transparent",
|
|
4194
|
+
marginBottom: "-1px",
|
|
4195
|
+
transition: "all 0.2s ease"
|
|
4196
|
+
},
|
|
4197
|
+
children: item.label
|
|
4198
|
+
},
|
|
4199
|
+
item.id
|
|
4200
|
+
);
|
|
4201
|
+
})
|
|
3455
4202
|
}
|
|
3456
4203
|
),
|
|
3457
|
-
/* @__PURE__ */ (0,
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
4204
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: activeTab === "access" ? "flex" : "none", flexDirection: "column", gap: "16px" }, children: [
|
|
4205
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4206
|
+
NetworkCard,
|
|
4207
|
+
{
|
|
4208
|
+
status,
|
|
4209
|
+
toggleTailscale,
|
|
4210
|
+
toggleLan,
|
|
4211
|
+
copyText,
|
|
4212
|
+
lang: currentLang
|
|
4213
|
+
}
|
|
4214
|
+
),
|
|
4215
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4216
|
+
QrPairingCard,
|
|
4217
|
+
{
|
|
4218
|
+
status,
|
|
4219
|
+
showCode,
|
|
4220
|
+
setShowCode,
|
|
4221
|
+
timeLeft,
|
|
4222
|
+
showQr,
|
|
4223
|
+
setShowQr,
|
|
4224
|
+
selectedTab,
|
|
4225
|
+
setSelectedTab: updateQrTab,
|
|
4226
|
+
generateQrSvg,
|
|
4227
|
+
refreshStatusAndCode,
|
|
4228
|
+
copyDirectLink,
|
|
4229
|
+
lang: currentLang
|
|
4230
|
+
}
|
|
4231
|
+
),
|
|
4232
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4233
|
+
SecretCard,
|
|
4234
|
+
{
|
|
4235
|
+
status,
|
|
4236
|
+
secretInput,
|
|
4237
|
+
setSecretInput,
|
|
4238
|
+
showSecret,
|
|
4239
|
+
setShowSecret,
|
|
4240
|
+
saveSecret,
|
|
4241
|
+
clearSecret,
|
|
4242
|
+
lang: currentLang
|
|
4243
|
+
}
|
|
4244
|
+
)
|
|
4245
|
+
] }),
|
|
4246
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: activeTab === "devices" ? "flex" : "none", flexDirection: "column", gap: "16px" }, children: [
|
|
4247
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4248
|
+
DeviceListCard,
|
|
4249
|
+
{
|
|
4250
|
+
status,
|
|
4251
|
+
revokeDevice,
|
|
4252
|
+
revokeAll,
|
|
4253
|
+
lang: currentLang
|
|
4254
|
+
}
|
|
4255
|
+
),
|
|
4256
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4257
|
+
SecurityCard,
|
|
4258
|
+
{
|
|
4259
|
+
status,
|
|
4260
|
+
unlockIp,
|
|
4261
|
+
clearIpStats,
|
|
4262
|
+
lang: currentLang
|
|
4263
|
+
}
|
|
4264
|
+
),
|
|
4265
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4266
|
+
ConfigCard,
|
|
4267
|
+
{
|
|
4268
|
+
maxVisitsInput,
|
|
4269
|
+
setMaxVisitsInput,
|
|
4270
|
+
maxFailedInput,
|
|
4271
|
+
setMaxFailedInput,
|
|
4272
|
+
lockDurationMinsInput,
|
|
4273
|
+
setLockDurationMinsInput,
|
|
4274
|
+
saveAdvancedConfig,
|
|
4275
|
+
resetAdvancedConfigDefaults,
|
|
4276
|
+
isSaving,
|
|
4277
|
+
lang: currentLang,
|
|
4278
|
+
copyText
|
|
4279
|
+
}
|
|
4280
|
+
)
|
|
4281
|
+
] }),
|
|
4282
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { display: activeTab === "style" ? "flex" : "none", flexDirection: "column", gap: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StylesCard, { lang: currentLang, showToast }) }),
|
|
4283
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { display: activeTab === "storage" ? "flex" : "none", flexDirection: "column", gap: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StorageCard, { status, lang: currentLang, copyText }) })
|
|
3473
4284
|
]
|
|
3474
4285
|
}
|
|
3475
4286
|
);
|