summaryrefslogtreecommitdiff
path: root/apps/web/src/components/ui/sidebar.tsx
diff options
context:
space:
mode:
authorMaze <167211895+mazeincoding@users.noreply.github.com>2026-02-23 03:24:02 +0100
committerGitHub <noreply@github.com>2026-02-23 03:24:02 +0100
commit93d1e3383ce47e45157d70f9ba6251239dae6bc2 (patch)
tree1e33a2d7533b65f0e7c8927f03905a1a99937bd1 /apps/web/src/components/ui/sidebar.tsx
parentfca99d6126c31fbb18ed9f1034cee6f940b040e8 (diff)
downloadopencut-93d1e3383ce47e45157d70f9ba6251239dae6bc2.tar.gz
feat: major editor overhaul (assets, properties, timeline, fonts) (#709)
* feat: major editor overhaul (assets, properties, timeline, fonts) Refactor editor core systems to standardize UI architecture and improve performance. Assets & Properties: - Replace monolithic property items with composable `Section` architecture. - Add specialized sections for Transform, Blending, and Text. - Implement `NumberField` with scrubbing and math evaluation. - Add new ColorPicker with EyeDropper and multiple format support. - Standardize asset panels using new `PanelView` layout. Fonts & Stickers: - Implement custom font atlas/sprite system for high-performance previews. - Add virtualized FontPicker with search and favorites. - Refactor stickers to use a provider-based architecture (icons, emoji, flags, shapes). - Standardize sticker IDs to `provider:value` format. Timeline & Interaction: - Convert bookmarks to rich objects with notes, colors, and duration. - Refactor drag-and-drop to use Command pattern (enabling proper undo/redo). - Add Shift modifier to disable snapping during moves/resizes. - Add new overlays for layout guides and text editing. Renderer: - Add support for multi-line text, custom line-height, and letter-spacing. - Implement global composite operation (blend modes). - Update sticker node to resolve dynamic provider IDs. Infrastructure: - Add storage migrations (v3->v6) for text weights, sticker IDs, and bookmarks. - Update global styles and core UI components (Button, Input, Popover). * add ts-nocheck directive to settings-legacy.tsx to suppress TypeScript errors * fix: correct global composite operation assignment in TextNode to ensure proper blend mode handling * deleted shadcn components with errors * formatting * fix linter issues * migrate from next middleware to proxy * add missing component back * add breadcrumb back * chore: add @radix-ui/react-primitive deps * chore: more deps * chore: add missing env vars to bun-ci * next env
Diffstat (limited to 'apps/web/src/components/ui/sidebar.tsx')
-rw-r--r--apps/web/src/components/ui/sidebar.tsx725
1 files changed, 0 insertions, 725 deletions
diff --git a/apps/web/src/components/ui/sidebar.tsx b/apps/web/src/components/ui/sidebar.tsx
deleted file mode 100644
index a41e25c7..00000000
--- a/apps/web/src/components/ui/sidebar.tsx
+++ /dev/null
@@ -1,725 +0,0 @@
-"use client";
-
-import { Slot } from "@radix-ui/react-slot";
-import { cva, type VariantProps } from "class-variance-authority";
-import { PanelLeftIcon } from "lucide-react";
-import * as React from "react";
-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";
-import { useIsMobile } from "@/hooks/use-mobile";
-import { cn } from "@/utils/ui";
-
-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<SidebarContextProps | null>(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<SidebarContextProps>(
- () => ({
- state,
- open,
- setOpen,
- isMobile,
- openMobile,
- setOpenMobile,
- toggleSidebar,
- }),
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
- );
-
- return (
- <SidebarContext.Provider value={contextValue}>
- <TooltipProvider delayDuration={0}>
- <div
- data-slot="sidebar-wrapper"
- style={
- {
- "--sidebar-width": SIDEBAR_WIDTH,
- "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
- ...style,
- } as React.CSSProperties
- }
- className={cn(
- "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
- className,
- )}
- {...props}
- >
- {children}
- </div>
- </TooltipProvider>
- </SidebarContext.Provider>
- );
-}
-
-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 (
- <div
- data-slot="sidebar"
- className={cn(
- "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
- className,
- )}
- {...props}
- >
- {children}
- </div>
- );
- }
-
- if (isMobile) {
- return (
- <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
- <SheetContent
- data-sidebar="sidebar"
- data-slot="sidebar"
- data-mobile="true"
- className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
- style={
- {
- "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
- } as React.CSSProperties
- }
- side={side}
- >
- <SheetHeader className="sr-only">
- <SheetTitle>Sidebar</SheetTitle>
- <SheetDescription>Displays the mobile sidebar.</SheetDescription>
- </SheetHeader>
- <div className="flex size-full flex-col">{children}</div>
- </SheetContent>
- </Sheet>
- );
- }
-
- return (
- <div
- className="group peer text-sidebar-foreground hidden md:block"
- data-state={state}
- data-collapsible={state === "collapsed" ? collapsible : ""}
- data-variant={variant}
- data-side={side}
- data-slot="sidebar"
- >
- {/* This is what handles the sidebar gap on desktop */}
- <div
- data-slot="sidebar-gap"
- className={cn(
- "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
- "group-data-[collapsible=offcanvas]:w-0",
- "group-data-[side=right]:rotate-180",
- variant === "floating" || variant === "inset"
- ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
- )}
- />
- <div
- data-slot="sidebar-container"
- className={cn(
- "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
- side === "left"
- ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
- : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
- // Adjust the padding for floating and inset variants.
- variant === "floating" || variant === "inset"
- ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
- className,
- )}
- {...props}
- >
- <div
- data-sidebar="sidebar"
- data-slot="sidebar-inner"
- className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex size-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
- >
- {children}
- </div>
- </div>
- </div>
- );
-}
-
-function SidebarTrigger({
- className,
- onClick,
- ...props
-}: React.ComponentProps<typeof Button>) {
- const { toggleSidebar } = useSidebar();
-
- return (
- <Button
- data-sidebar="trigger"
- data-slot="sidebar-trigger"
- variant="text"
- size="icon"
- className={cn("size-7", className)}
- onClick={(event) => {
- onClick?.(event);
- toggleSidebar();
- }}
- {...props}
- >
- <PanelLeftIcon />
- <span className="sr-only">Toggle Sidebar</span>
- </Button>
- );
-}
-
-function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar();
-
- return (
- <button
- data-sidebar="rail"
- data-slot="sidebar-rail"
- aria-label="Toggle Sidebar"
- tabIndex={-1}
- onClick={toggleSidebar}
- title="Toggle Sidebar"
- className={cn(
- "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
- "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
- "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
- "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
- "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
- "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
- className,
- )}
- {...props}
- />
- );
-}
-
-function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
- return (
- <main
- data-slot="sidebar-inset"
- className={cn(
- "bg-background relative flex w-full flex-1 flex-col",
- "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
- className,
- )}
- {...props}
- />
- );
-}
-
-function SidebarInput({
- className,
- ...props
-}: React.ComponentProps<typeof Input>) {
- return (
- <Input
- data-slot="sidebar-input"
- data-sidebar="input"
- className={cn("bg-background h-8 w-full shadow-none", className)}
- {...props}
- />
- );
-}
-
-function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
- <div
- data-slot="sidebar-header"
- data-sidebar="header"
- className={cn("flex flex-col gap-2 p-2", className)}
- {...props}
- />
- );
-}
-
-function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
- <div
- data-slot="sidebar-footer"
- data-sidebar="footer"
- className={cn("flex flex-col gap-2 p-2", className)}
- {...props}
- />
- );
-}
-
-function SidebarSeparator({
- className,
- ...props
-}: React.ComponentProps<typeof Separator>) {
- return (
- <Separator
- data-slot="sidebar-separator"
- data-sidebar="separator"
- className={cn("bg-sidebar-border mx-2 w-auto", className)}
- {...props}
- />
- );
-}
-
-function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
- <div
- data-slot="sidebar-content"
- data-sidebar="content"
- className={cn(
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
- className,
- )}
- {...props}
- />
- );
-}
-
-function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
- return (
- <div
- data-slot="sidebar-group"
- data-sidebar="group"
- className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
- {...props}
- />
- );
-}
-
-function SidebarGroupLabel({
- className,
- asChild = false,
- ...props
-}: React.ComponentProps<"div"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "div";
-
- return (
- <Comp
- data-slot="sidebar-group-label"
- data-sidebar="group-label"
- className={cn(
- "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>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 (
- <Comp
- data-slot="sidebar-group-action"
- data-sidebar="group-action"
- className={cn(
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>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 (
- <div
- data-slot="sidebar-group-content"
- data-sidebar="group-content"
- className={cn("w-full text-sm", className)}
- {...props}
- />
- );
-}
-
-function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
- return (
- <ul
- data-slot="sidebar-menu"
- data-sidebar="menu"
- className={cn("flex w-full min-w-0 flex-col gap-1", className)}
- {...props}
- />
- );
-}
-
-function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
- return (
- <li
- data-slot="sidebar-menu-item"
- data-sidebar="menu-item"
- className={cn("group/menu-item relative", className)}
- {...props}
- />
- );
-}
-
-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<typeof TooltipContent>;
-} & VariantProps<typeof sidebarMenuButtonVariants>) {
- const Comp = asChild ? Slot : "button";
- const { isMobile, state } = useSidebar();
-
- const button = (
- <Comp
- data-slot="sidebar-menu-button"
- data-sidebar="menu-button"
- data-size={size}
- data-active={isActive}
- className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
- {...props}
- />
- );
-
- if (!tooltip) {
- return button;
- }
-
- if (typeof tooltip === "string") {
- tooltip = {
- children: tooltip,
- };
- }
-
- return (
- <Tooltip>
- <TooltipTrigger asChild>{button}</TooltipTrigger>
- <TooltipContent
- side="right"
- align="center"
- hidden={state !== "collapsed" || isMobile}
- {...tooltip}
- />
- </Tooltip>
- );
-}
-
-function SidebarMenuAction({
- className,
- asChild = false,
- showOnHover = false,
- ...props
-}: React.ComponentProps<"button"> & {
- asChild?: boolean;
- showOnHover?: boolean;
-}) {
- const Comp = asChild ? Slot : "button";
-
- return (
- <Comp
- data-slot="sidebar-menu-action"
- data-sidebar="menu-action"
- className={cn(
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>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 (
- <div
- data-slot="sidebar-menu-badge"
- data-sidebar="menu-badge"
- className={cn(
- "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
- "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
- "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",
- className,
- )}
- {...props}
- />
- );
-}
-
-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 (
- <div
- data-slot="sidebar-menu-skeleton"
- data-sidebar="menu-skeleton"
- className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
- {...props}
- >
- {showIcon && (
- <Skeleton
- className="size-4 rounded-md"
- data-sidebar="menu-skeleton-icon"
- />
- )}
- <Skeleton
- className="h-4 max-w-(--skeleton-width) flex-1"
- data-sidebar="menu-skeleton-text"
- style={
- {
- "--skeleton-width": width,
- } as React.CSSProperties
- }
- />
- </div>
- );
-}
-
-function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
- return (
- <ul
- data-slot="sidebar-menu-sub"
- data-sidebar="menu-sub"
- className={cn(
- "border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
- "group-data-[collapsible=icon]:hidden",
- className,
- )}
- {...props}
- />
- );
-}
-
-function SidebarMenuSubItem({
- className,
- ...props
-}: React.ComponentProps<"li">) {
- return (
- <li
- data-slot="sidebar-menu-sub-item"
- data-sidebar="menu-sub-item"
- className={cn("group/menu-sub-item relative", className)}
- {...props}
- />
- );
-}
-
-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 (
- <Comp
- data-slot="sidebar-menu-sub-button"
- data-sidebar="menu-sub-button"
- data-size={size}
- data-active={isActive}
- className={cn(
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>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,
-};