mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(chat): replace thinking indicator with gooey loader (#5525)
* feat(chat): replace thinking indicator with gooey loader Promotes ThinkingLoader from the landing route group to the shared components/ui barrel and swaps it in for the 4-square color loader in the chat's PendingTagIndicator. Removes the now-dead animate-thinking-block keyframe/animation. * fix(chat): keep a stable Thinking… label instead of cycling phase text Greptile flagged that phase text repeatedly re-announces to assistive tech during a single pending stream; a static label avoids the repeated live-region updates while keeping the gooey shape morph.
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
import { WorkflowShowcase } from '@/app/(landing)/components/features/components/build-callout/components/workflow-showcase'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
|
||||
/**
|
||||
* The Build beat's callout - the finished workflow canvas centered on the
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import { Blimp } from '@sim/emcn/icons'
|
||||
import { ArrowUp, Mic, Paperclip, Plus, Slash } from 'lucide-react'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
|
||||
const PROMPT = 'Build a workflow to schedule and publish posts to my X account.'
|
||||
const REPLY =
|
||||
|
||||
@@ -13,8 +13,8 @@ import {
|
||||
ThumbsDown,
|
||||
ThumbsUp,
|
||||
} from 'lucide-react'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
import { HERO_TOOLTIP_OFFSET } from '@/app/(landing)/components/hero/components/hero-platform-loop/sidebar-hotspots'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
|
||||
/** The conversation the loop plays - mirrors the seeded capture chat. */
|
||||
const USER_MESSAGE = 'When a new lead signs up, enrich it with company data and post it to #sales.'
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
import { BlockHandles } from '@/app/(landing)/components/hero/components/hero-visual/block-handles'
|
||||
import {
|
||||
type HomeMode,
|
||||
@@ -37,7 +38,6 @@ import {
|
||||
TYPE_MS_PER_ATOM,
|
||||
WORKFLOW_FOCUS_SCALE,
|
||||
} from '@/app/(landing)/components/hero/components/hero-visual/workflow-data'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
|
||||
/**
|
||||
* Animated hero visual - the only client island in the hero, decorative and
|
||||
|
||||
+1
-1
@@ -2,11 +2,11 @@
|
||||
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
import { LandingPreviewChatInput } from '@/app/(landing)/components/landing-preview/components/landing-preview-chat/chat-input'
|
||||
import { LandingPreviewChatTitleBar } from '@/app/(landing)/components/landing-preview/components/landing-preview-chat/chat-title-bar'
|
||||
import type { PreviewChat } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data'
|
||||
import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/hooks/use-landing-submit'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
|
||||
interface LandingPreviewChatProps {
|
||||
/** The scripted exchange to play, or `null` to show only the input. */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { type CSSProperties, type ReactNode, useState } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import { ThinkingLoader } from '@/app/(landing)/components/thinking-loader'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
|
||||
interface LogoMarkProps {
|
||||
/** Server-rendered Sim wordmark, shown by default. */
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { ThinkingLoader, type ThinkingLoaderVariant } from './thinking-loader'
|
||||
+3
-18
@@ -14,6 +14,7 @@ import {
|
||||
toast,
|
||||
} from '@sim/emcn'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { ThinkingLoader } from '@/components/ui'
|
||||
import { canonicalWorkspaceFilePath } from '@/lib/copilot/vfs/path-utils'
|
||||
import { isSafeHttpUrl } from '@/lib/core/utils/urls'
|
||||
import { OAUTH_PROVIDERS } from '@/lib/oauth/oauth'
|
||||
@@ -390,13 +391,6 @@ export function parseSpecialTags(content: string, isStreaming: boolean): ParsedS
|
||||
return { segments, hasPendingTag }
|
||||
}
|
||||
|
||||
const THINKING_BLOCKS = [
|
||||
{ color: '#2ABBF8', delay: '0s' },
|
||||
{ color: '#00F701', delay: '0.2s' },
|
||||
{ color: '#FA4EDF', delay: '0.6s' },
|
||||
{ color: '#FFCC02', delay: '0.4s' },
|
||||
] as const
|
||||
|
||||
interface SpecialTagsProps {
|
||||
segment: Exclude<ContentSegment, { type: 'text' }>
|
||||
onOptionSelect?: (id: string) => void
|
||||
@@ -435,17 +429,8 @@ export function SpecialTags({
|
||||
*/
|
||||
export function PendingTagIndicator() {
|
||||
return (
|
||||
<div className='flex animate-stream-fade-in items-center gap-2 py-2'>
|
||||
<div className='grid size-[16px] grid-cols-2 gap-[1.5px]'>
|
||||
{THINKING_BLOCKS.map((block, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className='animate-thinking-block rounded-xs'
|
||||
style={{ backgroundColor: block.color, animationDelay: block.delay }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<span className='text-[var(--text-body)] text-sm'>Thinking…</span>
|
||||
<div className='animate-stream-fade-in py-2'>
|
||||
<ThinkingLoader size={20} startVariant='corners' label='Thinking…' labelRatio={0.7} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,3 +14,4 @@ export {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from './select'
|
||||
export { ThinkingLoader, type ThinkingLoaderVariant } from './thinking-loader'
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
import { type CSSProperties, type ReactNode, useEffect, useId, useState } from 'react'
|
||||
import { cn } from '@sim/emcn'
|
||||
import styles from '@/app/(landing)/components/thinking-loader/thinking-loader.module.css'
|
||||
import styles from '@/components/ui/thinking-loader.module.css'
|
||||
|
||||
const VARIANTS = [
|
||||
'metaballs',
|
||||
@@ -189,10 +189,6 @@ export default {
|
||||
from: { opacity: '0' },
|
||||
to: { opacity: '1' },
|
||||
},
|
||||
'thinking-block': {
|
||||
'0%, 100%': { opacity: '0.15' },
|
||||
'30%, 55%': { opacity: '1' },
|
||||
},
|
||||
'slide-in-right': {
|
||||
from: { transform: 'translateX(40px)' },
|
||||
to: { transform: 'translateX(0)' },
|
||||
@@ -251,7 +247,6 @@ export default {
|
||||
'ring-pulse': 'ring-pulse 1.5s ease-in-out infinite',
|
||||
'stream-fade-in': 'stream-fade-in 300ms ease-out forwards',
|
||||
'stream-fade-in-delayed': 'stream-fade-in 300ms ease-out 1.5s forwards',
|
||||
'thinking-block': 'thinking-block 1.6s ease-in-out infinite',
|
||||
'slide-in-right': 'slide-in-right 350ms ease-out forwards',
|
||||
'slide-in-bottom': 'slide-in-bottom 400ms cubic-bezier(0.16, 1, 0.3, 1)',
|
||||
'collapsible-down': 'collapsible-down 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
|
||||
Reference in New Issue
Block a user