diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..966e122 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +VITE_API_URL= +TWITCH_CLIENT_ID= +TWITCH_CLIENT_SECRET= diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..567d5e8 --- /dev/null +++ b/.mise.toml @@ -0,0 +1,3 @@ +[tools] +node = "22" +bun = "latest" diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..c060693 --- /dev/null +++ b/biome.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json", + "organizeImports": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "lineWidth": 100 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "asNeeded" + } + } +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..3fc2199 --- /dev/null +++ b/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/shared/components/ui", + "utils": "@/shared/lib/utils", + "ui": "@/shared/components/ui", + "lib": "@/shared/lib", + "hooks": "@/shared/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..821bc32 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + + + WhatToPlay + + + + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..302c6d2 --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "whattoplay", + "private": true, + "version": "2026.03.01", + "type": "module", + "scripts": { + "dev": "vite", + "dev:server": "cd server && bun run dev", + "dev:all": "bun run dev & bun run dev:server", + "build": "tsc -b && vite build", + "preview": "vite preview", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "test": "vitest run", + "prepare": "simple-git-hooks" + }, + "dependencies": { + "@electric-sql/pglite": "^0.2.17", + "@tanstack/react-form": "^1.0.0", + "@tanstack/react-router": "^1.114.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "hono": "^4.7.0", + "lucide-react": "^0.474.0", + "radix-ui": "^1.4.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^3.5.0", + "zod": "^3.24.0", + "zustand": "^5.0.0" + }, + "devDependencies": { + "@biomejs/biome": "^1.9.0", + "@tailwindcss/vite": "^4.0.0", + "@tanstack/router-plugin": "^1.114.0", + "@testing-library/react": "^16.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^4.4.0", + "lint-staged": "^15.0.0", + "simple-git-hooks": "^2.11.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.7.0", + "vite": "^6.2.0", + "vite-plugin-pwa": "^0.21.0", + "vitest": "^3.0.0", + "workbox-window": "^7.0.0" + }, + "simple-git-hooks": { + "pre-commit": "bunx lint-staged" + }, + "lint-staged": { + "*.{ts,tsx,js,json}": ["biome check --write"] + } +} diff --git a/src/.sync-conflict-20260301-130309-TZ5MTB7.DS_Store b/src/.sync-conflict-20260301-130309-TZ5MTB7.DS_Store new file mode 100644 index 0000000..f2b0070 Binary files /dev/null and b/src/.sync-conflict-20260301-130309-TZ5MTB7.DS_Store differ diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..12c40b8 --- /dev/null +++ b/src/app.css @@ -0,0 +1,72 @@ +@import "tailwindcss"; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --color-background: hsl(0 0% 100%); + --color-foreground: hsl(222.2 84% 4.9%); + --color-card: hsl(0 0% 100%); + --color-card-foreground: hsl(222.2 84% 4.9%); + --color-popover: hsl(0 0% 100%); + --color-popover-foreground: hsl(222.2 84% 4.9%); + --color-primary: hsl(222.2 47.4% 11.2%); + --color-primary-foreground: hsl(210 40% 98%); + --color-secondary: hsl(210 40% 96.1%); + --color-secondary-foreground: hsl(222.2 47.4% 11.2%); + --color-muted: hsl(210 40% 96.1%); + --color-muted-foreground: hsl(215.4 16.3% 46.9%); + --color-accent: hsl(210 40% 96.1%); + --color-accent-foreground: hsl(222.2 47.4% 11.2%); + --color-destructive: hsl(0 84.2% 60.2%); + --color-destructive-foreground: hsl(210 40% 98%); + --color-border: hsl(214.3 31.8% 91.4%); + --color-input: hsl(214.3 31.8% 91.4%); + --color-ring: hsl(222.2 84% 4.9%); + --radius: 0.5rem; + + --color-sidebar: hsl(0 0% 98%); + --color-sidebar-foreground: hsl(240 5.3% 26.1%); + --color-sidebar-primary: hsl(240 5.9% 10%); + --color-sidebar-primary-foreground: hsl(0 0% 98%); + --color-sidebar-accent: hsl(240 4.8% 95.9%); + --color-sidebar-accent-foreground: hsl(240 5.9% 10%); + --color-sidebar-border: hsl(220 13% 91%); + --color-sidebar-ring: hsl(217.2 91.2% 59.8%); +} + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-border); + } + body { + background-color: var(--color-background); + color: var(--color-foreground); + font-family: system-ui, -apple-system, sans-serif; + } +} + +.dark { + --color-background: hsl(222.2 84% 4.9%); + --color-foreground: hsl(210 40% 98%); + --color-card: hsl(222.2 84% 4.9%); + --color-card-foreground: hsl(210 40% 98%); + --color-popover: hsl(222.2 84% 4.9%); + --color-popover-foreground: hsl(210 40% 98%); + --color-primary: hsl(210 40% 98%); + --color-primary-foreground: hsl(222.2 47.4% 11.2%); + --color-secondary: hsl(217.2 32.6% 17.5%); + --color-secondary-foreground: hsl(210 40% 98%); + --color-muted: hsl(217.2 32.6% 17.5%); + --color-muted-foreground: hsl(215 20.2% 65.1%); + --color-accent: hsl(217.2 32.6% 17.5%); + --color-accent-foreground: hsl(210 40% 98%); + --color-destructive: hsl(0 62.8% 30.6%); + --color-destructive-foreground: hsl(210 40% 98%); + --color-border: hsl(217.2 32.6% 17.5%); + --color-input: hsl(217.2 32.6% 17.5%); + --color-ring: hsl(212.7 26.8% 83.9%); +} diff --git a/src/shared/components/ui/badge.tsx b/src/shared/components/ui/badge.tsx new file mode 100644 index 0000000..1fdb58a --- /dev/null +++ b/src/shared/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import { type VariantProps, cva } from "class-variance-authority" +import { Slot } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border border-transparent 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: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "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: + "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + link: "text-primary underline-offset-4 [a&]:hover:underline", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +) + +function Badge({ + className, + variant = "default", + asChild = false, + ...props +}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot.Root : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/src/shared/components/ui/button.tsx b/src/shared/components/ui/button.tsx new file mode 100644 index 0000000..1e15413 --- /dev/null +++ b/src/shared/components/ui/button.tsx @@ -0,0 +1,62 @@ +import { type VariantProps, cva } from "class-variance-authority" +import { Slot } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-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", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +) + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot.Root : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/shared/components/ui/card.tsx b/src/shared/components/ui/card.tsx new file mode 100644 index 0000000..760c10b --- /dev/null +++ b/src/shared/components/ui/card.tsx @@ -0,0 +1,75 @@ +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +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/shared/components/ui/dialog.tsx b/src/shared/components/ui/dialog.tsx new file mode 100644 index 0000000..9a53029 --- /dev/null +++ b/src/shared/components/ui/dialog.tsx @@ -0,0 +1,142 @@ +import { XIcon } from "lucide-react" +import { Dialog as DialogPrimitive } from "radix-ui" +import type * as React from "react" + +import { Button } from "@/shared/components/ui/button" +import { cn } from "@/shared/lib/utils" + +function Dialog({ ...props }: React.ComponentProps) { + return +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return +} + +function DialogClose({ ...props }: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + 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 && ( + + + + )} +
+ ) +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/shared/components/ui/dropdown-menu.tsx b/src/shared/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..f8b708d --- /dev/null +++ b/src/shared/components/ui/dropdown-menu.tsx @@ -0,0 +1,228 @@ +"use client" + +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" +import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function DropdownMenu({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/src/shared/components/ui/input.tsx b/src/shared/components/ui/input.tsx new file mode 100644 index 0000000..85189bf --- /dev/null +++ b/src/shared/components/ui/input.tsx @@ -0,0 +1,21 @@ +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/src/shared/components/ui/select.tsx b/src/shared/components/ui/select.tsx new file mode 100644 index 0000000..b09478f --- /dev/null +++ b/src/shared/components/ui/select.tsx @@ -0,0 +1,175 @@ +"use client" + +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" +import { Select as SelectPrimitive } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Select({ ...props }: React.ComponentProps) { + return +} + +function SelectGroup({ ...props }: React.ComponentProps) { + return +} + +function SelectValue({ ...props }: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default" +}) { + return ( + + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "item-aligned", + align = "center", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + 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/shared/components/ui/separator.tsx b/src/shared/components/ui/separator.tsx new file mode 100644 index 0000000..aad9ea7 --- /dev/null +++ b/src/shared/components/ui/separator.tsx @@ -0,0 +1,26 @@ +import { Separator as SeparatorPrimitive } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Separator({ + className, + orientation = "horizontal", + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Separator } diff --git a/src/shared/components/ui/sheet.tsx b/src/shared/components/ui/sheet.tsx new file mode 100644 index 0000000..1d9ec32 --- /dev/null +++ b/src/shared/components/ui/sheet.tsx @@ -0,0 +1,134 @@ +"use client" + +import { XIcon } from "lucide-react" +import { Dialog as SheetPrimitive } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ ...props }: React.ComponentProps) { + return +} + +function SheetClose({ ...props }: React.ComponentProps) { + return +} + +function SheetPortal({ ...props }: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + showCloseButton = true, + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/src/shared/components/ui/tabs.tsx b/src/shared/components/ui/tabs.tsx new file mode 100644 index 0000000..22d8b43 --- /dev/null +++ b/src/shared/components/ui/tabs.tsx @@ -0,0 +1,79 @@ +import { type VariantProps, cva } from "class-variance-authority" +import { Tabs as TabsPrimitive } from "radix-ui" +import type * as React from "react" + +import { cn } from "@/shared/lib/utils" + +function Tabs({ + className, + orientation = "horizontal", + ...props +}: React.ComponentProps) { + return ( + + ) +} + +const tabsListVariants = cva( + "rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col", + { + variants: { + variant: { + default: "bg-muted", + line: "gap-1 bg-transparent", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +) + +function TabsList({ + className, + variant = "default", + ...props +}: React.ComponentProps & VariantProps) { + return ( + + ) +} + +function TabsTrigger({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b6929c7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..af79c87 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,32 @@ +import tailwindcss from "@tailwindcss/vite" +import { TanStackRouterVite } from "@tanstack/router-plugin/vite" +import react from "@vitejs/plugin-react" +import { defineConfig } from "vite" +import { VitePWA } from "vite-plugin-pwa" + +export default defineConfig({ + plugins: [ + TanStackRouterVite(), + react(), + tailwindcss(), + VitePWA({ + registerType: "autoUpdate", + workbox: { + globPatterns: ["**/*.{js,css,html,ico,png,svg,wasm,data}"], + }, + }), + ], + resolve: { + alias: { + "@": "/src", + }, + }, + server: { + proxy: { + "/api": { + target: "http://localhost:3001", + changeOrigin: true, + }, + }, + }, +})