diff --git a/web/biome.json b/web/biome.json index cbff8337..525a77f2 100644 --- a/web/biome.json +++ b/web/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", "vcs": { "enabled": true, "clientKind": "git", @@ -13,7 +13,17 @@ "noExplicitAny": "off" }, "style": { - "useImportType": "off" + "useImportType": "off", + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error" }, "recommended": true, "a11y": { @@ -24,19 +34,16 @@ "noUnusedImports": "warn" } }, - "ignore": ["node_modules", "tsconfig*", "dist", "components/ui/**"] + "includes": ["**", "!**/node_modules", "!**/tsconfig*", "!**/dist", "!**/components/ui/**"] }, "formatter": { "indentStyle": "space", "indentWidth": 2, "enabled": true, "lineWidth": 120, - "ignore": ["node_modules", "tsconfig*", "dist"] - }, - "organizeImports": { - "enabled": true, - "ignore": ["node_modules", "dist", "components/ui/**"] + "includes": ["**", "!**/node_modules", "!**/tsconfig*", "!**/dist"] }, + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "javascript": { "formatter": { "quoteStyle": "double" diff --git a/web/bun.lockb b/web/bun.lockb index c5072ad1..c6973a84 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/copy-build.js b/web/copy-build.js index 27f3d3de..3be0c363 100644 --- a/web/copy-build.js +++ b/web/copy-build.js @@ -1,4 +1,4 @@ -import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; +import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { cp } from "node:fs/promises"; import { join, resolve } from "node:path"; diff --git a/web/package.json b/web/package.json index 2171b7b4..0e91cd98 100644 --- a/web/package.json +++ b/web/package.json @@ -14,67 +14,46 @@ "lint:fix": "bunx @biomejs/biome check ./ --write" }, "devDependencies": { - "@biomejs/biome": "1.9.4", - "@types/node": "^22.15.29", - "@types/react": "^19.1.6", + "@biomejs/biome": "2.0.5", + "@types/node": "^24.0.4", + "@types/react": "^19.1.8", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^19.1.6", "@types/react-syntax-highlighter": "^15.5.13", - "@vitejs/plugin-react": "^4.5.1", + "@vitejs/plugin-react": "^4.6.0", "rimraf": "^6.0.1", - "tailwindcss": "^4.1.8", + "tailwindcss": "^4.1.10", "typescript": "^5.8.3", - "vite": "^6.3.5", + "vite": "^7.0.0", "vite-bundle-visualizer": "^1.2.1" }, "dependencies": { - "@hookform/resolvers": "^5.0.1", - "@radix-ui/react-accordion": "^1.2.11", - "@radix-ui/react-alert-dialog": "^1.1.14", - "@radix-ui/react-aspect-ratio": "^1.1.7", - "@radix-ui/react-avatar": "^1.1.10", - "@radix-ui/react-checkbox": "^1.3.2", - "@radix-ui/react-context-menu": "^2.2.15", - "@radix-ui/react-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.15", - "@radix-ui/react-hover-card": "^1.1.14", - "@radix-ui/react-label": "^2.1.7", - "@radix-ui/react-menubar": "^1.1.15", + "@hookform/resolvers": "^5.1.1", "@radix-ui/react-navigation-menu": "^1.2.13", "@radix-ui/react-popover": "^1.1.14", - "@radix-ui/react-progress": "^1.1.7", - "@radix-ui/react-radio-group": "^1.3.7", - "@radix-ui/react-scroll-area": "^1.2.9", - "@radix-ui/react-select": "^2.2.5", - "@radix-ui/react-separator": "^1.1.7", - "@radix-ui/react-slot": "^1.2.3", - "@radix-ui/react-switch": "^1.2.5", - "@radix-ui/react-tabs": "^1.1.12", - "@radix-ui/react-toggle": "^1.1.9", - "@radix-ui/react-toggle-group": "^1.1.10", - "@radix-ui/react-tooltip": "^1.2.7", - "@tailwindcss/vite": "^4.1.8", - "@tanstack/react-query": "^5.80.3", + "@tailwindcss/vite": "^4.1.10", + "@tanstack/react-query": "^5.81.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "date-fns": "^4.1.0", + "framer-motion": "^12.19.1", "i18next": "^25.2.1", - "lucide-react": "^0.513.0", + "lucide-react": "^0.523.0", + "motion": "^12.19.1", + "radix-ui": "^1.4.2", "react": "^19.1.0", "react-copy-to-clipboard": "^5.1.0", - "react-day-picker": "9.7.0", "react-dom": "^19.1.0", - "react-hook-form": "^7.57.0", - "react-i18next": "^15.5.2", + "react-hook-form": "^7.58.1", + "react-i18next": "^15.5.3", "react-router": "^7.6.2", "react-router-dom": "^7.6.2", "react-syntax-highlighter": "^15.6.1", "sonner": "^2.0.5", - "tailwind-merge": "^3.3.0", - "tailwind-scrollbar": "^4.0.2", + "tailwind-merge": "^3.3.1", "tw-animate-css": "^1.3.4", - "yup": "^1.6.1", - "zod": "^3.25.51" + "yup": "^1.6.1" }, - "trustedDependencies": ["@biomejs/biome"] + "trustedDependencies": [ + "@biomejs/biome" + ] } diff --git a/web/src/components/code-viewer.tsx b/web/src/components/code-viewer.tsx index a9aab28d..19550f1f 100644 --- a/web/src/components/code-viewer.tsx +++ b/web/src/components/code-viewer.tsx @@ -1,5 +1,3 @@ -import { Button, buttonVariants } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; import { VariantProps } from "class-variance-authority"; import { Check, Copy } from "lucide-react"; import { type HTMLProps, type ReactNode, useCallback, useEffect, useState } from "react"; @@ -8,6 +6,8 @@ import { useTranslation } from "react-i18next"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { materialDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import { toast } from "sonner"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; interface CopyButtonProps extends React.ComponentProps<"button"> { value: string; diff --git a/web/src/components/copyable-field.tsx b/web/src/components/copyable-field.tsx index ff31546f..afd2f569 100644 --- a/web/src/components/copyable-field.tsx +++ b/web/src/components/copyable-field.tsx @@ -1,10 +1,10 @@ -import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; import { Check, Copy } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; interface CopyableFieldProps { label: string; diff --git a/web/src/components/layouts/root-layout.tsx b/web/src/components/layouts/root-layout.tsx index f6e6cf16..89a5f1ce 100644 --- a/web/src/components/layouts/root-layout.tsx +++ b/web/src/components/layouts/root-layout.tsx @@ -1,3 +1,5 @@ +import { NavLink } from "react-router"; +import { Outlet } from "react-router-dom"; import { LanguageSwitcher } from "@/components/language-switcher"; import { ModeToggle } from "@/components/mode-toggle.tsx"; import { ThemeProvider } from "@/components/theme-provider.tsx"; @@ -5,7 +7,8 @@ import { Button } from "@/components/ui/button"; import { Toaster } from "@/components/ui/sonner"; import VersionBadge from "@/components/version-badge"; import { GitHubIcon } from "@/icon"; -import { Outlet } from "react-router-dom"; +import { siteConfig } from "@/lib/config"; +import { MobileNav } from "../modile-nav"; export default function RootLayout() { return ( @@ -13,11 +16,21 @@ export default function RootLayout() {
-
-
-

MemShellParty - JavaWeb

+
+ +
+ + MemShellParty +
-
+ +
+ + +
+
+
Menu
+
+ + Home + + {items.map((item) => ( + + {item.label} + + ))} +
+
+
+
+ + ); +} + +function MobileLink({ + href, + className, + children, + onOpenChange, + ...props +}: Readonly<{ + href: string; + onOpenChange?: (open: boolean) => void; + children: React.ReactNode; + className?: string; +}>) { + return ( + { + onOpenChange?.(false); + }} + className={cn("text-2xl font-medium", className)} + {...props} + > + {children} + + ); +} diff --git a/web/src/components/package-config-card.tsx b/web/src/components/package-config-card.tsx index 7e2b2adf..a207bdf6 100644 --- a/web/src/components/package-config-card.tsx +++ b/web/src/components/package-config-card.tsx @@ -1,12 +1,12 @@ +import { PackageIcon } from "lucide-react"; +import { useEffect, useState } from "react"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group.tsx"; import { FormSchema } from "@/types/schema.ts"; import { PackerConfig } from "@/types/shell.ts"; -import { PackageIcon } from "lucide-react"; -import { useEffect, useState } from "react"; -import { FormProvider, UseFormReturn } from "react-hook-form"; -import { useTranslation } from "react-i18next"; type Option = { name: string; diff --git a/web/src/components/quick-usage.tsx b/web/src/components/quick-usage.tsx index 671ed538..d3f993b2 100644 --- a/web/src/components/quick-usage.tsx +++ b/web/src/components/quick-usage.tsx @@ -1,6 +1,6 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { ScrollTextIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; export function QuickUsage() { const { t } = useTranslation(); diff --git a/web/src/components/results/agent.tsx b/web/src/components/results/agent.tsx index 8199e522..40169b03 100644 --- a/web/src/components/results/agent.tsx +++ b/web/src/components/results/agent.tsx @@ -1,7 +1,7 @@ -import { downloadBytes, formatBytes } from "@/lib/utils"; -import { GenerateResult } from "@/types/shell"; import { ScrollTextIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; +import { downloadBytes, formatBytes } from "@/lib/utils"; +import { GenerateResult } from "@/types/shell"; import { Button } from "../ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; import { Separator } from "../ui/separator"; diff --git a/web/src/components/results/basic-info.tsx b/web/src/components/results/basic-info.tsx index 9bf67396..5c0fe353 100644 --- a/web/src/components/results/basic-info.tsx +++ b/web/src/components/results/basic-info.tsx @@ -1,3 +1,5 @@ +import { FileTextIcon } from "lucide-react"; +import { useTranslation } from "react-i18next"; import { shouldHidden } from "@/lib/utils"; import { AntSwordShellToolConfig, @@ -9,8 +11,6 @@ import { ShellToolType, Suo5ShellToolConfig, } from "@/types/shell"; -import { FileTextIcon } from "lucide-react"; -import { useTranslation } from "react-i18next"; import { CopyableField } from "../copyable-field"; import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; import { Separator } from "../ui/separator"; diff --git a/web/src/components/results/jar-result.tsx b/web/src/components/results/jar-result.tsx index d8f5cc45..4613cea2 100644 --- a/web/src/components/results/jar-result.tsx +++ b/web/src/components/results/jar-result.tsx @@ -1,6 +1,6 @@ +import { useTranslation } from "react-i18next"; import { downloadBytes } from "@/lib/utils"; import { GenerateResult } from "@/types/shell"; -import { useTranslation } from "react-i18next"; import { Button } from "../ui/button"; export function JarResult({ diff --git a/web/src/components/results/result-component.tsx b/web/src/components/results/result-component.tsx index fb9ec1ea..621fa96b 100644 --- a/web/src/components/results/result-component.tsx +++ b/web/src/components/results/result-component.tsx @@ -1,5 +1,5 @@ -import { GenerateResult } from "@/types/shell"; import { TFunction } from "i18next"; +import { GenerateResult } from "@/types/shell"; import { CodeViewer } from "../code-viewer"; import { AgentResult } from "./agent"; import { JarResult } from "./jar-result"; diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index 6e71c43d..214a025c 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -1,12 +1,12 @@ +import { DownloadIcon } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { CodeViewer } from "@/components/code-viewer.tsx"; import { QuickUsage } from "@/components/quick-usage.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; import { downloadBytes } from "@/lib/utils.ts"; import { GenerateResult } from "@/types/shell.ts"; -import { DownloadIcon } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; import { BasicInfo } from "./results/basic-info"; import { ResultComponent } from "./results/result-component"; diff --git a/web/src/components/tips/jre-tip.tsx b/web/src/components/tips/jre-tip.tsx index 68cb20cf..8a728584 100644 --- a/web/src/components/tips/jre-tip.tsx +++ b/web/src/components/tips/jre-tip.tsx @@ -1,6 +1,6 @@ -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx"; import { InfoIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx"; export function JreTip() { const { t } = useTranslation(); diff --git a/web/src/components/tools/antsword-tab.tsx b/web/src/components/tools/antsword-tab.tsx index 42197321..726a12f7 100644 --- a/web/src/components/tools/antsword-tab.tsx +++ b/web/src/components/tools/antsword-tab.tsx @@ -1,8 +1,8 @@ -import { FormSchema } from "@/types/schema"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; -import { FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; +import { FormControl, FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; import { TabsContent } from "../ui/tabs"; import { OptionalClassFormField } from "./classname-field"; @@ -42,7 +42,9 @@ export function AntSwordTabContent({ render={({ field }) => ( {t("shellToolConfig.headerName")} - + + + )} /> diff --git a/web/src/components/tools/behinder-tab.tsx b/web/src/components/tools/behinder-tab.tsx index 218cf16b..9f846ef1 100644 --- a/web/src/components/tools/behinder-tab.tsx +++ b/web/src/components/tools/behinder-tab.tsx @@ -1,6 +1,6 @@ -import { FormSchema } from "@/types/schema"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; import { FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; diff --git a/web/src/components/tools/classname-field.tsx b/web/src/components/tools/classname-field.tsx index cf071b9c..0164d209 100644 --- a/web/src/components/tools/classname-field.tsx +++ b/web/src/components/tools/classname-field.tsx @@ -1,15 +1,17 @@ +import { ChevronDown, ChevronUp, Settings } from "lucide-react"; +import { Fragment, useId, useState } from "react"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form.tsx"; import { Input } from "@/components/ui/input.tsx"; import { FormSchema } from "@/types/schema.ts"; -import { ChevronDown, ChevronUp, Settings } from "lucide-react"; -import { Fragment, useState } from "react"; -import { FormProvider, UseFormReturn } from "react-hook-form"; -import { useTranslation } from "react-i18next"; import { Button } from "../ui/button"; export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn }>) { const { t } = useTranslation(); const [showAdvanced, setShowAdvanced] = useState(false); + const shellClassNameId = useId(); + const injectClassNameId = useId(); return (
@@ -32,10 +34,10 @@ export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn< name="shellClassName" render={({ field }) => ( - + {t("mainConfig.shellClassName")} {t("optional")} - + )} /> @@ -44,10 +46,10 @@ export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn< name="injectorClassName" render={({ field }) => ( - + {t("mainConfig.injectorClassName")} {t("optional")} - + )} /> diff --git a/web/src/components/tools/command-tab.tsx b/web/src/components/tools/command-tab.tsx index 2f7d180f..17c85a67 100644 --- a/web/src/components/tools/command-tab.tsx +++ b/web/src/components/tools/command-tab.tsx @@ -1,8 +1,8 @@ -import { env } from "@/config"; -import { FormSchema } from "@/types/schema"; import { useQuery } from "@tanstack/react-query"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { env } from "@/config"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; import { FormControl, FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; diff --git a/web/src/components/tools/custom-tab.tsx b/web/src/components/tools/custom-tab.tsx index ccbfc88a..1c79493f 100644 --- a/web/src/components/tools/custom-tab.tsx +++ b/web/src/components/tools/custom-tab.tsx @@ -1,9 +1,9 @@ +import { t } from "i18next"; +import { useId, useState } from "react"; +import { FormProvider, UseFormReturn } from "react-hook-form"; import { Card, CardContent } from "@/components/ui/card"; import { TabsContent } from "@/components/ui/tabs"; import { FormSchema } from "@/types/schema"; -import { t } from "i18next"; -import { useState } from "react"; -import { FormProvider, UseFormReturn } from "react-hook-form"; import { FormControl, FormField, FormFieldItem, FormFieldLabel, FormMessage } from "../ui/form"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; @@ -18,7 +18,8 @@ export default function CustomTabContent({ shellTypes, }: Readonly<{ form: UseFormReturn; shellTypes: Array }>) { const [isFile, setIsFile] = useState(false); - + const optionOneId = useId(); + const optionTwoId = useId(); return ( @@ -43,12 +44,12 @@ export default function CustomTabContent({ className="flex items-center space-x-2" >
- - + +
- - + +
diff --git a/web/src/components/tools/godzilla-tab.tsx b/web/src/components/tools/godzilla-tab.tsx index 427d0924..017805a7 100644 --- a/web/src/components/tools/godzilla-tab.tsx +++ b/web/src/components/tools/godzilla-tab.tsx @@ -1,6 +1,6 @@ -import { FormSchema } from "@/types/schema"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; import { FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; diff --git a/web/src/components/tools/neoreg-tab.tsx b/web/src/components/tools/neoreg-tab.tsx index 8f4c687a..39b84d93 100644 --- a/web/src/components/tools/neoreg-tab.tsx +++ b/web/src/components/tools/neoreg-tab.tsx @@ -1,6 +1,6 @@ -import { FormSchema } from "@/types/schema"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; import { FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; diff --git a/web/src/components/tools/shelltype-field.tsx b/web/src/components/tools/shelltype-field.tsx index a19baa9d..5d84bfbf 100644 --- a/web/src/components/tools/shelltype-field.tsx +++ b/web/src/components/tools/shelltype-field.tsx @@ -1,10 +1,9 @@ +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; import { FormControl, FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form.tsx"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx"; import { FormSchema } from "@/types/schema.ts"; -import { FormProvider, UseFormReturn } from "react-hook-form"; -import { useTranslation } from "react-i18next"; - export function ShellTypeFormField({ form, shellTypes, diff --git a/web/src/components/tools/suo5-tab.tsx b/web/src/components/tools/suo5-tab.tsx index 29951e7e..78873567 100644 --- a/web/src/components/tools/suo5-tab.tsx +++ b/web/src/components/tools/suo5-tab.tsx @@ -1,6 +1,6 @@ -import { FormSchema } from "@/types/schema"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { FormSchema } from "@/types/schema"; import { Card, CardContent } from "../ui/card"; import { FormField, FormFieldItem, FormFieldLabel } from "../ui/form"; import { Input } from "../ui/input"; diff --git a/web/src/components/tools/urlpattern-field.tsx b/web/src/components/tools/urlpattern-field.tsx index 399ebe94..a2e72966 100644 --- a/web/src/components/tools/urlpattern-field.tsx +++ b/web/src/components/tools/urlpattern-field.tsx @@ -1,9 +1,9 @@ +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; import { FormField, FormFieldItem, FormFieldLabel, FormMessage } from "@/components/ui/form.tsx"; import { Input } from "@/components/ui/input.tsx"; import { shouldHidden } from "@/lib/utils"; import { FormSchema } from "@/types/schema.ts"; -import { FormProvider, UseFormReturn } from "react-hook-form"; -import { useTranslation } from "react-i18next"; export function UrlPatternFormField({ form }: Readonly<{ form: UseFormReturn }>) { const { t } = useTranslation(); diff --git a/web/src/components/ui/alert-dialog.tsx b/web/src/components/ui/alert-dialog.tsx index 36995311..d82179e4 100644 --- a/web/src/components/ui/alert-dialog.tsx +++ b/web/src/components/ui/alert-dialog.tsx @@ -1,8 +1,7 @@ +import { AlertDialog as AlertDialogPrimitive } from "radix-ui"; import * as React from "react"; -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; - -import { cn } from "@/lib/utils"; import { buttonVariants } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; function AlertDialog({ ...props }: React.ComponentProps) { return ; diff --git a/web/src/components/ui/alert.tsx b/web/src/components/ui/alert.tsx index aadf66c4..8f1e1f97 100644 --- a/web/src/components/ui/alert.tsx +++ b/web/src/components/ui/alert.tsx @@ -1,5 +1,5 @@ -import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; import { cn } from "@/lib/utils"; diff --git a/web/src/components/ui/badge.tsx b/web/src/components/ui/badge.tsx new file mode 100644 index 00000000..25784f66 --- /dev/null +++ b/web/src/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot as SlotPrimitive } from "radix-ui"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? SlotPrimitive.Slot : "span"; + + return ; +} + +export { Badge, badgeVariants }; diff --git a/web/src/components/ui/breadcrumb.tsx b/web/src/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..9bb12d07 --- /dev/null +++ b/web/src/components/ui/breadcrumb.tsx @@ -0,0 +1,92 @@ +import { ChevronRight, MoreHorizontal } from "lucide-react"; +import { Slot as SlotPrimitive } from "radix-ui"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return