mirror of
https://litchi.icu/ngc2207/judge4c-demo.git
synced 2025-05-18 16:07:29 +00:00
feat: 添加chat-support和需要的相关shadcn组建
This commit is contained in:
parent
f2373ba8b0
commit
3b2f2d3d2a
@ -1,3 +1,6 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "next/typescript"]
|
||||
"extends": ["next/core-web-vitals", "next/typescript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-empty-interface": "off"
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
"@ai-sdk/openai": "^0.0.72",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@prisma/client": "5.22.0",
|
||||
"@radix-ui/react-avatar": "^1.1.1",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"ai": "^3.4.33",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import localFont from "next/font/local";
|
||||
import "./globals.css";
|
||||
import ChatSupport from "@/components/chat-support";
|
||||
|
||||
const geistSans = localFont({
|
||||
src: "./fonts/GeistVF.woff",
|
||||
@ -29,6 +30,7 @@ export default function RootLayout({
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<div className="container mx-auto px-12">{children}</div>
|
||||
<ChatSupport />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
44
src/components/chat-support.tsx
Normal file
44
src/components/chat-support.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import {
|
||||
ChatBubble,
|
||||
ChatBubbleAvatar,
|
||||
ChatBubbleMessage,
|
||||
} from "@/components/ui/chat/chat-bubble";
|
||||
import { ChatInput } from "@/components/ui/chat/chat-input";
|
||||
import {
|
||||
ExpandableChat,
|
||||
ExpandableChatHeader,
|
||||
ExpandableChatBody,
|
||||
ExpandableChatFooter,
|
||||
} from "@/components/ui/chat/expandable-chat";
|
||||
import { ChatMessageList } from "@/components/ui/chat/chat-message-list";
|
||||
import { Button } from "./ui/button";
|
||||
import { Send } from "lucide-react";
|
||||
|
||||
export default function ChatSupport() {
|
||||
return (
|
||||
<ExpandableChat size="lg" position="bottom-right">
|
||||
<ExpandableChatHeader className="flex-col text-center justify-center">
|
||||
<h1 className="text-xl font-semibold">Chat with our AI ✨</h1>
|
||||
<p>Ask any question for our AI to answer</p>
|
||||
<div className="flex gap-2 items-center pt-2">
|
||||
<Button variant="secondary">New Chat</Button>
|
||||
<Button variant="secondary">See FAQ</Button>
|
||||
</div>
|
||||
</ExpandableChatHeader>
|
||||
<ExpandableChatBody>
|
||||
<ChatMessageList>
|
||||
<ChatBubble>
|
||||
<ChatBubbleAvatar />
|
||||
<ChatBubbleMessage>{/* {message.content} */}</ChatBubbleMessage>
|
||||
</ChatBubble>
|
||||
</ChatMessageList>
|
||||
</ExpandableChatBody>
|
||||
<ExpandableChatFooter>
|
||||
<ChatInput />
|
||||
<Button type="submit" size="icon">
|
||||
<Send className="size-4" />
|
||||
</Button>
|
||||
</ExpandableChatFooter>
|
||||
</ExpandableChat>
|
||||
);
|
||||
}
|
50
src/components/ui/avatar.tsx
Normal file
50
src/components/ui/avatar.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Image
|
||||
ref={ref}
|
||||
className={cn("aspect-square h-full w-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
57
src/components/ui/button.tsx
Normal file
57
src/components/ui/button.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
22
src/components/ui/textarea.tsx
Normal file
22
src/components/ui/textarea.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
React.ComponentProps<"textarea">
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Textarea.displayName = "Textarea"
|
||||
|
||||
export { Textarea }
|
Loading…
Reference in New Issue
Block a user