diff --git a/AGENTS.md b/AGENTS.md
index 582850b..0e09022 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,7 +4,7 @@
WonderQ-Admin-UI 是独立的 WonderQ 后台管理前端,用于维护小程序/H5 前台的首页结构、目的地、线路商品、活动入口和客户需求线索。
-当前项目是一个轻量单页后台应用,技术栈为 Vite + React + TypeScript + 普通 CSS。前端通过 `/api/admin/...` 调用后端管理接口,本地开发时由 Vite 代理到后端服务。
+当前项目是一个轻量单页后台应用,技术栈为 Vite + React + TypeScript + Tailwind CSS 4 + shadcn/ui 风格组件 + 普通 CSS。前端通过 `/api/admin/...` 调用后端管理接口,本地开发时由 Vite 代理到后端服务。
## 目录结构
@@ -12,6 +12,7 @@ WonderQ-Admin-UI 是独立的 WonderQ 后台管理前端,用于维护小程序
WonderQ-Admin-UI/
├─ AGENTS.md # Agent 项目规则
├─ README.md # 项目启动说明
+├─ components.json # shadcn/ui 组件配置
├─ docs/
│ ├─ README.md # 文档索引
│ └─ admin-backend-plan.md # 后台管理规划文档
@@ -22,8 +23,12 @@ WonderQ-Admin-UI/
├─ src/
│ ├─ App.tsx # 后台主界面、页面状态、表单和业务 UI
│ ├─ api.ts # Admin API 类型、Token 管理和请求封装
+│ ├─ components/
+│ │ └─ ui/ # 本地 shadcn/ui 风格基础组件
+│ ├─ lib/
+│ │ └─ utils.ts # className 合并工具
│ ├─ main.tsx # React 挂载入口
-│ ├─ styles.css # 全局样式与响应式布局
+│ ├─ styles.css # Tailwind 入口、设计变量、全局样式与响应式布局
│ └─ vite-env.d.ts # Vite 类型声明
├─ index.html # Vite HTML 入口
├─ package.json # 脚本与依赖
@@ -34,9 +39,11 @@ WonderQ-Admin-UI/
## 模块分工
-- `src/App.tsx`:集中实现登录页、侧边导航、结构维护、首页/目的地维护、商品维护、线索跟进、Toast 提示等后台 UI。
+- `src/App.tsx`:集中实现登录页、侧边导航、结构维护、首页/目的地维护、商品维护、线索跟进、Toast 提示等后台 UI,并优先复用 `src/components/ui/` 基础组件。
- `src/api.ts`:定义 `Product`、`Destination`、`Lead`、`SiteConfig` 等接口类型,封装登录、商品、目的地、站点配置、线索、发布和重置接口。
-- `src/styles.css`:全局布局、后台工作台、表格/表单、商品编辑器、移动端适配等样式。
+- `src/components/ui/`:本地 shadcn/ui 风格组件目录,当前包含 Button、Card、Input、Textarea、Badge、Alert、Switch、NativeSelect、Separator 等基础组件。
+- `src/lib/utils.ts`:封装 `clsx` + `tailwind-merge` 的 `cn` 工具。
+- `src/styles.css`:Tailwind CSS 4 入口、设计变量、全局布局、后台工作台、表格/表单、商品编辑器、移动端适配等样式。
- `public/assets/`:前台/后台预览用静态图片资源,代码中保留 `/assets/...` 路径引用。
- `docs/`:后台规划与后续协作边界,涉及后端 API 和数据模型时先参考这里,再看后端仓库文档。
@@ -48,6 +55,8 @@ WonderQ-Admin-UI/
yarn install
```
+本仓库使用 Yarn 1 锁文件。Windows 本地构建依赖 Vite/Rolldown、Tailwind Oxide 和 lightningcss 的 native binding,`package.json` 中固定了对应 Windows 包;未完整验证前不要随意移除这些依赖。
+
本地开发:
```bash
@@ -64,6 +73,7 @@ http://localhost:5601
- 后端 Admin API 默认运行在 `http://localhost:4000`。
- `vite.config.ts` 将 `/api` 代理到本地后端。
+- `vite.config.ts` 同时接入 `@tailwindcss/vite` 和 `@/*` 路径别名。
- 如需改 API 地址,优先使用环境变量 `VITE_API_BASE_URL`,不要硬编码生产地址。
类型检查与生产构建:
@@ -103,7 +113,8 @@ yarn build
- React 采用函数组件和 Hooks,不引入 class component。
- 遵循现有单文件轻量结构;未获授权前不要主动拆分大型组件或引入状态管理库。
- UI 图标优先复用 `lucide-react`。
-- 样式优先沿用 `src/styles.css` 的类名、色彩、间距和 6-8px 圆角习惯。
+- 通用按钮、输入框、卡片、提示、徽标、开关等基础控件优先复用 `src/components/ui/`,保持 shadcn/ui 风格一致。
+- 样式优先沿用 `src/styles.css` 的设计变量、类名、色彩、间距和 6-10px 圆角习惯;避免绕过组件体系写一套重复按钮/表单样式。
- API 访问统一走 `src/api.ts` 的 `request` 封装,不在组件里重复拼接鉴权逻辑。
- 中文文案文件按 UTF-8 处理;修改前确认编辑器编码,避免造成乱码。
@@ -113,6 +124,7 @@ yarn build
- 函数、变量使用 camelCase,例如 `getProducts`、`selectedId`。
- 联合类型字面量使用小写英文,例如 `"draft"`、`"published"`、`"leads"`。
- CSS class 沿用 kebab-case,例如 `.admin-shell`、`.product-table`。
+- 组件文件命名沿用 shadcn/ui 习惯,基础组件放在 `src/components/ui/`,工具函数放在 `src/lib/`。
- API 类型与后端字段保持同名,避免在前端私自改字段语义。
## 开发准则
diff --git a/README.md b/README.md
index bd82927..e608685 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# WonderQ-Admin-UI
-独立的 WonderQ 后台管理前端,基于 Vite、React、TypeScript 和普通 CSS。
+独立的 WonderQ 后台管理前端,基于 Vite、React、TypeScript、Tailwind CSS 4 和 shadcn/ui 风格组件。
## 本地启动
@@ -10,6 +10,8 @@
yarn install
```
+本项目使用 Yarn 1 锁文件。Windows 环境下,Vite 8、Tailwind CSS 4、lightningcss 依赖 native binding,`package.json` 中已固定对应的 Windows 构建包,避免 Yarn 1 漏装 optional dependency 导致构建失败。
+
2. 确认后端 API 运行在 `http://localhost:4000`。
3. 启动后台 UI:
@@ -24,8 +26,13 @@ yarn dev
## 目录说明
-- `src/`:后台管理 UI 和 API 客户端。
+- `src/App.tsx`:后台管理主界面和业务交互。
+- `src/api.ts`:Admin API 类型、Token 管理和请求封装。
+- `src/components/ui/`:本地 shadcn/ui 风格基础组件,包括 Button、Card、Input、Textarea、Badge、Alert、Switch 等。
+- `src/lib/utils.ts`:组件 className 合并工具。
+- `src/styles.css`:Tailwind 入口、设计变量、后台布局和响应式样式。
- `public/assets/`:后台预览所需静态资源,保留 `/assets/...` 引用方式。
-- `vite.config.ts`:开发环境将 `/api` 代理到 `http://localhost:4000`。
+- `components.json`:shadcn/ui 组件配置。
+- `vite.config.ts`:开发环境将 `/api` 代理到 `http://localhost:4000`,并接入 Tailwind Vite 插件与 `@/*` 路径别名。
本仓库已经独立,不再依赖 `WonderQ-MiniAPP` 的相对路径。
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..3ad1981
--- /dev/null
+++ b/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/styles.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
diff --git a/package.json b/package.json
index dfff1a8..33d4abf 100644
--- a/package.json
+++ b/package.json
@@ -9,16 +9,27 @@
"preview": "vite preview --host 0.0.0.0 --port 5602"
},
"dependencies": {
+ "@radix-ui/react-select": "^2.3.2",
+ "@radix-ui/react-slot": "^1.3.0",
+ "@radix-ui/react-switch": "^1.3.2",
+ "@rolldown/binding-win32-x64-msvc": "1.1.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.2",
+ "@tailwindcss/vite": "^4.3.2",
"@vitejs/plugin-react": "^6.0.3",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lightningcss-win32-x64-msvc": "1.32.0",
"lucide-react": "^1.21.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
+ "tailwind-merge": "^3.6.0",
+ "tailwindcss": "^4.3.2",
"vite": "^8.1.0"
},
"devDependencies": {
+ "@types/node": "^26.0.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"typescript": "^6.0.3"
}
}
-
diff --git a/src/App.tsx b/src/App.tsx
index 2982312..acac029 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -45,6 +45,14 @@ import {
updateProduct,
updateSiteConfigItem,
} from "./api";
+import { Alert, AlertDescription } from "@/components/ui/alert";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
+import { NativeSelect } from "@/components/ui/select";
+import { Switch } from "@/components/ui/switch";
+import { Textarea } from "@/components/ui/textarea";
type Tab = "structure" | "home" | "destinations" | "products" | "leads";
type PageId = "home" | "destination" | "detail" | "campaign" | "demand";
@@ -317,9 +325,9 @@ function ToastStack({ toasts, onClose }: { toasts: Toast[]; onClose: (id: string
{toast.title}
{toast.message}
-
))}
@@ -349,23 +357,31 @@ function LoginScreen({ onDone }: { onDone: () => void }) {
return (
-
+
+
+ 万趣运营后台
+ 万趣小程序管理端
+ 按前台页面结构维护内容、商品和线索。
+
+
+
+
+
);
}
@@ -495,18 +511,18 @@ function StructureWorkbench({
{fixedPage ? activePage.subtitle : "按用户看到的前台页面组织后台,逐层展开到可维护内容。"}
-
+
刷新
-
-
+
+
发布快照
-
-
+
+
重置贵州内容
-
+
{message ? {message}
: null}
@@ -515,13 +531,13 @@ function StructureWorkbench({
) : (
@@ -542,13 +558,13 @@ function StructureWorkbench({
页面模块
{activePage.modules.map((module, index) => (
- setModuleId(module.id)}>
+ setModuleId(module.id)}>
{index + 1}
{module.label}
{module.frontPosition}
-
+
))}
@@ -557,13 +573,13 @@ function StructureWorkbench({
{moduleEditable(moduleId) ? (
{editableItems.map((item) => (
-
selectItem(item)}>
+ selectItem(item)}>
{itemImage(item) ?
: }
{itemName(item)}
{itemMeta(item)}
-
+
))}
) : (
@@ -595,7 +611,7 @@ function ReferencePanel({ moduleId, products, onJump }: { moduleId: ModuleId; pr
return (
这个模块由客户需求列表维护,重点是状态流转、服务管家跟进和来源追踪。
-
onJump("leads")}>进入需求线索
+
onJump("leads")}>进入需求线索
);
}
@@ -611,7 +627,7 @@ function ReferencePanel({ moduleId, products, onJump }: { moduleId: ModuleId; pr
))}
- onJump("products")}>进入商品维护
+ onJump("products")}>进入商品维护
);
}
@@ -637,38 +653,38 @@ function SiteItemEditor({
编辑当前内容
保存后会影响对应前台模块
-
+
保存
-
+
{moduleId === "heroSlides" ? (
) : null}
{moduleId !== "destinations" ? (
) : null}
@@ -678,7 +694,7 @@ function SiteItemEditor({
@@ -806,10 +822,10 @@ function ProductManager({
商品维护
先管理商品列表,再点击单个商品进入详情维护。
-
+
新建商品
-
+
{message ? {message}
: null}
@@ -833,27 +849,29 @@ function ProductManager({
load().catch((err) => setMessage(err.message));
}}
>
-
setKeyword(event.target.value)} placeholder="搜索商品标题、短标题或标签" />
-
+ setKeyword(event.target.value)} placeholder="搜索商品标题、短标题或标签" />
+
{loading ? "查询中" : "查询"}
-
+
{products.map((product) => (
-
select(product)}>
+ select(product)}>
{product.coverImage ?
: }
{product.title}
{product.destination?.name || "未绑定目的地"} · {product.tags.slice(0, 3).join(" / ") || "暂无标签"}
- {productStatusLabels[product.status]}
+
+ {productStatusLabels[product.status]}
+
{product.priceAmount ? `¥${product.priceAmount}` : "未定价"}
详情维护
-
+
))}
{!products.length ?
暂无商品,点击右上角新建商品。
: null}
@@ -871,14 +889,14 @@ function ProductManager({
把列表卡片、销售信息、详情图文拆成可单独维护的模块。
-
+
返回列表
-
-
+
+
保存商品
-
+
{message ? {message}
: null}
@@ -910,19 +928,19 @@ function ProductManager({
@@ -930,28 +948,28 @@ function ProductManager({
@@ -962,7 +980,7 @@ function ProductManager({
updateDraft({ ...draft, images })} />
@@ -972,10 +990,10 @@ function ProductManager({
-
+
保存商品
-
+
@@ -999,18 +1017,18 @@ function TagEditor({ tags, onChange }: { tags: string[]; onChange: (tags: string
))}
{!tags.length ? 暂无标签,可点击添加后逐个维护。
: null}
- onChange([...tags, ""])}>
+ onChange([...tags, ""])}>
添加标签
-
+
);
}
@@ -1040,23 +1058,23 @@ function ProductImagesEditor({
- removeImage(index)} aria-label={`删除详情图片 ${index + 1}`}>
+ removeImage(index)} aria-label={`删除详情图片 ${index + 1}`}>
-
+
))}
{!images.length ? 暂无详情图片。封面图会继续用于商品卡,详情模块中也可以单独添加图片块。
: null}
- onChange([...images, { url: "", alt: "", sortOrder: images.length }])}>
+ onChange([...images, { url: "", alt: "", sortOrder: images.length }])}>
添加详情图片
-
+
);
}
@@ -1106,22 +1124,22 @@ function DetailSectionsEditor({
{section.label || "未命名模块"}
{section.blocks.length} 个内容块
- removeSection(sectionIndex)} aria-label={`删除详情模块 ${sectionIndex + 1}`}>
+ removeSection(sectionIndex)} aria-label={`删除详情模块 ${sectionIndex + 1}`}>
-
+
@@ -1132,9 +1150,9 @@ function DetailSectionsEditor({
{block.type === "image" ?
:
}
{block.type === "image" ? "图片内容" : "文字内容"} {blockIndex + 1}
-
removeBlock(sectionIndex, blockIndex)} aria-label={`删除内容块 ${blockIndex + 1}`}>
+ removeBlock(sectionIndex, blockIndex)} aria-label={`删除内容块 ${blockIndex + 1}`}>
-
+
{block.type === "image" ? (
@@ -1144,18 +1162,18 @@ function DetailSectionsEditor({
) : (
)}
@@ -1163,22 +1181,22 @@ function DetailSectionsEditor({
{!section.blocks.length ?
这个模块暂无内容块,可添加文字或图片。
: null}
- addBlock(sectionIndex, "text")}>
+ addBlock(sectionIndex, "text")}>
添加文字
-
- addBlock(sectionIndex, "image")}>
+
+ addBlock(sectionIndex, "image")}>
添加图片
-
+
))}
{!sections.length ? 暂无详情模块。可以从常用模块开始添加,再逐块维护标题、文字和图片。
: null}
- onChange([...sections, createEmptyDetailSection(sections.length)])}>
+ onChange([...sections, createEmptyDetailSection(sections.length)])}>
添加详情模块
-
+
);
}
@@ -1210,10 +1228,10 @@ function LeadManager({ notify }: { notify: (toast: Omit) => void })
需求线索跟进
对应前台「提交出行需求」和详情页「立即咨询」。
-
+
刷新
-
+
{message ? {message}
: null}
@@ -1231,11 +1249,11 @@ function LeadManager({ notify }: { notify: (toast: Omit
) => void })
{lead.destination || lead.note || "未填写"}
{lead.sourceProduct?.title || lead.sourcePage || "H5 表单"}
-
+
))}
{!leads.length ? 暂无客户需求。
: null}
@@ -1292,7 +1310,8 @@ export default function App() {
{group.items.map((tab) => {
const Icon = tab.icon;
return (
- {tab.label}
{tab.description}
-
+
);
})}
))}
- {
@@ -1321,7 +1341,7 @@ export default function App() {
>
退出登录
-
+
diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx
new file mode 100644
index 0000000..5606800
--- /dev/null
+++ b/src/components/ui/alert.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const alertVariants = cva("relative w-full rounded-lg border p-4 text-sm", {
+ variants: {
+ variant: {
+ default: "border-[var(--border)] bg-[var(--card)] text-[var(--card-foreground)]",
+ warning: "border-[var(--warning-border)] bg-[var(--warning-muted)] text-[var(--warning)]",
+ destructive: "border-[var(--destructive-border)] bg-[var(--destructive-muted)] text-[var(--destructive)]",
+ success: "border-[var(--success-border)] bg-[var(--success-muted)] text-[var(--success)]",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+});
+
+const Alert = React.forwardRef & VariantProps>(({ className, variant, ...props }, ref) => (
+
+));
+Alert.displayName = "Alert";
+
+const AlertTitle = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+AlertTitle.displayName = "AlertTitle";
+
+const AlertDescription = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+AlertDescription.displayName = "AlertDescription";
+
+export { Alert, AlertTitle, AlertDescription };
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
new file mode 100644
index 0000000..9efb7f3
--- /dev/null
+++ b/src/components/ui/badge.tsx
@@ -0,0 +1,28 @@
+import * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const badgeVariants = cva("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors", {
+ variants: {
+ variant: {
+ default: "border-transparent bg-[var(--primary)] text-[var(--primary-foreground)]",
+ secondary: "border-transparent bg-[var(--secondary)] text-[var(--secondary-foreground)]",
+ outline: "border-[var(--border)] text-[var(--foreground)]",
+ success: "border-transparent bg-[var(--success-muted)] text-[var(--success)]",
+ warning: "border-transparent bg-[var(--warning-muted)] text-[var(--warning)]",
+ muted: "border-transparent bg-[var(--muted)] text-[var(--muted-foreground)]",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+});
+
+export interface BadgeProps extends React.HTMLAttributes, VariantProps {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return ;
+}
+
+export { Badge, badgeVariants };
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..e68aa8a
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,43 @@
+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 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--background)] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ {
+ variants: {
+ variant: {
+ default: "bg-[var(--primary)] text-[var(--primary-foreground)] hover:bg-[var(--primary-hover)]",
+ destructive: "bg-[var(--destructive)] text-[var(--destructive-foreground)] hover:bg-[var(--destructive-hover)]",
+ outline: "border border-[var(--input)] bg-[var(--background)] hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",
+ secondary: "bg-[var(--secondary)] text-[var(--secondary-foreground)] hover:bg-[var(--secondary-hover)]",
+ ghost: "hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",
+ link: "text-[var(--primary)] underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-9 w-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
+);
+
+export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps {
+ asChild?: boolean;
+}
+
+const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return ;
+});
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
new file mode 100644
index 0000000..6a85405
--- /dev/null
+++ b/src/components/ui/card.tsx
@@ -0,0 +1,35 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Card = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+Card.displayName = "Card";
+
+const CardHeader = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+CardHeader.displayName = "CardHeader";
+
+const CardTitle = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+CardTitle.displayName = "CardTitle";
+
+const CardDescription = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+CardDescription.displayName = "CardDescription";
+
+const CardContent = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+CardContent.displayName = "CardContent";
+
+const CardFooter = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+CardFooter.displayName = "CardFooter";
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..b79867e
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,18 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Input = React.forwardRef>(({ className, type, ...props }, ref) => (
+
+));
+Input.displayName = "Input";
+
+export { Input };
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
new file mode 100644
index 0000000..82e5939
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const NativeSelect = React.forwardRef>(({ className, children, ...props }, ref) => (
+
+));
+NativeSelect.displayName = "NativeSelect";
+
+export { NativeSelect };
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
new file mode 100644
index 0000000..151b7f3
--- /dev/null
+++ b/src/components/ui/separator.tsx
@@ -0,0 +1,16 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Separator = React.forwardRef & { orientation?: "horizontal" | "vertical" }>(
+ ({ className, orientation = "horizontal", ...props }, ref) => (
+
+ ),
+);
+Separator.displayName = "Separator";
+
+export { Separator };
diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx
new file mode 100644
index 0000000..bb47959
--- /dev/null
+++ b/src/components/ui/switch.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+import * as SwitchPrimitives from "@radix-ui/react-switch";
+
+import { cn } from "@/lib/utils";
+
+const Switch = React.forwardRef, React.ComponentPropsWithoutRef>(({ className, ...props }, ref) => (
+
+
+
+));
+Switch.displayName = SwitchPrimitives.Root.displayName;
+
+export { Switch };
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..b0ada83
--- /dev/null
+++ b/src/components/ui/textarea.tsx
@@ -0,0 +1,17 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Textarea = React.forwardRef>(({ className, ...props }, ref) => (
+
+));
+Textarea.displayName = "Textarea";
+
+export { Textarea };
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..a5ef193
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/src/styles.css b/src/styles.css
index 0ce8bf3..5de7f1a 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,9 +1,41 @@
+@import "tailwindcss";
+
:root {
font-family: Inter, "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
- color: #1c2329;
- background: #eef1f4;
+ color: var(--foreground);
+ background: var(--background);
font-synthesis: none;
text-rendering: optimizeLegibility;
+ --background: #f8fafc;
+ --foreground: #0f172a;
+ --card: #ffffff;
+ --card-foreground: #0f172a;
+ --popover: #ffffff;
+ --popover-foreground: #0f172a;
+ --primary: #0f766e;
+ --primary-hover: #115e59;
+ --primary-foreground: #ffffff;
+ --secondary: #f1f5f9;
+ --secondary-hover: #e2e8f0;
+ --secondary-foreground: #0f172a;
+ --muted: #f1f5f9;
+ --muted-foreground: #64748b;
+ --accent: #f1f5f9;
+ --accent-foreground: #0f172a;
+ --destructive: #dc2626;
+ --destructive-hover: #b91c1c;
+ --destructive-foreground: #ffffff;
+ --destructive-muted: #fef2f2;
+ --destructive-border: #fecaca;
+ --border: #e2e8f0;
+ --input: #cbd5e1;
+ --ring: #0f766e;
+ --success: #047857;
+ --success-muted: #ecfdf5;
+ --success-border: #a7f3d0;
+ --warning: #92400e;
+ --warning-muted: #fffbeb;
+ --warning-border: #fde68a;
}
* {
@@ -12,6 +44,7 @@
body {
margin: 0;
+ background: var(--background);
}
button,
@@ -53,12 +86,23 @@ button {
font-size: 26px;
}
+.login-panel h3 {
+ margin: 0;
+ font-size: 26px;
+ line-height: 1.2;
+}
+
.login-note {
margin: -8px 0 4px;
color: #66727b;
font-size: 14px;
}
+.login-form-stack {
+ display: grid;
+ gap: 18px;
+}
+
label {
display: grid;
gap: 8px;
@@ -467,15 +511,21 @@ textarea {
.page-rail,
.module-rail {
+ align-self: start;
display: grid;
align-content: start;
- gap: 8px;
+ gap: 10px;
+ height: fit-content;
+ max-height: calc(100vh - 190px);
+ overflow-x: hidden;
+ overflow-y: auto;
}
.page-rail button,
.module-rail button,
.mapped-list button {
width: 100%;
+ height: auto;
min-width: 0;
border: 1px solid #e0e6eb;
border-radius: 7px;
@@ -491,10 +541,13 @@ textarea {
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: center;
+ min-height: 58px;
+ white-space: normal;
}
.module-rail button {
- grid-template-columns: 30px minmax(0, 1fr);
+ grid-template-columns: 32px minmax(0, 1fr);
+ min-height: 56px;
}
.page-rail button.active,
@@ -517,6 +570,13 @@ textarea {
white-space: nowrap;
}
+.page-rail button > span,
+.module-rail button > span {
+ min-width: 0;
+ display: grid;
+ gap: 4px;
+}
+
.page-rail small,
.module-rail small,
.mapped-list small,
@@ -524,6 +584,17 @@ textarea {
color: #68747d;
}
+.page-rail small,
+.module-rail small {
+ overflow: hidden;
+ display: -webkit-box;
+ line-height: 1.35;
+ text-overflow: clip;
+ white-space: normal;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+}
+
.module-rail em {
display: grid;
place-items: center;
@@ -550,7 +621,21 @@ textarea {
.front-context b,
.front-context small {
+ overflow: hidden;
display: block;
+ line-height: 1.45;
+}
+
+.front-context b {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.front-context small {
+ display: -webkit-box;
+ white-space: normal;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
}
.item-rail > p {
@@ -1339,6 +1424,287 @@ textarea {
padding: 20px;
}
+/* shadcn-style surface refresh */
+.login-shell,
+.admin-shell {
+ background:
+ radial-gradient(circle at top left, rgba(15, 118, 110, 0.08), transparent 34rem),
+ var(--background);
+}
+
+.login-panel,
+.page-rail,
+.page-focus-card,
+.module-rail,
+.item-rail,
+.edit-rail,
+.metric-card,
+.data-panel,
+.editor-pane,
+.list-pane,
+.product-list-page,
+.product-detail-page,
+.product-editor-sidebar,
+.lead-table,
+.admin-disclosure,
+.detail-section-card,
+.detail-block-card,
+.destination-row,
+.front-context,
+.product-list-summary span,
+.product-side-meta span,
+.image-editor-row,
+.phone-preview {
+ border-color: var(--border);
+ background: var(--card);
+ color: var(--card-foreground);
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
+}
+
+.login-panel,
+.page-rail,
+.page-focus-card,
+.module-rail,
+.item-rail,
+.edit-rail,
+.product-list-page,
+.product-detail-page,
+.lead-table {
+ border-radius: 10px;
+}
+
+label,
+.login-note,
+.section-head p,
+.topbar small,
+.metric-card span,
+.dense-list small,
+.destination-row small,
+.product-table small,
+.lead-row small,
+.page-focus-card small,
+.page-rail small,
+.module-rail small,
+.mapped-list small,
+.editor-head small,
+.item-rail > p,
+.field-help,
+.product-editor-sidebar p,
+.product-side-meta small,
+.muted,
+.empty-state {
+ color: var(--muted-foreground);
+}
+
+input,
+select,
+textarea {
+ border-color: var(--input);
+ border-radius: 8px;
+ color: var(--foreground);
+ background: var(--background);
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
+ transition:
+ border-color 150ms ease,
+ box-shadow 150ms ease,
+ background 150ms ease;
+}
+
+input:focus,
+select:focus,
+textarea:focus,
+button:focus-visible,
+summary:focus-visible {
+ outline: 2px solid transparent;
+ box-shadow: 0 0 0 2px var(--ring);
+}
+
+.primary-action {
+ border: 1px solid var(--primary);
+ border-radius: 8px;
+ background: var(--primary);
+ color: var(--primary-foreground);
+}
+
+.primary-action:hover {
+ background: var(--primary-hover);
+}
+
+.section-head button,
+.toolbar button,
+.action-row button,
+.icon-action,
+.inline-action {
+ border-color: var(--input);
+ border-radius: 8px;
+ background: var(--card);
+ color: var(--foreground);
+}
+
+.section-head button:hover,
+.toolbar button:hover,
+.action-row button:hover,
+.icon-action:hover,
+.inline-action:hover,
+.page-rail button:hover,
+.module-rail button:hover,
+.mapped-list button:hover,
+.product-table button:hover {
+ background: var(--accent);
+}
+
+.sidebar {
+ background: var(--card);
+ color: var(--foreground);
+ border-right: 1px solid var(--border);
+}
+
+.brand-block span,
+.sidebar-group > span,
+.sidebar button small {
+ color: var(--muted-foreground);
+}
+
+.sidebar button {
+ color: var(--foreground);
+ border: 1px solid transparent;
+}
+
+.sidebar button.active {
+ color: var(--primary);
+ background: var(--success-muted);
+ border-color: var(--success-border);
+ box-shadow: none;
+}
+
+.sidebar button.active small {
+ color: var(--primary);
+}
+
+.logout-button {
+ border-top-color: var(--border) !important;
+}
+
+.topbar {
+ background: color-mix(in srgb, var(--card) 92%, transparent);
+ border-bottom-color: var(--border);
+ backdrop-filter: blur(12px);
+}
+
+.admin-dirty-chip {
+ border-color: var(--border);
+ color: var(--muted-foreground);
+ background: var(--muted);
+}
+
+.admin-dirty-chip.is-dirty,
+.form-error,
+.notice {
+ border: 1px solid var(--warning-border);
+ color: var(--warning);
+ background: var(--warning-muted);
+}
+
+.page-focus-card {
+ background: var(--card);
+}
+
+.page-focus-card .focus-kicker,
+.module-rail em,
+.module-index {
+ color: var(--primary);
+ background: var(--success-muted);
+}
+
+.page-rail button,
+.module-rail button,
+.mapped-list button,
+.product-table button {
+ border-color: var(--border);
+ border-radius: 8px;
+ background: var(--card);
+}
+
+.page-rail button.active,
+.module-rail button.active,
+.mapped-list button.selected,
+.product-table button.selected {
+ border-color: var(--primary);
+ background: var(--success-muted);
+}
+
+.front-context,
+.mini-product-stack span,
+.product-list-summary span,
+.product-editor-sidebar,
+.image-editor-row,
+.detail-section-card {
+ background: var(--muted);
+}
+
+.admin-disclosure[open] {
+ border-color: var(--success-border);
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
+}
+
+.admin-disclosure-meta em {
+ color: var(--primary);
+ background: var(--success-muted);
+}
+
+.mapped-editor .asset-preview,
+.product-cover-preview,
+.image-editor-preview,
+.image-placeholder {
+ border-color: var(--border);
+ background: var(--muted);
+}
+
+.status-chip {
+ border-radius: 6px;
+}
+
+.status-chip.published {
+ color: var(--success);
+ background: var(--success-muted);
+}
+
+.status-chip.draft {
+ color: var(--warning);
+ background: var(--warning-muted);
+}
+
+.status-chip.archived {
+ color: var(--muted-foreground);
+ background: var(--muted);
+}
+
+.row-link,
+.product-table em,
+.destination-row em,
+.dense-list em {
+ color: var(--primary);
+}
+
+.inline-action.strong {
+ border-color: var(--success-border);
+ color: var(--primary);
+ background: var(--success-muted);
+}
+
+.danger-icon {
+ color: var(--destructive) !important;
+}
+
+.lead-table-head {
+ color: var(--muted-foreground);
+ background: var(--muted);
+}
+
+.lead-row {
+ border-top-color: var(--border);
+}
+
@media (max-width: 980px) {
.admin-shell {
grid-template-columns: 72px minmax(0, 1fr);
diff --git a/tsconfig.json b/tsconfig.json
index 4053da4..70dee15 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,6 +7,7 @@
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
+ "ignoreDeprecations": "6.0",
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
@@ -14,7 +15,11 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react-jsx"
+ "jsx": "react-jsx",
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"]
+ }
},
"include": ["src"]
}
diff --git a/vite.config.ts b/vite.config.ts
index df1b459..d7c763c 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,8 +1,15 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
+import tailwindcss from "@tailwindcss/vite";
+import path from "node:path";
export default defineConfig({
- plugins: [react()],
+ plugins: [react(), tailwindcss()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
server: {
port: 5601,
proxy: {
diff --git a/yarn.lock b/yarn.lock
index 638479e..23c0daa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,7 +2,7 @@
# yarn lockfile v1
-"@emnapi/core@1.11.1":
+"@emnapi/core@1.11.1", "@emnapi/core@^1.11.1":
version "1.11.1"
resolved "https://registry.npmmirror.com/@emnapi/core/-/core-1.11.1.tgz#b9e1064f3a6b1631e241e638eb48d736bfd372a6"
integrity sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==
@@ -10,21 +10,82 @@
"@emnapi/wasi-threads" "1.2.2"
tslib "^2.4.0"
-"@emnapi/runtime@1.11.1":
+"@emnapi/runtime@1.11.1", "@emnapi/runtime@^1.11.1":
version "1.11.1"
resolved "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.1.tgz#58f1f3d5d81a9b12f793ab688c96371901027c24"
integrity sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==
dependencies:
tslib "^2.4.0"
-"@emnapi/wasi-threads@1.2.2":
+"@emnapi/wasi-threads@1.2.2", "@emnapi/wasi-threads@^1.2.2":
version "1.2.2"
resolved "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz#4c93becf5bfa3b13d1bbdcc06aee38321ad8139a"
integrity sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==
dependencies:
tslib "^2.4.0"
-"@napi-rs/wasm-runtime@^1.1.6":
+"@floating-ui/core@^1.7.5":
+ version "1.7.5"
+ resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz#d4af157a03330af5a60e69da7a4692507ada0622"
+ integrity sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==
+ dependencies:
+ "@floating-ui/utils" "^0.2.11"
+
+"@floating-ui/dom@^1.7.6":
+ version "1.7.6"
+ resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.6.tgz#f915bba5abbb177e1f227cacee1b4d0634b187bf"
+ integrity sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==
+ dependencies:
+ "@floating-ui/core" "^1.7.5"
+ "@floating-ui/utils" "^0.2.11"
+
+"@floating-ui/react-dom@^2.0.0":
+ version "2.1.8"
+ resolved "https://registry.npmmirror.com/@floating-ui/react-dom/-/react-dom-2.1.8.tgz#5fb5a20d10aafb9505f38c24f38d00c8e1598893"
+ integrity sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==
+ dependencies:
+ "@floating-ui/dom" "^1.7.6"
+
+"@floating-ui/utils@^0.2.11":
+ version "0.2.11"
+ resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.11.tgz#a269e055e40e2f45873bae9d1a2fdccbd314ea3f"
+ integrity sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==
+
+"@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.13"
+ resolved "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f"
+ integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.5.0"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/remapping@^2.3.5":
+ version "2.3.5"
+ resolved "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1"
+ integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.2"
+ resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5":
+ version "1.5.5"
+ resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba"
+ integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==
+
+"@jridgewell/trace-mapping@^0.3.24":
+ version "0.3.31"
+ resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0"
+ integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@napi-rs/wasm-runtime@^1.1.4", "@napi-rs/wasm-runtime@^1.1.6":
version "1.1.6"
resolved "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz#ed33806d0f9be98dc76d0c3d4fd872fda701b5d5"
integrity sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==
@@ -36,6 +97,222 @@
resolved "https://registry.npmmirror.com/@oxc-project/types/-/types-0.137.0.tgz#56e77f8bb221fa05f18b1cd34d73f94f0954a773"
integrity sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==
+"@radix-ui/number@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/number/-/number-1.1.2.tgz#3ace52303a4a570d03dc79bf17d6da49ed40d0cf"
+ integrity sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==
+
+"@radix-ui/primitive@1.1.4":
+ version "1.1.4"
+ resolved "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.4.tgz#47ef0f6cff4a1a1c09ebbf6d79159b7f01b967cf"
+ integrity sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==
+
+"@radix-ui/react-arrow@1.1.11":
+ version "1.1.11"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz#be2a068bffe4453bd6941fc44eed1f1ea0e8226f"
+ integrity sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==
+ dependencies:
+ "@radix-ui/react-primitive" "2.1.7"
+
+"@radix-ui/react-collection@1.1.11":
+ version "1.1.11"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.11.tgz#816b5262e7c6af77fee7b67f2fbb2743f80698ea"
+ integrity sha512-djW9+zeg137KQdlPtmE8xnaD+K2rcXXMWFrSg0hsmYZ6HRbdTA7tDHFgpaW9+huWVEu0RCabL+985T4TA0BE7g==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-context" "1.1.4"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-slot" "1.3.0"
+
+"@radix-ui/react-compose-refs@1.1.3":
+ version "1.1.3"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz#5f1e61e1a5f52800d31e7f8affa6d046e38f50d1"
+ integrity sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==
+
+"@radix-ui/react-context@1.1.4":
+ version "1.1.4"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.1.4.tgz#5e39f26ebbefed27836e46e763e8f71e09999ccd"
+ integrity sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==
+
+"@radix-ui/react-direction@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.1.2.tgz#9cc69edd659d79fba4101ee0e2dbcffc2024504f"
+ integrity sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==
+
+"@radix-ui/react-dismissable-layer@1.1.14":
+ version "1.1.14"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.14.tgz#7d911f0c456463ac4af65fbcd356161d6512afb3"
+ integrity sha512-4lUhWTWAjbDIqFrAPWJ3WqBOpO5YchVZ88X3nh6H9Lu5AFi5nCUeTPj3D8FSDmabmFeRe9ME0BDA4MwKTha5GQ==
+ dependencies:
+ "@radix-ui/primitive" "1.1.4"
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-use-callback-ref" "1.1.2"
+ "@radix-ui/react-use-effect-event" "0.0.3"
+
+"@radix-ui/react-focus-guards@1.1.4":
+ version "1.1.4"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz#3ef07a117ae7aa1430442aaebd766507e69d391c"
+ integrity sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==
+
+"@radix-ui/react-focus-scope@1.1.11":
+ version "1.1.11"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.11.tgz#d34a0a181842582ae0b82c2244672894debf33f9"
+ integrity sha512-Mn88Vg2whaRocGJNOH+DKFqYm6ySFPQaiwHNxZPyjn99B52KAEJWWY9NP83+nWdk2HM3rdov+STu9AG471Rt9w==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-use-callback-ref" "1.1.2"
+
+"@radix-ui/react-id@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.1.2.tgz#6fe97e7289c7133b44f8c9c61fdddf2a6be1421d"
+ integrity sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-popper@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.3.2.tgz#5c24ca8a68ae2d52437760b59b041f6b96e1a9ec"
+ integrity sha512-3QXNeMkdshed1MR3LNoiCirBywRFPkD8ETJa/HlPuLwSajaQixf2ro+isoDNJlGABg9ug41XuZpINZJIle4XWg==
+ dependencies:
+ "@floating-ui/react-dom" "^2.0.0"
+ "@radix-ui/react-arrow" "1.1.11"
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-context" "1.1.4"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-use-callback-ref" "1.1.2"
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+ "@radix-ui/react-use-rect" "1.1.2"
+ "@radix-ui/react-use-size" "1.1.2"
+ "@radix-ui/rect" "1.1.2"
+
+"@radix-ui/react-portal@1.1.13":
+ version "1.1.13"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.13.tgz#8b80b8b33ef4fff449c6d3ab62492f4dca162c7e"
+ integrity sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==
+ dependencies:
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-presence@1.1.6":
+ version "1.1.6"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.6.tgz#f0edff4f119dbc8ef81611e539a8f58d9afb33c3"
+ integrity sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-primitive@2.1.7":
+ version "2.1.7"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz#1f487a06434770f865dbfb6c9a55bbefcbad8c82"
+ integrity sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==
+ dependencies:
+ "@radix-ui/react-slot" "1.3.0"
+
+"@radix-ui/react-select@^2.3.2":
+ version "2.3.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-select/-/react-select-2.3.2.tgz#3ef8b0593c10fe78e067db6133c253c03321f1f2"
+ integrity sha512-brXD6C/V0fVK0DDbscLVw6LsXrjQ+ay8jdOBaN+tLb4vsHsAMm6Gt6eT77wHX1Eq8GPtD5rJ+RxFtfDozsb4+Q==
+ dependencies:
+ "@radix-ui/number" "1.1.2"
+ "@radix-ui/primitive" "1.1.4"
+ "@radix-ui/react-collection" "1.1.11"
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-context" "1.1.4"
+ "@radix-ui/react-direction" "1.1.2"
+ "@radix-ui/react-dismissable-layer" "1.1.14"
+ "@radix-ui/react-focus-guards" "1.1.4"
+ "@radix-ui/react-focus-scope" "1.1.11"
+ "@radix-ui/react-id" "1.1.2"
+ "@radix-ui/react-popper" "1.3.2"
+ "@radix-ui/react-portal" "1.1.13"
+ "@radix-ui/react-presence" "1.1.6"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-slot" "1.3.0"
+ "@radix-ui/react-use-callback-ref" "1.1.2"
+ "@radix-ui/react-use-controllable-state" "1.2.3"
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+ "@radix-ui/react-use-previous" "1.1.2"
+ "@radix-ui/react-visually-hidden" "1.2.7"
+ aria-hidden "^1.2.4"
+ react-remove-scroll "^2.7.2"
+
+"@radix-ui/react-slot@1.3.0", "@radix-ui/react-slot@^1.3.0":
+ version "1.3.0"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.3.0.tgz#e311c7a6c8d65b1af9e69af8e3318c6c7105a212"
+ integrity sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.3"
+
+"@radix-ui/react-switch@^1.3.2":
+ version "1.3.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-switch/-/react-switch-1.3.2.tgz#921e56db774a1b7500f1404bf355a241ac354b0a"
+ integrity sha512-tgRBI3DdNwAJYE4BBZyZcz/HRRCvAsPkRvG1wvKc+41tBGMxPn/a87T/wikXAvyDypNQ9kaZwHbeZe+veHCGpA==
+ dependencies:
+ "@radix-ui/primitive" "1.1.4"
+ "@radix-ui/react-compose-refs" "1.1.3"
+ "@radix-ui/react-context" "1.1.4"
+ "@radix-ui/react-primitive" "2.1.7"
+ "@radix-ui/react-use-controllable-state" "1.2.3"
+ "@radix-ui/react-use-previous" "1.1.2"
+ "@radix-ui/react-use-size" "1.1.2"
+
+"@radix-ui/react-use-callback-ref@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz#ddc0bc1381ff3b62368c248808efc45a098bafde"
+ integrity sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==
+
+"@radix-ui/react-use-controllable-state@1.2.3":
+ version "1.2.3"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz#516996f6443207546aa15a59bc71cdf5b54e01d1"
+ integrity sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==
+ dependencies:
+ "@radix-ui/react-use-effect-event" "0.0.3"
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-use-effect-event@0.0.3":
+ version "0.0.3"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz#e8f45e8e6ef64ce5bea7b5a9effc373f067e3530"
+ integrity sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-use-layout-effect@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz#c882e66497174d061f250e65251974b699c65b65"
+ integrity sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==
+
+"@radix-ui/react-use-previous@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.2.tgz#8fd78d5874de9c150e7b21ab1a411d5bc1a26257"
+ integrity sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==
+
+"@radix-ui/react-use-rect@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz#83b9de1ea8f6abd1425eb79f2930e00047cb8d19"
+ integrity sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==
+ dependencies:
+ "@radix-ui/rect" "1.1.2"
+
+"@radix-ui/react-use-size@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz#33eb275755424d7dda33ffa32c23ea85ca23be40"
+ integrity sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.2"
+
+"@radix-ui/react-visually-hidden@1.2.7":
+ version "1.2.7"
+ resolved "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz#64fc5994ebd39b3b19f4e93c11da22bf03af684b"
+ integrity sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==
+ dependencies:
+ "@radix-ui/react-primitive" "2.1.7"
+
+"@radix-ui/rect@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.npmmirror.com/@radix-ui/rect/-/rect-1.1.2.tgz#0761a82af55c7e302d5b509eaf1c97ea1fc5feea"
+ integrity sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==
+
"@rolldown/binding-android-arm64@1.1.3":
version "1.1.3"
resolved "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz#cc6153029c3d9afc9caaae2dc362d899ae94ac4f"
@@ -120,13 +397,127 @@
resolved "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz#e3fcee093fbb5ce765e1ad088ff4de2889f6f9be"
integrity sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==
-"@tybys/wasm-util@^0.10.3":
+"@tailwindcss/node@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/node/-/node-4.3.2.tgz#2ba563b05ff662b9172c9645d78a5edd59f96eb3"
+ integrity sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==
+ dependencies:
+ "@jridgewell/remapping" "^2.3.5"
+ enhanced-resolve "5.21.6"
+ jiti "^2.7.0"
+ lightningcss "1.32.0"
+ magic-string "^0.30.21"
+ source-map-js "^1.2.1"
+ tailwindcss "4.3.2"
+
+"@tailwindcss/oxide-android-arm64@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz#add4f8eba265b20b14634a22717621a3350cd6d4"
+ integrity sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==
+
+"@tailwindcss/oxide-darwin-arm64@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz#2439b7c991679c006d16ed00264c60d540567554"
+ integrity sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==
+
+"@tailwindcss/oxide-darwin-x64@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz#016ffbb375bb5feabab0fd42c744b3cf21647968"
+ integrity sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==
+
+"@tailwindcss/oxide-freebsd-x64@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz#6fe112b103ff659671483293c61c853651635ee0"
+ integrity sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==
+
+"@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz#30fffb495ac59ea01046ee48c2bfa247ca6eda5e"
+ integrity sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==
+
+"@tailwindcss/oxide-linux-arm64-gnu@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz#910f4754e9aa8f8b04c018bebab627a52bd568b9"
+ integrity sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==
+
+"@tailwindcss/oxide-linux-arm64-musl@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz#bdb9861bb5064209ec5ff101afff6d046fb15ecd"
+ integrity sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==
+
+"@tailwindcss/oxide-linux-x64-gnu@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz#424276287610607303a35f52f2a172b95af4898a"
+ integrity sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==
+
+"@tailwindcss/oxide-linux-x64-musl@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz#606d5dc2fd7d2e8cdd7d1f1c4a1f4d5639056e05"
+ integrity sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==
+
+"@tailwindcss/oxide-wasm32-wasi@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz#f5d4ed2bcd12507217cc1a92e4fc507fdac6dd8c"
+ integrity sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==
+ dependencies:
+ "@emnapi/core" "^1.11.1"
+ "@emnapi/runtime" "^1.11.1"
+ "@emnapi/wasi-threads" "^1.2.2"
+ "@napi-rs/wasm-runtime" "^1.1.4"
+ "@tybys/wasm-util" "^0.10.2"
+ tslib "^2.8.1"
+
+"@tailwindcss/oxide-win32-arm64-msvc@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz#a4ec761083fef55c530e204fad43edba629ea1bf"
+ integrity sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==
+
+"@tailwindcss/oxide-win32-x64-msvc@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz#38bf0e3878d17afedb0260758b661973b2d9de70"
+ integrity sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==
+
+"@tailwindcss/oxide@4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/oxide/-/oxide-4.3.2.tgz#82157fb0d5bebf1188234855c5b7dc754da54065"
+ integrity sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==
+ optionalDependencies:
+ "@tailwindcss/oxide-android-arm64" "4.3.2"
+ "@tailwindcss/oxide-darwin-arm64" "4.3.2"
+ "@tailwindcss/oxide-darwin-x64" "4.3.2"
+ "@tailwindcss/oxide-freebsd-x64" "4.3.2"
+ "@tailwindcss/oxide-linux-arm-gnueabihf" "4.3.2"
+ "@tailwindcss/oxide-linux-arm64-gnu" "4.3.2"
+ "@tailwindcss/oxide-linux-arm64-musl" "4.3.2"
+ "@tailwindcss/oxide-linux-x64-gnu" "4.3.2"
+ "@tailwindcss/oxide-linux-x64-musl" "4.3.2"
+ "@tailwindcss/oxide-wasm32-wasi" "4.3.2"
+ "@tailwindcss/oxide-win32-arm64-msvc" "4.3.2"
+ "@tailwindcss/oxide-win32-x64-msvc" "4.3.2"
+
+"@tailwindcss/vite@^4.3.2":
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/@tailwindcss/vite/-/vite-4.3.2.tgz#35787e4d450a6b2430693245483441cfd78bf612"
+ integrity sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==
+ dependencies:
+ "@tailwindcss/node" "4.3.2"
+ "@tailwindcss/oxide" "4.3.2"
+ tailwindcss "4.3.2"
+
+"@tybys/wasm-util@^0.10.2", "@tybys/wasm-util@^0.10.3":
version "0.10.3"
resolved "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz#015cba9e9dd47ce14d03d2a8c5d547bfb169665d"
integrity sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==
dependencies:
tslib "^2.4.0"
+"@types/node@^26.0.1":
+ version "26.0.1"
+ resolved "https://registry.npmmirror.com/@types/node/-/node-26.0.1.tgz#4a60e2c7a6d68bd261e265f8983bfe1601263ce3"
+ integrity sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==
+ dependencies:
+ undici-types "~8.3.0"
+
"@types/react-dom@^19.2.3":
version "19.2.3"
resolved "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c"
@@ -146,6 +537,25 @@
dependencies:
"@rolldown/pluginutils" "^1.0.1"
+aria-hidden@^1.2.4:
+ version "1.2.6"
+ resolved "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a"
+ integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==
+ dependencies:
+ tslib "^2.0.0"
+
+class-variance-authority@^0.7.1:
+ version "0.7.1"
+ resolved "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz#4008a798a0e4553a781a57ac5177c9fb5d043787"
+ integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==
+ dependencies:
+ clsx "^2.1.1"
+
+clsx@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
csstype@^3.2.2:
version "3.2.3"
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
@@ -156,6 +566,19 @@ detect-libc@^2.0.3:
resolved "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
+detect-node-es@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
+ integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
+enhanced-resolve@5.21.6:
+ version "5.21.6"
+ resolved "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz#aa207b43cf658e6ab3ba06896edc00c13c3127c6"
+ integrity sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.3.3"
+
fdir@^6.5.0:
version "6.5.0"
resolved "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350"
@@ -166,6 +589,21 @@ fsevents@~2.3.3:
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+get-nonce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
+ integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
+graceful-fs@^4.2.4:
+ version "4.2.11"
+ resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+jiti@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz#974228f2f4ca2bc21885a1797b45fea68e950c64"
+ integrity sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==
+
lightningcss-android-arm64@1.32.0:
version "1.32.0"
resolved "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz#f033885116dfefd9c6f54787523e3514b61e1968"
@@ -221,7 +659,7 @@ lightningcss-win32-x64-msvc@1.32.0:
resolved "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz#141aa5605645064928902bb4af045fa7d9f4220a"
integrity sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==
-lightningcss@^1.32.0:
+lightningcss@1.32.0, lightningcss@^1.32.0:
version "1.32.0"
resolved "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz#b85aae96486dcb1bf49a7c8571221273f4f1e4a9"
integrity sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==
@@ -245,6 +683,13 @@ lucide-react@^1.21.0:
resolved "https://registry.npmmirror.com/lucide-react/-/lucide-react-1.22.0.tgz#f2930b21a1d3941fbee8a1017a5973d06ec4860b"
integrity sha512-c9o3l0PiNcgOQDW4F31BEYHudE7kgxVt3o30qMl36ZPwTxXlGB4QnLilhERvVM4uh/pl5MDyY1/gzZSYcHDtBg==
+magic-string@^0.30.21:
+ version "0.30.21"
+ resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91"
+ integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.5.5"
+
nanoid@^3.3.12:
version "3.3.15"
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.15.tgz#36c490fad8c6e86c824c940dfdde999b69ed4316"
@@ -276,6 +721,33 @@ react-dom@^19.2.7:
dependencies:
scheduler "^0.27.0"
+react-remove-scroll-bar@^2.3.7:
+ version "2.3.8"
+ resolved "https://registry.npmmirror.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223"
+ integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==
+ dependencies:
+ react-style-singleton "^2.2.2"
+ tslib "^2.0.0"
+
+react-remove-scroll@^2.7.2:
+ version "2.7.2"
+ resolved "https://registry.npmmirror.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz#6442da56791117661978ae99cd29be9026fecca0"
+ integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==
+ dependencies:
+ react-remove-scroll-bar "^2.3.7"
+ react-style-singleton "^2.2.3"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.3"
+ use-sidecar "^1.1.3"
+
+react-style-singleton@^2.2.2, react-style-singleton@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.npmmirror.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388"
+ integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==
+ dependencies:
+ get-nonce "^1.0.0"
+ tslib "^2.0.0"
+
react@^19.2.7:
version "19.2.7"
resolved "https://registry.npmmirror.com/react/-/react-19.2.7.tgz#1f47a1bfc06f8ec885752c6f4af14369a9f8260b"
@@ -315,6 +787,21 @@ source-map-js@^1.2.1:
resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+tailwind-merge@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.6.0.tgz#88d83242d1dd7bc847223f73dcf210dd1f2ee11c"
+ integrity sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==
+
+tailwindcss@4.3.2, tailwindcss@^4.3.2:
+ version "4.3.2"
+ resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.3.2.tgz#408ee67d767a0fef7b174674bb9c5ce136a5ace1"
+ integrity sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==
+
+tapable@^2.3.3:
+ version "2.3.3"
+ resolved "https://registry.npmmirror.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160"
+ integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==
+
tinyglobby@^0.2.17:
version "0.2.17"
resolved "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631"
@@ -323,7 +810,7 @@ tinyglobby@^0.2.17:
fdir "^6.5.0"
picomatch "^4.0.4"
-tslib@^2.4.0:
+tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.1:
version "2.8.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -333,6 +820,26 @@ typescript@^6.0.3:
resolved "https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21"
integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==
+undici-types@~8.3.0:
+ version "8.3.0"
+ resolved "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz#44e9fc9f3244648cdea35e4f9bb2d681e9410809"
+ integrity sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==
+
+use-callback-ref@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf"
+ integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==
+ dependencies:
+ tslib "^2.0.0"
+
+use-sidecar@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.npmmirror.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb"
+ integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==
+ dependencies:
+ detect-node-es "^1.1.0"
+ tslib "^2.0.0"
+
vite@^8.1.0:
version "8.1.0"
resolved "https://registry.npmmirror.com/vite/-/vite-8.1.0.tgz#0734dc1a48faeb2bd5f5b16b66dcbfae484fec55"