img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..807e1fa
--- /dev/null
+++ b/src/components/ui/dialog.tsx
@@ -0,0 +1,157 @@
+"use client"
+
+import * as React from "react"
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
+
+function Dialog({ ...props }: DialogPrimitive.Root.Props) {
+ return
+}
+
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
+ return
+}
+
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
+ return
+}
+
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
+ return
+}
+
+function DialogOverlay({
+ className,
+ ...props
+}: DialogPrimitive.Backdrop.Props) {
+ return (
+
+ )
+}
+
+function DialogContent({
+ className,
+ children,
+ showCloseButton = true,
+ ...props
+}: DialogPrimitive.Popup.Props & {
+ showCloseButton?: boolean
+}) {
+ return (
+
+
+
+ {children}
+ {showCloseButton && (
+
+ }
+ >
+
+ Close
+
+ )}
+
+
+ )
+}
+
+function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean
+}) {
+ return (
+
+ {children}
+ {showCloseButton && (
+ }>
+ Close
+
+ )}
+
+ )
+}
+
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
+ return (
+
+ )
+}
+
+function DialogDescription({
+ className,
+ ...props
+}: DialogPrimitive.Description.Props) {
+ return (
+
+ )
+}
+
+export {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
+}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..7d21bab
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,20 @@
+import * as React from "react"
+import { Input as InputPrimitive } from "@base-ui/react/input"
+
+import { cn } from "@/lib/utils"
+
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
+ return (
+
+ )
+}
+
+export { Input }
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
new file mode 100644
index 0000000..e8021f5
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,201 @@
+"use client"
+
+import * as React from "react"
+import { Select as SelectPrimitive } from "@base-ui/react/select"
+
+import { cn } from "@/lib/utils"
+import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
+
+const Select = SelectPrimitive.Root
+
+function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
+ return (
+
+ )
+}
+
+function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
+ return (
+
+ )
+}
+
+function SelectTrigger({
+ className,
+ size = "default",
+ children,
+ ...props
+}: SelectPrimitive.Trigger.Props & {
+ size?: "sm" | "default"
+}) {
+ return (
+
+ {children}
+
+ }
+ />
+
+ )
+}
+
+function SelectContent({
+ className,
+ children,
+ side = "bottom",
+ sideOffset = 4,
+ align = "center",
+ alignOffset = 0,
+ alignItemWithTrigger = true,
+ ...props
+}: SelectPrimitive.Popup.Props &
+ Pick<
+ SelectPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
+ >) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+function SelectLabel({
+ className,
+ ...props
+}: SelectPrimitive.GroupLabel.Props) {
+ return (
+
+ )
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: SelectPrimitive.Item.Props) {
+ return (
+
+
+ {children}
+
+
+ }
+ >
+
+
+
+ )
+}
+
+function SelectSeparator({
+ className,
+ ...props
+}: SelectPrimitive.Separator.Props) {
+ return (
+
+ )
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps
) {
+ return (
+
+
+
+ )
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+}
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
new file mode 100644
index 0000000..8dc13ae
--- /dev/null
+++ b/src/components/ui/table.tsx
@@ -0,0 +1,116 @@
+"use client"
+
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Table({ className, ...props }: React.ComponentProps<"table">) {
+ return (
+
+ )
+}
+
+function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
+ return (
+
+ )
+}
+
+function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
+ return (
+
+ )
+}
+
+function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
+ return (
+ tr]:last:border-b-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
+ return (
+
+ )
+}
+
+function TableHead({ className, ...props }: React.ComponentProps<"th">) {
+ return (
+ |
+ )
+}
+
+function TableCell({ className, ...props }: React.ComponentProps<"td">) {
+ return (
+ |
+ )
+}
+
+function TableCaption({
+ className,
+ ...props
+}: React.ComponentProps<"caption">) {
+ return (
+
+ )
+}
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..56c4288
--- /dev/null
+++ b/src/components/ui/tabs.tsx
@@ -0,0 +1,82 @@
+"use client"
+
+import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+function Tabs({
+ className,
+ orientation = "horizontal",
+ ...props
+}: TabsPrimitive.Root.Props) {
+ return (
+
+ )
+}
+
+const tabsListVariants = cva(
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function TabsList({
+ className,
+ variant = "default",
+ ...props
+}: TabsPrimitive.List.Props & VariantProps) {
+ return (
+
+ )
+}
+
+function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
+ return (
+
+ )
+}
+
+function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
+ return (
+
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
diff --git a/src/data/mockData.ts b/src/data/mockData.ts
new file mode 100644
index 0000000..4dd8f1c
--- /dev/null
+++ b/src/data/mockData.ts
@@ -0,0 +1,123 @@
+import { Item, Category, Location } from "@/types";
+
+// 模拟分类数据
+export const categories: Category[] = [
+ { id: "1", name: "电子产品", icon: "📱", color: "bg-blue-500" },
+ { id: "2", name: "书籍", icon: "📚", color: "bg-green-500" },
+ { id: "3", name: "衣物", icon: "👕", color: "bg-purple-500" },
+ { id: "4", name: "厨房用品", icon: "🍳", color: "bg-orange-500" },
+ { id: "5", name: "工具", icon: "🔧", color: "bg-gray-500" },
+ { id: "6", name: "文具", icon: "✏️", color: "bg-yellow-500" },
+];
+
+// 模拟位置数据
+export const locations: Location[] = [
+ { id: "1", name: "客厅", code: "LR", path: "客厅" },
+ { id: "2", name: "卧室", code: "BR", path: "卧室" },
+ { id: "3", name: "书房", code: "ST", path: "书房" },
+ { id: "4", name: "厨房", code: "KT", path: "厨房" },
+ { id: "5", name: "储物间", code: "STR", path: "储物间" },
+ { id: "6", name: "衣柜 A", code: "WD-A", parentId: "2", path: "卧室/衣柜 A" },
+ { id: "7", name: "书架 B", code: "BK-B", parentId: "3", path: "书房/书架 B" },
+ { id: "8", name: "橱柜 C", code: "CB-C", parentId: "4", path: "厨房/橱柜 C" },
+];
+
+// 模拟物品数据
+export const items: Item[] = [
+ {
+ id: "1",
+ name: "MacBook Pro",
+ description: "2023 款 14 寸,M3 Pro 芯片",
+ categoryId: "1",
+ locationId: "3",
+ quantity: 1,
+ unit: "台",
+ tags: ["电脑", "工作"],
+ createdAt: "2024-01-15",
+ updatedAt: "2024-01-15",
+ },
+ {
+ id: "2",
+ name: "iPhone 15 Pro",
+ description: "256GB 原色钛金属",
+ categoryId: "1",
+ locationId: "1",
+ quantity: 1,
+ unit: "台",
+ tags: ["手机", "通讯"],
+ createdAt: "2024-02-20",
+ updatedAt: "2024-02-20",
+ },
+ {
+ id: "3",
+ name: "设计心理学",
+ description: "唐·诺曼经典著作",
+ categoryId: "2",
+ locationId: "7",
+ quantity: 1,
+ unit: "本",
+ tags: ["设计", "产品"],
+ createdAt: "2023-06-10",
+ updatedAt: "2023-06-10",
+ },
+ {
+ id: "4",
+ name: "冬季外套",
+ description: "北面羽绒服,黑色 L 码",
+ categoryId: "3",
+ locationId: "6",
+ quantity: 2,
+ unit: "件",
+ tags: ["冬季", "外套"],
+ createdAt: "2023-11-01",
+ updatedAt: "2023-11-01",
+ },
+ {
+ id: "5",
+ name: "不粘锅套装",
+ description: "双立人三件套",
+ categoryId: "4",
+ locationId: "8",
+ quantity: 1,
+ unit: "套",
+ tags: ["厨具", "烹饪"],
+ createdAt: "2024-03-01",
+ updatedAt: "2024-03-01",
+ },
+ {
+ id: "6",
+ name: "螺丝刀套装",
+ description: "小米精修螺丝刀",
+ categoryId: "5",
+ locationId: "5",
+ quantity: 1,
+ unit: "套",
+ tags: ["工具", "维修"],
+ createdAt: "2023-08-15",
+ updatedAt: "2023-08-15",
+ },
+ {
+ id: "7",
+ name: "iPad Air",
+ description: "第五代 64GB 蓝色",
+ categoryId: "1",
+ locationId: "1",
+ quantity: 1,
+ unit: "台",
+ tags: ["平板", "娱乐"],
+ createdAt: "2023-05-20",
+ updatedAt: "2023-05-20",
+ },
+ {
+ id: "8",
+ name: "笔记本",
+ description: "Moleskine 经典黑色",
+ categoryId: "6",
+ locationId: "3",
+ quantity: 5,
+ unit: "本",
+ tags: ["文具", "记录"],
+ createdAt: "2024-01-10",
+ updatedAt: "2024-01-10",
+ },
+];
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..14d6180
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,40 @@
+// 物品类型
+export interface Item {
+ id: string;
+ name: string;
+ description: string;
+ categoryId: string;
+ locationId: string;
+ quantity: number;
+ unit: string;
+ imageUrl?: string;
+ tags: string[];
+ createdAt: string;
+ updatedAt: string;
+}
+
+// 分类类型
+export interface Category {
+ id: string;
+ name: string;
+ icon: string;
+ color: string;
+ parentId?: string;
+}
+
+// 位置类型
+export interface Location {
+ id: string;
+ name: string;
+ code: string;
+ parentId?: string;
+ path: string;
+}
+
+// 搜索筛选条件
+export interface SearchFilters {
+ keyword?: string;
+ categoryId?: string;
+ locationId?: string;
+ tags?: string[];
+}