diff --git a/app/static/public/css/chat.css b/app/static/public/css/chat.css index c3ec762..6cabe3b 100644 --- a/app/static/public/css/chat.css +++ b/app/static/public/css/chat.css @@ -685,16 +685,6 @@ body { animation-delay: var(--think-spin-delay, 0s); } -.think-block[data-thinking="true"] .think-agent-avatar { - animation: thinkSpinSlow 2.2s linear infinite; - animation-delay: var(--think-spin-delay, 0s); -} - -.think-block[data-thinking="true"] .think-rollout-title::before { - animation: thinkSpinSlow 2.2s linear infinite; - animation-delay: var(--think-spin-delay, 0s); -} - .think-summary::after { content: ""; width: 6px; @@ -971,16 +961,25 @@ body { gap: 8px; } -.think-rollout-title::before { - content: ""; +.think-rollout-avatar { width: 18px; height: 18px; + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 18px; border-radius: 50%; background: conic-gradient(from 180deg, #f59e0b, #f97316, #22c55e, #0ea5e9, #f59e0b); border: 1px solid #fff; box-shadow: 0 2px 8px rgba(17, 17, 17, 0.15); } +.think-rollout-label { + display: inline-flex; + align-items: center; + min-width: 0; +} + .think-rollout-body { margin-top: 8px; display: flex; diff --git a/app/static/public/js/chat.js b/app/static/public/js/chat.js index bef11d7..6434720 100644 --- a/app/static/public/js/chat.js +++ b/app/static/public/js/chat.js @@ -38,6 +38,8 @@ let followStreamScroll = true; let suppressScrollTracking = false; let userLockedStreamScroll = false; + const activeThinkSpinEntries = new Set(); + let thinkSpinRafId = 0; const feedbackUrl = 'https://github.com/chenyme/grok2api/issues/new'; const STORAGE_KEY = 'grok2api_chat_sessions'; const SIDEBAR_STATE_KEY = 'grok2api_chat_sidebar_collapsed'; @@ -1168,7 +1170,7 @@ }).join(''); const title = escapeHtml(group.id); const openAttr = openAllGroups ? ' open' : ''; - return `
${title}
${items}
`; + return `
${title}
${items}
`; }).join(''); }; @@ -1619,19 +1621,43 @@ if (!entry.thinkingActive) { block.removeAttribute('data-thinking'); node.style.removeProperty('--think-spin-delay'); - block.querySelectorAll('.think-agent-avatar').forEach((avatar) => { - avatar.style.removeProperty('--think-spin-delay'); + activeThinkSpinEntries.delete(entry); + block.querySelectorAll('.think-agent-avatar, .think-rollout-avatar').forEach((avatar) => { + avatar.style.removeProperty('transform'); }); } else { block.setAttribute('data-thinking', 'true'); node.style.setProperty('--think-spin-delay', spinOffset); - block.querySelectorAll('.think-agent-avatar').forEach((avatar) => { - avatar.style.setProperty('--think-spin-delay', spinOffset); - }); + activeThinkSpinEntries.add(entry); + ensureThinkSpinLoop(); } }); } + function ensureThinkSpinLoop() { + if (thinkSpinRafId) return; + const tick = () => { + thinkSpinRafId = 0; + if (!activeThinkSpinEntries.size) return; + const now = Date.now(); + activeThinkSpinEntries.forEach((entry) => { + if (!entry || !entry.contentNode || !entry.thinkingActive || !entry.contentNode.isConnected) { + activeThinkSpinEntries.delete(entry); + return; + } + const elapsedMs = Math.max(0, now - (entry.startedAt || now)); + const angle = ((elapsedMs % 2200) / 2200) * 360; + entry.contentNode.querySelectorAll('.think-block[data-thinking="true"] .think-agent-avatar, .think-block[data-thinking="true"] .think-rollout-avatar').forEach((avatar) => { + avatar.style.transform = `rotate(${angle}deg)`; + }); + }); + if (activeThinkSpinEntries.size) { + thinkSpinRafId = requestAnimationFrame(tick); + } + }; + thinkSpinRafId = requestAnimationFrame(tick); + } + function normalizeSourceText(value) { return String(value || '').replace(/\s+/g, ' ').trim(); }