@cnc_cbz/usefultools-plugin-official 1.0.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.
@@ -0,0 +1,667 @@
1
+ import { defineComponent, ref, watch, openBlock, createElementBlock, createCommentVNode, createElementVNode, normalizeClass, toDisplayString, createTextVNode, Fragment, withDirectives, renderList, vModelSelect, unref, vModelText, createBlock, Teleport } from "vue";
2
+ import { fetch } from "@tauri-apps/plugin-http";
3
+ const _hoisted_1 = { class: "flex flex-col h-full gap-4" };
4
+ const _hoisted_2 = { class: "flex flex-wrap items-center gap-3" };
5
+ const _hoisted_3 = { class: "flex items-center h-9 bg-deep-charcoal border-2 border-black rounded overflow-hidden" };
6
+ const _hoisted_4 = { class: "material-icons text-lg" };
7
+ const _hoisted_5 = {
8
+ key: 0,
9
+ class: "ml-0.5 w-2 h-2 rounded-full bg-neon-green"
10
+ };
11
+ const _hoisted_6 = {
12
+ key: 1,
13
+ class: "ml-0.5 w-2 h-2 rounded-full bg-coral-red"
14
+ };
15
+ const _hoisted_7 = { class: "flex items-center gap-2" };
16
+ const _hoisted_8 = ["value"];
17
+ const _hoisted_9 = ["value"];
18
+ const _hoisted_10 = {
19
+ key: 0,
20
+ class: "text-coral-red text-xs font-bold"
21
+ };
22
+ const _hoisted_11 = { class: "flex items-center gap-3" };
23
+ const _hoisted_12 = ["value"];
24
+ const _hoisted_13 = ["value"];
25
+ const _hoisted_14 = {
26
+ key: 0,
27
+ class: "px-4 py-2 bg-coral-red/20 border-2 border-coral-red rounded flex items-center gap-2 text-coral-red font-bold text-sm"
28
+ };
29
+ const _hoisted_15 = { class: "flex-1 grid grid-cols-1 lg:grid-cols-2 gap-4 min-h-0" };
30
+ const _hoisted_16 = { class: "flex flex-col min-h-0" };
31
+ const _hoisted_17 = { class: "flex flex-col min-h-0" };
32
+ const _hoisted_18 = { class: "flex items-center gap-2 mb-2" };
33
+ const _hoisted_19 = { class: "material-icons text-sm" };
34
+ const _hoisted_20 = { class: "flex-1 w-full bg-deep-charcoal border-4 border-black rounded-xl p-4 overflow-auto shadow-hard min-h-[200px] text-sm leading-relaxed flex flex-col" };
35
+ const _hoisted_21 = {
36
+ key: 0,
37
+ class: "text-gray-600"
38
+ };
39
+ const _hoisted_22 = {
40
+ key: 1,
41
+ class: "text-gray-100 whitespace-pre-wrap"
42
+ };
43
+ const _hoisted_23 = {
44
+ key: 0,
45
+ class: "fixed inset-0 z-50 flex items-center justify-center"
46
+ };
47
+ const _hoisted_24 = { class: "relative w-full max-w-lg bg-deep-charcoal border-4 border-black rounded-xl shadow-hard-xl p-6 flex flex-col gap-4" };
48
+ const _hoisted_25 = { class: "flex items-center gap-2" };
49
+ const _hoisted_26 = { class: "flex flex-col gap-1.5" };
50
+ const _hoisted_27 = { class: "flex flex-col gap-1.5" };
51
+ const _hoisted_28 = { class: "flex justify-end gap-3 mt-1" };
52
+ const GOOGLE_KEY = "translator-google-api-key";
53
+ const AI_KEY = "translator-ai-api-key";
54
+ const AI_MODEL_KEY = "translator-ai-model";
55
+ const ENGINE_KEY = "translator-engine";
56
+ const DEFAULT_MODEL = "Qwen/Qwen2.5-72B-Instruct";
57
+ const _sfc_main = /* @__PURE__ */ defineComponent({
58
+ __name: "index",
59
+ setup(__props) {
60
+ const engine = ref(localStorage.getItem(ENGINE_KEY) || "google");
61
+ watch(engine, (v) => localStorage.setItem(ENGINE_KEY, v));
62
+ const googleApiKey = ref(localStorage.getItem(GOOGLE_KEY) || "");
63
+ const aiApiKey = ref(localStorage.getItem(AI_KEY) || "");
64
+ const showSettings = ref(false);
65
+ const googleKeyInput = ref("");
66
+ const aiKeyInput = ref("");
67
+ const aiModel = ref(localStorage.getItem(AI_MODEL_KEY) || DEFAULT_MODEL);
68
+ const aiModels = ref([]);
69
+ const modelsLoading = ref(false);
70
+ const modelsError = ref("");
71
+ watch(aiModel, (v) => {
72
+ v ? localStorage.setItem(AI_MODEL_KEY, v) : localStorage.removeItem(AI_MODEL_KEY);
73
+ });
74
+ if (aiApiKey.value) fetchModels();
75
+ async function fetchModels() {
76
+ if (!aiApiKey.value) return;
77
+ modelsLoading.value = true;
78
+ modelsError.value = "";
79
+ try {
80
+ const res = await fetch("https://api.siliconflow.cn/v1/models?sub_type=chat", {
81
+ headers: { "Authorization": `Bearer ${aiApiKey.value}` }
82
+ });
83
+ if (!res.ok) throw new Error(`获取模型列表失败 (${res.status})`);
84
+ const json = await res.json();
85
+ const ids = ((json == null ? void 0 : json.data) || []).map((m) => m.id).sort();
86
+ aiModels.value = ids;
87
+ if (ids.length && !ids.includes(aiModel.value)) {
88
+ aiModel.value = ids.includes(DEFAULT_MODEL) ? DEFAULT_MODEL : ids[0];
89
+ }
90
+ } catch (e) {
91
+ modelsError.value = e.message || "获取模型列表失败";
92
+ } finally {
93
+ modelsLoading.value = false;
94
+ }
95
+ }
96
+ const sourceText = ref("");
97
+ const translatedText = ref("");
98
+ const sourceLang = ref("auto");
99
+ const targetLang = ref("zh-CN");
100
+ const loading = ref(false);
101
+ const errorMsg = ref("");
102
+ const copySuccess = ref(false);
103
+ const languages = [
104
+ { code: "auto", name: "自动检测" },
105
+ { code: "zh-CN", name: "中文(简体)" },
106
+ { code: "zh-TW", name: "中文(繁体)" },
107
+ { code: "en", name: "英语" },
108
+ { code: "ja", name: "日语" },
109
+ { code: "ko", name: "韩语" },
110
+ { code: "fr", name: "法语" },
111
+ { code: "de", name: "德语" },
112
+ { code: "es", name: "西班牙语" },
113
+ { code: "pt", name: "葡萄牙语" },
114
+ { code: "ru", name: "俄语" },
115
+ { code: "ar", name: "阿拉伯语" },
116
+ { code: "hi", name: "印地语" },
117
+ { code: "th", name: "泰语" },
118
+ { code: "vi", name: "越南语" },
119
+ { code: "it", name: "意大利语" },
120
+ { code: "nl", name: "荷兰语" },
121
+ { code: "pl", name: "波兰语" },
122
+ { code: "tr", name: "土耳其语" },
123
+ { code: "id", name: "印尼语" }
124
+ ];
125
+ const targetLanguages = languages.filter((l) => l.code !== "auto");
126
+ function getLangName(code) {
127
+ var _a;
128
+ return ((_a = languages.find((l) => l.code === code)) == null ? void 0 : _a.name) || code;
129
+ }
130
+ function openSettings() {
131
+ googleKeyInput.value = googleApiKey.value;
132
+ aiKeyInput.value = aiApiKey.value;
133
+ showSettings.value = true;
134
+ }
135
+ function saveKeys() {
136
+ googleApiKey.value = googleKeyInput.value.trim();
137
+ const oldAiKey = aiApiKey.value;
138
+ aiApiKey.value = aiKeyInput.value.trim();
139
+ googleApiKey.value ? localStorage.setItem(GOOGLE_KEY, googleApiKey.value) : localStorage.removeItem(GOOGLE_KEY);
140
+ aiApiKey.value ? localStorage.setItem(AI_KEY, aiApiKey.value) : localStorage.removeItem(AI_KEY);
141
+ showSettings.value = false;
142
+ if (aiApiKey.value && aiApiKey.value !== oldAiKey) fetchModels();
143
+ }
144
+ function swapLangs() {
145
+ if (sourceLang.value === "auto") {
146
+ sourceLang.value = targetLang.value;
147
+ targetLang.value = sourceLang.value === "en" ? "zh-CN" : "en";
148
+ } else {
149
+ const tmp = sourceLang.value;
150
+ sourceLang.value = targetLang.value;
151
+ targetLang.value = tmp;
152
+ }
153
+ const tmpText = sourceText.value;
154
+ sourceText.value = translatedText.value;
155
+ translatedText.value = tmpText;
156
+ }
157
+ async function translateGoogle() {
158
+ var _a, _b;
159
+ if (!googleApiKey.value) {
160
+ errorMsg.value = "请先配置 Google Translation API Key";
161
+ showSettings.value = true;
162
+ return;
163
+ }
164
+ const body = {
165
+ q: sourceText.value,
166
+ target: targetLang.value,
167
+ format: "text"
168
+ };
169
+ if (sourceLang.value !== "auto") body.source = sourceLang.value;
170
+ const res = await fetch(
171
+ `https://translation.googleapis.com/language/translate/v2?key=${encodeURIComponent(googleApiKey.value)}`,
172
+ { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }
173
+ );
174
+ const data = await res.json();
175
+ if (!res.ok) throw new Error(((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || `请求失败 (${res.status})`);
176
+ const translations = (_b = data == null ? void 0 : data.data) == null ? void 0 : _b.translations;
177
+ if (translations == null ? void 0 : translations.length) translatedText.value = translations[0].translatedText;
178
+ }
179
+ async function translateAI() {
180
+ var _a, _b, _c, _d, _e;
181
+ if (!aiApiKey.value) {
182
+ errorMsg.value = "请先配置 SiliconFlow API Key";
183
+ showSettings.value = true;
184
+ return;
185
+ }
186
+ const targetName = getLangName(targetLang.value);
187
+ const sourceName = sourceLang.value === "auto" ? "" : `源语言是${getLangName(sourceLang.value)},`;
188
+ const prompt = `你是一个专业翻译。${sourceName}请将以下文本翻译为${targetName}。只输出翻译结果,不要解释。
189
+
190
+ ${sourceText.value}`;
191
+ const res = await fetch("https://api.siliconflow.cn/v1/chat/completions", {
192
+ method: "POST",
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ "Authorization": `Bearer ${aiApiKey.value}`
196
+ },
197
+ body: JSON.stringify({
198
+ model: aiModel.value || DEFAULT_MODEL,
199
+ messages: [{ role: "user", content: prompt }],
200
+ stream: true
201
+ })
202
+ });
203
+ if (!res.ok) {
204
+ const data = await res.json();
205
+ throw new Error(((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || (data == null ? void 0 : data.message) || `请求失败 (${res.status})`);
206
+ }
207
+ const reader = (_b = res.body) == null ? void 0 : _b.getReader();
208
+ if (!reader) throw new Error("无法读取响应流");
209
+ const decoder = new TextDecoder();
210
+ let buffer = "";
211
+ while (true) {
212
+ const { done, value } = await reader.read();
213
+ if (done) break;
214
+ buffer += decoder.decode(value, { stream: true });
215
+ const lines = buffer.split("\n");
216
+ buffer = lines.pop() || "";
217
+ for (const line of lines) {
218
+ const trimmed = line.trim();
219
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
220
+ const payload = trimmed.slice(6);
221
+ if (payload === "[DONE]") return;
222
+ try {
223
+ const chunk = JSON.parse(payload);
224
+ const delta = (_e = (_d = (_c = chunk == null ? void 0 : chunk.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.content;
225
+ if (delta) translatedText.value += delta;
226
+ } catch {
227
+ }
228
+ }
229
+ }
230
+ }
231
+ async function translate() {
232
+ if (!sourceText.value.trim()) return;
233
+ loading.value = true;
234
+ errorMsg.value = "";
235
+ translatedText.value = "";
236
+ try {
237
+ if (engine.value === "google") await translateGoogle();
238
+ else await translateAI();
239
+ } catch (e) {
240
+ errorMsg.value = e.message || "翻译失败";
241
+ } finally {
242
+ loading.value = false;
243
+ }
244
+ }
245
+ async function copyResult() {
246
+ if (!translatedText.value) return;
247
+ await navigator.clipboard.writeText(translatedText.value);
248
+ copySuccess.value = true;
249
+ setTimeout(() => {
250
+ copySuccess.value = false;
251
+ }, 1500);
252
+ }
253
+ return (_ctx, _cache) => {
254
+ return openBlock(), createElementBlock("div", _hoisted_1, [
255
+ createCommentVNode(" Toolbar "),
256
+ createElementVNode("div", _hoisted_2, [
257
+ createCommentVNode(" 引擎切换 "),
258
+ createElementVNode("div", _hoisted_3, [
259
+ createElementVNode(
260
+ "button",
261
+ {
262
+ class: normalizeClass(["h-full px-3 text-sm font-bold transition-all", engine.value === "google" ? "bg-primary text-black" : "text-gray-400 hover:text-white"]),
263
+ onClick: _cache[0] || (_cache[0] = ($event) => engine.value = "google")
264
+ },
265
+ "Google",
266
+ 2
267
+ /* CLASS */
268
+ ),
269
+ createElementVNode(
270
+ "button",
271
+ {
272
+ class: normalizeClass(["h-full px-3 text-sm font-bold transition-all", engine.value === "ai" ? "bg-vibrant-purple text-white" : "text-gray-400 hover:text-white"]),
273
+ onClick: _cache[1] || (_cache[1] = ($event) => engine.value = "ai")
274
+ },
275
+ "AI 翻译",
276
+ 2
277
+ /* CLASS */
278
+ )
279
+ ]),
280
+ createElementVNode(
281
+ "button",
282
+ {
283
+ class: normalizeClass(["h-9 px-4 bg-primary text-black font-bold border-2 border-black rounded shadow-hard-sm hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5 transition-all flex items-center gap-1.5 text-sm", { "opacity-60 pointer-events-none": loading.value }]),
284
+ onClick: translate
285
+ },
286
+ [
287
+ createElementVNode(
288
+ "span",
289
+ _hoisted_4,
290
+ toDisplayString(loading.value ? "hourglass_top" : "translate"),
291
+ 1
292
+ /* TEXT */
293
+ ),
294
+ createTextVNode(
295
+ " " + toDisplayString(loading.value ? "翻译中..." : "翻译"),
296
+ 1
297
+ /* TEXT */
298
+ )
299
+ ],
300
+ 2
301
+ /* CLASS */
302
+ ),
303
+ createElementVNode("button", {
304
+ class: "h-9 px-3 bg-deep-charcoal text-gray-300 font-bold border-2 border-white/20 rounded hover:border-primary hover:text-primary transition-all text-sm flex items-center gap-1.5",
305
+ onClick: openSettings
306
+ }, [
307
+ _cache[11] || (_cache[11] = createElementVNode(
308
+ "span",
309
+ { class: "material-icons text-lg" },
310
+ "key",
311
+ -1
312
+ /* CACHED */
313
+ )),
314
+ _cache[12] || (_cache[12] = createTextVNode(
315
+ " API Key ",
316
+ -1
317
+ /* CACHED */
318
+ )),
319
+ engine.value === "google" && googleApiKey.value || engine.value === "ai" && aiApiKey.value ? (openBlock(), createElementBlock("span", _hoisted_5)) : (openBlock(), createElementBlock("span", _hoisted_6))
320
+ ]),
321
+ createCommentVNode(" AI 模型选择 "),
322
+ engine.value === "ai" ? (openBlock(), createElementBlock(
323
+ Fragment,
324
+ { key: 0 },
325
+ [
326
+ createElementVNode("div", _hoisted_7, [
327
+ _cache[14] || (_cache[14] = createElementVNode(
328
+ "span",
329
+ { class: "material-icons text-vibrant-purple text-base" },
330
+ "smart_toy",
331
+ -1
332
+ /* CACHED */
333
+ )),
334
+ withDirectives(createElementVNode(
335
+ "select",
336
+ {
337
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => aiModel.value = $event),
338
+ class: "h-9 bg-deep-charcoal text-white border-2 border-black rounded px-3 text-sm font-bold outline-none focus:border-vibrant-purple transition-colors max-w-70"
339
+ },
340
+ [
341
+ !aiModels.value.length ? (openBlock(), createElementBlock("option", {
342
+ key: 0,
343
+ value: aiModel.value
344
+ }, toDisplayString(aiModel.value), 9, _hoisted_8)) : createCommentVNode("v-if", true),
345
+ (openBlock(true), createElementBlock(
346
+ Fragment,
347
+ null,
348
+ renderList(aiModels.value, (m) => {
349
+ return openBlock(), createElementBlock("option", {
350
+ key: m,
351
+ value: m
352
+ }, toDisplayString(m), 9, _hoisted_9);
353
+ }),
354
+ 128
355
+ /* KEYED_FRAGMENT */
356
+ ))
357
+ ],
358
+ 512
359
+ /* NEED_PATCH */
360
+ ), [
361
+ [vModelSelect, aiModel.value]
362
+ ]),
363
+ createElementVNode(
364
+ "button",
365
+ {
366
+ class: normalizeClass(["h-9 w-9 flex items-center justify-center bg-deep-charcoal border-2 border-white/20 rounded hover:border-vibrant-purple hover:text-vibrant-purple transition-all", { "animate-spin pointer-events-none": modelsLoading.value }]),
367
+ title: "刷新模型列表",
368
+ onClick: fetchModels
369
+ },
370
+ [..._cache[13] || (_cache[13] = [
371
+ createElementVNode(
372
+ "span",
373
+ { class: "material-icons text-sm" },
374
+ "refresh",
375
+ -1
376
+ /* CACHED */
377
+ )
378
+ ])],
379
+ 2
380
+ /* CLASS */
381
+ )
382
+ ]),
383
+ modelsError.value ? (openBlock(), createElementBlock(
384
+ "span",
385
+ _hoisted_10,
386
+ toDisplayString(modelsError.value),
387
+ 1
388
+ /* TEXT */
389
+ )) : createCommentVNode("v-if", true)
390
+ ],
391
+ 64
392
+ /* STABLE_FRAGMENT */
393
+ )) : createCommentVNode("v-if", true)
394
+ ]),
395
+ createCommentVNode(" 语言选择栏 "),
396
+ createElementVNode("div", _hoisted_11, [
397
+ withDirectives(createElementVNode(
398
+ "select",
399
+ {
400
+ "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => sourceLang.value = $event),
401
+ class: "bg-deep-charcoal text-white border-2 border-black rounded px-3 py-1.5 text-sm font-bold outline-none focus:border-primary transition-colors"
402
+ },
403
+ [
404
+ (openBlock(), createElementBlock(
405
+ Fragment,
406
+ null,
407
+ renderList(languages, (l) => {
408
+ return createElementVNode("option", {
409
+ key: l.code,
410
+ value: l.code
411
+ }, toDisplayString(l.name), 9, _hoisted_12);
412
+ }),
413
+ 64
414
+ /* STABLE_FRAGMENT */
415
+ ))
416
+ ],
417
+ 512
418
+ /* NEED_PATCH */
419
+ ), [
420
+ [vModelSelect, sourceLang.value]
421
+ ]),
422
+ createElementVNode("button", {
423
+ class: "w-8 h-8 flex items-center justify-center bg-deep-charcoal border-2 border-white/20 rounded-full hover:border-primary hover:text-primary transition-all",
424
+ onClick: swapLangs
425
+ }, [..._cache[15] || (_cache[15] = [
426
+ createElementVNode(
427
+ "span",
428
+ { class: "material-icons text-base" },
429
+ "swap_horiz",
430
+ -1
431
+ /* CACHED */
432
+ )
433
+ ])]),
434
+ withDirectives(createElementVNode(
435
+ "select",
436
+ {
437
+ "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => targetLang.value = $event),
438
+ class: "bg-deep-charcoal text-white border-2 border-black rounded px-3 py-1.5 text-sm font-bold outline-none focus:border-primary transition-colors"
439
+ },
440
+ [
441
+ (openBlock(true), createElementBlock(
442
+ Fragment,
443
+ null,
444
+ renderList(unref(targetLanguages), (l) => {
445
+ return openBlock(), createElementBlock("option", {
446
+ key: l.code,
447
+ value: l.code
448
+ }, toDisplayString(l.name), 9, _hoisted_13);
449
+ }),
450
+ 128
451
+ /* KEYED_FRAGMENT */
452
+ ))
453
+ ],
454
+ 512
455
+ /* NEED_PATCH */
456
+ ), [
457
+ [vModelSelect, targetLang.value]
458
+ ])
459
+ ]),
460
+ createCommentVNode(" Error bar "),
461
+ errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_14, [
462
+ _cache[16] || (_cache[16] = createElementVNode(
463
+ "span",
464
+ { class: "material-icons text-lg" },
465
+ "error_outline",
466
+ -1
467
+ /* CACHED */
468
+ )),
469
+ createTextVNode(
470
+ " " + toDisplayString(errorMsg.value),
471
+ 1
472
+ /* TEXT */
473
+ )
474
+ ])) : createCommentVNode("v-if", true),
475
+ createCommentVNode(" 翻译面板 "),
476
+ createElementVNode("div", _hoisted_15, [
477
+ createCommentVNode(" 源文本 "),
478
+ createElementVNode("div", _hoisted_16, [
479
+ _cache[17] || (_cache[17] = createElementVNode(
480
+ "div",
481
+ { class: "flex items-center gap-2 mb-2" },
482
+ [
483
+ createElementVNode("span", { class: "material-icons text-primary text-lg" }, "edit_note"),
484
+ createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "原文")
485
+ ],
486
+ -1
487
+ /* CACHED */
488
+ )),
489
+ withDirectives(createElementVNode(
490
+ "textarea",
491
+ {
492
+ "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => sourceText.value = $event),
493
+ spellcheck: "false",
494
+ placeholder: "在此输入要翻译的文本...",
495
+ class: "flex-1 w-full bg-deep-charcoal text-gray-100 border-4 border-black rounded-xl p-4 font-mono text-sm leading-relaxed resize-none shadow-hard focus:border-primary focus:shadow-none focus:translate-x-[4px] focus:translate-y-[4px] transition-all outline-none placeholder-gray-600 min-h-[200px]"
496
+ },
497
+ null,
498
+ 512
499
+ /* NEED_PATCH */
500
+ ), [
501
+ [vModelText, sourceText.value]
502
+ ])
503
+ ]),
504
+ createCommentVNode(" 翻译结果 "),
505
+ createElementVNode("div", _hoisted_17, [
506
+ createElementVNode("div", _hoisted_18, [
507
+ _cache[18] || (_cache[18] = createElementVNode(
508
+ "span",
509
+ { class: "material-icons text-neon-green text-lg" },
510
+ "g_translate",
511
+ -1
512
+ /* CACHED */
513
+ )),
514
+ _cache[19] || (_cache[19] = createElementVNode(
515
+ "span",
516
+ { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" },
517
+ "译文",
518
+ -1
519
+ /* CACHED */
520
+ )),
521
+ translatedText.value ? (openBlock(), createElementBlock(
522
+ "button",
523
+ {
524
+ key: 0,
525
+ class: normalizeClass(["ml-auto px-2 py-0.5 bg-deep-charcoal font-bold border-2 rounded transition-all text-xs flex items-center gap-1", copySuccess.value ? "text-neon-green border-neon-green/40" : "text-gray-300 border-white/20 hover:border-primary hover:text-primary"]),
526
+ onClick: copyResult
527
+ },
528
+ [
529
+ createElementVNode(
530
+ "span",
531
+ _hoisted_19,
532
+ toDisplayString(copySuccess.value ? "check_circle" : "content_copy"),
533
+ 1
534
+ /* TEXT */
535
+ ),
536
+ createTextVNode(
537
+ " " + toDisplayString(copySuccess.value ? "已复制" : "复制"),
538
+ 1
539
+ /* TEXT */
540
+ )
541
+ ],
542
+ 2
543
+ /* CLASS */
544
+ )) : createCommentVNode("v-if", true)
545
+ ]),
546
+ createElementVNode("div", _hoisted_20, [
547
+ !translatedText.value ? (openBlock(), createElementBlock("div", _hoisted_21, " 翻译结果将显示在这里... ")) : (openBlock(), createElementBlock(
548
+ "div",
549
+ _hoisted_22,
550
+ toDisplayString(translatedText.value),
551
+ 1
552
+ /* TEXT */
553
+ ))
554
+ ])
555
+ ])
556
+ ]),
557
+ createCommentVNode(" API Key 设置弹窗 "),
558
+ (openBlock(), createBlock(Teleport, { to: "body" }, [
559
+ showSettings.value ? (openBlock(), createElementBlock("div", _hoisted_23, [
560
+ createElementVNode("div", {
561
+ class: "absolute inset-0 bg-black/60",
562
+ onClick: _cache[6] || (_cache[6] = ($event) => showSettings.value = false)
563
+ }),
564
+ createElementVNode("div", _hoisted_24, [
565
+ createElementVNode("div", _hoisted_25, [
566
+ _cache[21] || (_cache[21] = createElementVNode(
567
+ "span",
568
+ { class: "material-icons text-primary text-xl" },
569
+ "key",
570
+ -1
571
+ /* CACHED */
572
+ )),
573
+ _cache[22] || (_cache[22] = createElementVNode(
574
+ "span",
575
+ { class: "text-lg font-bold text-white" },
576
+ "配置 API Key",
577
+ -1
578
+ /* CACHED */
579
+ )),
580
+ createElementVNode("button", {
581
+ class: "ml-auto w-8 h-8 flex items-center justify-center text-gray-400 hover:text-white transition-colors",
582
+ onClick: _cache[7] || (_cache[7] = ($event) => showSettings.value = false)
583
+ }, [..._cache[20] || (_cache[20] = [
584
+ createElementVNode(
585
+ "span",
586
+ { class: "material-icons" },
587
+ "close",
588
+ -1
589
+ /* CACHED */
590
+ )
591
+ ])])
592
+ ]),
593
+ createCommentVNode(" Google API Key "),
594
+ createElementVNode("div", _hoisted_26, [
595
+ _cache[23] || (_cache[23] = createElementVNode(
596
+ "label",
597
+ { class: "text-xs font-bold text-gray-400 uppercase tracking-wider" },
598
+ "Google Translation API Key",
599
+ -1
600
+ /* CACHED */
601
+ )),
602
+ withDirectives(createElementVNode(
603
+ "input",
604
+ {
605
+ "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => googleKeyInput.value = $event),
606
+ type: "password",
607
+ placeholder: "AIzaSy...",
608
+ class: "w-full bg-bg-dark text-gray-100 border-2 border-black rounded-lg px-4 py-2.5 font-mono text-sm outline-none focus:border-primary transition-colors placeholder-gray-600"
609
+ },
610
+ null,
611
+ 512
612
+ /* NEED_PATCH */
613
+ ), [
614
+ [vModelText, googleKeyInput.value]
615
+ ])
616
+ ]),
617
+ createCommentVNode(" SiliconFlow API Key "),
618
+ createElementVNode("div", _hoisted_27, [
619
+ _cache[24] || (_cache[24] = createElementVNode(
620
+ "label",
621
+ { class: "text-xs font-bold text-gray-400 uppercase tracking-wider" },
622
+ "SiliconFlow API Key(AI 翻译)",
623
+ -1
624
+ /* CACHED */
625
+ )),
626
+ withDirectives(createElementVNode(
627
+ "input",
628
+ {
629
+ "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => aiKeyInput.value = $event),
630
+ type: "password",
631
+ placeholder: "sk-...",
632
+ class: "w-full bg-bg-dark text-gray-100 border-2 border-black rounded-lg px-4 py-2.5 font-mono text-sm outline-none focus:border-primary transition-colors placeholder-gray-600"
633
+ },
634
+ null,
635
+ 512
636
+ /* NEED_PATCH */
637
+ ), [
638
+ [vModelText, aiKeyInput.value]
639
+ ]),
640
+ _cache[25] || (_cache[25] = createElementVNode(
641
+ "p",
642
+ { class: "text-[11px] text-gray-600" },
643
+ "密钥从 cloud.siliconflow.cn 获取,保存后可在工具栏选择模型",
644
+ -1
645
+ /* CACHED */
646
+ ))
647
+ ]),
648
+ createElementVNode("div", _hoisted_28, [
649
+ createElementVNode("button", {
650
+ class: "px-4 py-2 bg-white/10 text-gray-300 font-bold border-2 border-white/20 rounded hover:border-white hover:text-white transition-all text-sm",
651
+ onClick: _cache[10] || (_cache[10] = ($event) => showSettings.value = false)
652
+ }, " 取消 "),
653
+ createElementVNode("button", {
654
+ class: "px-4 py-2 bg-primary text-black font-bold border-2 border-black rounded shadow-hard-sm hover:shadow-none hover:translate-x-[2px] hover:translate-y-[2px] transition-all text-sm",
655
+ onClick: saveKeys
656
+ }, " 保存 ")
657
+ ])
658
+ ])
659
+ ])) : createCommentVNode("v-if", true)
660
+ ]))
661
+ ]);
662
+ };
663
+ }
664
+ });
665
+ export {
666
+ _sfc_main as default
667
+ };