diff --git a/style.css b/style.css index ba88702..af3a368 100644 --- a/style.css +++ b/style.css @@ -1438,6 +1438,101 @@ flex-wrap: wrap; } +/* ==================== Memory Popup (Mobile) ==================== */ + +.bme-memory-popup-scrim { + position: fixed; + inset: 0; + z-index: 999; + background: rgba(0, 0, 0, 0.55); + backdrop-filter: blur(2px); + -webkit-backdrop-filter: blur(2px); + cursor: pointer; +} + +.bme-memory-popup-scrim[hidden] { + display: none !important; +} + +.bme-memory-popup { + display: none; + position: fixed; + left: 50%; + top: 50%; + transform: translate(-50%, -50%) scale(0.92); + width: min(460px, calc(100vw - 24px)); + max-height: min(82vh, 680px); + background: var(--bme-surface, #131316); + border: 1px solid var(--bme-border); + border-radius: 14px; + box-shadow: 0 12px 48px rgba(0, 0, 0, 0.65); + z-index: 1000; + overflow-y: auto; + padding: 18px; + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: transform 0.18s ease, opacity 0.18s ease, visibility 0.18s ease; +} + +.bme-memory-popup.open { + display: block; + transform: translate(-50%, -50%) scale(1); + opacity: 1; + visibility: visible; + pointer-events: auto; +} + +.bme-memory-popup__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 10px; +} + +.bme-memory-popup__title { + font-size: 16px; + font-weight: 700; + color: var(--bme-on-surface); + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bme-memory-popup__actions { + display: flex; + align-items: center; + gap: 2px; + flex-shrink: 0; +} + +.bme-memory-popup__badges { + display: flex; + gap: 6px; + flex-wrap: wrap; + margin-bottom: 12px; +} + +.bme-memory-popup__body { + font-size: 12px; + color: var(--bme-on-surface); +} + +.bme-memory-popup::-webkit-scrollbar { + width: 4px; +} + +.bme-memory-popup::-webkit-scrollbar-track { + background: transparent; +} + +.bme-memory-popup::-webkit-scrollbar-thumb { + background: var(--bme-surface-highest); + border-radius: 2px; +} + /* ==================== Injection Preview ==================== */ .bme-injection-token-bar { @@ -7063,11 +7158,11 @@ width: 100%; max-width: none; border-right: none; - border-bottom: 1px solid var(--bme-border); - max-height: 40vh; + border-bottom: none; + max-height: none; } .bme-memory-detail-panel { - padding: 14px; + display: none; } .bme-batch-stages { flex-wrap: wrap; diff --git a/ui/panel.html b/ui/panel.html index 8b99843..04c0d07 100644 --- a/ui/panel.html +++ b/ui/panel.html @@ -2986,6 +2986,26 @@
+ + +
+
+

节点详情

+
+ + + +
+
+
+
+
diff --git a/ui/panel.js b/ui/panel.js index 10f2e57..26cbdb9 100644 --- a/ui/panel.js +++ b/ui/panel.js @@ -932,6 +932,7 @@ export async function initPanel({ _bindTabs(); _bindClose(); _bindNodeDetailPanel(); + _bindMemoryPopup(); _bindResizeHandle(); _bindPanelResize(); _bindGraphControls(); @@ -1186,6 +1187,7 @@ export function openPanel() { export function closePanel() { if (!overlayEl) return; overlayEl.classList.remove("active"); + _closeMemoryPopup(); _clearScheduledVisibleGraphRefresh(); lastVisibleGraphRefreshToken = ""; } @@ -1246,6 +1248,7 @@ function _switchTab(tabId) { } currentTabId = next; _closeNodeDetailUi(); + _closeMemoryPopup(); panelEl?.querySelectorAll(".bme-tab-btn").forEach((btn) => { btn.classList.toggle("active", btn.dataset.tab === currentTabId); }); @@ -1352,6 +1355,7 @@ function _bindTaskNavigation() { function _switchTaskSection(sectionId) { currentTaskSectionId = sectionId || "pipeline"; + _closeMemoryPopup(); _syncTaskSectionState(); _refreshTaskMonitor(); } @@ -1758,7 +1762,12 @@ function _bindTaskMemoryListClick() { currentSelectedMemoryNodeId = item.dataset.nodeId || ""; list.querySelectorAll(".bme-memory-node-item").forEach((n) => n.classList.toggle("selected", n.dataset.nodeId === currentSelectedMemoryNodeId)); const graph = _getGraph?.(); - _renderTaskMemoryDetailSelection(graph); + if (_isMobile()) { + const node = (graph?.nodes || []).find((c) => c.id === currentSelectedMemoryNodeId) || null; + if (node) _openMemoryPopup(node, graph); + } else { + _renderTaskMemoryDetailSelection(graph); + } }); } @@ -1832,20 +1841,31 @@ function _renderTaskMemoryDetailPanel(detailEl, node, graph) { } function _saveTaskMemoryDetail() { - const detailEl = document.getElementById("bme-task-memory-detail"); - const bodyEl = detailEl?.querySelector("#bme-task-memory-editor-body"); + const popupBody = document.getElementById("bme-memory-popup-body"); + const popupOpen = document.getElementById("bme-memory-popup")?.classList.contains("open"); + const detailEl = popupOpen ? null : document.getElementById("bme-task-memory-detail"); + const bodyEl = popupOpen + ? popupBody + : detailEl?.querySelector("#bme-task-memory-editor-body"); const nodeId = currentSelectedMemoryNodeId; if (!nodeId || !bodyEl) return; - const collected = _collectNodeDetailEditorUpdates(bodyEl, { - idPrefix: "bme-task-detail", - }); + const idPrefix = popupOpen ? "bme-popup-detail" : "bme-task-detail"; + const collected = _collectNodeDetailEditorUpdates(bodyEl, { idPrefix }); if (!collected.ok) { toastr.error(collected.errorMessage || "保存失败", "ST-BME"); return; } - _persistNodeDetailEdits(nodeId, collected.updates); + _persistNodeDetailEdits(nodeId, collected.updates, { + afterSuccess: () => { + if (popupOpen) { + const graph = _getGraph?.(); + const refreshedNode = (graph?.nodes || []).find((n) => n.id === nodeId); + if (refreshedNode) _openMemoryPopup(refreshedNode, graph); + } + }, + }); } function _deleteTaskMemoryDetail() { @@ -1855,10 +1875,57 @@ function _deleteTaskMemoryDetail() { _deleteGraphNodeById(nodeId, { afterSuccess: () => { currentSelectedMemoryNodeId = ""; + _closeMemoryPopup(); }, }); } +function _openMemoryPopup(node, graph) { + const popup = document.getElementById("bme-memory-popup"); + const scrim = document.getElementById("bme-memory-popup-scrim"); + const titleEl = document.getElementById("bme-memory-popup-title"); + const badgesEl = document.getElementById("bme-memory-popup-badges"); + const bodyEl = document.getElementById("bme-memory-popup-body"); + if (!popup || !bodyEl) return; + + const displayName = getNodeDisplayName(node); + const scopeBadge = buildScopeBadgeText(node.scope); + const badges = [ + node.type ? `${_escHtml(_typeLabel(node.type))}` : "", + scopeBadge ? `${_escHtml(scopeBadge)}` : "", + node.archived ? 'ARCHIVED' : "", + ].filter(Boolean).join(""); + + if (titleEl) titleEl.textContent = displayName; + if (badgesEl) badgesEl.innerHTML = badges; + + bodyEl.replaceChildren( + _buildNodeDetailEditorFragment(node, { idPrefix: "bme-popup-detail" }), + ); + + scrim?.removeAttribute("hidden"); + popup.classList.add("open"); +} + +function _closeMemoryPopup() { + const popup = document.getElementById("bme-memory-popup"); + const scrim = document.getElementById("bme-memory-popup-scrim"); + popup?.classList.remove("open"); + scrim?.setAttribute("hidden", ""); +} + +function _bindMemoryPopup() { + const closeBtn = document.getElementById("bme-memory-popup-close"); + const scrim = document.getElementById("bme-memory-popup-scrim"); + const saveBtn = document.getElementById("bme-memory-popup-save"); + const deleteBtn = document.getElementById("bme-memory-popup-delete"); + + closeBtn?.addEventListener("click", () => _closeMemoryPopup()); + scrim?.addEventListener("click", () => _closeMemoryPopup()); + saveBtn?.addEventListener("click", () => _saveTaskMemoryDetail()); + deleteBtn?.addEventListener("click", () => _deleteTaskMemoryDetail()); +} + // ---------- Injection Preview ---------- function _refreshTaskInjectionPreview() {