fix: remove zustand and use input and setInput
This commit is contained in:
parent
6f69b878d5
commit
f476c903ef
8 changed files with 83 additions and 95 deletions
|
|
@ -4,25 +4,24 @@ import { type Message } from 'ai-connector'
|
||||||
|
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Separator } from '@/components/ui/separator'
|
||||||
import { ChatMessage } from '@/components/chat-message'
|
import { ChatMessage } from '@/components/chat-message'
|
||||||
import { EmptyScreen } from '@/components/empty-screen'
|
|
||||||
|
|
||||||
export interface ChatList {
|
export interface ChatList {
|
||||||
messages: Message[]
|
messages: Message[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatList({ messages }: ChatList) {
|
export function ChatList({ messages }: ChatList) {
|
||||||
|
if (!messages.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative mx-auto max-w-2xl px-4">
|
<div className="relative mx-auto max-w-2xl px-4">
|
||||||
{messages.length > 0 ? (
|
{messages.map((message, index) => (
|
||||||
messages.map((message, index) => (
|
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<ChatMessage message={message} />
|
<ChatMessage message={message} />
|
||||||
{index < messages.length - 1 && <Separator className="my-8" />}
|
{index < messages.length - 1 && <Separator className="my-8" />}
|
||||||
</div>
|
</div>
|
||||||
))
|
))}
|
||||||
) : (
|
|
||||||
<EmptyScreen />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { UseChatHelpers } from 'ai-connector'
|
import { type UseChatHelpers } from 'ai-connector'
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { ExternalLink } from '@/components/external-link'
|
import { ExternalLink } from '@/components/external-link'
|
||||||
|
|
@ -9,7 +9,13 @@ import { IconRefresh, IconStop } from '@/components/ui/icons'
|
||||||
export interface ChatPanelProps
|
export interface ChatPanelProps
|
||||||
extends Pick<
|
extends Pick<
|
||||||
UseChatHelpers,
|
UseChatHelpers,
|
||||||
'append' | 'isLoading' | 'reload' | 'messages' | 'stop'
|
| 'append'
|
||||||
|
| 'isLoading'
|
||||||
|
| 'reload'
|
||||||
|
| 'messages'
|
||||||
|
| 'stop'
|
||||||
|
| 'input'
|
||||||
|
| 'setInput'
|
||||||
> {
|
> {
|
||||||
id?: string
|
id?: string
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +25,8 @@ export function ChatPanel({
|
||||||
stop,
|
stop,
|
||||||
append,
|
append,
|
||||||
reload,
|
reload,
|
||||||
|
input,
|
||||||
|
setInput,
|
||||||
messages
|
messages
|
||||||
}: ChatPanelProps) {
|
}: ChatPanelProps) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -56,6 +64,8 @@ export function ChatPanel({
|
||||||
role: 'user'
|
role: 'user'
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
input={input}
|
||||||
|
setInput={setInput}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
/>
|
/>
|
||||||
<p className="hidden px-2 text-center text-xs leading-normal text-muted-foreground sm:block">
|
<p className="hidden px-2 text-center text-xs leading-normal text-muted-foreground sm:block">
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,32 @@
|
||||||
|
|
||||||
import { useChat, type Message } from 'ai-connector'
|
import { useChat, type Message } from 'ai-connector'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import { ChatList } from '@/components/chat-list'
|
import { ChatList } from '@/components/chat-list'
|
||||||
import { ChatPanel } from '@/components/chat-panel'
|
import { ChatPanel } from '@/components/chat-panel'
|
||||||
|
import { EmptyScreen } from '@/components/empty-screen'
|
||||||
|
|
||||||
export interface ChatProps {
|
export interface ChatProps extends React.ComponentProps<'div'> {
|
||||||
// create?: (input: string) => Chat | undefined;
|
|
||||||
initialMessages?: Message[]
|
initialMessages?: Message[]
|
||||||
id?: string
|
id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Chat({ id, initialMessages }: ChatProps) {
|
export function Chat({ id, initialMessages, className }: ChatProps) {
|
||||||
const { messages, append, reload, stop, isLoading } = useChat({
|
const { messages, append, reload, stop, isLoading, input, setInput } =
|
||||||
|
useChat({
|
||||||
initialMessages,
|
initialMessages,
|
||||||
id
|
id
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pb-[200px] pt-4 md:pt-10">
|
<>
|
||||||
|
<div className={cn('pb-[200px] pt-4 md:pt-10', className)}>
|
||||||
|
{messages.length ? (
|
||||||
<ChatList messages={messages} />
|
<ChatList messages={messages} />
|
||||||
|
) : (
|
||||||
|
<EmptyScreen setInput={setInput} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<ChatPanel
|
<ChatPanel
|
||||||
id={id}
|
id={id}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|
@ -27,7 +35,9 @@ export function Chat({ id, initialMessages }: ChatProps) {
|
||||||
append={append}
|
append={append}
|
||||||
reload={reload}
|
reload={reload}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
|
input={input}
|
||||||
|
setInput={setInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { useChatStore } from '@/lib/hooks/use-chat-store'
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { ExternalLink } from '@/components/external-link'
|
import { ExternalLink } from '@/components/external-link'
|
||||||
import { IconArrowRight } from '@/components/ui/icons'
|
import { IconArrowRight } from '@/components/ui/icons'
|
||||||
|
import { UseChatHelpers } from 'ai-connector'
|
||||||
|
|
||||||
const exampleMessages = [
|
const exampleMessages = [
|
||||||
{
|
{
|
||||||
|
|
@ -19,11 +19,10 @@ const exampleMessages = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export function EmptyScreen({ className }: React.ComponentProps<'div'>) {
|
export function EmptyScreen({ setInput }: Pick<UseChatHelpers, 'setInput'>) {
|
||||||
const { setDefaultMessage } = useChatStore()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('rounded-lg border bg-background p-8', className)}>
|
<div className="mx-auto max-w-2xl px-4">
|
||||||
|
<div className="rounded-lg border bg-background p-8">
|
||||||
<h1 className="mb-2 text-lg font-semibold">
|
<h1 className="mb-2 text-lg font-semibold">
|
||||||
Welcome to Next.js Chatbot!
|
Welcome to Next.js Chatbot!
|
||||||
</h1>
|
</h1>
|
||||||
|
|
@ -44,7 +43,7 @@ export function EmptyScreen({ className }: React.ComponentProps<'div'>) {
|
||||||
key={index}
|
key={index}
|
||||||
variant="link"
|
variant="link"
|
||||||
className="h-auto p-0 text-base"
|
className="h-auto p-0 text-base"
|
||||||
onClick={() => setDefaultMessage(message.message)}
|
onClick={() => setInput(message.message)}
|
||||||
>
|
>
|
||||||
<IconArrowRight className="mr-2 text-muted-foreground" />
|
<IconArrowRight className="mr-2 text-muted-foreground" />
|
||||||
{message.heading}
|
{message.heading}
|
||||||
|
|
@ -52,5 +51,6 @@ export function EmptyScreen({ className }: React.ComponentProps<'div'>) {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import * as React from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Textarea from 'react-textarea-autosize'
|
import Textarea from 'react-textarea-autosize'
|
||||||
|
|
||||||
import { useChatStore } from '@/lib/hooks/use-chat-store'
|
|
||||||
import { useEnterSubmit } from '@/lib/hooks/use-enter-submit'
|
import { useEnterSubmit } from '@/lib/hooks/use-enter-submit'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button, buttonVariants } from '@/components/ui/button'
|
import { Button, buttonVariants } from '@/components/ui/button'
|
||||||
|
|
@ -13,15 +12,20 @@ import {
|
||||||
TooltipTrigger
|
TooltipTrigger
|
||||||
} from '@/components/ui/tooltip'
|
} from '@/components/ui/tooltip'
|
||||||
import { IconArrowElbow, IconPlus } from '@/components/ui/icons'
|
import { IconArrowElbow, IconPlus } from '@/components/ui/icons'
|
||||||
|
import { UseChatHelpers } from 'ai-connector'
|
||||||
|
|
||||||
export interface PromptProps {
|
export interface PromptProps
|
||||||
|
extends Pick<UseChatHelpers, 'input' | 'setInput'> {
|
||||||
onSubmit: (value: string) => void
|
onSubmit: (value: string) => void
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PromptForm({ onSubmit, isLoading }: PromptProps) {
|
export function PromptForm({
|
||||||
const { defaultMessage } = useChatStore()
|
onSubmit,
|
||||||
const [input, setInput] = React.useState(defaultMessage)
|
input,
|
||||||
|
setInput,
|
||||||
|
isLoading
|
||||||
|
}: PromptProps) {
|
||||||
const { formRef, onKeyDown } = useEnterSubmit()
|
const { formRef, onKeyDown } = useEnterSubmit()
|
||||||
const inputRef = React.useRef<HTMLTextAreaElement>(null)
|
const inputRef = React.useRef<HTMLTextAreaElement>(null)
|
||||||
|
|
||||||
|
|
@ -31,10 +35,6 @@ export function PromptForm({ onSubmit, isLoading }: PromptProps) {
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
setInput(defaultMessage)
|
|
||||||
}, [defaultMessage])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={async e => {
|
onSubmit={async e => {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import { create } from 'zustand'
|
|
||||||
|
|
||||||
interface UseChatStore {
|
|
||||||
defaultMessage: string
|
|
||||||
setDefaultMessage: (message: string) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useChatStore = create<UseChatStore>()(set => ({
|
|
||||||
defaultMessage: '',
|
|
||||||
setDefaultMessage: message => set({ defaultMessage: message })
|
|
||||||
}))
|
|
||||||
|
|
@ -39,8 +39,7 @@
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-textarea-autosize": "^8.4.1",
|
"react-textarea-autosize": "^8.4.1",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
"remark-math": "^5.1.1",
|
"remark-math": "^5.1.1"
|
||||||
"zustand": "^4.3.8"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
|
|
|
||||||
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
|
|
@ -86,9 +86,6 @@ dependencies:
|
||||||
remark-math:
|
remark-math:
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.1.1
|
version: 5.1.1
|
||||||
zustand:
|
|
||||||
specifier: ^4.3.8
|
|
||||||
version: 4.3.8(react@18.2.0)
|
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@tailwindcss/typography':
|
'@tailwindcss/typography':
|
||||||
|
|
@ -5070,22 +5067,6 @@ packages:
|
||||||
/zod@3.21.4:
|
/zod@3.21.4:
|
||||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||||
|
|
||||||
/zustand@4.3.8(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==}
|
|
||||||
engines: {node: '>=12.7.0'}
|
|
||||||
peerDependencies:
|
|
||||||
immer: '>=9.0'
|
|
||||||
react: '>=16.8'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
immer:
|
|
||||||
optional: true
|
|
||||||
react:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/zwitch@2.0.4:
|
/zwitch@2.0.4:
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue