@opentiny/next-sdk 0.1.14 → 0.1.15

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.
Files changed (62) hide show
  1. package/agent/AgentModelProvider.ts +49 -20
  2. package/agent/type.ts +4 -4
  3. package/dist/McpSdk.d.ts +14 -0
  4. package/dist/WebAgent.d.ts +5 -0
  5. package/dist/WebMcp.d.ts +20 -0
  6. package/dist/WebMcpClient.d.ts +250 -1152
  7. package/dist/WebMcpServer.d.ts +190 -78
  8. package/dist/Zod.d.ts +1 -0
  9. package/dist/agent/AgentModelProvider.d.ts +6 -4
  10. package/dist/agent/type.d.ts +6 -2
  11. package/dist/agent/utils/getAISDKTools.d.ts +1 -0
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.es.dev.js +21741 -23457
  14. package/dist/index.es.js +24309 -23733
  15. package/dist/index.js +1789 -25
  16. package/dist/index.umd.dev.js +21720 -23436
  17. package/dist/index.umd.js +184 -132
  18. package/dist/{mcpsdk@1.17.0.dev.js → mcpsdk@1.23.0.dev.js} +14784 -15255
  19. package/dist/{mcpsdk@1.17.0.es.dev.js → mcpsdk@1.23.0.es.dev.js} +14787 -15258
  20. package/dist/mcpsdk@1.23.0.es.js +15584 -0
  21. package/dist/mcpsdk@1.23.0.js +43 -0
  22. package/dist/remoter/createRemoter.d.ts +9 -0
  23. package/dist/remoter/tooltips.d.ts +36 -0
  24. package/dist/script/utils.d.ts +1 -0
  25. package/dist/transport/ExtensionClientTransport.d.ts +3 -2
  26. package/dist/transport/ExtensionContentServerTransport.d.ts +3 -2
  27. package/dist/transport/ExtensionPageServerTransport.d.ts +3 -2
  28. package/dist/vite-build-tsc.d.ts +2 -0
  29. package/dist/vite.config.d.ts +2 -0
  30. package/dist/vite.config.mcpSdk.d.ts +2 -0
  31. package/dist/vite.config.webAgent.d.ts +2 -0
  32. package/dist/vite.config.webMcp.d.ts +2 -0
  33. package/dist/vite.config.webMcpFull.d.ts +2 -0
  34. package/dist/vite.config.zod.d.ts +2 -0
  35. package/dist/webagent.dev.js +18780 -18491
  36. package/dist/webagent.es.dev.js +18455 -18166
  37. package/dist/webagent.es.js +22389 -20343
  38. package/dist/webagent.js +172 -113
  39. package/dist/webmcp-full.dev.js +14943 -15356
  40. package/dist/webmcp-full.es.dev.js +14959 -15372
  41. package/dist/webmcp-full.es.js +13785 -12666
  42. package/dist/webmcp-full.js +43 -16
  43. package/package.json +3 -2
  44. package/remoter/createRemoter.ts +126 -71
  45. package/remoter/tooltips.ts +260 -0
  46. package/tsconfig.json +5 -3
  47. package/vite-build-tsc.ts +60 -0
  48. package/vite-env.d.ts +5 -0
  49. package/dist/WebMcpClient.js +0 -363
  50. package/dist/WebMcpServer.js +0 -283
  51. package/dist/agent/AgentModelProvider.js +0 -293
  52. package/dist/agent/type.js +0 -1
  53. package/dist/agent/utils/getAISDKTools.js +0 -36
  54. package/dist/mcpsdk@1.17.0.es.js +0 -14505
  55. package/dist/mcpsdk@1.17.0.js +0 -16
  56. package/dist/remoter/QrCode.js +0 -55
  57. package/dist/remoter/createRemoter.js +0 -743
  58. package/dist/transport/ExtensionClientTransport.js +0 -81
  59. package/dist/transport/ExtensionContentServerTransport.js +0 -128
  60. package/dist/transport/ExtensionPageServerTransport.js +0 -118
  61. package/dist/transport/messages.js +0 -51
  62. package/dist/utils/uuid.js +0 -10
@@ -1,743 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { QrCode } from './QrCode';
11
- const DEFAULT_REMOTE_URL = 'https://agent.opentiny.design/tiny-robot';
12
- const DEFAULT_QR_CODE_URL = 'https://ai.opentiny.design/next-remoter';
13
- const getDefaultMenuItems = (options) => {
14
- return [
15
- {
16
- action: 'qr-code',
17
- show: true,
18
- text: '弹出二维码',
19
- icon: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
20
- <rect x="3" y="3" width="6" height="6" rx="1" stroke="currentColor" stroke-width="2" fill="none"/>
21
- <rect x="15" y="3" width="6" height="6" rx="1" stroke="currentColor" stroke-width="2" fill="none"/>
22
- <rect x="3" y="15" width="6" height="6" rx="1" stroke="currentColor" stroke-width="2" fill="none"/>
23
- <line x1="9" y1="6" x2="9" y2="18" stroke="currentColor" stroke-width="1.5"/>
24
- <line x1="15" y1="6" x2="15" y2="18" stroke="currentColor" stroke-width="1.5"/>
25
- <line x1="6" y1="9" x2="18" y2="9" stroke="currentColor" stroke-width="1.5"/>
26
- <line x1="6" y1="15" x2="18" y2="15" stroke="currentColor" stroke-width="1.5"/>
27
- <circle cx="12" cy="12" r="1" fill="currentColor"/>
28
- </svg>`
29
- },
30
- {
31
- action: 'ai-chat',
32
- show: true,
33
- text: '弹出 AI 对话框',
34
- icon: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
35
- <path d="M20 2H4C2.9 2 2 2.9 2 4V22L6 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2ZM20 16H6L4 18V4H20V16Z" fill="currentColor"/>
36
- <path d="M7 9H17V11H7V9Z" fill="currentColor"/>
37
- <path d="M7 12H14V14H7V12Z" fill="currentColor"/>
38
- </svg>`
39
- },
40
- {
41
- action: 'remote-control',
42
- show: true,
43
- text: `识别码:${options.sessionId.slice(-6)}`,
44
- showCopyIcon: true,
45
- icon: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
46
- <rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="2" fill="none"/>
47
- <rect x="6" y="6" width="3" height="2" rx="0.5" fill="currentColor"/>
48
- <rect x="10" y="6" width="3" height="2" rx="0.5" fill="currentColor"/>
49
- <rect x="14" y="6" width="3" height="2" rx="0.5" fill="currentColor"/>
50
- <rect x="6" y="9" width="3" height="2" rx="0.5" fill="currentColor"/>
51
- <rect x="10" y="9" width="3" height="2" rx="0.5" fill="currentColor"/>
52
- <rect x="14" y="9" width="3" height="2" rx="0.5" fill="currentColor"/>
53
- <rect x="6" y="12" width="3" height="2" rx="0.5" fill="currentColor"/>
54
- <rect x="10" y="12" width="3" height="2" rx="0.5" fill="currentColor"/>
55
- <rect x="14" y="12" width="3" height="2" rx="0.5" fill="currentColor"/>
56
- </svg>`
57
- },
58
- {
59
- action: 'remote-url',
60
- show: true,
61
- text: `${options.remoteUrl}`,
62
- tip: options.remoteUrl,
63
- showCopyIcon: true,
64
- icon: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
65
- <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
66
- <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
67
- </svg>`
68
- }
69
- ];
70
- };
71
- class FloatingBlock {
72
- // 计算 sessionPrefix 属性
73
- get sessionPrefix() {
74
- var _a;
75
- return ((_a = this.options.qrCodeUrl) === null || _a === void 0 ? void 0 : _a.includes('?')) ? '&sessionId=' : '?sessionId=';
76
- }
77
- constructor(options) {
78
- this.isExpanded = false;
79
- if (!options.sessionId) {
80
- throw new Error('sessionId is required');
81
- }
82
- this.options = Object.assign(Object.assign({}, options), { qrCodeUrl: options.qrCodeUrl || DEFAULT_QR_CODE_URL, remoteUrl: options.remoteUrl || DEFAULT_REMOTE_URL });
83
- // 合并默认菜单项配置和用户配置
84
- this.menuItems = this.mergeMenuItems(options.menuItems);
85
- this.init();
86
- }
87
- /**
88
- * 合并菜单项配置
89
- * @param userMenuItems 用户自定义菜单项配置
90
- * @returns 合并后的菜单项配置
91
- */
92
- mergeMenuItems(userMenuItems) {
93
- if (!userMenuItems) {
94
- return getDefaultMenuItems(this.options);
95
- }
96
- return getDefaultMenuItems(this.options).map((defaultItem) => {
97
- const userItem = userMenuItems.find((item) => item.action === defaultItem.action);
98
- if (userItem) {
99
- return Object.assign(Object.assign(Object.assign({}, defaultItem), userItem), {
100
- // 确保show属性存在,默认为true
101
- show: userItem.show !== undefined ? userItem.show : defaultItem.show });
102
- }
103
- return defaultItem;
104
- });
105
- }
106
- init() {
107
- this.createFloatingBlock();
108
- this.createDropdownMenu();
109
- this.bindEvents();
110
- this.addStyles();
111
- }
112
- // 创建主浮动块
113
- createFloatingBlock() {
114
- this.floatingBlock = document.createElement('div');
115
- this.floatingBlock.className = 'tiny-remoter-floating-block';
116
- this.floatingBlock.innerHTML = `
117
- <div class="tiny-remoter-floating-block__icon">
118
- <img style="display: block; width: 56px;" src="${DEFAULT_QR_CODE_URL}/svgs/logo-next-no-bg-left.svg" alt="icon" />
119
- </div>
120
- `;
121
- document.body.appendChild(this.floatingBlock);
122
- }
123
- // 创建下拉菜单
124
- createDropdownMenu() {
125
- this.dropdownMenu = document.createElement('div');
126
- this.dropdownMenu.className = 'tiny-remoter-floating-dropdown';
127
- // 根据配置动态生成菜单项
128
- const menuItemsHTML = this.menuItems
129
- .filter((item) => item.show !== false) // 过滤掉show为false的菜单项
130
- .map((item) => `
131
- <div class="tiny-remoter-dropdown-item" data-action="${item.action}">
132
- <div class="tiny-remoter-dropdown-item__icon">
133
- ${item.icon}
134
- </div>
135
- <span title="${item.tip}">${item.text}</span>
136
- ${item.showCopyIcon
137
- ? `
138
- <div class="tiny-remoter-copy-icon" data-action="${item.action}">
139
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
140
- <path d="M16 1H4C2.9 1 2 1.9 2 3V17H4V3H16V1ZM19 5H8C6.9 5 6 5.9 6 7V21C6 22.1 6.9 23 8 23H19C20.1 23 21 22.1 21 21V7C21 5.9 20.1 5 19 5ZM19 21H8V7H19V21Z" fill="currentColor"/>
141
- </svg>
142
- </div>
143
- `
144
- : ''}
145
- </div>
146
- `)
147
- .join('');
148
- this.dropdownMenu.innerHTML = menuItemsHTML;
149
- document.body.appendChild(this.dropdownMenu);
150
- }
151
- bindEvents() {
152
- // 绑定浮动块点击事件
153
- this.floatingBlock.addEventListener('click', () => {
154
- this.toggleDropdown();
155
- });
156
- // 绑定菜单项点击事件
157
- this.dropdownMenu.addEventListener('click', (e) => {
158
- const target = e.target;
159
- // 检查是否点击了复制图标
160
- const copyIcon = target.closest('.tiny-remoter-copy-icon');
161
- if (copyIcon) {
162
- e.stopPropagation(); // 阻止事件冒泡,避免触发菜单项点击
163
- const action = copyIcon.dataset.action;
164
- if (action) {
165
- this.handleAction(action);
166
- }
167
- return;
168
- }
169
- // 处理普通菜单项点击
170
- const actionItem = target.closest('.tiny-remoter-dropdown-item');
171
- const action = actionItem === null || actionItem === void 0 ? void 0 : actionItem.dataset.action;
172
- if (action) {
173
- this.handleAction(action);
174
- }
175
- });
176
- // 点击外部关闭菜单
177
- document.addEventListener('click', (e) => {
178
- const target = e.target;
179
- if (!this.floatingBlock.contains(target) && !this.dropdownMenu.contains(target)) {
180
- this.closeDropdown();
181
- }
182
- });
183
- // ESC键关闭菜单
184
- document.addEventListener('keydown', (e) => {
185
- if (e.key === 'Escape') {
186
- this.closeDropdown();
187
- }
188
- });
189
- }
190
- toggleDropdown() {
191
- if (this.isExpanded) {
192
- this.closeDropdown();
193
- }
194
- else {
195
- this.openDropdown();
196
- }
197
- }
198
- openDropdown() {
199
- this.isExpanded = true;
200
- this.floatingBlock.classList.add('expanded');
201
- this.dropdownMenu.classList.add('show');
202
- }
203
- closeDropdown() {
204
- this.isExpanded = false;
205
- this.floatingBlock.classList.remove('expanded');
206
- this.dropdownMenu.classList.remove('show');
207
- }
208
- handleAction(action) {
209
- switch (action) {
210
- case 'qr-code':
211
- this.showQRCode();
212
- break;
213
- case 'ai-chat':
214
- this.showAIChat();
215
- break;
216
- case 'remote-control':
217
- this.copyRemoteControl();
218
- break;
219
- case 'remote-url':
220
- this.copyRemoteURL();
221
- break;
222
- }
223
- this.closeDropdown();
224
- }
225
- copyRemoteControl() {
226
- this.copyToClipboard(this.options.sessionId.slice(-6));
227
- }
228
- copyRemoteURL() {
229
- this.copyToClipboard(this.options.remoteUrl + this.sessionPrefix + this.options.sessionId);
230
- }
231
- // 实现复制到剪贴板功能
232
- copyToClipboard(text) {
233
- return __awaiter(this, void 0, void 0, function* () {
234
- try {
235
- // 优先使用现代浏览器的 Clipboard API
236
- if (navigator.clipboard && window.isSecureContext) {
237
- yield navigator.clipboard.writeText(text);
238
- this.showCopyFeedback(true);
239
- }
240
- else {
241
- // 降级方案:使用传统的 document.execCommand
242
- const textArea = document.createElement('textarea');
243
- textArea.value = text;
244
- textArea.style.position = 'fixed';
245
- textArea.style.left = '-999999px';
246
- textArea.style.top = '-999999px';
247
- document.body.appendChild(textArea);
248
- textArea.focus();
249
- textArea.select();
250
- const successful = document.execCommand('copy');
251
- document.body.removeChild(textArea);
252
- if (successful) {
253
- this.showCopyFeedback(true);
254
- }
255
- else {
256
- this.showCopyFeedback(false);
257
- }
258
- }
259
- }
260
- catch (error) {
261
- console.error('复制失败:', error);
262
- this.showCopyFeedback(false);
263
- }
264
- });
265
- }
266
- // 显示复制反馈提示
267
- showCopyFeedback(success) {
268
- const message = success ? '复制成功!' : '复制失败,请手动复制';
269
- const feedback = document.createElement('div');
270
- feedback.className = `tiny-remoter-copy-feedback ${success ? 'success' : 'error'}`;
271
- feedback.textContent = message;
272
- document.body.appendChild(feedback);
273
- // 添加显示动画
274
- setTimeout(() => feedback.classList.add('show'), 10);
275
- // 3秒后自动移除
276
- setTimeout(() => {
277
- feedback.classList.remove('show');
278
- setTimeout(() => {
279
- if (feedback.parentNode) {
280
- feedback.parentNode.removeChild(feedback);
281
- }
282
- }, 300);
283
- }, 1500);
284
- }
285
- // 创建二维码弹窗
286
- showQRCode() {
287
- return __awaiter(this, void 0, void 0, function* () {
288
- const qrCode = new QrCode((this.options.qrCodeUrl || '') + this.sessionPrefix + this.options.sessionId, {});
289
- const base64 = yield qrCode.toDataURL();
290
- const modal = this.createModal('扫码前往智能遥控器', `
291
- <div style="text-align: center; padding: 32px;">
292
- <!-- 二维码容器 - 添加渐变背景和阴影效果 -->
293
- <div style="
294
- width: 240px;
295
- height: 240px;
296
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
297
- margin: 0 auto 24px;
298
- display: flex;
299
- align-items: center;
300
- justify-content: center;
301
- border-radius: 20px;
302
- box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
303
- position: relative;
304
- overflow: hidden;
305
- ">
306
- <!-- 装饰性背景元素 -->
307
- <div style="
308
- position: absolute;
309
- top: -50%;
310
- left: -50%;
311
- width: 200%;
312
- height: 200%;
313
- background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
314
- animation: rotate 20s linear infinite;
315
- "></div>
316
-
317
- <!-- 二维码图片容器 -->
318
- <div style="
319
- width: 200px;
320
- height: 200px;
321
- background: white;
322
- border-radius: 16px;
323
- padding: 16px;
324
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
325
- position: relative;
326
- z-index: 1;
327
- ">
328
- <img src="${base64}" alt="二维码" style="
329
- width: 100%;
330
- height: 100%;
331
- object-fit: contain;
332
- border-radius: 8px;
333
- ">
334
- </div>
335
- </div>
336
-
337
- <!-- 标题文字 -->
338
- <h3 style="
339
- color: #333;
340
- margin: 0 0 12px 0;
341
- font-size: 20px;
342
- font-weight: 600;
343
- letter-spacing: 0.5px;
344
- ">扫描二维码</h3>
345
-
346
- <!-- 描述文字 -->
347
- <p style="
348
- color: #666;
349
- margin: 0 auto;
350
- margin-bottom: 20px;
351
- font-size: 14px;
352
- line-height: 1.6;
353
- max-width: 280px;
354
- ">请使用手机微信或者浏览器扫描二维码跳转到智能遥控器</p>
355
-
356
- <!-- 提示图标和文字 -->
357
- <div style="
358
- display: flex;
359
- align-items: center;
360
- justify-content: center;
361
- gap: 8px;
362
- color: #999;
363
- font-size: 12px;
364
- ">
365
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="opacity: 0.7;">
366
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="currentColor"/>
367
- </svg>
368
- <span>支持微信、浏览器等多种方式</span>
369
- </div>
370
- </div>
371
- `);
372
- this.showModal(modal);
373
- });
374
- }
375
- // 创建AI对话弹窗--- 暂时调 “用户函数”
376
- showAIChat() {
377
- var _a, _b;
378
- (_b = (_a = this.options).onShowAIChat) === null || _b === void 0 ? void 0 : _b.call(_a);
379
- }
380
- createModal(title, content) {
381
- const modal = document.createElement('div');
382
- modal.className = 'tiny-remoter-floating-modal';
383
- modal.innerHTML = `
384
- <div class="tiny-remoter-modal-overlay"></div>
385
- <div class="tiny-remoter-modal-content">
386
- <div class="tiny-remoter-modal-header">
387
- <h3>${title}</h3>
388
- <button class="tiny-remoter-modal-close">&times;</button>
389
- </div>
390
- <div class="tiny-remoter-modal-body">
391
- ${content}
392
- </div>
393
- </div>
394
- `;
395
- // 绑定关闭事件
396
- const closeBtn = modal.querySelector('.tiny-remoter-modal-close');
397
- const overlay = modal.querySelector('.tiny-remoter-modal-overlay');
398
- closeBtn.addEventListener('click', () => this.hideModal(modal));
399
- overlay.addEventListener('click', () => this.hideModal(modal));
400
- return modal;
401
- }
402
- showModal(modal) {
403
- document.body.appendChild(modal);
404
- // 添加显示动画
405
- setTimeout(() => modal.classList.add('show'), 10);
406
- }
407
- hideModal(modal) {
408
- modal.classList.remove('show');
409
- setTimeout(() => {
410
- if (modal.parentNode) {
411
- modal.parentNode.removeChild(modal);
412
- }
413
- }, 100);
414
- }
415
- // 创建样式表
416
- addStyles() {
417
- const style = document.createElement('style');
418
- style.textContent = `
419
- /* 浮动块样式 */
420
- .tiny-remoter-floating-block {
421
- position: fixed;
422
- bottom: 30px;
423
- right: 30px;
424
- width: 60px;
425
- height: 60px;
426
- cursor: pointer;
427
- display: flex;
428
- align-items: center;
429
- justify-content: center;
430
- color: white;
431
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
432
- z-index: 99;
433
- overflow: hidden;
434
- border-radius: 50%;
435
- }
436
-
437
- .tiny-remoter-floating-block__icon {
438
- transform: scale(0.8);
439
- transition: transform 0.3s ease;
440
- }
441
-
442
- .tiny-remoter-floating-block__icon:hover {
443
- transform: scale(1.1);
444
- }
445
-
446
- .tiny-remoter-floating-block.expanded .tiny-remoter-floating-block__icon {
447
- transform: scale(1.1);
448
- }
449
-
450
- /* 下拉菜单样式 */
451
- .tiny-remoter-floating-dropdown {
452
- position: fixed;
453
- bottom: 100px;
454
- right: 30px;
455
- background: white;
456
- border-radius: 16px;
457
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
458
- padding: 8px;
459
- opacity: 0;
460
- visibility: hidden;
461
- transform: translateY(20px) scale(0.95);
462
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
463
- z-index: 999;
464
- min-width: 200px;
465
- }
466
-
467
- .tiny-remoter-floating-dropdown.show {
468
- opacity: 1;
469
- visibility: visible;
470
- transform: translateY(0) scale(1);
471
- }
472
-
473
- .tiny-remoter-dropdown-item {
474
- display: flex;
475
- align-items: center;
476
- gap: 12px;
477
- padding: 12px 16px;
478
- border-radius: 12px;
479
- cursor: pointer;
480
- transition: all 0.2s ease;
481
- color: #333;
482
- }
483
-
484
- .tiny-remoter-dropdown-item > span {
485
- flex: 1;
486
- overflow: hidden;
487
- max-width: 120px;
488
- text-overflow: ellipsis;
489
- white-space: nowrap;
490
- }
491
-
492
- .tiny-remoter-dropdown-item:hover {
493
- background: #f8f9fa;
494
- transform: translateX(4px);
495
- }
496
-
497
- .tiny-remoter-dropdown-item__icon {
498
- display: flex;
499
- align-items: center;
500
- justify-content: center;
501
- width: 32px;
502
- height: 32px;
503
- background: #f8f9fa;
504
- border-radius: 8px;
505
- color: #667eea;
506
- }
507
-
508
- /* 复制图标样式 */
509
- .tiny-remoter-copy-icon {
510
- display: flex;
511
- align-items: center;
512
- justify-content: center;
513
- width: 24px;
514
- height: 24px;
515
- background: #f0f0f0;
516
- border-radius: 6px;
517
- color: #666;
518
- cursor: pointer;
519
- transition: all 0.2s ease;
520
- opacity: 0.7;
521
- margin-left: auto;
522
- }
523
-
524
- .tiny-remoter-copy-icon:hover {
525
- background: #e0e0e0;
526
- color: #333;
527
- opacity: 1;
528
- transform: scale(1.1);
529
- }
530
-
531
- .tiny-remoter-copy-icon:active {
532
- transform: scale(0.95);
533
- }
534
-
535
- /* 弹窗样式 */
536
- .tiny-remoter-floating-modal {
537
- position: fixed;
538
- top: 0;
539
- left: 0;
540
- width: 100%;
541
- height: 100%;
542
- z-index: 2000;
543
- display: flex;
544
- align-items: center;
545
- justify-content: center;
546
- }
547
-
548
- .tiny-remoter-modal-overlay {
549
- position: absolute;
550
- top: 0;
551
- left: 0;
552
- width: 100%;
553
- height: 100%;
554
- background: rgba(0, 0, 0, 0.5);
555
- backdrop-filter: blur(4px);
556
- opacity: 0;
557
- transition: opacity 0.3s ease;
558
- }
559
-
560
- .tiny-remoter-modal-content {
561
- background: white;
562
- border-radius: 16px;
563
- box-shadow: 0 25px 80px rgba(0, 0, 0, 0.2);
564
- max-width: 500px;
565
- width: 90%;
566
- max-height: 80vh;
567
- overflow: hidden;
568
- transform: scale(0.9) translateY(20px);
569
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
570
- }
571
-
572
- .tiny-remoter-floating-modal.show .tiny-remoter-modal-overlay {
573
- opacity: 1;
574
- }
575
-
576
- .tiny-remoter-floating-modal.show .tiny-remoter-modal-content {
577
- transform: scale(1) translateY(0);
578
- }
579
-
580
- .tiny-remoter-modal-header {
581
- display: flex;
582
- align-items: center;
583
- justify-content: space-between;
584
- padding: 20px 24px;
585
- border-bottom: 1px solid #f0f0f0;
586
- }
587
-
588
- .tiny-remoter-modal-header h3 {
589
- margin: 0;
590
- font-size: 18px;
591
- font-weight: 600;
592
- color: #333;
593
- }
594
-
595
- .tiny-remoter-modal-close {
596
- background: none;
597
- border: none;
598
- font-size: 24px;
599
- cursor: pointer;
600
- color: #999;
601
- padding: 0;
602
- width: 32px;
603
- height: 32px;
604
- border-radius: 50%;
605
- display: flex;
606
- align-items: center;
607
- justify-content: center;
608
- transition: all 0.2s ease;
609
- }
610
-
611
- .tiny-remoter-modal-close:hover {
612
- background: #f5f5f5;
613
- color: #666;
614
- }
615
-
616
- .tiny-remoter-modal-body {
617
- padding: 24px;
618
- }
619
-
620
- /* 二维码弹窗动画 */
621
- @keyframes rotate {
622
- from {
623
- transform: rotate(0deg);
624
- }
625
- to {
626
- transform: rotate(360deg);
627
- }
628
- }
629
-
630
- /* 响应式设计 */
631
- @media (max-width: 768px) {
632
- .tiny-remoter-floating-block {
633
- bottom: 20px;
634
- right: 20px;
635
- width: 56px;
636
- height: 56px;
637
- }
638
-
639
- .tiny-remoter-floating-dropdown {
640
- bottom: 90px;
641
- right: 20px;
642
- min-width: 180px;
643
- }
644
-
645
- .tiny-remoter-modal-content {
646
- width: 95%;
647
- margin: 20px;
648
- }
649
- }
650
-
651
- /* 复制反馈提示样式 */
652
- .tiny-remoter-copy-feedback {
653
- position: fixed;
654
- top: 50%;
655
- left: 50%;
656
- transform: translate(-50%, -50%);
657
- background: rgba(0, 0, 0, 0.8);
658
- color: white;
659
- padding: 12px 24px;
660
- border-radius: 8px;
661
- font-size: 14px;
662
- font-weight: 500;
663
- z-index: 10000;
664
- opacity: 0;
665
- visibility: hidden;
666
- transition: all 0.3s ease;
667
- backdrop-filter: blur(4px);
668
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
669
- }
670
-
671
- .tiny-remoter-copy-feedback.show {
672
- opacity: 1;
673
- visibility: visible;
674
- transform: translate(-50%, -50%) scale(1);
675
- }
676
-
677
- .tiny-remoter-copy-feedback.success {
678
- background: rgba(34, 197, 94, 0.9);
679
- }
680
-
681
- .tiny-remoter-copy-feedback.error {
682
- background: rgba(239, 68, 68, 0.9);
683
- }
684
-
685
- /* 深色主题支持 */
686
- @media (prefers-color-scheme: dark) {
687
- .tiny-remoter-floating-dropdown {
688
- background: #1a1a1a;
689
- color: white;
690
- }
691
-
692
- .tiny-remoter-dropdown-item {
693
- color: white;
694
- }
695
-
696
- .tiny-remoter-dropdown-item:hover {
697
- background: #2a2a2a;
698
- }
699
-
700
- .tiny-remoter-dropdown-item__icon {
701
- background: #2a2a2a;
702
- }
703
-
704
- .tiny-remoter-copy-icon {
705
- background: #2a2a2a;
706
- color: #ccc;
707
- }
708
-
709
- .tiny-remoter-copy-icon:hover {
710
- background: #3a3a3a;
711
- color: white;
712
- }
713
-
714
- .tiny-remoter-modal-content {
715
- background: #1a1a1a;
716
- color: white;
717
- }
718
-
719
- .tiny-remoter-modal-header {
720
- border-bottom-color: #333;
721
- }
722
-
723
- .tiny-remoter-modal-header h3 {
724
- color: white;
725
- }
726
- }
727
- `;
728
- document.head.appendChild(style);
729
- }
730
- // 销毁组件
731
- destroy() {
732
- if (this.floatingBlock.parentNode) {
733
- this.floatingBlock.parentNode.removeChild(this.floatingBlock);
734
- }
735
- if (this.dropdownMenu.parentNode) {
736
- this.dropdownMenu.parentNode.removeChild(this.dropdownMenu);
737
- }
738
- }
739
- }
740
- // 导出组件
741
- export const createRemoter = (options = {}) => {
742
- return new FloatingBlock(options);
743
- };