diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index 0743278..f577e57 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -164,7 +164,81 @@ body { } } +/* AI 工作中·三点波动(比 animate-pulse 更明显:竖向弹跳 + 亮度,供 ThinkingIndicator 用)。 */ +.ai-dot { + animation: ai-dot 1.2s ease-in-out infinite; +} +@keyframes ai-dot { + 0%, + 80%, + 100% { + transform: translateY(0); + opacity: 0.4; + } + 40% { + transform: translateY(-3px); + opacity: 1; + } +} + +/* AI 流式/处理中·不确定进度条(细条来回扫,明确传达"正在工作")。 */ +.ai-stream-track { + position: relative; + overflow: hidden; + background: var(--color-cinnabar-wash); +} +.ai-stream-track::after { + content: ""; + position: absolute; + inset-block: 0; + left: -40%; + width: 40%; + border-radius: 9999px; + background: var(--color-cinnabar); + animation: ai-stream 1.4s ease-in-out infinite; +} +@keyframes ai-stream { + 0% { + left: -40%; + width: 35%; + } + 50% { + width: 55%; + } + 100% { + left: 100%; + width: 35%; + } +} + +/* AI 构思中·占位微光(正文区首 token 前的呼吸感,比骨架更"活")。 */ +.ai-breathe { + animation: ai-breathe 1.8s ease-in-out infinite; +} +@keyframes ai-breathe { + 0%, + 100% { + opacity: 0.55; + } + 50% { + opacity: 1; + } +} + @media (prefers-reduced-motion: reduce) { + .ai-dot { + animation: none; + opacity: 0.85; + } + .ai-stream-track::after { + animation: none; + left: 0; + width: 100%; + opacity: 0.35; + } + .ai-breathe { + animation: none; + } .typewriter-cursor { animation: none; } diff --git a/apps/web/components/ThinkingIndicator.tsx b/apps/web/components/ThinkingIndicator.tsx index d778d11..0ac916b 100644 --- a/apps/web/components/ThinkingIndicator.tsx +++ b/apps/web/components/ThinkingIndicator.tsx @@ -17,12 +17,12 @@ export function ThinkingIndicator({ role="status" aria-live="polite" > -