From 64b0c3684ae59b764d2592aa6f2830141dddae80 Mon Sep 17 00:00:00 2001 From: Tomasz Kielar Date: Tue, 24 Feb 2026 11:29:06 +0100 Subject: [PATCH 01/18] chore: update better auth secret example --- apps/api/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/.env.example b/apps/api/.env.example index 93aa3e1..5e8d952 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -27,7 +27,7 @@ AWS_BUCKET_NAME=2m3d-boilerplate-prod # AUTH -BETTER_AUTH_SECRET="secret999" +BETTER_AUTH_SECRET="secret99secret99secret99secret99secret99" BETTER_AUTH_URL=http://localhost:3000 GOOGLE_CLIENT_ID=1111111111111-example.apps.googleusercontent.com From 6f625ee9b9c50865acb8fd8e095f9063b0ceb83f Mon Sep 17 00:00:00 2001 From: Tomasz Kielar Date: Tue, 24 Feb 2026 11:29:30 +0100 Subject: [PATCH 02/18] feat: update shadcn and radix components --- apps/web-app/app/components/ui/accordion.tsx | 64 + .../app/components/ui/alert-dialog.tsx | 196 +++ apps/web-app/app/components/ui/alert.tsx | 66 + .../app/components/ui/aspect-ratio.tsx | 11 + apps/web-app/app/components/ui/avatar.tsx | 78 +- apps/web-app/app/components/ui/badge.tsx | 48 + apps/web-app/app/components/ui/breadcrumb.tsx | 41 +- .../app/components/ui/button-group.tsx | 83 + apps/web-app/app/components/ui/button.tsx | 52 +- apps/web-app/app/components/ui/calendar.tsx | 218 +++ apps/web-app/app/components/ui/card.tsx | 34 +- apps/web-app/app/components/ui/carousel.tsx | 241 +++ apps/web-app/app/components/ui/chart.tsx | 355 ++++ apps/web-app/app/components/ui/checkbox.tsx | 32 + .../web-app/app/components/ui/collapsible.tsx | 22 +- apps/web-app/app/components/ui/combobox.tsx | 310 ++++ apps/web-app/app/components/ui/command.tsx | 184 ++ .../app/components/ui/context-menu.tsx | 252 +++ apps/web-app/app/components/ui/dialog.tsx | 156 ++ apps/web-app/app/components/ui/direction.tsx | 22 + apps/web-app/app/components/ui/drawer.tsx | 133 ++ .../app/components/ui/dropdown-menu.tsx | 95 +- apps/web-app/app/components/ui/empty.tsx | 104 ++ apps/web-app/app/components/ui/field.tsx | 248 +++ apps/web-app/app/components/ui/form.tsx | 165 ++ apps/web-app/app/components/ui/hover-card.tsx | 42 + .../web-app/app/components/ui/input-group.tsx | 168 ++ apps/web-app/app/components/ui/input-otp.tsx | 77 + apps/web-app/app/components/ui/input.tsx | 14 +- apps/web-app/app/components/ui/item.tsx | 193 +++ apps/web-app/app/components/ui/kbd.tsx | 28 + apps/web-app/app/components/ui/label.tsx | 10 +- apps/web-app/app/components/ui/menubar.tsx | 276 +++ .../app/components/ui/native-select.tsx | 53 + .../app/components/ui/navigation-menu.tsx | 52 +- apps/web-app/app/components/ui/pagination.tsx | 127 ++ apps/web-app/app/components/ui/popover.tsx | 87 + apps/web-app/app/components/ui/progress.tsx | 31 + .../web-app/app/components/ui/radio-group.tsx | 43 + apps/web-app/app/components/ui/resizable.tsx | 53 + .../web-app/app/components/ui/scroll-area.tsx | 56 + apps/web-app/app/components/ui/select.tsx | 190 ++ apps/web-app/app/components/ui/separator.tsx | 12 +- apps/web-app/app/components/ui/sheet.tsx | 76 +- apps/web-app/app/components/ui/sidebar.tsx | 306 ++-- apps/web-app/app/components/ui/skeleton.tsx | 8 +- apps/web-app/app/components/ui/slider.tsx | 61 + apps/web-app/app/components/ui/sonner.tsx | 33 +- apps/web-app/app/components/ui/spinner.tsx | 16 + apps/web-app/app/components/ui/switch.tsx | 33 + apps/web-app/app/components/ui/table.tsx | 116 ++ apps/web-app/app/components/ui/tabs.tsx | 89 + apps/web-app/app/components/ui/textarea.tsx | 18 + .../app/components/ui/toggle-group.tsx | 83 + apps/web-app/app/components/ui/toggle.tsx | 47 + apps/web-app/app/components/ui/tooltip.tsx | 28 +- apps/web-app/app/hooks/use-mobile.ts | 22 +- apps/web-app/app/modules/Global/Providers.tsx | 7 +- apps/web-app/package.json | 19 +- pnpm-lock.yaml | 1539 +++++++++++++++-- 60 files changed, 6670 insertions(+), 553 deletions(-) create mode 100644 apps/web-app/app/components/ui/accordion.tsx create mode 100644 apps/web-app/app/components/ui/alert-dialog.tsx create mode 100644 apps/web-app/app/components/ui/alert.tsx create mode 100644 apps/web-app/app/components/ui/aspect-ratio.tsx create mode 100644 apps/web-app/app/components/ui/badge.tsx create mode 100644 apps/web-app/app/components/ui/button-group.tsx create mode 100644 apps/web-app/app/components/ui/calendar.tsx create mode 100644 apps/web-app/app/components/ui/carousel.tsx create mode 100644 apps/web-app/app/components/ui/chart.tsx create mode 100644 apps/web-app/app/components/ui/checkbox.tsx create mode 100644 apps/web-app/app/components/ui/combobox.tsx create mode 100644 apps/web-app/app/components/ui/command.tsx create mode 100644 apps/web-app/app/components/ui/context-menu.tsx create mode 100644 apps/web-app/app/components/ui/dialog.tsx create mode 100644 apps/web-app/app/components/ui/direction.tsx create mode 100644 apps/web-app/app/components/ui/drawer.tsx create mode 100644 apps/web-app/app/components/ui/empty.tsx create mode 100644 apps/web-app/app/components/ui/field.tsx create mode 100644 apps/web-app/app/components/ui/form.tsx create mode 100644 apps/web-app/app/components/ui/hover-card.tsx create mode 100644 apps/web-app/app/components/ui/input-group.tsx create mode 100644 apps/web-app/app/components/ui/input-otp.tsx create mode 100644 apps/web-app/app/components/ui/item.tsx create mode 100644 apps/web-app/app/components/ui/kbd.tsx create mode 100644 apps/web-app/app/components/ui/menubar.tsx create mode 100644 apps/web-app/app/components/ui/native-select.tsx create mode 100644 apps/web-app/app/components/ui/pagination.tsx create mode 100644 apps/web-app/app/components/ui/popover.tsx create mode 100644 apps/web-app/app/components/ui/progress.tsx create mode 100644 apps/web-app/app/components/ui/radio-group.tsx create mode 100644 apps/web-app/app/components/ui/resizable.tsx create mode 100644 apps/web-app/app/components/ui/scroll-area.tsx create mode 100644 apps/web-app/app/components/ui/select.tsx create mode 100644 apps/web-app/app/components/ui/slider.tsx create mode 100644 apps/web-app/app/components/ui/spinner.tsx create mode 100644 apps/web-app/app/components/ui/switch.tsx create mode 100644 apps/web-app/app/components/ui/table.tsx create mode 100644 apps/web-app/app/components/ui/tabs.tsx create mode 100644 apps/web-app/app/components/ui/textarea.tsx create mode 100644 apps/web-app/app/components/ui/toggle-group.tsx create mode 100644 apps/web-app/app/components/ui/toggle.tsx diff --git a/apps/web-app/app/components/ui/accordion.tsx b/apps/web-app/app/components/ui/accordion.tsx new file mode 100644 index 0000000..37d2d97 --- /dev/null +++ b/apps/web-app/app/components/ui/accordion.tsx @@ -0,0 +1,64 @@ +import * as React from "react" +import { ChevronDownIcon } from "lucide-react" +import { Accordion as AccordionPrimitive } from "radix-ui" + +import { cn } from "~/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/apps/web-app/app/components/ui/alert-dialog.tsx b/apps/web-app/app/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..e4c09a9 --- /dev/null +++ b/apps/web-app/app/components/ui/alert-dialog.tsx @@ -0,0 +1,196 @@ +"use client" + +import * as React from "react" +import { AlertDialog as AlertDialogPrimitive } from "radix-ui" + +import { cn } from "~/lib/utils" +import { Button } from "~/components/ui/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + size = "default", + ...props +}: React.ComponentProps & { + size?: "default" | "sm" +}) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogMedia({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogAction({ + className, + variant = "default", + size = "default", + ...props +}: React.ComponentProps & + Pick, "variant" | "size">) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + variant = "outline", + size = "default", + ...props +}: React.ComponentProps & + Pick, "variant" | "size">) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogMedia, + AlertDialogOverlay, + AlertDialogPortal, + AlertDialogTitle, + AlertDialogTrigger, +} diff --git a/apps/web-app/app/components/ui/alert.tsx b/apps/web-app/app/components/ui/alert.tsx new file mode 100644 index 0000000..56b3946 --- /dev/null +++ b/apps/web-app/app/components/ui/alert.tsx @@ -0,0 +1,66 @@ +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 px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/apps/web-app/app/components/ui/aspect-ratio.tsx b/apps/web-app/app/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..57e38fa --- /dev/null +++ b/apps/web-app/app/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +"use client" + +import { AspectRatio as AspectRatioPrimitive } from "radix-ui" + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return +} + +export { AspectRatio } diff --git a/apps/web-app/app/components/ui/avatar.tsx b/apps/web-app/app/components/ui/avatar.tsx index 065cca3..d1dffda 100644 --- a/apps/web-app/app/components/ui/avatar.tsx +++ b/apps/web-app/app/components/ui/avatar.tsx @@ -1,24 +1,26 @@ -"use client"; +import * as React from "react" +import { Avatar as AvatarPrimitive } from "radix-ui" -import * as React from "react"; -import * as AvatarPrimitive from "@radix-ui/react-avatar"; - -import { cn } from "~/lib/utils"; +import { cn } from "~/lib/utils" function Avatar({ className, + size = "default", ...props -}: React.ComponentProps) { +}: React.ComponentProps & { + size?: "default" | "sm" | "lg" +}) { return ( - ); + ) } function AvatarImage({ @@ -31,7 +33,7 @@ function AvatarImage({ className={cn("aspect-square size-full", className)} {...props} /> - ); + ) } function AvatarFallback({ @@ -42,12 +44,64 @@ function AvatarFallback({ + ) +} + +function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { + return ( + svg]:hidden", + "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", + "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", + className + )} + {...props} + /> + ) +} + +function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AvatarGroupCount({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className )} {...props} /> - ); + ) } -export { Avatar, AvatarImage, AvatarFallback }; +export { + Avatar, + AvatarImage, + AvatarFallback, + AvatarBadge, + AvatarGroup, + AvatarGroupCount, +} diff --git a/apps/web-app/app/components/ui/badge.tsx b/apps/web-app/app/components/ui/badge.tsx new file mode 100644 index 0000000..6daa783 --- /dev/null +++ b/apps/web-app/app/components/ui/badge.tsx @@ -0,0 +1,48 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from "radix-ui" + +import { cn } from "~/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/apps/web-app/app/components/ui/breadcrumb.tsx b/apps/web-app/app/components/ui/breadcrumb.tsx index 904baa1..a2005f8 100644 --- a/apps/web-app/app/components/ui/breadcrumb.tsx +++ b/apps/web-app/app/components/ui/breadcrumb.tsx @@ -1,11 +1,11 @@ -import * as React from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; +import * as React from "react" +import { ChevronRight, MoreHorizontal } from "lucide-react" +import { Slot } from "radix-ui" -import { cn } from "~/lib/utils"; +import { cn } from "~/lib/utils" function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { - return