From f8906ef62bc9afeb04d2a8a642a6083c9b8d0d8e Mon Sep 17 00:00:00 2001 From: Dhanji Prasanna Date: Fri, 7 Nov 2025 10:56:19 +1100 Subject: [PATCH] small style --- crates/g3-console/web/js/router.js | 62 +++++++++++-------- crates/g3-console/web/styles/app.css | 92 ++++++++++++++-------------- 2 files changed, 82 insertions(+), 72 deletions(-) diff --git a/crates/g3-console/web/js/router.js b/crates/g3-console/web/js/router.js index 8edb69b..66a52ff 100644 --- a/crates/g3-console/web/js/router.js +++ b/crates/g3-console/web/js/router.js @@ -84,8 +84,9 @@ const router = { this.renderInProgress = true; try { - console.log('[Router] Showing spinner'); - container.innerHTML = components.spinner('Loading instances...'); + // Check if we already have a container for instances + let instancesList = container.querySelector('.instances-list'); + const isInitialLoad = !instancesList; console.log('[Router] Fetching instances from API'); const instances = await api.getInstances(); @@ -97,23 +98,23 @@ const router = { return; } - // Check if we already have a container for instances - let instancesList = container.querySelector('.instances-list'); - const isInitialLoad = !instancesList; - - if (isInitialLoad) { - instancesList = document.createElement('div'); - instancesList.className = 'instances-list'; - } if (instances.length === 0) { console.log('[Router] No instances, showing empty state'); - container.innerHTML = components.emptyState( - 'No running instances. Click "+ New Run" to start one.' - ); + // Check if we already have empty state + if (!container.querySelector('.empty-state')) { + container.innerHTML = components.emptyState( + 'No running instances. Click "+ New Run" to start one.' + ); + } } else { console.log('[Router] Building HTML for', instances.length, 'instances'); + if (isInitialLoad) { + instancesList = document.createElement('div'); + instancesList.className = 'instances-list'; + } + // Build a map of existing panels for efficient lookup const existingPanels = new Map(); if (!isInitialLoad) { @@ -133,7 +134,7 @@ const router = { const existingPanel = existingPanels.get(instance.id); if (existingPanel) { - // Update existing panel in-place + // Update existing panel in-place by replacing inner content const tempDiv = document.createElement('div'); tempDiv.innerHTML = newHtml; const newPanel = tempDiv.firstElementChild; @@ -154,7 +155,10 @@ const router = { }); if (isInitialLoad) { - container.innerHTML = ''; + // Only clear if container doesn't already have instances-list + if (container.firstChild && container.firstChild !== instancesList) { + container.innerHTML = ''; + } container.appendChild(instancesList); } @@ -171,7 +175,12 @@ const router = { } } catch (error) { console.error('[Router] Error in renderHome:', error); - container.innerHTML = components.error('Failed to load instances: ' + error.message); + // Don't clear container on error, just show error message + if (!container.querySelector('.error-message')) { + const errorDiv = document.createElement('div'); + errorDiv.innerHTML = components.error('Failed to load instances: ' + error.message); + container.appendChild(errorDiv.firstElementChild); + } } finally { this.renderInProgress = false; console.log('[Router] renderHome complete, renderInProgress reset to false'); @@ -183,15 +192,11 @@ const router = { this.currentInstanceId = id; - // Check if we already have a detail view for this instance - let detailView = container.querySelector('.detail-view'); - const isInitialLoad = !detailView || detailView.getAttribute('data-instance-id') !== id; - - if (isInitialLoad) { - container.innerHTML = components.spinner('Loading instance details...'); - } - try { + // Check if we already have a detail view for this instance + let detailView = container.querySelector('.detail-view'); + const isInitialLoad = !detailView || detailView.getAttribute('data-instance-id') !== id; + const instance = await api.getInstance(id); const logs = await api.getInstanceLogs(id); @@ -306,7 +311,12 @@ const router = { } } catch (error) { console.error('[Router] Error in renderDetail:', error); - container.innerHTML = components.error('Failed to load instance: ' + error.message); + // Don't clear container on error, just show error message + if (!container.querySelector('.error-message')) { + const errorDiv = document.createElement('div'); + errorDiv.innerHTML = components.error('Failed to load instance: ' + error.message); + container.appendChild(errorDiv.firstElementChild); + } } }, @@ -406,7 +416,7 @@ const router = { // Re-apply syntax highlighting to any new code blocks detailView.querySelectorAll('pre code:not(.hljs)').forEach((block) => { hljs.highlightElement(block); - } + }); } }; diff --git a/crates/g3-console/web/styles/app.css b/crates/g3-console/web/styles/app.css index 1d8ce73..1fb8e3a 100644 --- a/crates/g3-console/web/styles/app.css +++ b/crates/g3-console/web/styles/app.css @@ -39,7 +39,7 @@ body { background-color: var(--bg-secondary); color: var(--text-primary); line-height: 1.6; - font-size: 75%; + font-size: 10.5px; /* 75% of 14px */ } /* Header */ @@ -59,7 +59,7 @@ body { } .header-title { - font-size: 1.5rem; + font-size: 0.9375rem; /* 75% of 1.25rem */ font-weight: 700; color: var(--text-primary); } @@ -73,7 +73,7 @@ body { .main-content { max-width: 1400px; margin: 0 auto; - padding: 2rem; + padding: 1.5rem; /* Reduced padding */ } /* Buttons */ @@ -126,7 +126,7 @@ body { .btn-sm { padding: 0.375rem 0.75rem; - font-size: 0.8125rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } /* Badges */ @@ -134,7 +134,7 @@ body { display: inline-block; padding: 0.25rem 0.75rem; border-radius: 9999px; - font-size: 0.75rem; + font-size: 0.5625rem; /* 75% of 0.75rem */ font-weight: 600; text-transform: uppercase; } @@ -163,14 +163,14 @@ body { .instances-list { display: flex; flex-direction: column; - gap: 1.5rem; + gap: 1rem; /* Reduced gap */ } .instance-panel { background-color: var(--bg-primary); border: 1px solid var(--border); border-radius: 0.75rem; - padding: 1.5rem; + padding: 1rem; /* Reduced padding */ box-shadow: 0 1px 3px var(--shadow); transition: all 0.2s; cursor: pointer; @@ -182,7 +182,7 @@ body { } .panel-header { - margin-bottom: 1rem; + margin-bottom: 0.75rem; /* Reduced margin */ } .panel-title { @@ -193,7 +193,7 @@ body { } .panel-title h3 { - font-size: 1.125rem; + font-size: 0.75rem; /* 75% of 1rem */ font-weight: 600; color: var(--text-primary); } @@ -205,14 +205,14 @@ body { } .meta-item { - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ color: var(--text-secondary); } /* Progress Bar */ .progress-bar { position: relative; - height: 2rem; + height: 1.5rem; /* 75% of 2rem */ background-color: var(--bg-tertiary); border-radius: 0.5rem; overflow: hidden; @@ -258,7 +258,7 @@ body { top: 50%; left: 50%; transform: translate(-50%, -50%); - font-size: 0.875rem; + font-size: 0.65625rem; /* 75% of 0.875rem */ font-weight: 600; color: var(--text-primary); } @@ -277,14 +277,14 @@ body { } .stat-label { - font-size: 0.75rem; + font-size: 0.515625rem; /* 75% of 0.6875rem */ color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; } .stat-value { - font-size: 1.5rem; + font-size: 0.9375rem; /* 75% of 1.25rem */ font-weight: 700; color: var(--text-primary); } @@ -293,7 +293,7 @@ body { padding: 0.75rem; background-color: var(--bg-secondary); border-radius: 0.5rem; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ color: var(--text-secondary); margin-bottom: 1rem; } @@ -351,7 +351,7 @@ body { } .modal-header h2 { - font-size: 1.25rem; + font-size: 0.84375rem; /* 75% of 1.125rem */ font-weight: 600; } @@ -387,7 +387,7 @@ body { .form-group label { display: block; margin-bottom: 0.5rem; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ font-weight: 500; color: var(--text-primary); } @@ -401,7 +401,7 @@ body { border-radius: 0.5rem; background-color: var(--bg-secondary); color: var(--text-primary); - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } .form-group input:focus, @@ -460,7 +460,7 @@ body { .radio-label small { display: block; color: var(--text-secondary); - font-size: 0.8125rem; + font-size: 0.5625rem; /* 75% of 0.75rem */ margin-top: 0.25rem; } @@ -474,8 +474,8 @@ body { } .spinner { - width: 3rem; - height: 3rem; + width: 2.25rem; /* 75% of 3rem */ + height: 2.25rem; /* 75% of 3rem */ border: 3px solid var(--border); border-top-color: var(--primary); border-radius: 50%; @@ -502,21 +502,21 @@ body { .detail-view { background-color: var(--bg-primary); border-radius: 0.75rem; - padding: 1.5rem; + padding: 1rem; /* Reduced padding */ } .detail-header { display: flex; align-items: center; gap: 1rem; - margin-bottom: 1.5rem; - padding-bottom: 1rem; + margin-bottom: 1rem; /* Reduced margin */ + padding-bottom: 0.75rem; /* Reduced padding */ border-bottom: 1px solid var(--border); } .detail-header h2 { flex: 1; - font-size: 1.5rem; + font-size: 0.9375rem; /* 75% of 1.25rem */ font-weight: 600; } @@ -524,7 +524,7 @@ body { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; - margin-bottom: 2rem; + margin-bottom: 1.5rem; /* Reduced margin */ } .stat-card { @@ -535,7 +535,7 @@ body { } .stat-card .stat-label { - font-size: 0.75rem; + font-size: 0.515625rem; /* 75% of 0.6875rem */ color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; @@ -543,23 +543,23 @@ body { } .stat-card .stat-value { - font-size: 2rem; + font-size: 1.125rem; /* 75% of 1.5rem */ font-weight: 700; color: var(--text-primary); } /* Detail content wrapper */ .detail-content { - margin-top: 2rem; + margin-top: 1.5rem; /* Reduced margin */ } /* Chat View */ .chat-view { - margin-top: 2rem; + margin-top: 1.5rem; /* Reduced margin */ } .chat-view h3 { - font-size: 1.25rem; + font-size: 0.84375rem; /* 75% of 1.125rem */ font-weight: 600; margin-bottom: 1rem; } @@ -588,7 +588,7 @@ body { } .message-agent { - font-size: 0.75rem; + font-size: 0.515625rem; /* 75% of 0.6875rem */ font-weight: 600; text-transform: uppercase; color: var(--text-secondary); @@ -609,7 +609,7 @@ body { .message-content code { font-family: 'Monaco', 'Courier New', monospace; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } /* Tool Call */ @@ -635,7 +635,7 @@ body { .tool-name { font-family: 'Monaco', 'Courier New', monospace; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ font-weight: 600; } @@ -667,7 +667,7 @@ body { .tool-section strong { display: block; margin-bottom: 0.5rem; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } .tool-section pre { @@ -678,7 +678,7 @@ body { } .tool-meta { - font-size: 0.8125rem; + font-size: 0.5625rem; /* 75% of 0.75rem */ color: var(--text-secondary); } @@ -706,7 +706,7 @@ body { } .git-changes { - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ color: var(--text-secondary); } @@ -720,7 +720,7 @@ body { .file-status { display: block; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ margin-bottom: 0.5rem; } @@ -742,7 +742,7 @@ body { } .git-file-group li { - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ color: var(--text-secondary); font-family: 'Monaco', 'Courier New', monospace; } @@ -776,7 +776,7 @@ body { .file-name { font-weight: 600; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } .file-toggle { @@ -803,7 +803,7 @@ body { background-color: var(--bg-primary); padding: 0.75rem; border-radius: 0.375rem; - font-size: 0.8125rem; + font-size: 0.5625rem; /* 75% of 0.75rem */ } /* Detail sections */ @@ -812,7 +812,7 @@ body { } .detail-section h3 { - font-size: 1.25rem; + font-size: 0.84375rem; /* 75% of 1.125rem */ font-weight: 600; margin-bottom: 1rem; } @@ -822,7 +822,7 @@ body { display: flex; flex-direction: column; gap: 0.75rem; - margin-bottom: 2rem; + margin-bottom: 1.5rem; /* Reduced margin */ } .tool-header-right { @@ -832,7 +832,7 @@ body { } .tool-time { - font-size: 0.8125rem; + font-size: 0.5625rem; /* 75% of 0.75rem */ color: var(--text-secondary); font-family: 'Monaco', 'Courier New', monospace; } @@ -867,7 +867,7 @@ body { border-radius: 6px; color: var(--text-primary); font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } .file-browser-list { @@ -915,7 +915,7 @@ body { .file-browser-name { flex: 1; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; - font-size: 0.875rem; + font-size: 0.609375rem; /* 75% of 0.8125rem */ } .file-browser-item:last-child {