feat(desktop): add StepDots component and minor onboarding tweaks
- Add StepDots progress indicator to all steps - Update animations for consistency - Minor copy and layout adjustments Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
437dc05db0
commit
d189b14a15
4 changed files with 93 additions and 96 deletions
|
|
@ -42,7 +42,7 @@ export default function PermissionsStep({ onNext }: PermissionsStepProps) {
|
|||
const [agreed, setAgreed] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center px-6 py-8">
|
||||
<div className="h-full flex items-center justify-center px-6 py-8 animate-in fade-in duration-300">
|
||||
<div className="w-full max-w-md space-y-6">
|
||||
{/* Header */}
|
||||
<div className="space-y-2">
|
||||
|
|
|
|||
|
|
@ -1,27 +1,34 @@
|
|||
import { useNavigate } from 'react-router-dom'
|
||||
import { Button } from '@multica/ui/components/ui/button'
|
||||
import { Loading } from '@multica/ui/components/ui/loading'
|
||||
import { ChatView } from '@multica/ui/components/chat-view'
|
||||
import { Separator } from '@multica/ui/components/ui/separator'
|
||||
import { HugeiconsIcon } from '@hugeicons/react'
|
||||
import { ArrowLeft02Icon } from '@hugeicons/core-free-icons'
|
||||
import { SamplePrompt } from '../../../components/onboarding/sample-prompt'
|
||||
import {
|
||||
ArrowLeft02Icon,
|
||||
ArrowRight01Icon,
|
||||
Search01Icon,
|
||||
FolderOpenIcon,
|
||||
CommandLineIcon,
|
||||
} from '@hugeicons/core-free-icons'
|
||||
import { StepDots } from './step-dots'
|
||||
import { useLocalChat } from '../../../hooks/use-local-chat'
|
||||
|
||||
const samplePrompts = [
|
||||
const tryPrompts = [
|
||||
{
|
||||
title: 'Latest AI news',
|
||||
prompt:
|
||||
"Search the web for today's top AI news and give me a 3-bullet summary with sources.",
|
||||
icon: Search01Icon,
|
||||
title: 'Search the web',
|
||||
description: "Get today's AI news",
|
||||
prompt: "Search the web for today's top AI news and give me a 3-bullet summary with sources.",
|
||||
},
|
||||
{
|
||||
title: 'Analyze this project',
|
||||
prompt:
|
||||
'Look at the files in my current directory and give me a brief summary of what this project is about.',
|
||||
icon: FolderOpenIcon,
|
||||
title: 'Read your files',
|
||||
description: 'Summarize this directory',
|
||||
prompt: 'Look at the files in my current directory and give me a brief summary of what this project is about.',
|
||||
},
|
||||
{
|
||||
title: 'Quick task',
|
||||
prompt:
|
||||
'Write a one-liner shell command that shows my system info (OS, CPU cores, memory) and run it.',
|
||||
icon: CommandLineIcon,
|
||||
title: 'Run a command',
|
||||
description: 'Show system info',
|
||||
prompt: 'Write a one-liner shell command that shows my system info (OS, CPU cores, memory) and run it.',
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -31,91 +38,81 @@ interface TryItStepProps {
|
|||
}
|
||||
|
||||
export default function TryItStep({ onComplete, onBack }: TryItStepProps) {
|
||||
const {
|
||||
agentId,
|
||||
initError,
|
||||
messages,
|
||||
streamingIds,
|
||||
isLoading,
|
||||
isLoadingHistory,
|
||||
isLoadingMore,
|
||||
hasMore,
|
||||
error,
|
||||
pendingApprovals,
|
||||
sendMessage,
|
||||
loadMore,
|
||||
resolveApproval,
|
||||
} = useLocalChat()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const handlePromptClick = (prompt: string) => {
|
||||
console.log('[TryItStep] Selected prompt:', prompt)
|
||||
// TODO: Pass prompt to chat page
|
||||
onComplete()
|
||||
navigate('/chat')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full flex">
|
||||
{/* Left column — prompts */}
|
||||
<div className="flex-1 flex items-center justify-center px-12 py-8">
|
||||
<div className="max-w-md w-full space-y-6">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<HugeiconsIcon icon={ArrowLeft02Icon} className="size-4" />
|
||||
Back
|
||||
</button>
|
||||
<div className="h-full flex items-center justify-center px-6 py-8 animate-in fade-in duration-300">
|
||||
<div className="w-full max-w-md space-y-6">
|
||||
{/* Back button */}
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<HugeiconsIcon icon={ArrowLeft02Icon} className="size-4" />
|
||||
Back
|
||||
</button>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">
|
||||
Try it out
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Your agent can search the web, read files, and run commands.
|
||||
Click a prompt to see it in action.
|
||||
</p>
|
||||
</div>
|
||||
{/* Header */}
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-2xl font-semibold tracking-tight">
|
||||
You're all set 🎉
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Your agent is ready to help. Try a sample task, or dive right in.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
{samplePrompts.map((sp) => (
|
||||
<SamplePrompt
|
||||
key={sp.title}
|
||||
title={sp.title}
|
||||
prompt={sp.prompt}
|
||||
onClick={() => sendMessage(sp.prompt)}
|
||||
/>
|
||||
{/* Try prompts */}
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
✨ Quick start
|
||||
</p>
|
||||
<div className="rounded-xl border border-border bg-card divide-y divide-border">
|
||||
{tryPrompts.map((item) => (
|
||||
<button
|
||||
key={item.title}
|
||||
onClick={() => handlePromptClick(item.prompt)}
|
||||
className="w-full flex items-center justify-between px-4 py-3 hover:bg-accent/50 transition-colors text-left"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center justify-center size-8 rounded-lg bg-muted shrink-0">
|
||||
<HugeiconsIcon
|
||||
icon={item.icon}
|
||||
className="size-4 text-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium">{item.title}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<HugeiconsIcon
|
||||
icon={ArrowRight01Icon}
|
||||
className="size-4 text-muted-foreground"
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<StepDots />
|
||||
<Button size="lg" onClick={onComplete}>
|
||||
Open Multica
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right column — live chat */}
|
||||
<div className="flex-1 flex flex-col min-h-0 border-l">
|
||||
{initError ? (
|
||||
<div className="flex-1 flex items-center justify-center text-sm text-destructive px-8 text-center">
|
||||
{initError}
|
||||
</div>
|
||||
) : !agentId ? (
|
||||
<div className="flex-1 flex items-center justify-center gap-2 text-muted-foreground text-sm">
|
||||
<Loading />
|
||||
Initializing agent...
|
||||
</div>
|
||||
) : (
|
||||
<ChatView
|
||||
messages={messages}
|
||||
streamingIds={streamingIds}
|
||||
isLoading={isLoading}
|
||||
isLoadingHistory={isLoadingHistory}
|
||||
isLoadingMore={isLoadingMore}
|
||||
hasMore={hasMore}
|
||||
error={error}
|
||||
pendingApprovals={pendingApprovals}
|
||||
sendMessage={sendMessage}
|
||||
loadMore={loadMore}
|
||||
resolveApproval={resolveApproval}
|
||||
/>
|
||||
)}
|
||||
<Separator />
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex items-center justify-between">
|
||||
<StepDots />
|
||||
<Button size="sm" onClick={onComplete}>
|
||||
Go to Multica
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ interface WelcomeStepProps {
|
|||
|
||||
export default function WelcomeStep({ onStart }: WelcomeStepProps) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center px-12 py-8">
|
||||
<div className="h-full flex items-center justify-center px-12 py-8 animate-in fade-in duration-300">
|
||||
<div className="max-w-md w-full flex flex-col items-center text-center space-y-6">
|
||||
{/* Brand Title */}
|
||||
<div className="flex items-center gap-2.5">
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default function OnboardingPage() {
|
|||
/>
|
||||
<main
|
||||
key={currentStep}
|
||||
className="flex-1 overflow-auto animate-in fade-in duration-300"
|
||||
className="flex-1 overflow-auto"
|
||||
>
|
||||
<WelcomeStep onStart={nextStep} />
|
||||
</main>
|
||||
|
|
@ -73,7 +73,7 @@ export default function OnboardingPage() {
|
|||
{/* Step content */}
|
||||
<main
|
||||
key={currentStep}
|
||||
className="flex-1 overflow-auto animate-in fade-in duration-300"
|
||||
className="flex-1 overflow-auto"
|
||||
>
|
||||
{currentStep === 1 && <PermissionsStep onNext={nextStep} />}
|
||||
{currentStep === 2 && <SetupStep onNext={nextStep} onBack={prevStep} />}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue