@lessly/ui 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +80 -11
- package/dist/index.js +278 -134
- package/dist/styles.css +16 -16
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -652,6 +652,8 @@ declare function ConfirmDialog({ open, onOpenChange, trigger, title, description
|
|
|
652
652
|
|
|
653
653
|
interface UserMenuUser {
|
|
654
654
|
name: string;
|
|
655
|
+
/** Second line of the row. The shipped rail shows the org name here. */
|
|
656
|
+
subtitle?: string;
|
|
655
657
|
email?: string;
|
|
656
658
|
avatarUrl?: string;
|
|
657
659
|
}
|
|
@@ -822,10 +824,22 @@ declare function SidebarNav({ items, collapsed, basePath, LinkComponent, isItemA
|
|
|
822
824
|
|
|
823
825
|
interface AppSidebarProps {
|
|
824
826
|
items: NavItem[];
|
|
827
|
+
/** Expanded-slot mark/wordmark, rendered when `header` is absent. Also the collapsed-rail
|
|
828
|
+
* fallback when `logoCollapsed` isn't given — see `logoCollapsed`. */
|
|
825
829
|
logo?: React$1.ReactNode;
|
|
830
|
+
/** Collapsed-rail identity — a small mark, shown overlaid by the pin on hover/focus when
|
|
831
|
+
* `collapsible`. A collapsible rail should supply this (or `logo`): `header` is expanded-only
|
|
832
|
+
* and is never read while collapsed, so without a mark the collapsed rail shows just the pin. */
|
|
826
833
|
logoCollapsed?: React$1.ReactNode;
|
|
834
|
+
/** Identity slot above the rail — e.g. a <SidebarProductHeader/>. Falls back to `logo`.
|
|
835
|
+
* Expanded-only: rendering it in the 52px collapsed rail would overflow, so the collapsed
|
|
836
|
+
* branch never reads it — supply `logoCollapsed` (or `logo`) for that state instead. */
|
|
827
837
|
header?: React$1.ReactNode;
|
|
838
|
+
/** Account slot below the rail — e.g. a <UserMenu/>. Its divider renders only with it. */
|
|
828
839
|
footer?: React$1.ReactNode;
|
|
840
|
+
/** Render the built-in collapse pin. Off by default: the shipped rail has none.
|
|
841
|
+
* `collapsed` is still honoured without it, for consumers driving collapse themselves. */
|
|
842
|
+
collapsible?: boolean;
|
|
829
843
|
collapsed?: boolean;
|
|
830
844
|
defaultCollapsed?: boolean;
|
|
831
845
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
@@ -834,7 +848,38 @@ interface AppSidebarProps {
|
|
|
834
848
|
isItemActive?: (item: NavItem, pathname: string) => boolean;
|
|
835
849
|
className?: string;
|
|
836
850
|
}
|
|
837
|
-
declare function AppSidebar({ items, logo, logoCollapsed, header, footer, collapsed: controlled, defaultCollapsed, onCollapsedChange, basePath, LinkComponent, isItemActive, className, }: AppSidebarProps): React$1.JSX.Element;
|
|
851
|
+
declare function AppSidebar({ items, logo, logoCollapsed, header, footer, collapsible, collapsed: controlled, defaultCollapsed, onCollapsedChange, basePath, LinkComponent, isItemActive, className, }: AppSidebarProps): React$1.JSX.Element;
|
|
852
|
+
|
|
853
|
+
interface SidebarProductHeaderOwnProps {
|
|
854
|
+
/** Product name. Rendered at 13/600, truncated. */
|
|
855
|
+
name: string;
|
|
856
|
+
/** Leading mark, rendered in a fixed 28px box (the shipped tile). */
|
|
857
|
+
icon?: React$1.ReactNode;
|
|
858
|
+
/** Right-aligned adornment. Defaults to the 14px ChevronsUpDown of the shipped header;
|
|
859
|
+
* pass `null` for none. */
|
|
860
|
+
trailing?: React$1.ReactNode;
|
|
861
|
+
className?: string;
|
|
862
|
+
}
|
|
863
|
+
/** Render the single child element instead of a button — e.g. a MenuPopup trigger.
|
|
864
|
+
* The header composes its content from props, so the child's own children are replaced. */
|
|
865
|
+
type SidebarProductHeaderProps = SidebarProductHeaderOwnProps & Omit<React$1.ComponentPropsWithoutRef<'button'>, 'children' | 'name'> & ({
|
|
866
|
+
asChild: true;
|
|
867
|
+
children: React$1.ReactElement;
|
|
868
|
+
} | {
|
|
869
|
+
asChild?: false;
|
|
870
|
+
children?: never;
|
|
871
|
+
});
|
|
872
|
+
/** Identity row for the sidebar header slot: product tile + name, opening the product menu.
|
|
873
|
+
*
|
|
874
|
+
* Deliberately inert on hover — no background, no transition — unlike the rail rows below
|
|
875
|
+
* it. `rounded-xl` is not dead weight despite nothing tinting the box: this declares no
|
|
876
|
+
* focus-visible ring, so the UA default ring is the only focus affordance, and that ring
|
|
877
|
+
* follows border-radius.
|
|
878
|
+
*
|
|
879
|
+
* Pair with `AppSidebar`'s `header` slot: the slot's 12px sides plus this trigger's own 6px
|
|
880
|
+
* land the tile at 18px, while the trigger's box stays flush with the rail rows at 12px —
|
|
881
|
+
* which anchors a `MenuPopup` at left:12 with the default sideOffset, no alignOffset. */
|
|
882
|
+
declare const SidebarProductHeader: React$1.ForwardRefExoticComponent<SidebarProductHeaderProps & React$1.RefAttributes<HTMLButtonElement>>;
|
|
838
883
|
|
|
839
884
|
interface AppShellProps {
|
|
840
885
|
/** The sidebar, typically an <AppSidebar/>. Rendered in the desktop rail and,
|
|
@@ -941,24 +986,48 @@ interface ConnectionCardProps extends React$1.HTMLAttributes<HTMLDivElement> {
|
|
|
941
986
|
glyph?: React$1.ReactNode;
|
|
942
987
|
/** Override the default status label (e.g. "Token expired" for `error`). */
|
|
943
988
|
statusLabel?: string;
|
|
944
|
-
/**
|
|
989
|
+
/**
|
|
990
|
+
* How many products hold a segment of this connection. `undefined` renders the
|
|
991
|
+
* "Not granted to any product yet" default — pass it ONLY on a surface where
|
|
992
|
+
* that claim is true and knowable (the org roster); on a product surface pass
|
|
993
|
+
* neither `grantedCount` nor a footer `action` to render no footer at all.
|
|
994
|
+
*/
|
|
945
995
|
grantedCount?: number;
|
|
946
|
-
/**
|
|
996
|
+
/**
|
|
997
|
+
* Footer action — typically a <Button> ("Manage", "Reconnect", "Connect").
|
|
998
|
+
* Flat mode: a disconnected card shows it in the header. Collapsible mode: the
|
|
999
|
+
* header is a disclosure trigger (nesting a button would be invalid), so the
|
|
1000
|
+
* action always renders in the expanded footer instead.
|
|
1001
|
+
*/
|
|
947
1002
|
action?: React$1.ReactNode;
|
|
948
1003
|
/**
|
|
949
1004
|
* Blast-radius disclosure. Some providers (GitHub, ClickUp) grant all-or-nothing
|
|
950
|
-
* access to the whole external org — there is no per-repo/per-space permission,
|
|
951
|
-
*
|
|
952
|
-
*
|
|
1005
|
+
* access to the whole external org — there is no per-repo/per-space permission,
|
|
1006
|
+
* and the vended credential genuinely reaches the whole external org. Copy passed
|
|
1007
|
+
* here must state that blast radius honestly (e.g. "Full org access — any product
|
|
1008
|
+
* granted this connection can reach every repository"); do NOT claim the segment
|
|
1009
|
+
* is enforced by Lessly — for these providers it is not.
|
|
953
1010
|
*/
|
|
954
1011
|
access?: React$1.ReactNode;
|
|
955
1012
|
/**
|
|
956
|
-
* Drawer content rendered below the card body — the
|
|
957
|
-
*
|
|
958
|
-
*
|
|
959
|
-
* children
|
|
1013
|
+
* Drawer content rendered below the card body — the per-product grants roster,
|
|
1014
|
+
* inline requests, "+ Grant to a product". Flat mode: the caller owns visibility,
|
|
1015
|
+
* pass children only while open (unchanged behavior). Collapsible mode: pass
|
|
1016
|
+
* children unconditionally — the card shows them while expanded.
|
|
960
1017
|
*/
|
|
961
1018
|
children?: React$1.ReactNode;
|
|
1019
|
+
/**
|
|
1020
|
+
* Disclosure mode: the header row toggles the card open/closed; the footer and
|
|
1021
|
+
* drawer render only while open. The `access` blast-radius notice stays visible
|
|
1022
|
+
* even while collapsed — it is a safety disclosure, not a detail. Collapsed by
|
|
1023
|
+
* default.
|
|
1024
|
+
*/
|
|
1025
|
+
collapsible?: boolean;
|
|
1026
|
+
/** Uncontrolled initial state (collapsible mode). Default: false (collapsed). */
|
|
1027
|
+
defaultOpen?: boolean;
|
|
1028
|
+
/** Controlled open state (collapsible mode); pair with `onOpenChange`. */
|
|
1029
|
+
open?: boolean;
|
|
1030
|
+
onOpenChange?: (open: boolean) => void;
|
|
962
1031
|
}
|
|
963
1032
|
declare const ConnectionCard: React$1.ForwardRefExoticComponent<ConnectionCardProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
964
1033
|
|
|
@@ -986,4 +1055,4 @@ interface RequestRowProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, '
|
|
|
986
1055
|
}
|
|
987
1056
|
declare const RequestRow: React$1.ForwardRefExoticComponent<RequestRowProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
988
1057
|
|
|
989
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AspectRatio, AuthenticatedLayout, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, type CarouselContextProps, CarouselItem, CarouselNext, type CarouselOptions, type CarouselPlugin, CarouselPrevious, type CarouselProps, Checkbox, Col, type ColProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, type ConnectionAuth, ConnectionCard, type ConnectionCardProps, type ConnectionScope, type ConnectionStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DeltaDirection, type DeltaTone, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DocsLink, type DocsLinkProps, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExtensionIcon, type ExtensionIconProps, ExtensionLink, type ExtensionLinkProps, type ExtensionLinkUiMode, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Grid, GridOverlay, type GridOverlayProps, type GridProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Label, MenuDivider, MenuPopup, type MenuPopupProps, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavItem, type NavLinkComponent, NavRow, type NavRowProps, type NavRowVariant, NavSectionLabel, type NavSectionLabelProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RequestRow, type RequestRowProps, type RequestState, type RequestSurface, type ResolvedTheme, type Responsive, ScrollArea, ScrollBar, SectionIntro, type SectionIntroProps, SegmentChip, type SegmentChipProps, Select, type SelectOption, type SelectProps, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, type Theme, ThemeToggle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UseSidebarOptions, type UseSidebarResult, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuUser, alertVariants, badgeVariants, buttonVariants, cn, isKnownExtensionIcon, navigationMenuTriggerStyle, segmentChipVariants, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
|
|
1058
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AspectRatio, AuthenticatedLayout, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, type CarouselContextProps, CarouselItem, CarouselNext, type CarouselOptions, type CarouselPlugin, CarouselPrevious, type CarouselProps, Checkbox, Col, type ColProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, type ConnectionAuth, ConnectionCard, type ConnectionCardProps, type ConnectionScope, type ConnectionStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DeltaDirection, type DeltaTone, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DocsLink, type DocsLinkProps, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExtensionIcon, type ExtensionIconProps, ExtensionLink, type ExtensionLinkProps, type ExtensionLinkUiMode, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Grid, GridOverlay, type GridOverlayProps, type GridProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Label, MenuDivider, MenuPopup, type MenuPopupProps, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavItem, type NavLinkComponent, NavRow, type NavRowProps, type NavRowVariant, NavSectionLabel, type NavSectionLabelProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RequestRow, type RequestRowProps, type RequestState, type RequestSurface, type ResolvedTheme, type Responsive, ScrollArea, ScrollBar, SectionIntro, type SectionIntroProps, SegmentChip, type SegmentChipProps, Select, type SelectOption, type SelectProps, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, SidebarProductHeader, type SidebarProductHeaderProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, type Theme, ThemeToggle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UseSidebarOptions, type UseSidebarResult, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuUser, alertVariants, badgeVariants, buttonVariants, cn, isKnownExtensionIcon, navigationMenuTriggerStyle, segmentChipVariants, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { Slot } from "@radix-ui/react-slot";
|
|
|
11
11
|
import { cva } from "class-variance-authority";
|
|
12
12
|
import { jsx } from "react/jsx-runtime";
|
|
13
13
|
var buttonVariants = cva(
|
|
14
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus disabled:pointer-events-none disabled:opacity-50",
|
|
14
|
+
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus disabled:pointer-events-none disabled:opacity-50",
|
|
15
15
|
{
|
|
16
16
|
variants: {
|
|
17
17
|
variant: {
|
|
@@ -2618,8 +2618,9 @@ function initialsOf(name) {
|
|
|
2618
2618
|
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
2619
2619
|
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
2620
2620
|
}
|
|
2621
|
-
function UserMenu({ user, items, collapsed = false, align = "
|
|
2622
|
-
const
|
|
2621
|
+
function UserMenu({ user, items, collapsed = false, align = "start" }) {
|
|
2622
|
+
const secondLine = user.subtitle ?? user.email;
|
|
2623
|
+
const avatar = /* @__PURE__ */ jsxs25(Avatar, { className: collapsed ? "size-9" : "size-7", children: [
|
|
2623
2624
|
user.avatarUrl && /* @__PURE__ */ jsx52(AvatarImage, { src: user.avatarUrl, alt: user.name }),
|
|
2624
2625
|
/* @__PURE__ */ jsx52(AvatarFallback, { className: "text-xs", children: initialsOf(user.name) })
|
|
2625
2626
|
] });
|
|
@@ -2635,14 +2636,14 @@ function UserMenu({ user, items, collapsed = false, align = "end" }) {
|
|
|
2635
2636
|
"button",
|
|
2636
2637
|
{
|
|
2637
2638
|
type: "button",
|
|
2638
|
-
className: "flex w-full items-center gap-2.5 rounded-xl px-
|
|
2639
|
+
className: "flex w-full items-center gap-2.5 rounded-xl px-1.5 py-[5px] text-left transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
2639
2640
|
children: [
|
|
2640
2641
|
avatar,
|
|
2641
|
-
/* @__PURE__ */ jsxs25("span", { className: "min-w-0 flex-1", children: [
|
|
2642
|
-
/* @__PURE__ */ jsx52("span", { className: "
|
|
2643
|
-
|
|
2642
|
+
/* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
2643
|
+
/* @__PURE__ */ jsx52("span", { className: "truncate text-sm leading-[normal] font-medium text-text-primary", children: user.name }),
|
|
2644
|
+
secondLine && /* @__PURE__ */ jsx52("span", { className: "truncate text-xs leading-[normal] text-text-tertiary", children: secondLine })
|
|
2644
2645
|
] }),
|
|
2645
|
-
/* @__PURE__ */ jsx52(ChevronsUpDown, {
|
|
2646
|
+
/* @__PURE__ */ jsx52(ChevronsUpDown, { size: 14, "aria-hidden": "true", className: "shrink-0 text-text-tertiary" })
|
|
2646
2647
|
]
|
|
2647
2648
|
}
|
|
2648
2649
|
);
|
|
@@ -2661,7 +2662,7 @@ function UserMenu({ user, items, collapsed = false, align = "end" }) {
|
|
|
2661
2662
|
children: [
|
|
2662
2663
|
/* @__PURE__ */ jsxs25(DropdownMenuLabel, { className: "px-2 pt-1.5 pb-1 text-xs font-medium text-text-tertiary", children: [
|
|
2663
2664
|
/* @__PURE__ */ jsx52("span", { className: "block truncate text-sm font-medium text-text-primary", children: user.name }),
|
|
2664
|
-
|
|
2665
|
+
secondLine && /* @__PURE__ */ jsx52("span", { className: "block truncate text-xs font-normal text-text-tertiary", children: secondLine })
|
|
2665
2666
|
] }),
|
|
2666
2667
|
/* @__PURE__ */ jsx52(DropdownMenuSeparator, { className: "mx-0 shrink-0 bg-border-subtle" }),
|
|
2667
2668
|
items.map((item, i) => {
|
|
@@ -2938,8 +2939,8 @@ function SidebarNav({
|
|
|
2938
2939
|
"nav",
|
|
2939
2940
|
{
|
|
2940
2941
|
className: cn(
|
|
2941
|
-
"flex flex-col gap-
|
|
2942
|
-
collapsed
|
|
2942
|
+
"flex flex-col gap-2",
|
|
2943
|
+
collapsed && "items-center",
|
|
2943
2944
|
className
|
|
2944
2945
|
),
|
|
2945
2946
|
children: items.map((item) => {
|
|
@@ -2964,13 +2965,27 @@ function SidebarNav({
|
|
|
2964
2965
|
|
|
2965
2966
|
// src/components/app-sidebar.tsx
|
|
2966
2967
|
import { PanelLeft } from "lucide-react";
|
|
2967
|
-
import { jsx as jsx59, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2968
|
+
import { Fragment as Fragment3, jsx as jsx59, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2969
|
+
function Divider({ collapsed, testId, className }) {
|
|
2970
|
+
return /* @__PURE__ */ jsx59(
|
|
2971
|
+
"div",
|
|
2972
|
+
{
|
|
2973
|
+
"data-testid": testId,
|
|
2974
|
+
className: cn(
|
|
2975
|
+
"h-px shrink-0 bg-border-subtle",
|
|
2976
|
+
collapsed ? "ml-[6px] w-[40px]" : "ml-[14px] w-[220px]",
|
|
2977
|
+
className
|
|
2978
|
+
)
|
|
2979
|
+
}
|
|
2980
|
+
);
|
|
2981
|
+
}
|
|
2968
2982
|
function AppSidebar({
|
|
2969
2983
|
items,
|
|
2970
2984
|
logo,
|
|
2971
2985
|
logoCollapsed,
|
|
2972
2986
|
header,
|
|
2973
2987
|
footer,
|
|
2988
|
+
collapsible = false,
|
|
2974
2989
|
collapsed: controlled,
|
|
2975
2990
|
defaultCollapsed,
|
|
2976
2991
|
onCollapsedChange,
|
|
@@ -2984,18 +2999,49 @@ function AppSidebar({
|
|
|
2984
2999
|
defaultCollapsed,
|
|
2985
3000
|
onCollapsedChange
|
|
2986
3001
|
});
|
|
3002
|
+
const pin = collapsible ? /* @__PURE__ */ jsx59(
|
|
3003
|
+
"button",
|
|
3004
|
+
{
|
|
3005
|
+
type: "button",
|
|
3006
|
+
onClick: toggle,
|
|
3007
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3008
|
+
"aria-expanded": !collapsed,
|
|
3009
|
+
className: "flex size-6 shrink-0 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
3010
|
+
children: /* @__PURE__ */ jsx59(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
3011
|
+
}
|
|
3012
|
+
) : null;
|
|
2987
3013
|
return /* @__PURE__ */ jsxs29(
|
|
2988
3014
|
"aside",
|
|
2989
3015
|
{
|
|
2990
3016
|
"data-collapsed": collapsed,
|
|
2991
3017
|
className: cn(
|
|
2992
|
-
"flex h-full flex-col overflow-hidden
|
|
2993
|
-
collapsed ? "w-[52px]" : "w-[
|
|
3018
|
+
"flex h-full shrink-0 flex-col overflow-hidden transition-[width] duration-200 ease-in-out",
|
|
3019
|
+
collapsed ? "w-[52px]" : "w-[248px]",
|
|
2994
3020
|
className
|
|
2995
3021
|
),
|
|
2996
3022
|
children: [
|
|
2997
|
-
|
|
2998
|
-
/*
|
|
3023
|
+
/* @__PURE__ */ jsx59("div", { className: cn("flex items-center gap-2", collapsed ? "justify-center px-1 pt-2" : "px-3 pt-[13px]"), children: collapsed ? collapsible ? logoCollapsed ?? logo ? (
|
|
3024
|
+
/* The collapsed rail (52px) can't fit the logo mark beside the pin side by side —
|
|
3025
|
+
so the pin overlays the mark instead, revealed on hover/focus, same as pre-flat-rail. */
|
|
3026
|
+
/* @__PURE__ */ jsxs29("div", { className: "group relative flex size-8 items-center justify-center", children: [
|
|
3027
|
+
/* @__PURE__ */ jsx59("span", { className: "pointer-events-none transition-opacity group-hover:opacity-0 group-focus-within:opacity-0", children: logoCollapsed ?? logo }),
|
|
3028
|
+
/* @__PURE__ */ jsx59(
|
|
3029
|
+
"button",
|
|
3030
|
+
{
|
|
3031
|
+
type: "button",
|
|
3032
|
+
onClick: toggle,
|
|
3033
|
+
"aria-label": "Expand sidebar",
|
|
3034
|
+
"aria-expanded": false,
|
|
3035
|
+
className: "absolute inset-0 flex items-center justify-center rounded-md text-text-secondary opacity-0 transition-opacity hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-border-focus group-hover:opacity-100 group-focus-within:opacity-100",
|
|
3036
|
+
children: /* @__PURE__ */ jsx59(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
3037
|
+
}
|
|
3038
|
+
)
|
|
3039
|
+
] })
|
|
3040
|
+
) : (
|
|
3041
|
+
/* No mark to hide behind (no `logoCollapsed`/`logo` given — `header` doesn't
|
|
3042
|
+
count, it's expanded-only). Hover-revealing the pin over nothing would leave
|
|
3043
|
+
an invisible 32px box as the only way back to expanded, so render it plain
|
|
3044
|
+
and fully visible instead. */
|
|
2999
3045
|
/* @__PURE__ */ jsx59(
|
|
3000
3046
|
"button",
|
|
3001
3047
|
{
|
|
@@ -3003,80 +3049,107 @@ function AppSidebar({
|
|
|
3003
3049
|
onClick: toggle,
|
|
3004
3050
|
"aria-label": "Expand sidebar",
|
|
3005
3051
|
"aria-expanded": false,
|
|
3006
|
-
className: "
|
|
3052
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
3007
3053
|
children: /* @__PURE__ */ jsx59(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
3008
3054
|
}
|
|
3009
3055
|
)
|
|
3010
|
-
|
|
3056
|
+
) : logoCollapsed ?? logo : /* @__PURE__ */ jsxs29(Fragment3, { children: [
|
|
3011
3057
|
header ?? logo,
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3058
|
+
pin
|
|
3059
|
+
] }) }),
|
|
3060
|
+
/* @__PURE__ */ jsx59(Divider, { collapsed, testId: "sidebar-divider-header", className: "mt-3" }),
|
|
3061
|
+
/* @__PURE__ */ jsx59(
|
|
3062
|
+
"div",
|
|
3063
|
+
{
|
|
3064
|
+
"data-testid": "sidebar-scroll",
|
|
3065
|
+
className: cn(
|
|
3066
|
+
"min-h-0 flex-1 overflow-y-auto overflow-x-hidden pt-3 pb-2",
|
|
3067
|
+
collapsed ? "px-1" : "px-3"
|
|
3068
|
+
),
|
|
3069
|
+
children: /* @__PURE__ */ jsx59(SidebarNav, { items, collapsed, basePath, LinkComponent, isItemActive })
|
|
3070
|
+
}
|
|
3071
|
+
),
|
|
3072
|
+
footer && /* @__PURE__ */ jsxs29(Fragment3, { children: [
|
|
3073
|
+
/* @__PURE__ */ jsx59(Divider, { collapsed, testId: "sidebar-divider-account" }),
|
|
3074
|
+
/* @__PURE__ */ jsx59("div", { className: cn("py-2", collapsed ? "px-1" : "px-3"), children: footer })
|
|
3075
|
+
] })
|
|
3026
3076
|
]
|
|
3027
3077
|
}
|
|
3028
3078
|
);
|
|
3029
3079
|
}
|
|
3030
3080
|
|
|
3031
|
-
// src/components/
|
|
3081
|
+
// src/components/sidebar-product-header.tsx
|
|
3032
3082
|
import * as React50 from "react";
|
|
3083
|
+
import { Slot as Slot5 } from "@radix-ui/react-slot";
|
|
3084
|
+
import { ChevronsUpDown as ChevronsUpDown2 } from "lucide-react";
|
|
3085
|
+
import { Fragment as Fragment4, jsx as jsx60, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3086
|
+
var SidebarProductHeader = React50.forwardRef(
|
|
3087
|
+
function SidebarProductHeader2({ name, icon, trailing, asChild = false, className, children, ...props }, ref) {
|
|
3088
|
+
const adornment = trailing === void 0 ? /* @__PURE__ */ jsx60(ChevronsUpDown2, { size: 14, "aria-hidden": "true", className: "shrink-0 text-text-tertiary" }) : trailing;
|
|
3089
|
+
const content = /* @__PURE__ */ jsxs30(Fragment4, { children: [
|
|
3090
|
+
icon && /* @__PURE__ */ jsx60("span", { className: "flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-md", "aria-hidden": "true", children: icon }),
|
|
3091
|
+
/* @__PURE__ */ jsx60("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-text-primary", children: name }),
|
|
3092
|
+
adornment && /* @__PURE__ */ jsx60("span", { className: "flex shrink-0 items-center", children: adornment })
|
|
3093
|
+
] });
|
|
3094
|
+
const classes = cn("flex w-full items-center gap-2.5 rounded-xl px-1.5 py-0 text-left", className);
|
|
3095
|
+
if (asChild) {
|
|
3096
|
+
const child = React50.Children.only(children);
|
|
3097
|
+
return /* @__PURE__ */ jsx60(Slot5, { ref, className: classes, ...props, children: React50.cloneElement(child, void 0, content) });
|
|
3098
|
+
}
|
|
3099
|
+
return /* @__PURE__ */ jsx60("button", { ref, type: "button", className: classes, ...props, children: content });
|
|
3100
|
+
}
|
|
3101
|
+
);
|
|
3102
|
+
SidebarProductHeader.displayName = "SidebarProductHeader";
|
|
3103
|
+
|
|
3104
|
+
// src/components/app-shell.tsx
|
|
3105
|
+
import * as React51 from "react";
|
|
3033
3106
|
import { Menu as Menu2 } from "lucide-react";
|
|
3034
3107
|
import { useLocation as useLocation2 } from "react-router";
|
|
3035
|
-
import { jsx as
|
|
3108
|
+
import { jsx as jsx61, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3036
3109
|
function expandedSidebar(sidebar) {
|
|
3037
|
-
return
|
|
3110
|
+
return React51.isValidElement(sidebar) ? React51.cloneElement(sidebar, { collapsed: false }) : sidebar;
|
|
3038
3111
|
}
|
|
3039
3112
|
function AppShell({ sidebar, topBar, children, className }) {
|
|
3040
3113
|
const { pathname } = useLocation2();
|
|
3041
|
-
const [mobileOpen, setMobileOpen] =
|
|
3042
|
-
|
|
3114
|
+
const [mobileOpen, setMobileOpen] = React51.useState(false);
|
|
3115
|
+
React51.useEffect(() => {
|
|
3043
3116
|
setMobileOpen(false);
|
|
3044
3117
|
}, [pathname]);
|
|
3045
3118
|
const isMobile = useIsMobile();
|
|
3046
3119
|
if (isMobile) {
|
|
3047
|
-
return /* @__PURE__ */
|
|
3048
|
-
/* @__PURE__ */
|
|
3049
|
-
/* @__PURE__ */
|
|
3050
|
-
/* @__PURE__ */
|
|
3051
|
-
/* @__PURE__ */
|
|
3052
|
-
/* @__PURE__ */
|
|
3053
|
-
/* @__PURE__ */
|
|
3120
|
+
return /* @__PURE__ */ jsx61(TooltipProvider, { children: /* @__PURE__ */ jsxs31("div", { className: cn("flex min-h-screen flex-col bg-bg-surface", className), children: [
|
|
3121
|
+
/* @__PURE__ */ jsxs31("header", { className: "flex shrink-0 items-center justify-between border-b border-border-subtle bg-bg-surface px-4 py-3", children: [
|
|
3122
|
+
/* @__PURE__ */ jsxs31(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
|
|
3123
|
+
/* @__PURE__ */ jsx61(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx61(Button, { variant: "ghost", size: "icon", className: "size-8 text-text-secondary", "aria-label": "Open navigation", children: /* @__PURE__ */ jsx61(Menu2, { className: "size-5" }) }) }),
|
|
3124
|
+
/* @__PURE__ */ jsxs31(SheetContent, { side: "left", className: "w-[248px] bg-bg-surface p-0", children: [
|
|
3125
|
+
/* @__PURE__ */ jsx61(SheetTitle, { className: "sr-only", children: "Navigation" }),
|
|
3126
|
+
/* @__PURE__ */ jsx61(SheetDescription, { className: "sr-only", children: "Application navigation menu" }),
|
|
3054
3127
|
expandedSidebar(sidebar)
|
|
3055
3128
|
] })
|
|
3056
3129
|
] }),
|
|
3057
|
-
/* @__PURE__ */
|
|
3130
|
+
/* @__PURE__ */ jsx61("div", { className: "flex items-center gap-2", children: topBar })
|
|
3058
3131
|
] }),
|
|
3059
|
-
/* @__PURE__ */
|
|
3132
|
+
/* @__PURE__ */ jsx61("main", { className: "flex-1 overflow-auto", children })
|
|
3060
3133
|
] }) });
|
|
3061
3134
|
}
|
|
3062
|
-
return /* @__PURE__ */
|
|
3063
|
-
/* @__PURE__ */
|
|
3064
|
-
/* @__PURE__ */
|
|
3065
|
-
/* @__PURE__ */
|
|
3066
|
-
/* @__PURE__ */
|
|
3135
|
+
return /* @__PURE__ */ jsx61(TooltipProvider, { children: /* @__PURE__ */ jsxs31("div", { className: cn("flex min-h-screen gap-3 bg-bg-surface p-4", className), children: [
|
|
3136
|
+
/* @__PURE__ */ jsx61("div", { className: "sticky top-4 h-[calc(100vh-32px)] shrink-0", children: sidebar }),
|
|
3137
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", children: [
|
|
3138
|
+
topBar && /* @__PURE__ */ jsx61("div", { className: "flex shrink-0 items-center justify-end gap-2", children: topBar }),
|
|
3139
|
+
/* @__PURE__ */ jsx61("main", { className: "flex-1 overflow-y-auto", children })
|
|
3067
3140
|
] })
|
|
3068
3141
|
] }) });
|
|
3069
3142
|
}
|
|
3070
3143
|
var AuthenticatedLayout = AppShell;
|
|
3071
3144
|
|
|
3072
3145
|
// src/components/grid.tsx
|
|
3073
|
-
import * as
|
|
3074
|
-
import { Slot as
|
|
3075
|
-
import { jsx as
|
|
3076
|
-
var Grid =
|
|
3146
|
+
import * as React52 from "react";
|
|
3147
|
+
import { Slot as Slot6 } from "@radix-ui/react-slot";
|
|
3148
|
+
import { jsx as jsx62 } from "react/jsx-runtime";
|
|
3149
|
+
var Grid = React52.forwardRef(
|
|
3077
3150
|
({ fluid = false, asChild = false, className, ...props }, ref) => {
|
|
3078
|
-
const Comp = asChild ?
|
|
3079
|
-
return /* @__PURE__ */
|
|
3151
|
+
const Comp = asChild ? Slot6 : "div";
|
|
3152
|
+
return /* @__PURE__ */ jsx62(
|
|
3080
3153
|
Comp,
|
|
3081
3154
|
{
|
|
3082
3155
|
ref,
|
|
@@ -3094,9 +3167,9 @@ var Grid = React51.forwardRef(
|
|
|
3094
3167
|
Grid.displayName = "Grid";
|
|
3095
3168
|
|
|
3096
3169
|
// src/components/col.tsx
|
|
3097
|
-
import * as
|
|
3098
|
-
import { Slot as
|
|
3099
|
-
import { jsx as
|
|
3170
|
+
import * as React53 from "react";
|
|
3171
|
+
import { Slot as Slot7 } from "@radix-ui/react-slot";
|
|
3172
|
+
import { jsx as jsx63 } from "react/jsx-runtime";
|
|
3100
3173
|
var TIER_MAX = { base: 4, md: 8, xl: 12 };
|
|
3101
3174
|
var SPAN = {
|
|
3102
3175
|
base: { 1: "col-span-1", 2: "col-span-2", 3: "col-span-3", 4: "col-span-4" },
|
|
@@ -3216,22 +3289,22 @@ function responsiveClasses(span, offset) {
|
|
|
3216
3289
|
}
|
|
3217
3290
|
return cn(...spanClasses, ...startClasses);
|
|
3218
3291
|
}
|
|
3219
|
-
var Col =
|
|
3292
|
+
var Col = React53.forwardRef(
|
|
3220
3293
|
({ span, offset, asChild = false, className, ...props }, ref) => {
|
|
3221
|
-
const Comp = asChild ?
|
|
3222
|
-
return /* @__PURE__ */
|
|
3294
|
+
const Comp = asChild ? Slot7 : "div";
|
|
3295
|
+
return /* @__PURE__ */ jsx63(Comp, { ref, className: cn(responsiveClasses(span, offset), className), ...props });
|
|
3223
3296
|
}
|
|
3224
3297
|
);
|
|
3225
3298
|
Col.displayName = "Col";
|
|
3226
3299
|
|
|
3227
3300
|
// src/components/grid-overlay.tsx
|
|
3228
|
-
import * as
|
|
3229
|
-
import { jsx as
|
|
3301
|
+
import * as React54 from "react";
|
|
3302
|
+
import { jsx as jsx64 } from "react/jsx-runtime";
|
|
3230
3303
|
var BASELINE = "var(--grid-gutter) / 2";
|
|
3231
|
-
var GridOverlay =
|
|
3304
|
+
var GridOverlay = React54.forwardRef(
|
|
3232
3305
|
({ columns, baseline = false, className, style, ...props }, ref) => {
|
|
3233
3306
|
const count = Number.isFinite(columns) ? Math.max(1, Math.floor(columns)) : 1;
|
|
3234
|
-
return /* @__PURE__ */
|
|
3307
|
+
return /* @__PURE__ */ jsx64(
|
|
3235
3308
|
"div",
|
|
3236
3309
|
{
|
|
3237
3310
|
ref,
|
|
@@ -3248,7 +3321,7 @@ var GridOverlay = React53.forwardRef(
|
|
|
3248
3321
|
...style
|
|
3249
3322
|
},
|
|
3250
3323
|
...props,
|
|
3251
|
-
children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */
|
|
3324
|
+
children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ jsx64("span", { style: { backgroundColor: "var(--bg-brand)", opacity: 0.1 } }, i))
|
|
3252
3325
|
}
|
|
3253
3326
|
);
|
|
3254
3327
|
}
|
|
@@ -3256,10 +3329,10 @@ var GridOverlay = React53.forwardRef(
|
|
|
3256
3329
|
GridOverlay.displayName = "GridOverlay";
|
|
3257
3330
|
|
|
3258
3331
|
// src/components/segment-chip.tsx
|
|
3259
|
-
import * as
|
|
3332
|
+
import * as React55 from "react";
|
|
3260
3333
|
import { cva as cva9 } from "class-variance-authority";
|
|
3261
3334
|
import { Link2 as Link22, KeyRound, Clock, Plus } from "lucide-react";
|
|
3262
|
-
import { jsx as
|
|
3335
|
+
import { jsx as jsx65, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3263
3336
|
var segmentChipVariants = cva9(
|
|
3264
3337
|
"inline-flex items-center gap-1.5 rounded-lg border px-2.5 py-1 text-sm font-medium leading-tight",
|
|
3265
3338
|
{
|
|
@@ -3280,11 +3353,11 @@ var kindIcons = {
|
|
|
3280
3353
|
pending: Clock,
|
|
3281
3354
|
available: Plus
|
|
3282
3355
|
};
|
|
3283
|
-
var SegmentChip =
|
|
3356
|
+
var SegmentChip = React55.forwardRef(
|
|
3284
3357
|
({ kind, resource, icon, hideIcon = false, className, ...props }, ref) => {
|
|
3285
3358
|
const Icon = icon ?? kindIcons[kind ?? "granted"];
|
|
3286
|
-
return /* @__PURE__ */
|
|
3287
|
-
!hideIcon && /* @__PURE__ */
|
|
3359
|
+
return /* @__PURE__ */ jsxs32("span", { ref, className: cn(segmentChipVariants({ kind }), className), ...props, children: [
|
|
3360
|
+
!hideIcon && /* @__PURE__ */ jsx65(Icon, { className: "size-3.5 shrink-0 opacity-90", "aria-hidden": "true" }),
|
|
3288
3361
|
resource
|
|
3289
3362
|
] });
|
|
3290
3363
|
}
|
|
@@ -3292,9 +3365,9 @@ var SegmentChip = React54.forwardRef(
|
|
|
3292
3365
|
SegmentChip.displayName = "SegmentChip";
|
|
3293
3366
|
|
|
3294
3367
|
// src/components/connection-card.tsx
|
|
3295
|
-
import * as
|
|
3296
|
-
import { AlertTriangle } from "lucide-react";
|
|
3297
|
-
import { Fragment as
|
|
3368
|
+
import * as React56 from "react";
|
|
3369
|
+
import { AlertTriangle, ChevronDown as ChevronDown4 } from "lucide-react";
|
|
3370
|
+
import { Fragment as Fragment5, jsx as jsx66, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3298
3371
|
var authLabels = { app: "App", oauth: "OAuth", token: "token" };
|
|
3299
3372
|
var statusMeta = {
|
|
3300
3373
|
connected: { label: "Connected", badge: "success", dot: "success" },
|
|
@@ -3304,85 +3377,155 @@ var statusMeta = {
|
|
|
3304
3377
|
function monogram(name) {
|
|
3305
3378
|
return name.replace(/[^a-zA-Z0-9 ]/g, " ").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
|
|
3306
3379
|
}
|
|
3307
|
-
var ConnectionCard =
|
|
3308
|
-
({
|
|
3380
|
+
var ConnectionCard = React56.forwardRef(
|
|
3381
|
+
({
|
|
3382
|
+
name,
|
|
3383
|
+
scope,
|
|
3384
|
+
auth,
|
|
3385
|
+
status,
|
|
3386
|
+
glyph,
|
|
3387
|
+
statusLabel,
|
|
3388
|
+
grantedCount,
|
|
3389
|
+
action,
|
|
3390
|
+
access,
|
|
3391
|
+
children,
|
|
3392
|
+
collapsible = false,
|
|
3393
|
+
defaultOpen,
|
|
3394
|
+
open,
|
|
3395
|
+
onOpenChange,
|
|
3396
|
+
className,
|
|
3397
|
+
...props
|
|
3398
|
+
}, ref) => {
|
|
3309
3399
|
const meta = statusMeta[status];
|
|
3310
3400
|
const connected = status !== "disconnected";
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
"
|
|
3401
|
+
const glyphBox = /* @__PURE__ */ jsx66(
|
|
3402
|
+
"div",
|
|
3403
|
+
{
|
|
3404
|
+
"aria-hidden": "true",
|
|
3405
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-lg border border-border-subtle bg-bg-elevated text-sm font-bold text-text-secondary",
|
|
3406
|
+
children: glyph ?? monogram(name)
|
|
3407
|
+
}
|
|
3408
|
+
);
|
|
3409
|
+
const identity = /* @__PURE__ */ jsxs33("div", { className: "min-w-0", children: [
|
|
3410
|
+
/* @__PURE__ */ jsx66("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
|
|
3411
|
+
/* @__PURE__ */ jsxs33("div", { className: "mt-0.5 flex flex-wrap gap-1", children: [
|
|
3412
|
+
/* @__PURE__ */ jsx66(Badge, { variant: "secondary", children: scope }),
|
|
3413
|
+
/* @__PURE__ */ jsx66(Badge, { variant: "secondary", children: authLabels[auth] })
|
|
3414
|
+
] })
|
|
3415
|
+
] });
|
|
3416
|
+
const statusBadge = /* @__PURE__ */ jsxs33(Badge, { variant: meta.badge, className: "gap-1.5", children: [
|
|
3417
|
+
/* @__PURE__ */ jsx66(StatusDot, { status: meta.dot, size: "sm" }),
|
|
3418
|
+
statusLabel ?? meta.label
|
|
3419
|
+
] });
|
|
3420
|
+
const accessNote = access ? /* @__PURE__ */ jsxs33(
|
|
3421
|
+
"div",
|
|
3422
|
+
{
|
|
3423
|
+
role: "note",
|
|
3424
|
+
className: "flex items-start gap-2 border-t border-border-subtle bg-bg-warning-subtle px-4 py-2.5 text-xs font-medium text-text-warning",
|
|
3425
|
+
children: [
|
|
3426
|
+
/* @__PURE__ */ jsx66(AlertTriangle, { className: "mt-0.5 size-3.5 shrink-0", "aria-hidden": "true" }),
|
|
3427
|
+
/* @__PURE__ */ jsx66("span", { children: access })
|
|
3428
|
+
]
|
|
3429
|
+
}
|
|
3430
|
+
) : null;
|
|
3431
|
+
const footerAction = collapsible ? action : connected && action;
|
|
3432
|
+
const footer = grantedCount !== void 0 || footerAction ? /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between border-t border-border-subtle px-4 py-3", children: [
|
|
3433
|
+
/* @__PURE__ */ jsx66("span", { className: "text-sm text-text-secondary", children: grantedCount !== void 0 ? /* @__PURE__ */ jsxs33(Fragment5, { children: [
|
|
3434
|
+
"Granted to ",
|
|
3435
|
+
/* @__PURE__ */ jsx66("span", { className: "font-semibold text-text-primary", children: grantedCount }),
|
|
3436
|
+
" ",
|
|
3437
|
+
grantedCount === 1 ? "product" : "products"
|
|
3438
|
+
] }) : /* @__PURE__ */ jsx66("span", { className: "text-text-tertiary", children: "Not granted to any product yet" }) }),
|
|
3439
|
+
footerAction
|
|
3440
|
+
] }) : null;
|
|
3441
|
+
const drawer = children ? /* @__PURE__ */ jsx66("div", { "data-slot": "drawer", className: "border-t border-border-subtle", children }) : null;
|
|
3442
|
+
if (!collapsible) {
|
|
3443
|
+
return /* @__PURE__ */ jsxs33(
|
|
3444
|
+
Card,
|
|
3335
3445
|
{
|
|
3336
|
-
|
|
3337
|
-
className: "
|
|
3446
|
+
ref,
|
|
3447
|
+
className: cn(status === "disconnected" && "border-dashed border-border-default", className),
|
|
3448
|
+
...props,
|
|
3338
3449
|
children: [
|
|
3339
|
-
/* @__PURE__ */
|
|
3340
|
-
|
|
3450
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-3 p-4", children: [
|
|
3451
|
+
glyphBox,
|
|
3452
|
+
identity,
|
|
3453
|
+
/* @__PURE__ */ jsx66("div", { className: "ml-auto shrink-0", children: connected ? statusBadge : action })
|
|
3454
|
+
] }),
|
|
3455
|
+
accessNote,
|
|
3456
|
+
footer,
|
|
3457
|
+
drawer
|
|
3341
3458
|
]
|
|
3342
3459
|
}
|
|
3343
|
-
)
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3460
|
+
);
|
|
3461
|
+
}
|
|
3462
|
+
return /* @__PURE__ */ jsx66(Collapsible, { defaultOpen, open, onOpenChange, children: /* @__PURE__ */ jsxs33(
|
|
3463
|
+
Card,
|
|
3464
|
+
{
|
|
3465
|
+
ref,
|
|
3466
|
+
className: cn(status === "disconnected" && "border-dashed border-border-default", className),
|
|
3467
|
+
...props,
|
|
3468
|
+
children: [
|
|
3469
|
+
/* @__PURE__ */ jsx66(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs33(
|
|
3470
|
+
"button",
|
|
3471
|
+
{
|
|
3472
|
+
type: "button",
|
|
3473
|
+
className: "group flex w-full cursor-pointer items-center gap-3 rounded-[inherit] p-4 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
3474
|
+
children: [
|
|
3475
|
+
glyphBox,
|
|
3476
|
+
identity,
|
|
3477
|
+
/* @__PURE__ */ jsxs33("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
|
|
3478
|
+
statusBadge,
|
|
3479
|
+
/* @__PURE__ */ jsx66(
|
|
3480
|
+
ChevronDown4,
|
|
3481
|
+
{
|
|
3482
|
+
"aria-hidden": "true",
|
|
3483
|
+
className: "size-4 shrink-0 text-text-tertiary transition-transform group-data-[state=open]:rotate-180"
|
|
3484
|
+
}
|
|
3485
|
+
)
|
|
3486
|
+
] })
|
|
3487
|
+
]
|
|
3488
|
+
}
|
|
3489
|
+
) }),
|
|
3490
|
+
accessNote,
|
|
3491
|
+
/* @__PURE__ */ jsxs33(CollapsibleContent2, { children: [
|
|
3492
|
+
footer,
|
|
3493
|
+
drawer
|
|
3494
|
+
] })
|
|
3495
|
+
]
|
|
3496
|
+
}
|
|
3497
|
+
) });
|
|
3355
3498
|
}
|
|
3356
3499
|
);
|
|
3357
3500
|
ConnectionCard.displayName = "ConnectionCard";
|
|
3358
3501
|
|
|
3359
3502
|
// src/components/request-row.tsx
|
|
3360
|
-
import * as
|
|
3361
|
-
import { Fragment as
|
|
3503
|
+
import * as React57 from "react";
|
|
3504
|
+
import { Fragment as Fragment6, jsx as jsx67, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3362
3505
|
function monogram2(name) {
|
|
3363
3506
|
return name.replace(/[^a-zA-Z0-9 ]/g, " ").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
|
|
3364
3507
|
}
|
|
3365
|
-
var RequestRow =
|
|
3508
|
+
var RequestRow = React57.forwardRef(
|
|
3366
3509
|
({ surface, name, state: state2, glyph, subtitle, grantedResource, onApprove, onDeny, onRequest, action, className, ...props }, ref) => {
|
|
3367
3510
|
let controls = action;
|
|
3368
3511
|
if (controls === void 0) {
|
|
3369
3512
|
if (surface === "org" && state2 === "pending") {
|
|
3370
|
-
controls = /* @__PURE__ */
|
|
3371
|
-
/* @__PURE__ */
|
|
3372
|
-
/* @__PURE__ */
|
|
3513
|
+
controls = /* @__PURE__ */ jsxs34(Fragment6, { children: [
|
|
3514
|
+
/* @__PURE__ */ jsx67(Button, { variant: "outline", size: "sm", onClick: onDeny, children: "Deny" }),
|
|
3515
|
+
/* @__PURE__ */ jsx67(Button, { size: "sm", onClick: onApprove, children: "Approve" })
|
|
3373
3516
|
] });
|
|
3374
3517
|
} else if (state2 === "available") {
|
|
3375
|
-
controls = /* @__PURE__ */
|
|
3518
|
+
controls = /* @__PURE__ */ jsx67(Button, { size: "sm", onClick: onRequest, children: "Request" });
|
|
3376
3519
|
} else if (state2 === "pending") {
|
|
3377
|
-
controls = /* @__PURE__ */
|
|
3378
|
-
/* @__PURE__ */
|
|
3520
|
+
controls = /* @__PURE__ */ jsxs34(Badge, { variant: "secondary", className: "gap-1.5", children: [
|
|
3521
|
+
/* @__PURE__ */ jsx67(StatusDot, { status: "neutral", size: "sm" }),
|
|
3379
3522
|
"Pending"
|
|
3380
3523
|
] });
|
|
3381
3524
|
} else if (state2 === "granted") {
|
|
3382
|
-
controls = /* @__PURE__ */
|
|
3525
|
+
controls = /* @__PURE__ */ jsx67(SegmentChip, { kind: "granted", resource: grantedResource ?? "a segment" });
|
|
3383
3526
|
}
|
|
3384
3527
|
}
|
|
3385
|
-
return /* @__PURE__ */
|
|
3528
|
+
return /* @__PURE__ */ jsxs34(
|
|
3386
3529
|
"div",
|
|
3387
3530
|
{
|
|
3388
3531
|
ref,
|
|
@@ -3392,7 +3535,7 @@ var RequestRow = React56.forwardRef(
|
|
|
3392
3535
|
),
|
|
3393
3536
|
...props,
|
|
3394
3537
|
children: [
|
|
3395
|
-
/* @__PURE__ */
|
|
3538
|
+
/* @__PURE__ */ jsx67(
|
|
3396
3539
|
"div",
|
|
3397
3540
|
{
|
|
3398
3541
|
"aria-hidden": "true",
|
|
@@ -3400,11 +3543,11 @@ var RequestRow = React56.forwardRef(
|
|
|
3400
3543
|
children: glyph ?? monogram2(name)
|
|
3401
3544
|
}
|
|
3402
3545
|
),
|
|
3403
|
-
/* @__PURE__ */
|
|
3404
|
-
/* @__PURE__ */
|
|
3405
|
-
subtitle && /* @__PURE__ */
|
|
3546
|
+
/* @__PURE__ */ jsxs34("div", { className: "min-w-0", children: [
|
|
3547
|
+
/* @__PURE__ */ jsx67("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
|
|
3548
|
+
subtitle && /* @__PURE__ */ jsx67("p", { className: "truncate text-xs text-text-tertiary", children: subtitle })
|
|
3406
3549
|
] }),
|
|
3407
|
-
/* @__PURE__ */
|
|
3550
|
+
/* @__PURE__ */ jsx67("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: controls })
|
|
3408
3551
|
]
|
|
3409
3552
|
}
|
|
3410
3553
|
);
|
|
@@ -3610,6 +3753,7 @@ export {
|
|
|
3610
3753
|
SheetTrigger,
|
|
3611
3754
|
SidebarNav,
|
|
3612
3755
|
SidebarNavLink,
|
|
3756
|
+
SidebarProductHeader,
|
|
3613
3757
|
Skeleton,
|
|
3614
3758
|
Slider,
|
|
3615
3759
|
StatCard,
|
package/dist/styles.css
CHANGED
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
:root {
|
|
14
|
-
--bg-primary: #
|
|
14
|
+
--bg-primary: #191b24;
|
|
15
15
|
--bg-secondary: #12141b;
|
|
16
|
-
--bg-surface: #
|
|
17
|
-
--bg-elevated: #
|
|
18
|
-
--bg-sunken: #
|
|
16
|
+
--bg-surface: #1f222d;
|
|
17
|
+
--bg-elevated: #252936;
|
|
18
|
+
--bg-sunken: #0e1015;
|
|
19
19
|
--bg-brand: #06297d;
|
|
20
|
-
--bg-brand-subtle: #
|
|
20
|
+
--bg-brand-subtle: #1f2541;
|
|
21
21
|
--bg-brand-hover: #08349b;
|
|
22
22
|
--bg-brand-bright: #165ff2;
|
|
23
23
|
--bg-brand-bright-hover: #3d7af4;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
--bg-rose-subtle: #1a090b;
|
|
34
34
|
--text-primary: #eeeff0;
|
|
35
35
|
--text-secondary: #a5a9b5;
|
|
36
|
-
--text-tertiary: #
|
|
36
|
+
--text-tertiary: #8a93a8;
|
|
37
37
|
--text-disabled: #60687f;
|
|
38
38
|
--text-inverse: #0e1015;
|
|
39
39
|
--text-on-brand: #f6f7f7;
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
--icon-success: #2eda76;
|
|
58
58
|
--icon-warning: #efb042;
|
|
59
59
|
--icon-danger: #f06a6a;
|
|
60
|
-
--border-subtle: #
|
|
60
|
+
--border-subtle: #2a2e3b;
|
|
61
61
|
--border-default: #60687f;
|
|
62
62
|
--border-strong: #737c95;
|
|
63
63
|
--border-brand: #165ff2;
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
--field-bg-hover: #12141b;
|
|
70
70
|
--field-bg-focus: #0e1015;
|
|
71
71
|
--field-bg-valid: #191b24;
|
|
72
|
-
--field-border: #
|
|
72
|
+
--field-border: #2a2e3b;
|
|
73
73
|
--field-border-hover: #393d4b;
|
|
74
74
|
--field-border-focus: #165ff2;
|
|
75
75
|
--field-border-filled: #393d4b;
|
|
@@ -271,12 +271,12 @@
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
.light {
|
|
274
|
-
--bg-primary: #
|
|
275
|
-
--bg-secondary: #
|
|
276
|
-
--bg-surface: #
|
|
277
|
-
--bg-elevated: #
|
|
278
|
-
--bg-sunken: #
|
|
279
|
-
--bg-brand-subtle: #
|
|
274
|
+
--bg-primary: #f6f7f7;
|
|
275
|
+
--bg-secondary: #eeeff0;
|
|
276
|
+
--bg-surface: #f2f3f4;
|
|
277
|
+
--bg-elevated: #edeef0;
|
|
278
|
+
--bg-sunken: #e1e2e4;
|
|
279
|
+
--bg-brand-subtle: #e4ecfe;
|
|
280
280
|
--bg-brand-hover: #05226a;
|
|
281
281
|
--bg-brand-bright-hover: #0b4cd5;
|
|
282
282
|
--bg-success-subtle: #ebf3ef;
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
--text-tertiary: #535a6e;
|
|
292
292
|
--text-disabled: #737c95;
|
|
293
293
|
--text-inverse: #f6f7f7;
|
|
294
|
-
--text-brand: #
|
|
294
|
+
--text-brand: #0b4cd5;
|
|
295
295
|
--text-success: #13703c;
|
|
296
296
|
--text-warning: #7a5409;
|
|
297
297
|
--text-danger: #94120e;
|
|
@@ -303,7 +303,7 @@
|
|
|
303
303
|
--icon-primary: #252936;
|
|
304
304
|
--icon-secondary: #535a6e;
|
|
305
305
|
--icon-disabled: #8a91a7;
|
|
306
|
-
--icon-brand: #
|
|
306
|
+
--icon-brand: #165ff2;
|
|
307
307
|
--icon-success: #13703c;
|
|
308
308
|
--icon-warning: #7a5409;
|
|
309
309
|
--icon-danger: #94120e;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lessly/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Lessly design system — shared UI primitives, tokens, and theme",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.30.3",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@lessly/tokens": "^0.
|
|
60
|
+
"@lessly/tokens": "^0.2.0",
|
|
61
61
|
"@radix-ui/react-accordion": "^1.2.16",
|
|
62
62
|
"@radix-ui/react-alert-dialog": "^1.1.19",
|
|
63
63
|
"@radix-ui/react-aspect-ratio": "^1.1.11",
|