use shadcn avatar component
This commit is contained in:
@@ -4,10 +4,12 @@ import { useChat } from "@ai-sdk/react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { UserProfile } from "@/components/auth/user-profile"
|
||||
import { useSession } from "@/lib/auth-client"
|
||||
import { useState } from "react"
|
||||
|
||||
export default function ChatPage() {
|
||||
const { data: session, isPending } = useSession()
|
||||
const { messages, input, handleInputChange, handleSubmit } = useChat()
|
||||
const { messages, sendMessage, status } = useChat()
|
||||
const [input, setInput] = useState("")
|
||||
|
||||
if (isPending) {
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>
|
||||
@@ -56,14 +58,23 @@ export default function ChatPage() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="flex gap-2">
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
const text = input.trim()
|
||||
if (!text) return
|
||||
sendMessage({ text })
|
||||
setInput("")
|
||||
}}
|
||||
className="flex gap-2"
|
||||
>
|
||||
<input
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="Type your message..."
|
||||
className="flex-1 p-2 border border-border rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
/>
|
||||
<Button type="submit" disabled={!input.trim()}>
|
||||
<Button type="submit" disabled={!input.trim() || status === "streaming"}>
|
||||
Send
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -1,40 +1,45 @@
|
||||
"use client"
|
||||
"use client";
|
||||
|
||||
import { useSession } from "@/lib/auth-client"
|
||||
import { SignInButton } from "./sign-in-button"
|
||||
import { SignOutButton } from "./sign-out-button"
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import { SignInButton } from "./sign-in-button";
|
||||
import { SignOutButton } from "./sign-out-button";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||
|
||||
export function UserProfile() {
|
||||
const { data: session, isPending } = useSession()
|
||||
const { data: session, isPending } = useSession();
|
||||
|
||||
if (isPending) {
|
||||
return <div>Loading...</div>
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4 p-6">
|
||||
<h2 className="text-xl font-semibold">Welcome</h2>
|
||||
<p className="text-muted-foreground">Please sign in to continue</p>
|
||||
<SignInButton />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4 p-6">
|
||||
<div className="text-center">
|
||||
{session.user?.image && (
|
||||
<img
|
||||
src={session.user.image}
|
||||
alt={session.user.name || "User"}
|
||||
className="w-16 h-16 rounded-full mx-auto mb-4"
|
||||
<Avatar className="size-16 mx-auto mb-4">
|
||||
<AvatarImage
|
||||
src={session.user?.image || ""}
|
||||
alt={session.user?.name || "User"}
|
||||
/>
|
||||
)}
|
||||
<AvatarFallback>
|
||||
{(
|
||||
session.user?.name?.[0] ||
|
||||
session.user?.email?.[0] ||
|
||||
"U"
|
||||
).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<h2 className="text-xl font-semibold">{session.user?.name}</h2>
|
||||
<p className="text-muted-foreground">{session.user?.email}</p>
|
||||
</div>
|
||||
<SignOutButton />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
53
src/components/ui/avatar.tsx
Normal file
53
src/components/ui/avatar.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Avatar({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
||||
return (
|
||||
<AvatarPrimitive.Root
|
||||
data-slot="avatar"
|
||||
className={cn(
|
||||
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarImage({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||
return (
|
||||
<AvatarPrimitive.Image
|
||||
data-slot="avatar-image"
|
||||
className={cn("aspect-square size-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarFallback({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||
return (
|
||||
<AvatarPrimitive.Fallback
|
||||
data-slot="avatar-fallback"
|
||||
className={cn(
|
||||
"bg-muted flex size-full items-center justify-center rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
Reference in New Issue
Block a user