From 4577be71ce2e4c9591d8e2231c70d3cd4e889463 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Thu, 18 Dec 2025 15:28:14 +0800 Subject: [PATCH] feat: Add notification system for core memory view with animations --- .../dashboard-css/14-graph-explorer.css | 133 +++++++++++++++--- .../dashboard-css/17-core-memory.css | 119 ++++++++++++++++ .../dashboard-js/views/core-memory.js | 48 +++++++ 3 files changed, 282 insertions(+), 18 deletions(-) diff --git a/ccw/src/templates/dashboard-css/14-graph-explorer.css b/ccw/src/templates/dashboard-css/14-graph-explorer.css index 929ddb4f..00e70d86 100644 --- a/ccw/src/templates/dashboard-css/14-graph-explorer.css +++ b/ccw/src/templates/dashboard-css/14-graph-explorer.css @@ -262,7 +262,6 @@ * ======================================== */ .node-details-panel { width: 320px; - display: none; flex-direction: column; background: hsl(var(--card)); border: 1px solid hsl(var(--border)); @@ -272,7 +271,11 @@ max-height: 100%; } -.node-details-panel.visible { +.node-details-panel.hidden { + display: none; +} + +.node-details-panel:not(.hidden) { display: flex; animation: slideInRight 0.3s ease; } @@ -1180,14 +1183,14 @@ } .graph-sidebar { - width: 240px; - min-width: 240px; + width: 280px; + min-width: 280px; flex-shrink: 0; display: flex; flex-direction: column; gap: 0; overflow-y: auto; - padding: 0.5rem 1rem 0.5rem 0; + padding: 0.5rem 1.25rem 0.5rem 0; border-right: 1px solid hsl(var(--border)); margin-right: 1rem; } @@ -1210,22 +1213,22 @@ font-size: 0.75rem; font-weight: 600; color: hsl(var(--muted-foreground)); - margin: 0 0 0.75rem 0; + margin: 0 0 1rem 0; text-transform: uppercase; letter-spacing: 0.05em; } .graph-legend-section { border-top: 1px solid hsl(var(--border)); - padding-top: 1rem; - margin-top: 0.5rem; + padding-top: 1.5rem; + margin-top: 1.5rem; } /* Graph Legend */ .graph-legend { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.75rem; } .legend-title { @@ -1234,7 +1237,8 @@ color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.05em; - margin-bottom: 0.25rem; + margin-bottom: 0.5rem; + margin-top: 0.5rem; } .legend-dot { @@ -1334,13 +1338,13 @@ .filter-dropdowns { display: flex; flex-direction: column; - gap: 1rem; + gap: 1.5rem; } .filter-group { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.75rem; } .filter-group > label { @@ -1349,42 +1353,135 @@ color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.05em; + margin-bottom: 0.25rem; } .filter-checkbox { display: flex; align-items: center; - gap: 0.5rem; + gap: 0.625rem; + padding: 0.5rem 0; font-size: 0.8125rem; color: hsl(var(--foreground)); cursor: pointer; + transition: background 0.15s ease; + border-radius: 0.25rem; +} + +.filter-checkbox:hover { + background: hsl(var(--hover)); + padding-left: 0.375rem; + padding-right: 0.375rem; } .filter-checkbox input[type="checkbox"] { - width: 14px; - height: 14px; + width: 16px; + height: 16px; cursor: pointer; accent-color: hsl(var(--primary)); + flex-shrink: 0; +} + +.filter-checkbox span { + flex: 1; + user-select: none; +} + +/* Scope Filter */ +.scope-filter { + padding-bottom: 1rem; + border-bottom: 1px solid hsl(var(--border)); + margin-bottom: 0.5rem; +} + +.scope-selector { + display: flex; + flex-direction: column; + gap: 0.625rem; + margin-top: 0.5rem; +} + +.filter-radio { + display: flex; + align-items: center; + gap: 0.625rem; + padding: 0.5rem 0; + font-size: 0.8125rem; + color: hsl(var(--foreground)); + cursor: pointer; + transition: background 0.15s ease; + border-radius: 0.25rem; +} + +.filter-radio:hover { + background: hsl(var(--hover)); + padding-left: 0.375rem; + padding-right: 0.375rem; +} + +.filter-radio input[type="radio"] { + width: 16px; + height: 16px; + cursor: pointer; + accent-color: hsl(var(--primary)); + flex-shrink: 0; +} + +.filter-radio span { + flex: 1; + user-select: none; +} + +/* Filter Select Dropdown */ +.filter-select { + width: 100%; + padding: 0.625rem 0.75rem; + margin-top: 0.5rem; + font-size: 0.8125rem; + font-weight: 400; + color: hsl(var(--foreground)); + background: hsl(var(--background)); + border: 1px solid hsl(var(--border)); + border-radius: 0.375rem; + cursor: pointer; + transition: all 0.15s ease; + outline: none; +} + +.filter-select:hover { + background: hsl(var(--hover)); + border-color: hsl(var(--primary) / 0.3); +} + +.filter-select:focus { + border-color: hsl(var(--primary)); + box-shadow: 0 0 0 3px hsl(var(--primary) / 0.1); +} + +.filter-select option { + padding: 0.5rem; } /* Legend Items */ .legend-section { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.625rem; } .legend-section-title { font-size: 0.75rem; font-weight: 600; color: hsl(var(--muted-foreground)); - margin-bottom: 0.25rem; + margin-bottom: 0.375rem; + margin-top: 0.5rem; } .legend-item { display: flex; align-items: center; - gap: 0.5rem; + gap: 0.625rem; + padding: 0.375rem 0; font-size: 0.8125rem; color: hsl(var(--foreground)); } diff --git a/ccw/src/templates/dashboard-css/17-core-memory.css b/ccw/src/templates/dashboard-css/17-core-memory.css index a78a775b..183aae0d 100644 --- a/ccw/src/templates/dashboard-css/17-core-memory.css +++ b/ccw/src/templates/dashboard-css/17-core-memory.css @@ -2,6 +2,102 @@ Core Memory Styles ============================================ */ +/* Modal Base Styles */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + animation: fadeIn 0.2s ease-out; + backdrop-filter: blur(2px); +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.modal-content { + background: hsl(var(--card)); + border: 1px solid hsl(var(--border)); + border-radius: 12px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + max-height: 90vh; + display: flex; + flex-direction: column; + animation: slideUpModal 0.3s ease-out; + overflow: hidden; +} + +@keyframes slideUpModal { + from { + opacity: 0; + transform: translateY(20px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.25rem 1.5rem; + border-bottom: 1px solid hsl(var(--border)); +} + +.modal-header h2 { + font-size: 1.25rem; + font-weight: 600; + color: hsl(var(--foreground)); + margin: 0; +} + +.modal-close { + background: none; + border: none; + padding: 0.5rem; + cursor: pointer; + color: hsl(var(--muted-foreground)); + display: flex; + align-items: center; + justify-content: center; + border-radius: 6px; + transition: all 0.2s; +} + +.modal-close:hover { + background: hsl(var(--hover)); + color: hsl(var(--foreground)); +} + +.modal-close i { + width: 20px; + height: 20px; +} + +.modal-body { + flex: 1; + overflow-y: auto; + padding: 1.5rem; +} + +.modal-footer { + display: flex; + justify-content: flex-end; + gap: 0.75rem; + padding: 1.25rem 1.5rem; + border-top: 1px solid hsl(var(--border)); +} + .core-memory-container { padding: 1.5rem; } @@ -454,6 +550,29 @@ font-style: italic; } +/* Notification Animations */ +@keyframes slideInRight { + from { + opacity: 0; + transform: translateX(100px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slideOutRight { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(100px); + } +} + /* Dark Mode Adjustments */ [data-theme="dark"] .memory-card { background: #1e293b; diff --git a/ccw/src/templates/dashboard-js/views/core-memory.js b/ccw/src/templates/dashboard-js/views/core-memory.js index aa940b9d..bbe466fd 100644 --- a/ccw/src/templates/dashboard-js/views/core-memory.js +++ b/ccw/src/templates/dashboard-js/views/core-memory.js @@ -1,6 +1,54 @@ // Core Memory View // Manages strategic context entries with knowledge graph and evolution tracking +// Notification function +function showNotification(message, type = 'info') { + // Create notification container if it doesn't exist + let container = document.getElementById('notificationContainer'); + if (!container) { + container = document.createElement('div'); + container.id = 'notificationContainer'; + container.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px;'; + document.body.appendChild(container); + } + + // Create notification element + const notification = document.createElement('div'); + const bgColors = { + success: 'hsl(var(--success))', + error: 'hsl(var(--destructive))', + warning: 'hsl(var(--warning))', + info: 'hsl(var(--info))' + }; + + notification.style.cssText = ` + background: ${bgColors[type] || bgColors.info}; + color: white; + padding: 12px 20px; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + max-width: 350px; + animation: slideInRight 0.3s ease-out; + font-size: 14px; + line-height: 1.5; + `; + notification.textContent = message; + + // Add to container + container.appendChild(notification); + + // Auto remove after 3 seconds + setTimeout(() => { + notification.style.animation = 'slideOutRight 0.3s ease-out'; + setTimeout(() => { + container.removeChild(notification); + if (container.children.length === 0) { + document.body.removeChild(container); + } + }, 300); + }, 3000); +} + // State for visualization (prefixed to avoid collision with memory.js) var coreMemGraphSvg = null; var coreMemGraphGroup = null;