multica/apps/web/components/component-example.tsx
Naiyuan Qing 84fe9d99f5 Add monorepo setup with Turborepo and Web client
- Add pnpm workspace and Turborepo configuration
- Extract Gateway SDK to packages/sdk as independent package
- Add Next.js + shadcn Web client in apps/web
- Update root package.json with turbo scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 16:33:35 +08:00

471 lines
19 KiB
TypeScript

"use client"
import * as React from "react"
import {
Example,
ExampleWrapper,
} from "@/components/example"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogMedia,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
import { HugeiconsIcon } from "@hugeicons/react"
import { PlusSignIcon, BluetoothIcon, MoreVerticalCircle01Icon, FileIcon, FolderIcon, FolderOpenIcon, CodeIcon, MoreHorizontalCircle01Icon, SearchIcon, FloppyDiskIcon, DownloadIcon, EyeIcon, LayoutIcon, PaintBoardIcon, SunIcon, MoonIcon, ComputerIcon, UserIcon, CreditCardIcon, SettingsIcon, KeyboardIcon, LanguageCircleIcon, NotificationIcon, MailIcon, ShieldIcon, HelpCircleIcon, File01Icon, LogoutIcon } from "@hugeicons/core-free-icons"
export function ComponentExample() {
return (
<ExampleWrapper>
<CardExample />
<FormExample />
</ExampleWrapper>
)
}
function CardExample() {
return (
<Example title="Card" className="items-center justify-center">
<Card className="relative w-full max-w-sm overflow-hidden pt-0">
<div className="bg-primary absolute inset-0 z-30 aspect-video opacity-50 mix-blend-color" />
<img
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Photo by mymind on Unsplash"
title="Photo by mymind on Unsplash"
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
/>
<CardHeader>
<CardTitle>Observability Plus is replacing Monitoring</CardTitle>
<CardDescription>
Switch to the improved way to explore your data, with natural
language. Monitoring will no longer be available on the Pro plan in
November, 2025
</CardDescription>
</CardHeader>
<CardFooter>
<AlertDialog>
<AlertDialogTrigger render={<Button />}>
<HugeiconsIcon icon={PlusSignIcon} strokeWidth={2} data-icon="inline-start" />
Show Dialog
</AlertDialogTrigger>
<AlertDialogContent size="sm">
<AlertDialogHeader>
<AlertDialogMedia>
<HugeiconsIcon icon={BluetoothIcon} strokeWidth={2} />
</AlertDialogMedia>
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
<AlertDialogDescription>
Do you want to allow the USB accessory to connect to this
device?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Don&apos;t allow</AlertDialogCancel>
<AlertDialogAction>Allow</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<Badge variant="secondary" className="ml-auto">
Warning
</Badge>
</CardFooter>
</Card>
</Example>
)
}
const frameworks = [
"Next.js",
"SvelteKit",
"Nuxt.js",
"Remix",
"Astro",
] as const
const roleItems = [
{ label: "Developer", value: "developer" },
{ label: "Designer", value: "designer" },
{ label: "Manager", value: "manager" },
{ label: "Other", value: "other" },
]
function FormExample() {
const [notifications, setNotifications] = React.useState({
email: true,
sms: false,
push: true,
})
const [theme, setTheme] = React.useState("light")
return (
<Example title="Form">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>User Information</CardTitle>
<CardDescription>Please fill in your details below</CardDescription>
<CardAction>
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="ghost" size="icon" />}
>
<HugeiconsIcon icon={MoreVerticalCircle01Icon} strokeWidth={2} />
<span className="sr-only">More options</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuGroup>
<DropdownMenuLabel>File</DropdownMenuLabel>
<DropdownMenuItem>
<HugeiconsIcon icon={FileIcon} strokeWidth={2} />
New File
<DropdownMenuShortcut>N</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={FolderIcon} strokeWidth={2} />
New Folder
<DropdownMenuShortcut>N</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<HugeiconsIcon icon={FolderOpenIcon} strokeWidth={2} />
Open Recent
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
<DropdownMenuItem>
<HugeiconsIcon icon={CodeIcon} strokeWidth={2} />
Project Alpha
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={CodeIcon} strokeWidth={2} />
Project Beta
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<HugeiconsIcon icon={MoreHorizontalCircle01Icon} strokeWidth={2} />
More Projects
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>
<HugeiconsIcon icon={CodeIcon} strokeWidth={2} />
Project Gamma
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={CodeIcon} strokeWidth={2} />
Project Delta
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<HugeiconsIcon icon={SearchIcon} strokeWidth={2} />
Browse...
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>
<HugeiconsIcon icon={FloppyDiskIcon} strokeWidth={2} />
Save
<DropdownMenuShortcut>S</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={DownloadIcon} strokeWidth={2} />
Export
<DropdownMenuShortcut>E</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuLabel>View</DropdownMenuLabel>
<DropdownMenuCheckboxItem
checked={notifications.email}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
email: checked === true,
})
}
>
<HugeiconsIcon icon={EyeIcon} strokeWidth={2} />
Show Sidebar
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.sms}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
sms: checked === true,
})
}
>
<HugeiconsIcon icon={LayoutIcon} strokeWidth={2} />
Show Status Bar
</DropdownMenuCheckboxItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<HugeiconsIcon icon={PaintBoardIcon} strokeWidth={2} />
Theme
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
<DropdownMenuRadioGroup
value={theme}
onValueChange={setTheme}
>
<DropdownMenuRadioItem value="light">
<HugeiconsIcon icon={SunIcon} strokeWidth={2} />
Light
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="dark">
<HugeiconsIcon icon={MoonIcon} strokeWidth={2} />
Dark
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="system">
<HugeiconsIcon icon={ComputerIcon} strokeWidth={2} />
System
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuLabel>Account</DropdownMenuLabel>
<DropdownMenuItem>
<HugeiconsIcon icon={UserIcon} strokeWidth={2} />
Profile
<DropdownMenuShortcut>P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={CreditCardIcon} strokeWidth={2} />
Billing
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<HugeiconsIcon icon={SettingsIcon} strokeWidth={2} />
Settings
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Preferences</DropdownMenuLabel>
<DropdownMenuItem>
<HugeiconsIcon icon={KeyboardIcon} strokeWidth={2} />
Keyboard Shortcuts
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={LanguageCircleIcon} strokeWidth={2} />
Language
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<HugeiconsIcon icon={NotificationIcon} strokeWidth={2} />
Notifications
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuGroup>
<DropdownMenuLabel>
Notification Types
</DropdownMenuLabel>
<DropdownMenuCheckboxItem
checked={notifications.push}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
push: checked === true,
})
}
>
<HugeiconsIcon icon={NotificationIcon} strokeWidth={2} />
Push Notifications
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={notifications.email}
onCheckedChange={(checked) =>
setNotifications({
...notifications,
email: checked === true,
})
}
>
<HugeiconsIcon icon={MailIcon} strokeWidth={2} />
Email Notifications
</DropdownMenuCheckboxItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<HugeiconsIcon icon={ShieldIcon} strokeWidth={2} />
Privacy & Security
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<HugeiconsIcon icon={HelpCircleIcon} strokeWidth={2} />
Help & Support
</DropdownMenuItem>
<DropdownMenuItem>
<HugeiconsIcon icon={File01Icon} strokeWidth={2} />
Documentation
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<HugeiconsIcon icon={LogoutIcon} strokeWidth={2} />
Sign Out
<DropdownMenuShortcut>Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</CardAction>
</CardHeader>
<CardContent>
<form>
<FieldGroup>
<div className="grid grid-cols-2 gap-4">
<Field>
<FieldLabel htmlFor="small-form-name">Name</FieldLabel>
<Input
id="small-form-name"
placeholder="Enter your name"
required
/>
</Field>
<Field>
<FieldLabel htmlFor="small-form-role">Role</FieldLabel>
<Select items={roleItems} defaultValue={null}>
<SelectTrigger id="small-form-role">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{roleItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Field>
</div>
<Field>
<FieldLabel htmlFor="small-form-framework">
Framework
</FieldLabel>
<Combobox items={frameworks}>
<ComboboxInput
id="small-form-framework"
placeholder="Select a framework"
required
/>
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
</Field>
<Field>
<FieldLabel htmlFor="small-form-comments">Comments</FieldLabel>
<Textarea
id="small-form-comments"
placeholder="Add any additional comments"
/>
</Field>
<Field orientation="horizontal">
<Button type="submit">Submit</Button>
<Button variant="outline" type="button">
Cancel
</Button>
</Field>
</FieldGroup>
</form>
</CardContent>
</Card>
</Example>
)
}