diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5ed39d11..853691d3 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,8 @@
{
"files.associations": {
"tsconfig.json": "jsonc",
- "typescript-config/*.json": "jsonc"
+ "typescript-config/*.json": "jsonc",
+ "*.css": "tailwindcss"
},
// Javascript and TypeScript settings
@@ -16,6 +17,10 @@
"typescript.suggestionActions.enabled": true,
"typescript.preferences.importModuleSpecifier": "shortest",
+ "editor.quickSuggestions": {
+ "strings": "on"
+ },
+
"editor.codeActionsOnSave": {
"source.organizeImports": "always",
"quickfix.biome": "always",
diff --git a/apps/web/package.json b/apps/web/package.json
index d1e38a16..2a81cd51 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -31,7 +31,6 @@
"react-secure-storage": "^1.3.2",
"tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.6",
- "tailwindcss-animate": "^1.0.7",
"tw-animate-css": "^1.2.9",
"vite-plugin-html": "^3.2.2"
},
diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs
index b62ffe34..a1523e19 100644
--- a/apps/web/postcss.config.mjs
+++ b/apps/web/postcss.config.mjs
@@ -1 +1 @@
-export { default } from "@repo/shadcn-ui/postcss.config";
+export { default } from "@repo/shadcn-ui/postcss.config.mjs";
diff --git a/apps/web/src/app.css b/apps/web/src/app.css
index a041a744..b28b04f6 100644
--- a/apps/web/src/app.css
+++ b/apps/web/src/app.css
@@ -1,3 +1,3 @@
-@import "tailwindcss";
+
diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx
index 08f19afa..85801035 100644
--- a/apps/web/src/app.tsx
+++ b/apps/web/src/app.tsx
@@ -31,7 +31,6 @@ export const App = () => {
-
{import.meta.env.MODE === "development" && }
diff --git a/apps/web/src/global.css b/apps/web/src/global.css
index ac7fa1ee..60145b34 100644
--- a/apps/web/src/global.css
+++ b/apps/web/src/global.css
@@ -1,30 +1,15 @@
@import 'tailwindcss';
-@plugin "tailwindcss-animate";
+@import "tw-animate-css";
@import '@repo/shadcn-ui/globals.css';
@import '@repo/rdx-ui/globals.css';
-@custom-variant dark (&:is(.dark *));
-
-@layer base {
-
- * {
- @apply border-border;
- }
-
- body {
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- tab-size: 4;
- font-feature-settings: normal;
- font-variation-settings: normal;
- font-feature-settings: "rlig" 1, "calt" 1;
- @apply h-full text-foreground bg-background /*font-poppins*/;
- }
-
- #factuges {
- @apply flex min-h-screen min-w-[320px] flex-col;
- }
-
-
-}
\ No newline at end of file
+/**
+ * Tailwind CSS official document:
+ * https://tailwindcss.com/docs/detecting-classes-in-source-files
+ *
+ * if you ever need to explicitly add a source that's excluded by default,
+ * you can always add it with the @source directive.
+ */
+@source '../node_modules/@repo/shadcn-ui';
+@source '../node_modules/@repo/rdx-ui';
\ No newline at end of file
diff --git a/biome.json b/biome.json
index 6172acaf..15af6286 100644
--- a/biome.json
+++ b/biome.json
@@ -19,6 +19,7 @@
"rules": {
"recommended": true,
"correctness": {
+ "useExhaustiveDependencies": "info",
"noUnreachable": "off"
},
"complexity": {
diff --git a/packages/rdx-ui/package.json b/packages/rdx-ui/package.json
index d460ebc1..4aea26a0 100644
--- a/packages/rdx-ui/package.json
+++ b/packages/rdx-ui/package.json
@@ -31,6 +31,7 @@
"esbuild-plugin-react18": "^0.2.6",
"esbuild-plugin-react18-css": "^0.0.4",
"tailwindcss": "^4.1.5",
+ "tw-animate-css": "^1.2.9",
"tsup": "^8.4.0",
"typescript": "^5.8.3",
"typescript-plugin-css-modules": "^5.1.0",
diff --git a/packages/rdx-ui/src/components/layout/app-breadcrumb.tsx b/packages/rdx-ui/src/components/layout/app-breadcrumb.tsx
new file mode 100644
index 00000000..68221261
--- /dev/null
+++ b/packages/rdx-ui/src/components/layout/app-breadcrumb.tsx
@@ -0,0 +1,32 @@
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ Separator,
+ SidebarTrigger,
+} from "@repo/shadcn-ui/components";
+
+export const AppBreadcrumb = () => {
+ return (
+
+ );
+};
diff --git a/packages/rdx-ui/src/components/layout/app-content.tsx b/packages/rdx-ui/src/components/layout/app-content.tsx
new file mode 100644
index 00000000..246e1bf8
--- /dev/null
+++ b/packages/rdx-ui/src/components/layout/app-content.tsx
@@ -0,0 +1,5 @@
+import { PropsWithChildren } from "react";
+
+export const AppContent = ({ children }: PropsWithChildren) => {
+ return
{children}
;
+};
diff --git a/packages/rdx-ui/src/components/layout/app-layout.tsx b/packages/rdx-ui/src/components/layout/app-layout.tsx
index add928af..80585627 100644
--- a/packages/rdx-ui/src/components/layout/app-layout.tsx
+++ b/packages/rdx-ui/src/components/layout/app-layout.tsx
@@ -1,7 +1,6 @@
import { SidebarInset, SidebarProvider } from "@repo/shadcn-ui/components";
import { Outlet } from "react-router";
import { AppSidebar } from "./app-sidebar.tsx";
-import { SiteHeader } from "./site-header.tsx";
export const AppLayout: React.FC = () => {
return (
@@ -15,15 +14,7 @@ export const AppLayout: React.FC = () => {
>
-
-
-
+
);
diff --git a/packages/rdx-ui/src/components/layout/index.tsx b/packages/rdx-ui/src/components/layout/index.tsx
index 615e1c50..437da7db 100644
--- a/packages/rdx-ui/src/components/layout/index.tsx
+++ b/packages/rdx-ui/src/components/layout/index.tsx
@@ -1 +1,3 @@
+export * from "./app-breadcrumb.tsx";
+export * from "./app-content.tsx";
export * from "./app-layout.tsx";
diff --git a/packages/rdx-ui/src/components/layout/site-header.tsx b/packages/rdx-ui/src/components/layout/site-header.tsx
deleted file mode 100644
index c04ce418..00000000
--- a/packages/rdx-ui/src/components/layout/site-header.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Separator } from "@repo/shadcn-ui/components/separator";
-import { SidebarTrigger } from "@repo/shadcn-ui/components/sidebar";
-
-export const SiteHeader = ({ title }: { title: string }) => {
- return (
-
- );
-};
diff --git a/packages/rdx-ui/src/styles/globals.css b/packages/rdx-ui/src/styles/globals.css
index 27bf2e1a..3825f26b 100644
--- a/packages/rdx-ui/src/styles/globals.css
+++ b/packages/rdx-ui/src/styles/globals.css
@@ -1,3 +1 @@
-@import 'tailwindcss';
@import '@repo/shadcn-ui/globals.css';
-
diff --git a/packages/shadcn-ui/@/components/ui/button.tsx b/packages/shadcn-ui/@/components/ui/button.tsx
deleted file mode 100644
index a2df8dce..00000000
--- a/packages/shadcn-ui/@/components/ui/button.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-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 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 shadow-xs hover:bg-primary/90",
- destructive:
- "bg-destructive text-white shadow-xs 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 shadow-xs 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",
- 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",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
-)
-
-function Button({
- className,
- variant,
- size,
- asChild = false,
- ...props
-}: React.ComponentProps<"button"> &
- VariantProps & {
- asChild?: boolean
- }) {
- const Comp = asChild ? Slot : "button"
-
- return (
-
- )
-}
-
-export { Button, buttonVariants }
diff --git a/packages/shadcn-ui/@/components/ui/input.tsx b/packages/shadcn-ui/@/components/ui/input.tsx
deleted file mode 100644
index 03295ca6..00000000
--- a/packages/shadcn-ui/@/components/ui/input.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@/lib/utils"
-
-function Input({ className, type, ...props }: React.ComponentProps<"input">) {
- return (
-
- )
-}
-
-export { Input }
diff --git a/packages/shadcn-ui/@/components/ui/separator.tsx b/packages/shadcn-ui/@/components/ui/separator.tsx
deleted file mode 100644
index 67c73e5a..00000000
--- a/packages/shadcn-ui/@/components/ui/separator.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-"use client"
-
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
-
-import { cn } from "@/lib/utils"
-
-function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Separator }
diff --git a/packages/shadcn-ui/@/components/ui/sheet.tsx b/packages/shadcn-ui/@/components/ui/sheet.tsx
deleted file mode 100644
index 84649ad0..00000000
--- a/packages/shadcn-ui/@/components/ui/sheet.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-"use client"
-
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { XIcon } from "lucide-react"
-
-import { cn } from "@/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",
- ...props
-}: React.ComponentProps & {
- side?: "top" | "right" | "bottom" | "left"
-}) {
- return (
-
-
-
- {children}
-
-
- 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/packages/shadcn-ui/@/components/ui/sidebar.tsx b/packages/shadcn-ui/@/components/ui/sidebar.tsx
deleted file mode 100644
index 7ffbc078..00000000
--- a/packages/shadcn-ui/@/components/ui/sidebar.tsx
+++ /dev/null
@@ -1,726 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { VariantProps, cva } from "class-variance-authority"
-import { PanelLeftIcon } from "lucide-react"
-
-import { useIsMobile } from "@/hooks/use-mobile"
-import { cn } from "@/lib/utils"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Separator } from "@/components/ui/separator"
-import {
- Sheet,
- SheetContent,
- SheetDescription,
- SheetHeader,
- SheetTitle,
-} from "@/components/ui/sheet"
-import { Skeleton } from "@/components/ui/skeleton"
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip"
-
-const SIDEBAR_COOKIE_NAME = "sidebar_state"
-const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
-const SIDEBAR_WIDTH = "16rem"
-const SIDEBAR_WIDTH_MOBILE = "18rem"
-const SIDEBAR_WIDTH_ICON = "3rem"
-const SIDEBAR_KEYBOARD_SHORTCUT = "b"
-
-type SidebarContextProps = {
- state: "expanded" | "collapsed"
- open: boolean
- setOpen: (open: boolean) => void
- openMobile: boolean
- setOpenMobile: (open: boolean) => void
- isMobile: boolean
- toggleSidebar: () => void
-}
-
-const SidebarContext = React.createContext(null)
-
-function useSidebar() {
- const context = React.useContext(SidebarContext)
- if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.")
- }
-
- return context
-}
-
-function SidebarProvider({
- defaultOpen = true,
- open: openProp,
- onOpenChange: setOpenProp,
- className,
- style,
- children,
- ...props
-}: React.ComponentProps<"div"> & {
- defaultOpen?: boolean
- open?: boolean
- onOpenChange?: (open: boolean) => void
-}) {
- const isMobile = useIsMobile()
- const [openMobile, setOpenMobile] = React.useState(false)
-
- // This is the internal state of the sidebar.
- // We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen)
- const open = openProp ?? _open
- const setOpen = React.useCallback(
- (value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value
- if (setOpenProp) {
- setOpenProp(openState)
- } else {
- _setOpen(openState)
- }
-
- // This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
- },
- [setOpenProp, open]
- )
-
- // Helper to toggle the sidebar.
- const toggleSidebar = React.useCallback(() => {
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
- }, [isMobile, setOpen, setOpenMobile])
-
- // Adds a keyboard shortcut to toggle the sidebar.
- React.useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (
- event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
- (event.metaKey || event.ctrlKey)
- ) {
- event.preventDefault()
- toggleSidebar()
- }
- }
-
- window.addEventListener("keydown", handleKeyDown)
- return () => window.removeEventListener("keydown", handleKeyDown)
- }, [toggleSidebar])
-
- // We add a state so that we can do data-state="expanded" or "collapsed".
- // This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed"
-
- const contextValue = React.useMemo(
- () => ({
- state,
- open,
- setOpen,
- isMobile,
- openMobile,
- setOpenMobile,
- toggleSidebar,
- }),
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- )
-
- return (
-
-
-
- {children}
-
-
-
- )
-}
-
-function Sidebar({
- side = "left",
- variant = "sidebar",
- collapsible = "offcanvas",
- className,
- children,
- ...props
-}: React.ComponentProps<"div"> & {
- side?: "left" | "right"
- variant?: "sidebar" | "floating" | "inset"
- collapsible?: "offcanvas" | "icon" | "none"
-}) {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
-
- if (collapsible === "none") {
- return (
-
- {children}
-
- )
- }
-
- if (isMobile) {
- return (
-
-
-
- Sidebar
- Displays the mobile sidebar.
-
- {children}
-
-
- )
- }
-
- return (
-
- {/* This is what handles the sidebar gap on desktop */}
-
-
-
- )
-}
-
-function SidebarTrigger({
- className,
- onClick,
- ...props
-}: React.ComponentProps) {
- const { toggleSidebar } = useSidebar()
-
- return (
-
- )
-}
-
-function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar()
-
- return (
-
- )
-}
-
-function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
- return (
-
- )
-}
-
-function SidebarInput({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarGroupLabel({
- className,
- asChild = false,
- ...props
-}: React.ComponentProps<"div"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "div"
-
- return (
- svg]:size-4 [&>svg]:shrink-0",
- "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
- className
- )}
- {...props}
- />
- )
-}
-
-function SidebarGroupAction({
- className,
- asChild = false,
- ...props
-}: React.ComponentProps<"button"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "button"
-
- return (
- svg]:size-4 [&>svg]:shrink-0",
- // Increases the hit area of the button on mobile.
- "after:absolute after:-inset-2 md:after:hidden",
- "group-data-[collapsible=icon]:hidden",
- className
- )}
- {...props}
- />
- )
-}
-
-function SidebarGroupContent({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
- return (
-
- )
-}
-
-function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
- return (
-
- )
-}
-
-const sidebarMenuButtonVariants = cva(
- "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
- {
- variants: {
- variant: {
- default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
- outline:
- "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
- },
- size: {
- default: "h-8 text-sm",
- sm: "h-7 text-xs",
- lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
-)
-
-function SidebarMenuButton({
- asChild = false,
- isActive = false,
- variant = "default",
- size = "default",
- tooltip,
- className,
- ...props
-}: React.ComponentProps<"button"> & {
- asChild?: boolean
- isActive?: boolean
- tooltip?: string | React.ComponentProps
-} & VariantProps) {
- const Comp = asChild ? Slot : "button"
- const { isMobile, state } = useSidebar()
-
- const button = (
-
- )
-
- if (!tooltip) {
- return button
- }
-
- if (typeof tooltip === "string") {
- tooltip = {
- children: tooltip,
- }
- }
-
- return (
-
- {button}
-
-
- )
-}
-
-function SidebarMenuAction({
- className,
- asChild = false,
- showOnHover = false,
- ...props
-}: React.ComponentProps<"button"> & {
- asChild?: boolean
- showOnHover?: boolean
-}) {
- const Comp = asChild ? Slot : "button"
-
- return (
- svg]:size-4 [&>svg]:shrink-0",
- // Increases the hit area of the button on mobile.
- "after:absolute after:-inset-2 md:after:hidden",
- "peer-data-[size=sm]/menu-button:top-1",
- "peer-data-[size=default]/menu-button:top-1.5",
- "peer-data-[size=lg]/menu-button:top-2.5",
- "group-data-[collapsible=icon]:hidden",
- showOnHover &&
- "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
- className
- )}
- {...props}
- />
- )
-}
-
-function SidebarMenuBadge({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function SidebarMenuSkeleton({
- className,
- showIcon = false,
- ...props
-}: React.ComponentProps<"div"> & {
- showIcon?: boolean
-}) {
- // Random width between 50 to 90%.
- const width = React.useMemo(() => {
- return `${Math.floor(Math.random() * 40) + 50}%`
- }, [])
-
- return (
-
- {showIcon && (
-
- )}
-
-
- )
-}
-
-function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
- return (
-
- )
-}
-
-function SidebarMenuSubItem({
- className,
- ...props
-}: React.ComponentProps<"li">) {
- return (
-
- )
-}
-
-function SidebarMenuSubButton({
- asChild = false,
- size = "md",
- isActive = false,
- className,
- ...props
-}: React.ComponentProps<"a"> & {
- asChild?: boolean
- size?: "sm" | "md"
- isActive?: boolean
-}) {
- const Comp = asChild ? Slot : "a"
-
- return (
- svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
- "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
- size === "sm" && "text-xs",
- size === "md" && "text-sm",
- "group-data-[collapsible=icon]:hidden",
- className
- )}
- {...props}
- />
- )
-}
-
-export {
- Sidebar,
- SidebarContent,
- SidebarFooter,
- SidebarGroup,
- SidebarGroupAction,
- SidebarGroupContent,
- SidebarGroupLabel,
- SidebarHeader,
- SidebarInput,
- SidebarInset,
- SidebarMenu,
- SidebarMenuAction,
- SidebarMenuBadge,
- SidebarMenuButton,
- SidebarMenuItem,
- SidebarMenuSkeleton,
- SidebarMenuSub,
- SidebarMenuSubButton,
- SidebarMenuSubItem,
- SidebarProvider,
- SidebarRail,
- SidebarSeparator,
- SidebarTrigger,
- useSidebar,
-}
diff --git a/packages/shadcn-ui/@/components/ui/skeleton.tsx b/packages/shadcn-ui/@/components/ui/skeleton.tsx
deleted file mode 100644
index 32ea0ef7..00000000
--- a/packages/shadcn-ui/@/components/ui/skeleton.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { cn } from "@/lib/utils"
-
-function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-export { Skeleton }
diff --git a/packages/shadcn-ui/@/components/ui/tooltip.tsx b/packages/shadcn-ui/@/components/ui/tooltip.tsx
deleted file mode 100644
index 4ee26b38..00000000
--- a/packages/shadcn-ui/@/components/ui/tooltip.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-"use client"
-
-import * as React from "react"
-import * as TooltipPrimitive from "@radix-ui/react-tooltip"
-
-import { cn } from "@/lib/utils"
-
-function TooltipProvider({
- delayDuration = 0,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function Tooltip({
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-function TooltipTrigger({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function TooltipContent({
- className,
- sideOffset = 0,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
-
- )
-}
-
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/packages/shadcn-ui/@/hooks/use-mobile.ts b/packages/shadcn-ui/@/hooks/use-mobile.ts
deleted file mode 100644
index 2b0fe1df..00000000
--- a/packages/shadcn-ui/@/hooks/use-mobile.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as React from "react"
-
-const MOBILE_BREAKPOINT = 768
-
-export function useIsMobile() {
- const [isMobile, setIsMobile] = React.useState(undefined)
-
- React.useEffect(() => {
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
- const onChange = () => {
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- }
- mql.addEventListener("change", onChange)
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- return () => mql.removeEventListener("change", onChange)
- }, [])
-
- return !!isMobile
-}
diff --git a/packages/shadcn-ui/components.json b/packages/shadcn-ui/components.json
index 76a1c7da..db6d0ef3 100644
--- a/packages/shadcn-ui/components.json
+++ b/packages/shadcn-ui/components.json
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
- "style": "new-york",
+ "style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
@@ -11,11 +11,11 @@
"prefix": ""
},
"aliases": {
- "components": "@/components",
- "utils": "@/lib/utils",
- "ui": "@/components/ui",
- "lib": "@/lib",
- "hooks": "@/hooks"
+ "components": "@repo/shadcn-ui/components",
+ "utils": "@repo/shadcn-ui/lib/utils",
+ "ui": "@repo/shadcn-ui/components",
+ "lib": "@repo/shadcn-ui/lib",
+ "hooks": "@repo/shadcn-ui/hooks"
},
"iconLibrary": "lucide"
}
diff --git a/packages/shadcn-ui/package.json b/packages/shadcn-ui/package.json
index 2cb84ef2..c40eae4c 100644
--- a/packages/shadcn-ui/package.json
+++ b/packages/shadcn-ui/package.json
@@ -4,13 +4,13 @@
"type": "module",
"private": true,
"exports": {
- "./tailwind.config": "./tailwind.config.mts",
+ "./tailwind.config.mts": "./tailwind.config.mts",
"./globals.css": "./src/styles/globals.css",
- "./postcss.config": "./postcss.config.mjs",
+ "./postcss.config.mjs": "./postcss.config.mjs",
"./components": "./src/components/index.tsx",
"./components/*": "./src/components/*.tsx",
"./lib/*": "./src/lib/*.ts",
- "./hooks": ["./src/hooks/index.ts"]
+ "./hooks/*": ["./src/hooks/*.ts", "./src/hooks/*/index.ts"]
},
"scripts": {
"lint": "biome lint --fix",
@@ -80,7 +80,6 @@
"sonner": "^2.0.3",
"tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.5",
- "tailwindcss-animate": "^1.0.7",
"tw-animate-css": "^1.2.9",
"vaul": "^1.1.2",
"zod": "^3.24.4"
diff --git a/packages/shadcn-ui/postcss.config.mjs b/packages/shadcn-ui/postcss.config.mjs
index 79bcf135..7a2280c7 100644
--- a/packages/shadcn-ui/postcss.config.mjs
+++ b/packages/shadcn-ui/postcss.config.mjs
@@ -1,4 +1,5 @@
/** @type {import('postcss-load-config').Config} */
+
const config = {
plugins: {
"@tailwindcss/postcss": {},
diff --git a/packages/shadcn-ui/src/components/sidebar.tsx b/packages/shadcn-ui/src/components/sidebar.tsx
index 5ba38984..22537abb 100644
--- a/packages/shadcn-ui/src/components/sidebar.tsx
+++ b/packages/shadcn-ui/src/components/sidebar.tsx
@@ -1,56 +1,56 @@
-"use client";
+"use client"
-import { Slot } from "@radix-ui/react-slot";
-import { VariantProps, cva } from "class-variance-authority";
-import { PanelLeftIcon } from "lucide-react";
-import * as React from "react";
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { VariantProps, cva } from "class-variance-authority"
+import { PanelLeftIcon } from "lucide-react"
-import { Button } from "@repo/shadcn-ui/components/button";
-import { Input } from "@repo/shadcn-ui/components/input";
-import { Separator } from "@repo/shadcn-ui/components/separator";
+import { useIsMobile } from "@repo/shadcn-ui/hooks/use-mobile"
+import { cn } from "@repo/shadcn-ui/lib/utils"
+import { Button } from "@repo/shadcn-ui/components/button"
+import { Input } from "@repo/shadcn-ui/components/input"
+import { Separator } from "@repo/shadcn-ui/components/separator"
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
-} from "@repo/shadcn-ui/components/sheet";
-import { Skeleton } from "@repo/shadcn-ui/components/skeleton";
+} from "@repo/shadcn-ui/components/sheet"
+import { Skeleton } from "@repo/shadcn-ui/components/skeleton"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
-} from "@repo/shadcn-ui/components/tooltip";
-import { cn } from "@repo/shadcn-ui/lib/utils";
-import { useIsMobile } from "../hooks/use-mobile.ts";
+} from "@repo/shadcn-ui/components/tooltip"
-const SIDEBAR_COOKIE_NAME = "sidebar_state";
-const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
-const SIDEBAR_WIDTH = "16rem";
-const SIDEBAR_WIDTH_MOBILE = "18rem";
-const SIDEBAR_WIDTH_ICON = "3rem";
-const SIDEBAR_KEYBOARD_SHORTCUT = "b";
+const SIDEBAR_COOKIE_NAME = "sidebar_state"
+const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
+const SIDEBAR_WIDTH = "16rem"
+const SIDEBAR_WIDTH_MOBILE = "18rem"
+const SIDEBAR_WIDTH_ICON = "3rem"
+const SIDEBAR_KEYBOARD_SHORTCUT = "b"
type SidebarContextProps = {
- state: "expanded" | "collapsed";
- open: boolean;
- setOpen: (open: boolean) => void;
- openMobile: boolean;
- setOpenMobile: (open: boolean) => void;
- isMobile: boolean;
- toggleSidebar: () => void;
-};
+ state: "expanded" | "collapsed"
+ open: boolean
+ setOpen: (open: boolean) => void
+ openMobile: boolean
+ setOpenMobile: (open: boolean) => void
+ isMobile: boolean
+ toggleSidebar: () => void
+}
-const SidebarContext = React.createContext(null);
+const SidebarContext = React.createContext(null)
function useSidebar() {
- const context = React.useContext(SidebarContext);
+ const context = React.useContext(SidebarContext)
if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.");
+ throw new Error("useSidebar must be used within a SidebarProvider.")
}
- return context;
+ return context
}
function SidebarProvider({
@@ -62,55 +62,57 @@ function SidebarProvider({
children,
...props
}: React.ComponentProps<"div"> & {
- defaultOpen?: boolean;
- open?: boolean;
- onOpenChange?: (open: boolean) => void;
+ defaultOpen?: boolean
+ open?: boolean
+ onOpenChange?: (open: boolean) => void
}) {
- const isMobile = useIsMobile();
- const [openMobile, setOpenMobile] = React.useState(false);
+ const isMobile = useIsMobile()
+ const [openMobile, setOpenMobile] = React.useState(false)
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen);
- const open = openProp ?? _open;
+ const [_open, _setOpen] = React.useState(defaultOpen)
+ const open = openProp ?? _open
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value;
+ const openState = typeof value === "function" ? value(open) : value
if (setOpenProp) {
- setOpenProp(openState);
+ setOpenProp(openState)
} else {
- _setOpen(openState);
+ _setOpen(openState)
}
// This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
},
[setOpenProp, open]
- );
+ )
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
- }, [isMobile, setOpen]);
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
+ }, [isMobile, setOpen, setOpenMobile])
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
- event.preventDefault();
- toggleSidebar();
+ if (
+ event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
+ (event.metaKey || event.ctrlKey)
+ ) {
+ event.preventDefault()
+ toggleSidebar()
}
- };
+ }
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, [toggleSidebar]);
+ window.addEventListener("keydown", handleKeyDown)
+ return () => window.removeEventListener("keydown", handleKeyDown)
+ }, [toggleSidebar])
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed";
+ const state = open ? "expanded" : "collapsed"
- // biome-ignore lint/correctness/useExhaustiveDependencies:
const contextValue = React.useMemo(
() => ({
state,
@@ -122,13 +124,13 @@ function SidebarProvider({
toggleSidebar,
}),
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- );
+ )
return (
- );
+ )
}
function Sidebar({
@@ -157,16 +159,16 @@ function Sidebar({
children,
...props
}: React.ComponentProps<"div"> & {
- side?: "left" | "right";
- variant?: "sidebar" | "floating" | "inset";
- collapsible?: "offcanvas" | "icon" | "none";
+ side?: "left" | "right"
+ variant?: "sidebar" | "floating" | "inset"
+ collapsible?: "offcanvas" | "icon" | "none"
}) {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
if (collapsible === "none") {
return (
{children}
- );
+ )
}
if (isMobile) {
return (
-
+
Sidebar
Displays the mobile sidebar.
- {children}
+ {children}
- );
+ )
}
return (
{/* This is what handles the sidebar gap on desktop */}
- );
+ )
}
-function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps
) {
- const { toggleSidebar } = useSidebar();
+function SidebarTrigger({
+ className,
+ onClick,
+ ...props
+}: React.ComponentProps) {
+ const { toggleSidebar } = useSidebar()
return (
- );
+ )
}
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar();
+ const { toggleSidebar } = useSidebar()
return (