--- name: 导出至 Eagle description: 将当前选中的元素或纯图片快速推送保存至 Eagle 灵感库。 author: ymjr version: 1.0.0 license: MIT usage: 选中画板元素后运行,弹出非模态悬浮窗(可拖拽标题栏移动),不影响画板操作。 features: - 悬浮非模态 UI 面板(支持自由拖拽) - 自动识别纯图片直传,混合元素渲染 SVG 上传 - 导出失败时智能提示检查 Eagle 软件与 API 状态 --- /* ```javascript */ var locales = { zh: { notice_select: "请先选中需要导出的连线或元素!", export_title: "🦅 导出至 Eagle", tags_label: "标签 (逗号分隔)", tags_ph: "例如: Obsidian, Excalidraw", btn_export: "确认导出", btn_exporting: "发送中...", settings_toggle: "⚙️ 接口设置", eagle_url: "Eagle 接口", eagle_token: "Eagle 令牌 (Token)", export_success: "✅ 成功发送到 Eagle!", export_fail: "❌ 导出失败!请检查:\n1. Eagle 软件是否已打开\n2. Token 与端口设置是否正确", file_not_found: "找不到图片源文件: {id}" }, en: { notice_select: "Please select elements to export first!", export_title: "🦅 Export to Eagle", tags_label: "Tags (Comma separated)", tags_ph: "e.g., Obsidian, Excalidraw", btn_export: "Confirm Export", btn_exporting: "Sending...", settings_toggle: "⚙️ API Settings", eagle_url: "Eagle URL", eagle_token: "Eagle Token", export_success: "✅ Successfully sent to Eagle!", export_fail: "❌ Export failed! Please check:\n1. Is Eagle running?\n2. Are URL/Token correct?", file_not_found: "Source file not found: {id}" } }; const path = require('path'); const selectedEls = ea.getViewSelectedElements(); if (selectedEls.length === 0) { new Notice(t("notice_select")); return; } await ea.addElementsToView(); const targetView = ea.targetView; const plugin = ea.plugin; const activeFile = app.workspace.getActiveFile(); const isAllImages = selectedEls.every(el => el.type === "image"); // SVG Base64 function embedFontsInSVG(svg, plugin) { if (!plugin.settings.exportSVGFont) return svg; const defs = svg.querySelector("defs") || document.createElement("defs"); if(!svg.querySelector("defs")) svg.prepend(defs); let fonts = ``; defs.innerHTML += fonts; return svg; } let base64SVG = ""; if (!isAllImages) { try { let svgNode = await targetView.svg(targetView.getScene(true), undefined, true); if (plugin.settings.exportSVGFont) svgNode = embedFontsInSVG(svgNode, plugin); base64SVG = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svgNode.outerHTML.replaceAll(" ", " "))))}`; } catch(e) { console.warn("SVG Generate Warn:", e); } } // 读取设置 let settings = ea.getScriptSettings() || {}; if (!settings["ymjr_eagle_config"]) { settings["ymjr_eagle_config"] = { "eagle url": "http://localhost:41595", "eagle token": "bcb88edd-23c6-434a-beb1-b7d891cf3613" }; ea.setScriptSettings(settings); } const currentConfig = Object.assign({}, settings["ymjr_eagle_config"]); // 清理旧 UI 并注入新 UI if (ExcalidrawAutomate.plugin._ymjr_eaglePanel) { ExcalidrawAutomate.plugin._ymjr_eaglePanel.remove(); } document.getElementById("ymjr-eagle-style")?.remove(); const styleEl = document.createElement("style"); styleEl.id = "ymjr-eagle-style"; styleEl.innerHTML = ` .ymjr-eagle-panel { position: fixed; bottom: 30px; right: 30px; z-index: 999999; background: var(--background-primary); border: 1px solid var(--background-modifier-border); border-radius: 12px; width: 340px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); display: flex; flex-direction: column; overflow: hidden; font-family: var(--font-interface); color: var(--text-normal); animation: slideInUp 0.3s cubic-bezier(0.16, 1, 0.3, 1); } .ymjr-header { padding: 14px 18px; font-weight: 600; font-size: 1.1em; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--background-modifier-border); background: var(--background-secondary-alt); cursor: grab; user-select: none; } .ymjr-header:active { cursor: grabbing; } .ymjr-close { cursor: pointer; opacity: 0.6; transition: 0.2s; font-size: 1.2em; border: none; background: transparent; color: inherit; padding: 0;} .ymjr-close:hover { opacity: 1; color: var(--text-error); } .ymjr-body { padding: 18px; display: flex; flex-direction: column; gap: 14px; } .ymjr-form-group { display: flex; flex-direction: column; gap: 6px; } .ymjr-form-group label { font-size: 0.85em; opacity: 0.8; font-weight: 500; } .ymjr-input { background: var(--background-modifier-form-field); border: 1px solid var(--background-modifier-border); border-radius: 6px; padding: 8px 10px; color: var(--text-normal); font-size: 0.95em; outline: none; } .ymjr-input:focus { border-color: var(--interactive-accent); box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2); } .ymjr-settings-toggle { font-size: 0.85em; cursor: pointer; opacity: 0.7; user-select: none; } .ymjr-settings-panel { background: var(--background-secondary); border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 10px; border: 1px solid var(--background-modifier-border); } .ymjr-btn-submit { background: var(--interactive-accent); color: var(--text-on-accent); border: none; border-radius: 8px; padding: 10px; font-weight: 600; font-size: 1em; cursor: pointer; transition: 0.2s; margin-top: 5px; } .ymjr-btn-submit:hover { opacity: 0.9; transform: translateY(-1px); } .ymjr-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; } @keyframes slideInUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } `; document.head.appendChild(styleEl); const panel = document.createElement("div"); panel.className = "ymjr-eagle-panel"; panel.innerHTML = `