diff --git a/plugin/lib/dialog/controller.js b/plugin/lib/dialog/controller.js index d753bab..f5e9fb2 100644 --- a/plugin/lib/dialog/controller.js +++ b/plugin/lib/dialog/controller.js @@ -321,6 +321,39 @@ document.addEventListener("DOMContentLoaded", () => { filterInput.focus(); } break; + + case "wait-button": + document.getElementById("wait-button").style.display = "block"; + document.body.classList.add("dialog-wait-button"); + + // 创建按钮组 + const waitButtonContainer = document.getElementById("wait-button"); + const buttonGroup = document.createElement("div"); + buttonGroup.className = "wait-button-group"; + + // 创建主按钮 + const waitBtn = document.createElement("button"); + waitBtn.id = "wait-btn"; + waitBtn.textContent = config.text; + waitBtn.onclick = () => { + ipcRenderer.sendTo(parentId, "dialog-result", true); + }; + + buttonGroup.appendChild(waitBtn); + + // 如果需要显示取消按钮 + if (config.showCancel) { + const cancelBtn = document.createElement("button"); + cancelBtn.id = "wait-cancel-btn"; + cancelBtn.innerHTML = "✕"; // 使用 × 符号 + cancelBtn.onclick = () => { + ipcRenderer.sendTo(parentId, "dialog-result", false); + }; + buttonGroup.appendChild(cancelBtn); + } + + waitButtonContainer.appendChild(buttonGroup); + break; } ipcRenderer.sendTo(parentId, "dialog-ready", calculateHeight()); }); diff --git a/plugin/lib/dialog/service.js b/plugin/lib/dialog/service.js index 2502564..06b064e 100644 --- a/plugin/lib/dialog/service.js +++ b/plugin/lib/dialog/service.js @@ -3,9 +3,10 @@ const { createBrowserWindow } = utools; /** * 创建对话框窗口 * @param {object} config - 对话框配置 + * @param {object} [customOptions] - 自定义窗口选项 * @returns {Promise} 返回对话框结果 */ -const createDialog = (config) => { +const createDialog = (config, customOptions = {}) => { return new Promise((resolve) => { const dialogPath = "lib/dialog/view.html"; const preloadPath = "lib/dialog/controller.js"; @@ -24,7 +25,9 @@ const createDialog = (config) => { opacity: 0, webPreferences: { preload: preloadPath, + devTools: utools.isDev(), }, + ...customOptions, // 合并自定义选项 }; // 创建窗口 @@ -53,9 +56,12 @@ const createDialog = (config) => { UBrowser.setOpacity(1); ipcRenderer.removeListener("dialog-ready", dialogReadyHandler); }; - ipcRenderer.on("dialog-ready", dialogReadyHandler); - // 添加监听器 + // 监听子窗口返回的计算高度, 等待按钮有自己的计算逻辑 + config.type !== "wait-button" && + ipcRenderer.on("dialog-ready", dialogReadyHandler); + + // 监听子窗口返回的返回值 ipcRenderer.on("dialog-result", dialogResultHandler); // 发送配置到子窗口 @@ -183,6 +189,81 @@ const showSystemSelectList = async (items, options = {}) => { }); }; +/** + * 显示一个系统级等待按钮 + * @param {object} options - 配置选项 + * @param {string} [options.text="等待操作"] - 按钮文本 + * @param {string} [options.position="bottom-right"] - 按钮位置,可选值:top-left, top-right, bottom-left, bottom-right + * @param {boolean} [options.showCancel=false] - 是否显示取消按钮 + * @returns {Promise} 点击确定返回true,点击取消返回false + */ +const showSystemWaitButton = async (options = {}) => { + const { + text = "等待操作", + position = "bottom-right", + showCancel = true, + } = options; + + // 创建临时span计算文本宽度 + const span = document.createElement("span"); + span.style.font = + '14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'; + span.style.visibility = "hidden"; + span.style.position = "absolute"; + span.textContent = text; + document.body.appendChild(span); + + // 计算窗口尺寸 + const textWidth = span.offsetWidth; + document.body.removeChild(span); + + const dialogOptions = { + width: Math.max(textWidth + 32 + (showCancel ? 25 : 0), 80), // 文本宽度 + padding + 取消按钮宽度(如果有) + height: 36, + opacity: 1, + }; + + // 获取主屏幕尺寸 + const primaryDisplay = utools.getPrimaryDisplay(); + const { width, height } = primaryDisplay.workAreaSize; + + // 根据position计算窗口位置 + const padding = 20; + let x, y; + + switch (position) { + case "top-left": + x = padding; + y = padding; + break; + case "top-right": + x = width - dialogOptions.width - padding; + y = padding; + break; + case "bottom-left": + x = padding; + y = height - dialogOptions.height - padding; + break; + case "bottom-right": + default: + x = width - dialogOptions.width - padding; + y = height - dialogOptions.height - padding; + break; + } + + dialogOptions.x = x; + dialogOptions.y = y; + + return await createDialog( + { + type: "wait-button", + text, + showCancel, + }, + dialogOptions + ); +}; + module.exports = { showSystemMessageBox, showSystemInputBox, @@ -190,4 +271,5 @@ module.exports = { showSystemButtonBox, showSystemTextArea, showSystemSelectList, + showSystemWaitButton, }; diff --git a/plugin/lib/dialog/style.css b/plugin/lib/dialog/style.css index 7747ca0..406dffa 100644 --- a/plugin/lib/dialog/style.css +++ b/plugin/lib/dialog/style.css @@ -20,10 +20,6 @@ --title-bg: #2d2d2d; --input-bg: #2d2d2d; --input-border: #404040; - --input-focus: #0d6efd; - --button-bg: #0d6efd; - --button-hover: #0b5ed7; - --button-text: #fff; --cancel-bg: #4a4a4a; --cancel-border: #4a4a4a; } @@ -459,3 +455,57 @@ .dialog-select .button-bar { display: none; } + + .dialog-wait-button .title-bar, + .dialog-wait-button .button-bar { + display: none; + } + + .dialog-wait-button .content-wrapper { + padding: 0; + } + + /* 按钮容器和按钮样式 */ + #wait-button { + display: none; + position: absolute; + inset: 0; + } + + .wait-button-group { + display: flex; + height: 100%; + border: none; + background: none; + } + + #wait-btn, + #wait-cancel-btn { + height: 100%; + border-radius: 0; + cursor: pointer; + color: white; + } + + #wait-btn:hover, + #wait-cancel-btn:hover { + filter: brightness(1.1); + } + + #wait-btn { + width: 100%; + background: var(--button-bg); + font-size: 14px; + white-space: nowrap; + } + + #wait-cancel-btn { + width: 25px; + min-width: 25px; + font-size: 18px; + padding: 0; + } + + #wait-cancel-btn:hover { + background-color: #ec3535; + } diff --git a/plugin/lib/dialog/view.html b/plugin/lib/dialog/view.html index b0f4904..2f28cd9 100644 --- a/plugin/lib/dialog/view.html +++ b/plugin/lib/dialog/view.html @@ -48,6 +48,9 @@
+ + +
diff --git a/src/js/composer/commands/uiCommands.js b/src/js/composer/commands/uiCommands.js index 2ccc956..e2d227b 100644 --- a/src/js/composer/commands/uiCommands.js +++ b/src/js/composer/commands/uiCommands.js @@ -331,6 +331,44 @@ export const uiCommands = { }, ], }, + { + value: "quickcommand.showSystemWaitButton", + label: "等待操作按钮", + isAsync: true, + config: [ + { + component: "OptionEditor", + options: { + text: { + label: "按钮文本", + component: "VariableInput", + width: 6, + }, + position: { + label: "按钮位置", + component: "QSelect", + width: 3, + options: [ + { label: "屏幕左上角", value: "top-left" }, + { label: "屏幕右上角", value: "top-right" }, + { label: "屏幕左下角", value: "bottom-left" }, + { label: "屏幕右下角", value: "bottom-right" }, + ], + }, + showCancel: { + label: "显示取消按钮", + component: "CheckButton", + width: 3, + }, + }, + defaultValue: { + text: newVarInputVal("str", "点击继续"), + position: "bottom-right", + showCancel: true, + }, + }, + ], + }, { value: "utools.showOpenDialog", label: "文件选择框", diff --git a/src/plugins/monaco/types/quickcommand.api.d.ts b/src/plugins/monaco/types/quickcommand.api.d.ts index 585020c..2b57b67 100644 --- a/src/plugins/monaco/types/quickcommand.api.d.ts +++ b/src/plugins/monaco/types/quickcommand.api.d.ts @@ -628,6 +628,27 @@ interface quickcommandApi { } ): Promise<{ id: number; text: string | object }>; + /** + * 显示一个系统级等待按钮 + * @param options 配置选项 + * @param options.text 按钮文本 + * @param options.position 按钮位置,可选值:top-left, top-right, bottom-left, bottom-right + * @param options.showCancel 是否显示取消按钮,默认 true + * + * ```js + * const result = await quickcommand.showSystemWaitButton({ + * text: "等待操作", + * position: "bottom-right", + * }) + * console.log(result) // true 或 false + * ``` + */ + showSystemWaitButton(options?: { + text?: string; + position?: "top-left" | "top-right" | "bottom-left" | "bottom-right"; + showCancel?: boolean; + }): Promise; + /** * 运行代码 * @param code 代码