feat: implement basic web app

This commit is contained in:
Henry Li
2026-01-15 23:40:21 +08:00
parent b44144dd2c
commit 9f2b94ed52
49 changed files with 4142 additions and 626 deletions

View File

@@ -1,10 +1,7 @@
"use client";
import { Button } from "@/components/ui/button";
import {
ButtonGroup,
ButtonGroupText,
} from "@/components/ui/button-group";
import { ButtonGroup, ButtonGroupText } from "@/components/ui/button-group";
import {
Tooltip,
TooltipContent,
@@ -30,9 +27,9 @@ export type MessageProps = HTMLAttributes<HTMLDivElement> & {
export const Message = ({ className, from, ...props }: MessageProps) => (
<div
className={cn(
"group flex w-full max-w-[95%] flex-col gap-2",
"group flex w-full flex-col gap-2",
from === "user" ? "is-user ml-auto justify-end" : "is-assistant",
className
className,
)}
{...props}
/>
@@ -47,10 +44,10 @@ export const MessageContent = ({
}: MessageContentProps) => (
<div
className={cn(
"is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden text-sm",
"group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
"is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden",
"group-[.is-user]:bg-secondary group-[.is-user]:text-foreground group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:px-4 group-[.is-user]:py-3",
"group-[.is-assistant]:text-foreground",
className
className,
)}
{...props}
>
@@ -116,7 +113,7 @@ type MessageBranchContextType = {
};
const MessageBranchContext = createContext<MessageBranchContextType | null>(
null
null,
);
const useMessageBranch = () => {
@@ -124,7 +121,7 @@ const useMessageBranch = () => {
if (!context) {
throw new Error(
"MessageBranch components must be used within MessageBranch"
"MessageBranch components must be used within MessageBranch",
);
}
@@ -201,7 +198,7 @@ export const MessageBranchContent = ({
<div
className={cn(
"grid gap-2 overflow-hidden [&>div]:pb-0",
index === currentBranch ? "block" : "hidden"
index === currentBranch ? "block" : "hidden",
)}
key={branch.key}
{...props}
@@ -294,8 +291,8 @@ export const MessageBranchPage = ({
return (
<ButtonGroupText
className={cn(
"border-none bg-transparent text-muted-foreground shadow-none",
className
"text-muted-foreground border-none bg-transparent shadow-none",
className,
)}
{...props}
>
@@ -311,12 +308,12 @@ export const MessageResponse = memo(
<Streamdown
className={cn(
"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
className
className,
)}
{...props}
/>
),
(prevProps, nextProps) => prevProps.children === nextProps.children
(prevProps, nextProps) => prevProps.children === nextProps.children,
);
MessageResponse.displayName = "MessageResponse";
@@ -343,7 +340,7 @@ export function MessageAttachment({
<div
className={cn(
"group relative size-24 overflow-hidden rounded-lg",
className
className,
)}
{...props}
>
@@ -359,7 +356,7 @@ export function MessageAttachment({
{onRemove && (
<Button
aria-label="Remove attachment"
className="absolute top-2 right-2 size-6 rounded-full bg-background/80 p-0 opacity-0 backdrop-blur-sm transition-opacity hover:bg-background group-hover:opacity-100 [&>svg]:size-3"
className="bg-background/80 hover:bg-background absolute top-2 right-2 size-6 rounded-full p-0 opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100 [&>svg]:size-3"
onClick={(e) => {
e.stopPropagation();
onRemove();
@@ -376,7 +373,7 @@ export function MessageAttachment({
<>
<Tooltip>
<TooltipTrigger asChild>
<div className="flex size-full shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
<div className="bg-muted text-muted-foreground flex size-full shrink-0 items-center justify-center rounded-lg">
<PaperclipIcon className="size-4" />
</div>
</TooltipTrigger>
@@ -387,7 +384,7 @@ export function MessageAttachment({
{onRemove && (
<Button
aria-label="Remove attachment"
className="size-6 shrink-0 rounded-full p-0 opacity-0 transition-opacity hover:bg-accent group-hover:opacity-100 [&>svg]:size-3"
className="hover:bg-accent size-6 shrink-0 rounded-full p-0 opacity-0 transition-opacity group-hover:opacity-100 [&>svg]:size-3"
onClick={(e) => {
e.stopPropagation();
onRemove();
@@ -420,7 +417,7 @@ export function MessageAttachments({
<div
className={cn(
"ml-auto flex w-fit flex-wrap items-start gap-2",
className
className,
)}
{...props}
>
@@ -439,7 +436,7 @@ export const MessageToolbar = ({
<div
className={cn(
"mt-4 flex w-full items-center justify-between gap-4",
className
className,
)}
{...props}
>