use shadcn avatar component

This commit is contained in:
Leon van Zyl
2025-08-13 09:41:10 +02:00
parent 4eae69b8ce
commit 616ebb8fcc
6 changed files with 220 additions and 21 deletions

View File

@@ -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>

View File

@@ -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>
)
}
);
}

View 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 }