feat: loading spinner on sidebar open while connecting to server

Shows an amber spinner with "Connecting..." when the sidebar first opens,
replacing the empty state. After the first successful /sidebar-chat poll:
- If chat history exists: renders it immediately
- If no history: shows the welcome message

Prevents the jarring empty-then-populated flash on sidebar open.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-22 19:24:57 -07:00
parent 9d5409c420
commit 4e70c69d10
3 changed files with 44 additions and 2 deletions
+22
View File
@@ -158,6 +158,28 @@ body::after {
flex-direction: column;
gap: 8px;
}
.chat-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
color: var(--text-meta);
gap: 12px;
font-size: 13px;
}
.chat-loading-spinner {
width: 24px;
height: 24px;
border: 2px solid var(--border);
border-top-color: var(--amber-500);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.chat-welcome {
display: flex;
flex-direction: column;
+5 -1
View File
@@ -17,7 +17,11 @@
<!-- Chat Tab (default, full height) -->
<main id="tab-chat" class="tab-content active">
<div class="chat-messages" id="chat-messages">
<div class="chat-welcome">
<div class="chat-loading" id="chat-loading">
<div class="chat-loading-spinner"></div>
<p>Connecting...</p>
</div>
<div class="chat-welcome" id="chat-welcome" style="display:none">
<div class="chat-welcome-icon">G</div>
<p>Send a message to Claude Code.</p>
<p class="muted">Your agent will see it and act on it.</p>
+17 -1
View File
@@ -288,6 +288,8 @@ commandInput.addEventListener('keydown', (e) => {
sendBtn.addEventListener('click', sendMessage);
// Poll for new chat messages
let initialLoadDone = false;
async function pollChat() {
if (!serverUrl || !serverToken) return;
try {
@@ -297,7 +299,21 @@ async function pollChat() {
});
if (!resp.ok) return;
const data = await resp.json();
// First successful poll — hide loading spinner
if (!initialLoadDone) {
initialLoadDone = true;
const loading = document.getElementById('chat-loading');
const welcome = document.getElementById('chat-welcome');
if (loading) loading.style.display = 'none';
// Show welcome only if no chat history
if (data.total === 0 && welcome) welcome.style.display = '';
}
if (data.entries && data.entries.length > 0) {
// Hide welcome on first real entry
const welcome = document.getElementById('chat-welcome');
if (welcome) welcome.style.display = 'none';
for (const entry of data.entries) {
addChatEntry(entry);
}
@@ -319,7 +335,7 @@ document.getElementById('clear-chat').addEventListener('click', async () => {
agentTextEl = null;
agentText = '';
chatMessages.innerHTML = `
<div class="chat-welcome">
<div class="chat-welcome" id="chat-welcome">
<div class="chat-welcome-icon">G</div>
<p>Send a message to Claude Code.</p>
<p class="muted">Your agent will see it and act on it.</p>