mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-05 05:05:08 +02:00
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:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user