From bd678e75bfc221674de1a33ab0b01fb6742456ec Mon Sep 17 00:00:00 2001 From: fofolee Date: Mon, 20 Jan 2025 10:50:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80showSystemSelectList=E5=92=8C?= =?UTF-8?q?showSelect=E7=9A=84=E5=8F=82=E6=95=B0=EF=BC=8C=E7=BC=96?= =?UTF-8?q?=E6=8E=92=E7=94=A8=E6=88=B7=E4=BA=A4=E4=BA=92=E5=88=86=E7=B1=BB?= =?UTF-8?q?=E7=9A=84=E9=80=89=E6=8B=A9=E5=88=97=E8=A1=A8=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=BC=B9=E7=AA=97=E7=9A=84=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/lib/dialog/controller.js | 36 +- plugin/lib/dialog/service.js | 21 +- plugin/lib/dialog/style.css | 461 ++++++++++++++++++ plugin/lib/dialog/view.html | 449 +---------------- .../composer/ui/SelectListEditor.vue | 196 ++++---- .../monaco/types/quickcommand.api.d.ts | 28 +- 6 files changed, 631 insertions(+), 560 deletions(-) create mode 100644 plugin/lib/dialog/style.css diff --git a/plugin/lib/dialog/controller.js b/plugin/lib/dialog/controller.js index d834cfa..d753bab 100644 --- a/plugin/lib/dialog/controller.js +++ b/plugin/lib/dialog/controller.js @@ -111,6 +111,14 @@ document.addEventListener("DOMContentLoaded", () => { let hoverTimeout = null; let isKeyboardNavigation = false; + if (!config.enableSearch) { + filterInput.style.display = "none"; + } + + if (config.placeholder) { + filterInput.placeholder = config.placeholder; + } + // 创建选项 const createSelectItem = (item, index) => { const div = document.createElement("div"); @@ -129,7 +137,7 @@ document.addEventListener("DOMContentLoaded", () => { ipcRenderer.sendTo(parentId, "dialog-result", result); }; - // 鼠标移入事件(带防抖) + // 鼠标移入事件 div.onmouseenter = () => { if (isKeyboardNavigation) return; if (hoverTimeout) { @@ -141,7 +149,7 @@ document.addEventListener("DOMContentLoaded", () => { } div.classList.add("selected"); currentSelected = div; - }, 50); + }, 0); }; // 鼠标移动事件 @@ -243,15 +251,17 @@ document.addEventListener("DOMContentLoaded", () => { updateList(); // 添加筛选功能 - let filterTimeout = null; - filterInput.addEventListener("input", (e) => { - if (filterTimeout) { - clearTimeout(filterTimeout); - } - filterTimeout = setTimeout(() => { - updateList(e.target.value); - }, 100); - }); + if (config.enableSearch) { + let filterTimeout = null; + filterInput.addEventListener("input", (e) => { + if (filterTimeout) { + clearTimeout(filterTimeout); + } + filterTimeout = setTimeout(() => { + updateList(e.target.value); + }, 100); + }); + } // 添加键盘导航 const keydownHandler = (e) => { @@ -307,7 +317,9 @@ document.addEventListener("DOMContentLoaded", () => { document.addEventListener("keydown", keydownHandler); // 聚焦筛选框 - filterInput.focus(); + if (config.enableSearch) { + filterInput.focus(); + } break; } ipcRenderer.sendTo(parentId, "dialog-ready", calculateHeight()); diff --git a/plugin/lib/dialog/service.js b/plugin/lib/dialog/service.js index d45a8db..2502564 100644 --- a/plugin/lib/dialog/service.js +++ b/plugin/lib/dialog/service.js @@ -21,6 +21,7 @@ const createDialog = (config) => { skipTaskbar: true, alwaysOnTop: true, frame: false, + opacity: 0, webPreferences: { preload: preloadPath, }, @@ -49,6 +50,7 @@ const createDialog = (config) => { }; // 设置新的位置和大小 UBrowser.setBounds(newBounds); + UBrowser.setOpacity(1); ipcRenderer.removeListener("dialog-ready", dialogReadyHandler); }; ipcRenderer.on("dialog-ready", dialogReadyHandler); @@ -159,18 +161,25 @@ const showSystemTextArea = async (placeholder = "请输入", defaultText = "") = * @param {Array} items - 选项列表 * @param {object} [options] - 配置选项 * @param {string} [options.title] - 对话框标题 + * @param {string} [options.placeholder] - 输入框占位符 + * @param {boolean} [options.enableSearch] - 是否启用搜索 * @returns {Promise<{id: number, text: string, data: any}>} 选择的结果 */ const showSystemSelectList = async (items, options = {}) => { - const defaultOptions = { - title: "", - }; - const finalOptions = { ...defaultOptions, ...options }; + const { + title = "请选择", + placeholder = "", + enableSearch = true, + optionType = "plaintext", + } = options; return await createDialog({ type: "select", - title: finalOptions.title, - items: items, + title, + placeholder, + enableSearch, + items, + optionType, }); }; diff --git a/plugin/lib/dialog/style.css b/plugin/lib/dialog/style.css new file mode 100644 index 0000000..7747ca0 --- /dev/null +++ b/plugin/lib/dialog/style.css @@ -0,0 +1,461 @@ + :root { + --bg-color: #fff; + --text-color: #333; + --border-color: #ddd; + --title-bg: #f5f5f5; + --input-bg: #fff; + --input-border: #ddd; + --input-focus: #0d6efd; + --button-bg: #0d6efd; + --button-hover: #0b5ed7; + --button-text: #fff; + --cancel-bg: #6c757d; + --cancel-border: #6c757d; + } + + :root[data-theme="dark"] { + --bg-color: #282727; + --text-color: #e0e0e0; + --border-color: #404040; + --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; + } + + body { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", Arial, sans-serif; + background: var(--bg-color); + color: var(--text-color); + user-select: none; + height: 100vh; + display: flex; + flex-direction: column; + overflow: hidden; + } + + /* 自定义滚动条样式 */ + ::-webkit-scrollbar { + width: 4px; + height: 4px; + } + + ::-webkit-scrollbar-track { + background: transparent; + } + + ::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0); + transition: background-color 0.3s; + } + + :root[data-theme="dark"] ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0); + } + + /* 悬浮时显示滚动条 */ + *:hover::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.3); + transition: background-color 0.3s; + } + + :root[data-theme="dark"] *:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } + + /* 标题栏样式 */ + .title-bar { + background: var(--title-bg); + border-bottom: 1px solid var(--border-color); + padding: 4px 12px; + -webkit-app-region: drag; + display: flex; + align-items: center; + flex-shrink: 0; + } + + .title-left { + flex: 1; + display: flex; + align-items: center; + } + + .logo { + width: 20px; + height: 20px; + margin-right: 6px; + } + + .title-text { + font-size: 13px; + font-weight: 500; + color: var(--text-color); + margin: 0; + } + + .close-btn { + -webkit-app-region: no-drag; + background-color: rgba(0, 0, 0, 0.05); + width: 16px; + height: 16px; + min-width: 16px; + min-height: 16px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + cursor: pointer; + opacity: 0.8; + transition: all 0.2s; + margin-left: 8px; + position: relative; + } + + :root[data-theme="dark"] .close-btn { + background-color: rgba(255, 255, 255, 0.1); + } + + .close-btn:hover { + opacity: 1; + background-color: #ff4d4d; + } + + .close-btn::before, + .close-btn::after { + content: ""; + position: absolute; + width: 8px; + height: 1px; + background-color: var(--text-color); + transform-origin: center; + } + + .close-btn::before { + transform: rotate(45deg); + } + + .close-btn::after { + transform: rotate(-45deg); + } + + .close-btn:hover::before, + .close-btn:hover::after { + background-color: #fff; + } + + .container { + display: flex; + flex-direction: column; + height: 100vh; + } + + .content-wrapper { + padding: 16px; + min-height: 60px; + max-height: 449px; + overflow-y: auto; + overflow-x: hidden; + flex: 1; + } + + /* 选择列表对话框的内容区域padding和高度 */ + .dialog-select .content-wrapper { + padding: 16px 8px; + max-height: 600px; + } + + #content { + line-height: 1.4; + font-size: 13px; + user-select: text; + } + + .button-bar { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 0 16px 16px; + flex-shrink: 0; + background: var(--bg-color); + } + + button { + padding: 4px 12px; + border-radius: 4px; + border: 1px solid var(--button-bg); + background: linear-gradient(180deg, + rgba(255, 255, 255, 0.08) 0%, + rgba(0, 0, 0, 0.05) 100%), + var(--button-bg); + color: var(--button-text); + cursor: pointer; + font-size: 13px; + min-width: 70px; + transition: all 0.2s ease; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08); + } + + button:hover { + background: linear-gradient(180deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(0, 0, 0, 0.05) 100%), + var(--button-hover); + } + + button:active { + background: linear-gradient(180deg, + rgba(0, 0, 0, 0.05) 0%, + rgba(255, 255, 255, 0.08) 100%), + var(--button-bg); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + } + + #ok-btn { + padding: 0 12px; + height: 20px; + } + + #cancel-btn { + padding: 0 12px; + background: linear-gradient(180deg, + rgba(255, 255, 255, 0.08) 0%, + rgba(0, 0, 0, 0.05) 100%), + var(--cancel-bg); + border: 1px solid var(--cancel-border); + height: 20px; + } + + #cancel-btn:hover { + background: linear-gradient(180deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(0, 0, 0, 0.05) 100%), + var(--cancel-bg); + } + + #input-container { + display: flex; + flex-direction: column; + gap: 8px; + } + + .input-group label { + display: block; + padding: 0 0 4px 2px; + color: var(--text-color); + font-size: 13px; + } + + .input-group input { + width: 100%; + padding: 6px 8px; + border: 1px solid var(--input-border); + border-radius: 4px; + font-size: 13px; + box-sizing: border-box; + background: var(--input-bg); + color: var(--text-color); + } + + .input-group input:focus { + border-color: var(--input-focus); + outline: none; + box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25); + } + + /* 文本区域样式 */ + textarea { + width: 100%; + height: 400px; + padding: 6px 8px; + border: 1px solid var(--input-border); + border-radius: 4px; + font-size: 13px; + resize: none; + box-sizing: border-box; + background: var(--input-bg); + color: var(--text-color); + } + + textarea:focus { + border-color: var(--input-focus); + outline: none; + box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25); + } + + /* 按钮组样式 */ + #button-container { + display: flex; + flex-direction: column; + gap: 10px; + padding-top: 4px; + } + + #button-container button { + width: 100%; + text-align: center; + padding: 6px 12px; + } + + /* 根据对话框类型显示/隐藏取消按钮 */ + .dialog-message #cancel-btn { + display: none; + } + + .dialog-buttons .button-bar { + display: none; + } + + /* 隐藏所有对话框内容 */ + #input, + #confirm, + #buttons, + #textarea, + #select { + display: none; + } + + /* 选择列表样式 */ + .select-list { + display: flex; + flex-direction: column; + gap: 4px; + max-height: 505px; + overflow-y: auto; + } + + .filter-input { + padding: 0 2px 8px 2px; + } + + .filter-input input { + width: 100%; + padding: 6px 8px; + border: 1px solid var(--input-border); + border-radius: 4px; + font-size: 13px; + box-sizing: border-box; + background: var(--input-bg); + color: var(--text-color); + } + + .filter-input input:focus { + border-color: var(--input-focus); + outline: none; + box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25); + } + + .select-list-container { + display: flex; + flex-direction: column; + gap: 4px; + max-height: 360px; + overflow-y: auto; + } + + .select-item { + display: flex; + align-items: center; + padding: 6px 8px; + border-radius: 8px; + cursor: pointer; + position: relative; + transform: translateY(0) scale(1); + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + will-change: transform; + } + + .select-item.selected { + background-color: rgba(13, 110, 253, 0.1); + position: relative; + transform: translateY(-1px) scale(0.995); + will-change: transform; + } + + .select-item-icon { + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + will-change: transform; + padding-right: 8px; + } + + .select-item.selected .select-item-icon { + transform: scale(1.05); + filter: brightness(1.05); + } + + :root[data-theme="dark"] .select-list:not(.keyboard-nav) .select-item:hover { + background-color: rgba(13, 110, 253, 0.2); + } + + :root[data-theme="dark"] .select-item.selected { + background-color: rgba(13, 110, 253, 0.2); + } + + /* 添加选择时的轻微阴影效果 */ + .select-item.selected, + .select-list:not(.keyboard-nav) .select-item:hover { + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02); + } + + :root[data-theme="dark"] .select-item.selected, + :root[data-theme="dark"] .select-list:not(.keyboard-nav) .select-item:hover { + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + } + + .select-item-icon { + width: 34px; + height: 34px; + margin-right: 8px; + border-radius: 4px; + overflow: hidden; + } + + .select-item-icon img { + width: 100%; + height: 100%; + object-fit: cover; + } + + .select-item-content { + flex: 1; + min-width: 0; + } + + .select-item-title { + font-size: 13px; + line-height: 1.4; + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .select-item-description { + font-size: 12px; + color: rgba(0, 0, 0, 0.6); + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + :root[data-theme="dark"] .select-item-description { + color: rgba(255, 255, 255, 0.6); + } + + /* 搜索结果高亮样式 */ + .highlight { + color: #ec3535; + } + + /* 隐藏确定和取消按钮 */ + .dialog-select .button-bar { + display: none; + } diff --git a/plugin/lib/dialog/view.html b/plugin/lib/dialog/view.html index 396039b..b0f4904 100644 --- a/plugin/lib/dialog/view.html +++ b/plugin/lib/dialog/view.html @@ -3,454 +3,7 @@ 对话框 - +
diff --git a/src/components/composer/ui/SelectListEditor.vue b/src/components/composer/ui/SelectListEditor.vue index 85e707a..861df43 100644 --- a/src/components/composer/ui/SelectListEditor.vue +++ b/src/components/composer/ui/SelectListEditor.vue @@ -1,17 +1,20 @@
+
+ +
+ +
+ +
+ + + + + +
+
+