@betterinternship/components 2.7.0 → 2.8.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"animated-count.js","sources":["../../../src/components/ui/animated-count.tsx"],"sourcesContent":["import { useRef, useEffect } from 'react';\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion';\n\n/**\n * A number that rolls up or down when its value changes.\n * @prop value The number displayed by the component.\n */\nexport const AnimatedCount = ({ value }: { value: number }) => {\n const reduceMotion = useReducedMotion();\n const prev = useRef(value);\n const direction = value >= prev.current ? 1 : -1;\n\n useEffect(() => {\n prev.current = value;\n }, [value]);\n\n return (\n <span className=\"relative inline-flex justify-center overflow-hidden tabular-nums\">\n {/* keeps the box the right width without clipping the rolling digit */}\n <span className=\"invisible\">{value}</span>\n <AnimatePresence initial={false}>\n <motion.span\n key={value}\n className=\"absolute inset-0 flex items-center justify-center\"\n initial={\n reduceMotion ? false : { y: `${direction * 100}%`, opacity: 0 }\n }\n animate={{ y: '0%', opacity: 1 }}\n exit={\n reduceMotion\n ? { opacity: 0 }\n : { y: `${direction * -100}%`, opacity: 0 }\n }\n transition={{ duration: 0.18, ease: 'easeOut' }}\n >\n {value}\n </motion.span>\n </AnimatePresence>\n </span>\n );\n};\n\nexport default AnimatedCount;\n"],"names":["_jsxs","_jsx"],"mappings":";;;;AAGA;;;AAGG;MACU,aAAa,GAAG,CAAC,EAAE,KAAK,EAAqB,KAAI;AAC5D,IAAA,MAAM,YAAY,GAAG,gBAAgB,EAAE;AACvC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AAC1B,IAAA,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE;IAEhD,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACtB,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAEX,IAAA,QACEA,IAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kEAAkE,EAAA,QAAA,EAAA,CAEhFC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,WAAW,EAAA,QAAA,EAAE,KAAK,EAAA,CAAQ,EAC1CA,GAAA,CAAC,eAAe,EAAA,EAAC,OAAO,EAAE,KAAK,EAAA,QAAA,EAC7BA,GAAA,CAAC,MAAM,CAAC,IAAI,EAAA,EAEV,SAAS,EAAC,mDAAmD,EAC7D,OAAO,EACL,YAAY,GAAG,KAAK,GAAG,EAAE,CAAC,EAAE,CAAA,EAAG,SAAS,GAAG,GAAG,CAAA,CAAA,CAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAEjE,OAAO,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,EAChC,IAAI,EACF;AACE,0BAAE,EAAE,OAAO,EAAE,CAAC;AACd,0BAAE,EAAE,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAE/C,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAA,QAAA,EAE9C,KAAK,IAbD,KAAK,CAcE,EAAA,CACE,CAAA,EAAA,CACb;AAEX;;;;"}
1
+ {"version":3,"file":"animated-count.js","sources":["../../../src/components/ui/animated-count.tsx"],"sourcesContent":["import { useRef, useEffect } from 'react';\r\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion';\r\n\r\n/**\r\n * A number that rolls up or down when its value changes.\r\n * @prop value The number displayed by the component.\r\n */\r\nexport const AnimatedCount = ({ value }: { value: number }) => {\r\n const reduceMotion = useReducedMotion();\r\n const prev = useRef(value);\r\n const direction = value >= prev.current ? 1 : -1;\r\n\r\n useEffect(() => {\r\n prev.current = value;\r\n }, [value]);\r\n\r\n return (\r\n <span className=\"relative inline-flex justify-center overflow-hidden tabular-nums\">\r\n {/* keeps the box the right width without clipping the rolling digit */}\r\n <span className=\"invisible\">{value}</span>\r\n <AnimatePresence initial={false}>\r\n <motion.span\r\n key={value}\r\n className=\"absolute inset-0 flex items-center justify-center\"\r\n initial={\r\n reduceMotion ? false : { y: `${direction * 100}%`, opacity: 0 }\r\n }\r\n animate={{ y: '0%', opacity: 1 }}\r\n exit={\r\n reduceMotion\r\n ? { opacity: 0 }\r\n : { y: `${direction * -100}%`, opacity: 0 }\r\n }\r\n transition={{ duration: 0.18, ease: 'easeOut' }}\r\n >\r\n {value}\r\n </motion.span>\r\n </AnimatePresence>\r\n </span>\r\n );\r\n};\r\n\r\nexport default AnimatedCount;\r\n"],"names":["_jsxs","_jsx"],"mappings":";;;;AAGA;;;AAGG;MACU,aAAa,GAAG,CAAC,EAAE,KAAK,EAAqB,KAAI;AAC5D,IAAA,MAAM,YAAY,GAAG,gBAAgB,EAAE;AACvC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AAC1B,IAAA,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE;IAEhD,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACtB,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAEX,IAAA,QACEA,IAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,kEAAkE,EAAA,QAAA,EAAA,CAEhFC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,WAAW,EAAA,QAAA,EAAE,KAAK,EAAA,CAAQ,EAC1CA,GAAA,CAAC,eAAe,EAAA,EAAC,OAAO,EAAE,KAAK,EAAA,QAAA,EAC7BA,GAAA,CAAC,MAAM,CAAC,IAAI,EAAA,EAEV,SAAS,EAAC,mDAAmD,EAC7D,OAAO,EACL,YAAY,GAAG,KAAK,GAAG,EAAE,CAAC,EAAE,CAAA,EAAG,SAAS,GAAG,GAAG,CAAA,CAAA,CAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAEjE,OAAO,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,EAChC,IAAI,EACF;AACE,0BAAE,EAAE,OAAO,EAAE,CAAC;AACd,0BAAE,EAAE,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAE/C,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAA,QAAA,EAE9C,KAAK,IAbD,KAAK,CAcE,EAAA,CACE,CAAA,EAAA,CACb;AAEX;;;;"}
@@ -7,7 +7,8 @@ export interface NavItem {
7
7
  icon?: LucideIcon;
8
8
  }
9
9
  interface AppHeaderProps {
10
- portal: string;
10
+ /** Optional site name. */
11
+ siteName?: string;
11
12
  homeHref: string;
12
13
  nav: NavItem[];
13
14
  userPrimary?: string;
@@ -23,6 +24,18 @@ interface AppHeaderProps {
23
24
  logoPath?: string;
24
25
  /** Extra controls rendered next to the nav (desktop) and inside the drawer (mobile). */
25
26
  actions?: ReactNode;
27
+ /**
28
+ * Inline search control rendered in the header's center region on desktop
29
+ * (`md` and up only). Purely a layout slot — the consumer owns all search
30
+ * state and behavior. For mobile, pair with `onSearchClick`.
31
+ */
32
+ search?: ReactNode;
33
+ /**
34
+ * When set, renders a search icon button on mobile immediately left of the
35
+ * hamburger. Typically opens a full-screen search overlay owned by the
36
+ * consumer.
37
+ */
38
+ onSearchClick?: () => void;
26
39
  }
27
- export declare function AppHeader({ portal, homeHref, nav, userPrimary, userSecondary, logout: logoutFn, postLogoutPath, profileHref, userAvatarUrl, accountNav, brand, logoPath, actions, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
40
+ export declare function AppHeader({ siteName, homeHref, nav, userPrimary, userSecondary, logout: logoutFn, postLogoutPath, profileHref, userAvatarUrl, accountNav, brand, logoPath, actions, search, onSearchClick, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
28
41
  export {};
@@ -1,4 +1,4 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import Link from 'next/link';
3
3
  import Image from 'next/image';
4
4
  import { usePathname, useRouter } from 'next/navigation';
@@ -7,7 +7,7 @@ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSep
7
7
  import { Button } from './button.js';
8
8
  import { Separator } from './separator.js';
9
9
  import { cn } from '../../utils.js';
10
- import { UserRound, ChevronDown, LogOut, X, Menu, ChevronRight, LayoutDashboard, FileSignature, SearchCheck, Building2, GraduationCap, FileText, History, Users, Mail, Handshake } from 'lucide-react';
10
+ import { UserRound, ChevronDown, LogOut, Search, X, Menu, ChevronRight, LayoutDashboard, FileSignature, SearchCheck, Building2, GraduationCap, FileText, History, Users, Mail, Handshake } from 'lucide-react';
11
11
  import { useState, useEffect } from 'react';
12
12
 
13
13
  function labelIcon(label) {
@@ -26,7 +26,7 @@ function labelIcon(label) {
26
26
  };
27
27
  return map[label] ?? Handshake;
28
28
  }
29
- function AppHeader({ portal, homeHref, nav, userPrimary, userSecondary, logout: logoutFn, postLogoutPath, profileHref, userAvatarUrl, accountNav = [], brand = 'Partners', logoPath = '/betterinternship-logo.png', actions, }) {
29
+ function AppHeader({ siteName, homeHref, nav, userPrimary, userSecondary, logout: logoutFn, postLogoutPath, profileHref, userAvatarUrl, accountNav = [], brand = 'Partners', logoPath = '/betterinternship-logo.png', actions, search, onSearchClick, }) {
30
30
  const pathname = usePathname() ?? '';
31
31
  const router = useRouter();
32
32
  const queryClient = useQueryClient();
@@ -48,18 +48,18 @@ function AppHeader({ portal, homeHref, nav, userPrimary, userSecondary, logout:
48
48
  },
49
49
  });
50
50
  const isActive = (href) => pathname === href || pathname.startsWith(`${href}/`);
51
- return (jsxs("header", { className: "bg-background/70 sticky top-0 z-40 border-b py-2 backdrop-blur", children: [jsxs("div", { className: "mx-auto flex h-16 items-center justify-between gap-2 px-4 sm:px-6 lg:px-8", children: [jsx(Link, { href: homeHref, className: "block flex-shrink-0 border-none text-black! outline-none focus:outline-none", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(Image, { src: logoPath, alt: "", width: 25, height: 25, className: "flex-none" }), jsxs("div", { className: "flex items-center", children: [jsx("h1", { className: "font-display text-lg font-bold text-gray-900", children: brand }), jsx("span", { className: "mx-2.5 text-gray-300", "aria-hidden": "true", children: "|" }), jsx("span", { className: "font-display text-gray-500", children: portal === 'Platform Admin' ? portal : `${portal} Portal` })] })] }) }), jsxs("div", { className: "hidden flex-1 items-center justify-end gap-2 md:flex", children: [nav.map((item) => {
51
+ return (jsxs("header", { className: "bg-background/70 sticky top-0 z-40 border-b py-2 backdrop-blur", children: [jsxs("div", { className: "mx-auto flex h-16 items-center justify-between gap-2 px-4 sm:px-6 lg:px-8", children: [jsx(Link, { href: homeHref, className: "block shrink-0 border-none text-black! outline-none focus:outline-none", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(Image, { src: logoPath, alt: "", width: 25, height: 25, className: "flex-none" }), jsxs("div", { className: "flex items-center", children: [jsx("h1", { className: "font-display text-lg font-bold text-gray-900", children: brand }), siteName && (jsxs(Fragment, { children: [jsx("span", { className: "mx-2.5 text-gray-300", "aria-hidden": "true", children: "|" }), jsx("span", { className: "font-display text-gray-500", children: siteName })] }))] })] }) }), jsx("div", { className: "hidden min-w-0 flex-1 md:flex md:items-center md:px-4", children: search }), jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [nav.map((item) => {
52
52
  const Icon = item.icon ?? labelIcon(item.label);
53
53
  return (jsxs(Button, { variant: "ghost", className: cn('relative h-auto min-w-0 flex-col items-center justify-center gap-1 rounded-[0.33em] px-3 py-1', isActive(item.href)
54
54
  ? 'text-primary'
55
- : 'opacity-80 hover:bg-gray-100 hover:opacity-100'), onClick: () => router.push(item.href), children: [jsx(Icon, { className: "!h-6 !w-6", strokeWidth: 1.7 }), jsx("span", { className: "text-xs", children: item.label }), !!item.badge && (jsx("span", { className: "absolute -top-0.5 right-5.5 inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900", children: item.badge }))] }, item.href));
55
+ : 'opacity-80 hover:bg-gray-100 hover:opacity-100'), onClick: () => router.push(item.href), children: [jsx(Icon, { className: "h-6! w-6!", strokeWidth: 1.7 }), jsx("span", { className: "text-xs", children: item.label }), !!item.badge && (jsx("span", { className: "absolute -top-0.5 right-5.5 inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900", children: item.badge }))] }, item.href));
56
56
  }), actions, jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button, { variant: "ghost", className: cn('group h-auto w-20 flex-col items-center justify-center gap-1 rounded-[0.33em] px-2 py-1', (profileHref && isActive(profileHref)) ||
57
57
  accountNav.some((item) => isActive(item.href))
58
58
  ? 'text-primary'
59
- : 'opacity-80 hover:bg-gray-100 hover:opacity-100'), children: [jsx("div", { className: "flex h-6 w-6 items-center justify-center overflow-hidden rounded-full bg-gray-100", children: userAvatarUrl ? (jsx("img", { src: userAvatarUrl, alt: "", className: "h-full w-full object-contain" })) : (jsx(UserRound, { className: "h-5 w-5 text-gray-500" })) }), jsxs("div", { className: "flex items-center gap-0.5", children: [jsx("span", { className: "text-xs", children: "Account" }), jsx(ChevronDown, { className: "!h-3 !w-3 transition-transform group-data-[state=open]:rotate-180" })] })] }) }), jsxs(DropdownMenuContent, { align: "end", className: "w-max min-w-44", children: [userPrimary && (jsxs("div", { className: "px-2 py-1.5", children: [jsx("div", { className: "text-center text-sm font-medium", children: userPrimary }), userSecondary && (jsx("div", { className: "text-muted-foreground text-center text-xs", children: userSecondary }))] })), jsx(DropdownMenuSeparator, {}), profileHref && (jsx(DropdownMenuItem, { asChild: true, children: jsxs(Link, { href: profileHref, children: [jsx(UserRound, { className: "h-4 w-4" }), "Profile"] }) })), accountNav.map((item) => {
59
+ : 'opacity-80 hover:bg-gray-100 hover:opacity-100'), children: [jsx("div", { className: "flex h-6 w-6 items-center justify-center overflow-hidden rounded-full bg-gray-100", children: userAvatarUrl ? (jsx("img", { src: userAvatarUrl, alt: "", className: "h-full w-full object-contain" })) : (jsx(UserRound, { className: "h-5 w-5 text-gray-500" })) }), jsxs("div", { className: "flex items-center gap-0.5", children: [jsx("span", { className: "text-xs", children: "Account" }), jsx(ChevronDown, { className: "h-3! w-3! transition-transform group-data-[state=open]:rotate-180" })] })] }) }), jsxs(DropdownMenuContent, { align: "end", className: "w-max min-w-44", children: [userPrimary && (jsxs("div", { className: "px-2 py-1.5", children: [jsx("div", { className: "text-center text-sm font-medium", children: userPrimary }), userSecondary && (jsx("div", { className: "text-muted-foreground text-center text-xs", children: userSecondary }))] })), jsx(DropdownMenuSeparator, {}), profileHref && (jsx(DropdownMenuItem, { asChild: true, children: jsxs(Link, { href: profileHref, children: [jsx(UserRound, { className: "h-4 w-4" }), "Profile"] }) })), accountNav.map((item) => {
60
60
  const Icon = item.icon ?? labelIcon(item.label);
61
61
  return (jsx(DropdownMenuItem, { asChild: true, children: jsxs(Link, { href: item.href, children: [jsx(Icon, { className: "h-4 w-4" }), item.label] }) }, item.href));
62
- }), (profileHref || accountNav.length > 0) && (jsx(DropdownMenuSeparator, {})), jsxs(DropdownMenuItem, { variant: "destructive", disabled: logout.isPending, onClick: () => logout.mutate(), children: [jsx(LogOut, { className: "h-4 w-4" }), logout.isPending ? 'Logging out...' : 'Sign Out'] })] })] })] }), jsx("button", { type: "button", "aria-label": isDrawerOpen ? 'Close menu' : 'Open menu', className: "inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50 md:hidden", onClick: () => setIsDrawerOpen(!isDrawerOpen), children: isDrawerOpen ? (jsx(X, { className: "h-5 w-5" })) : (jsx(Menu, { className: "h-5 w-5" })) })] }), isDrawerOpen && (jsx("div", { className: "fixed inset-0 z-[30] duration-200 md:hidden", onClick: () => setIsDrawerOpen(false) })), jsx("div", { className: cn('fixed top-0 right-0 z-[31] h-[100svh] w-full max-w-[92%] border-l border-gray-200 bg-white shadow-xl sm:max-w-[420px] md:hidden', 'transition-transform duration-250 ease-out', isDrawerOpen ? 'translate-x-0' : 'translate-x-full'), role: "dialog", "aria-modal": "true", "aria-label": "Mobile menu", children: jsxs("div", { className: "flex h-full flex-col", children: [jsxs("div", { className: "mt-1 flex items-center justify-between border-b px-4 py-3", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Image, { src: logoPath, alt: "", width: 25, height: 25, className: "h-6 w-6 rounded object-contain" }), jsx("span", { className: "text-sm font-semibold", children: brand }), jsx("span", { className: "rounded border border-gray-200 bg-gray-50 px-1 py-0 text-[10px] font-medium text-gray-400 leading-none", children: portal })] }), jsx("button", { type: "button", "aria-label": "Close menu", className: "inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-gray-100", onClick: () => setIsDrawerOpen(false), children: jsx(X, { className: "h-5 w-5" }) })] }), jsxs("div", { className: "flex-1 overflow-y-auto p-4", children: [userPrimary && (jsxs("div", { className: "flex items-center gap-2 pb-2", children: [jsx(UserRound, { className: "h-5 w-5 text-gray-500" }), jsx("span", { className: "text-sm font-semibold text-gray-900", children: userPrimary })] })), jsx(Separator, { className: "my-4" }), actions && jsx("div", { className: "mb-2", children: actions }), jsx("nav", { className: "space-y-1", children: nav.map((item) => {
62
+ }), (profileHref || accountNav.length > 0) && (jsx(DropdownMenuSeparator, {})), jsxs(DropdownMenuItem, { variant: "destructive", disabled: logout.isPending, onClick: () => logout.mutate(), children: [jsx(LogOut, { className: "h-4 w-4" }), logout.isPending ? 'Logging out...' : 'Sign Out'] })] })] })] }), jsxs("div", { className: "flex items-center gap-1 md:hidden", children: [onSearchClick && (jsx("button", { type: "button", "aria-label": "Search", className: "inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50", onClick: onSearchClick, children: jsx(Search, { className: "h-5 w-5" }) })), jsx("button", { type: "button", "aria-label": isDrawerOpen ? 'Close menu' : 'Open menu', className: "inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50", onClick: () => setIsDrawerOpen(!isDrawerOpen), children: isDrawerOpen ? (jsx(X, { className: "h-5 w-5" })) : (jsx(Menu, { className: "h-5 w-5" })) })] })] }), isDrawerOpen && (jsx("div", { className: "fixed inset-0 z-[30] duration-200 md:hidden", onClick: () => setIsDrawerOpen(false) })), jsx("div", { className: cn('fixed top-0 right-0 z-[31] h-[100svh] w-full max-w-[92%] border-l border-gray-200 bg-white shadow-xl sm:max-w-[420px] md:hidden', 'transition-transform duration-250 ease-out', isDrawerOpen ? 'translate-x-0' : 'translate-x-full'), role: "dialog", "aria-modal": "true", "aria-label": "Mobile menu", children: jsxs("div", { className: "flex h-full flex-col", children: [jsxs("div", { className: "mt-1 flex items-center justify-between border-b px-4 py-3", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Image, { src: logoPath, alt: "", width: 25, height: 25, className: "h-6 w-6 rounded object-contain" }), jsx("span", { className: "text-sm font-semibold", children: brand }), jsx("span", { className: "rounded border border-gray-200 bg-gray-50 px-1 py-0 text-[10px] font-medium text-gray-400 leading-none", children: portal })] }), jsx("button", { type: "button", "aria-label": "Close menu", className: "inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-gray-100", onClick: () => setIsDrawerOpen(false), children: jsx(X, { className: "h-5 w-5" }) })] }), jsxs("div", { className: "flex-1 overflow-y-auto p-4", children: [userPrimary && (jsxs("div", { className: "flex items-center gap-2 pb-2", children: [jsx(UserRound, { className: "h-5 w-5 text-gray-500" }), jsx("span", { className: "text-sm font-semibold text-gray-900", children: userPrimary })] })), jsx(Separator, { className: "my-4" }), actions && jsx("div", { className: "mb-2", children: actions }), jsx("nav", { className: "space-y-1", children: nav.map((item) => {
63
63
  const Icon = item.icon ?? labelIcon(item.label);
64
64
  return (jsx(Link, { href: item.href, className: "block w-full", children: jsxs("button", { className: "flex w-full items-center justify-between rounded-md border border-transparent px-3 py-2 text-sm transition-colors hover:border-gray-200 hover:bg-gray-50", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Icon, { className: "h-4 w-4 text-gray-500" }), jsx("span", { children: item.label }), !!item.badge && (jsx("span", { className: "inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900", children: "!" }))] }), jsx(ChevronRight, { className: "h-4 w-4 text-gray-300" })] }) }, item.href));
65
65
  }) })] }), jsxs("div", { className: "mt-auto border-t px-4 py-3 space-y-1", children: [profileHref && (jsx(Link, { href: profileHref, className: "block w-full", children: jsxs("button", { className: "flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors hover:bg-gray-50", children: [jsx(UserRound, { className: "h-4 w-4" }), "Profile"] }) })), accountNav.map((item) => {
@@ -1 +1 @@
1
- {"version":3,"file":"app-header.js","sources":["../../../src/components/ui/app-header.tsx"],"sourcesContent":["import Link from 'next/link';\nimport Image from 'next/image';\nimport { usePathname, useRouter } from 'next/navigation';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n} from '@/components/ui/dropdown-menu';\nimport { Button } from '@/components/ui/button';\nimport { Separator } from '@/components/ui/separator';\nimport { cn } from '@/utils';\nimport {\n LogOut,\n Menu,\n X,\n UserRound,\n ChevronDown,\n ChevronRight,\n Handshake,\n Mail,\n History,\n FileText,\n Users,\n LayoutDashboard,\n FileSignature,\n GraduationCap,\n Building2,\n SearchCheck,\n} from 'lucide-react';\nimport { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport type { LucideIcon } from 'lucide-react';\n\nexport interface NavItem {\n href: string;\n label: string;\n badge?: number;\n icon?: LucideIcon;\n}\n\ninterface AppHeaderProps {\n portal: string;\n homeHref: string;\n nav: NavItem[];\n userPrimary?: string;\n userSecondary?: string;\n logout: () => Promise<unknown>;\n postLogoutPath: string;\n profileHref?: string;\n userAvatarUrl?: string | null;\n accountNav?: NavItem[];\n /** Overrides the hardcoded \"Partners\" brand text. */\n brand?: string;\n /** Overrides the hardcoded \"/betterinternship-logo.png\" logo path. */\n logoPath?: string;\n /** Extra controls rendered next to the nav (desktop) and inside the drawer (mobile). */\n actions?: ReactNode;\n}\n\nfunction labelIcon(label: string): LucideIcon {\n const map: Record<string, LucideIcon> = {\n Partners: Handshake,\n Invites: Mail,\n Invitations: Mail,\n Accounts: Users,\n 'Activity Log': History,\n 'MOA Templates': FileText,\n Universities: GraduationCap,\n Companies: Building2,\n 'Company Reviews': SearchCheck,\n 'Request MOA': FileSignature,\n Dashboard: LayoutDashboard,\n };\n return map[label] ?? Handshake;\n}\n\nexport function AppHeader({\n portal,\n homeHref,\n nav,\n userPrimary,\n userSecondary,\n logout: logoutFn,\n postLogoutPath,\n profileHref,\n userAvatarUrl,\n accountNav = [],\n brand = 'Partners',\n logoPath = '/betterinternship-logo.png',\n actions,\n}: AppHeaderProps) {\n const pathname = usePathname() ?? '';\n const router = useRouter();\n const queryClient = useQueryClient();\n const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n\n useEffect(() => {\n setIsDrawerOpen(false);\n }, [pathname]);\n\n useEffect(() => {\n document.body.style.overflow = isDrawerOpen ? 'hidden' : '';\n return () => {\n document.body.style.overflow = '';\n };\n }, [isDrawerOpen]);\n\n const logout = useMutation({\n mutationFn: logoutFn,\n onSettled: () => {\n queryClient.clear();\n router.replace(postLogoutPath);\n },\n });\n\n const isActive = (href: string) =>\n pathname === href || pathname.startsWith(`${href}/`);\n\n return (\n <header className=\"bg-background/70 sticky top-0 z-40 border-b py-2 backdrop-blur\">\n <div className=\"mx-auto flex h-16 items-center justify-between gap-2 px-4 sm:px-6 lg:px-8\">\n {/* Brand */}\n <Link\n href={homeHref}\n className=\"block flex-shrink-0 border-none text-black! outline-none focus:outline-none\"\n >\n <div className=\"flex items-center gap-2\">\n <Image\n src={logoPath}\n alt=\"\"\n width={25}\n height={25}\n className=\"flex-none\"\n />\n <div className=\"flex items-center\">\n <h1 className=\"font-display text-lg font-bold text-gray-900\">\n {brand}\n </h1>\n <span className=\"mx-2.5 text-gray-300\" aria-hidden=\"true\">\n |\n </span>\n <span className=\"font-display text-gray-500\">\n {portal === 'Platform Admin' ? portal : `${portal} Portal`}\n </span>\n </div>\n </div>\n </Link>\n\n {/* Desktop right side: nav buttons + user */}\n <div className=\"hidden flex-1 items-center justify-end gap-2 md:flex\">\n {nav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Button\n key={item.href}\n variant=\"ghost\"\n className={cn(\n 'relative h-auto min-w-0 flex-col items-center justify-center gap-1 rounded-[0.33em] px-3 py-1',\n isActive(item.href)\n ? 'text-primary'\n : 'opacity-80 hover:bg-gray-100 hover:opacity-100',\n )}\n onClick={() => router.push(item.href)}\n >\n <Icon className=\"!h-6 !w-6\" strokeWidth={1.7} />\n <span className=\"text-xs\">{item.label}</span>\n {!!item.badge && (\n <span className=\"absolute -top-0.5 right-5.5 inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900\">\n {item.badge}\n </span>\n )}\n </Button>\n );\n })}\n\n {actions}\n\n {/* User dropdown */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className={cn(\n 'group h-auto w-20 flex-col items-center justify-center gap-1 rounded-[0.33em] px-2 py-1',\n (profileHref && isActive(profileHref)) ||\n accountNav.some((item) => isActive(item.href))\n ? 'text-primary'\n : 'opacity-80 hover:bg-gray-100 hover:opacity-100',\n )}\n >\n <div className=\"flex h-6 w-6 items-center justify-center overflow-hidden rounded-full bg-gray-100\">\n {userAvatarUrl ? (\n <img\n src={userAvatarUrl}\n alt=\"\"\n className=\"h-full w-full object-contain\"\n />\n ) : (\n <UserRound className=\"h-5 w-5 text-gray-500\" />\n )}\n </div>\n <div className=\"flex items-center gap-0.5\">\n <span className=\"text-xs\">Account</span>\n <ChevronDown className=\"!h-3 !w-3 transition-transform group-data-[state=open]:rotate-180\" />\n </div>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-max min-w-44\">\n {userPrimary && (\n <div className=\"px-2 py-1.5\">\n <div className=\"text-center text-sm font-medium\">\n {userPrimary}\n </div>\n {userSecondary && (\n <div className=\"text-muted-foreground text-center text-xs\">\n {userSecondary}\n </div>\n )}\n </div>\n )}\n <DropdownMenuSeparator />\n {profileHref && (\n <DropdownMenuItem asChild>\n <Link href={profileHref}>\n <UserRound className=\"h-4 w-4\" />\n Profile\n </Link>\n </DropdownMenuItem>\n )}\n {accountNav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <DropdownMenuItem key={item.href} asChild>\n <Link href={item.href}>\n <Icon className=\"h-4 w-4\" />\n {item.label}\n </Link>\n </DropdownMenuItem>\n );\n })}\n {(profileHref || accountNav.length > 0) && (\n <DropdownMenuSeparator />\n )}\n <DropdownMenuItem\n variant=\"destructive\"\n disabled={logout.isPending}\n onClick={() => logout.mutate()}\n >\n <LogOut className=\"h-4 w-4\" />\n {logout.isPending ? 'Logging out...' : 'Sign Out'}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* Mobile hamburger */}\n <button\n type=\"button\"\n aria-label={isDrawerOpen ? 'Close menu' : 'Open menu'}\n className=\"inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50 md:hidden\"\n onClick={() => setIsDrawerOpen(!isDrawerOpen)}\n >\n {isDrawerOpen ? (\n <X className=\"h-5 w-5\" />\n ) : (\n <Menu className=\"h-5 w-5\" />\n )}\n </button>\n </div>\n\n {/* Mobile right drawer */}\n {isDrawerOpen && (\n <div\n className=\"fixed inset-0 z-[30] duration-200 md:hidden\"\n onClick={() => setIsDrawerOpen(false)}\n />\n )}\n\n <div\n className={cn(\n 'fixed top-0 right-0 z-[31] h-[100svh] w-full max-w-[92%] border-l border-gray-200 bg-white shadow-xl sm:max-w-[420px] md:hidden',\n 'transition-transform duration-250 ease-out',\n isDrawerOpen ? 'translate-x-0' : 'translate-x-full',\n )}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Mobile menu\"\n >\n <div className=\"flex h-full flex-col\">\n <div className=\"mt-1 flex items-center justify-between border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Image\n src={logoPath}\n alt=\"\"\n width={25}\n height={25}\n className=\"h-6 w-6 rounded object-contain\"\n />\n <span className=\"text-sm font-semibold\">{brand}</span>\n <span className=\"rounded border border-gray-200 bg-gray-50 px-1 py-0 text-[10px] font-medium text-gray-400 leading-none\">\n {portal}\n </span>\n </div>\n <button\n type=\"button\"\n aria-label=\"Close menu\"\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-gray-100\"\n onClick={() => setIsDrawerOpen(false)}\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n {userPrimary && (\n <div className=\"flex items-center gap-2 pb-2\">\n <UserRound className=\"h-5 w-5 text-gray-500\" />\n <span className=\"text-sm font-semibold text-gray-900\">\n {userPrimary}\n </span>\n </div>\n )}\n\n <Separator className=\"my-4\" />\n\n {actions && <div className=\"mb-2\">{actions}</div>}\n\n <nav className=\"space-y-1\">\n {nav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Link\n key={item.href}\n href={item.href}\n className=\"block w-full\"\n >\n <button className=\"flex w-full items-center justify-between rounded-md border border-transparent px-3 py-2 text-sm transition-colors hover:border-gray-200 hover:bg-gray-50\">\n <div className=\"flex items-center gap-2\">\n <Icon className=\"h-4 w-4 text-gray-500\" />\n <span>{item.label}</span>\n {!!item.badge && (\n <span className=\"inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900\">\n !\n </span>\n )}\n </div>\n <ChevronRight className=\"h-4 w-4 text-gray-300\" />\n </button>\n </Link>\n );\n })}\n </nav>\n </div>\n\n <div className=\"mt-auto border-t px-4 py-3 space-y-1\">\n {profileHref && (\n <Link href={profileHref} className=\"block w-full\">\n <button className=\"flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors hover:bg-gray-50\">\n <UserRound className=\"h-4 w-4\" />\n Profile\n </button>\n </Link>\n )}\n {accountNav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Link key={item.href} href={item.href} className=\"block w-full\">\n <button className=\"flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors hover:bg-gray-50\">\n <Icon className=\"h-4 w-4\" />\n {item.label}\n </button>\n </Link>\n );\n })}\n <button\n onClick={() => logout.mutate()}\n disabled={logout.isPending}\n className=\"flex w-full items-center justify-center gap-2 rounded-md py-2 font-medium text-red-600 transition-colors hover:bg-red-50\"\n >\n <LogOut className=\"h-4 w-4\" />\n {logout.isPending ? 'Logging out...' : 'Sign Out'}\n </button>\n </div>\n </div>\n </div>\n </header>\n );\n}\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"app-header.js","sources":["../../../src/components/ui/app-header.tsx"],"sourcesContent":["import Link from 'next/link';\nimport Image from 'next/image';\nimport { usePathname, useRouter } from 'next/navigation';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n} from '@/components/ui/dropdown-menu';\nimport { Button } from '@/components/ui/button';\nimport { Separator } from '@/components/ui/separator';\nimport { cn } from '@/utils';\nimport {\n LogOut,\n Menu,\n Search,\n X,\n UserRound,\n ChevronDown,\n ChevronRight,\n Handshake,\n Mail,\n History,\n FileText,\n Users,\n LayoutDashboard,\n FileSignature,\n GraduationCap,\n Building2,\n SearchCheck,\n} from 'lucide-react';\nimport { useState, useEffect } from 'react';\nimport type { ReactNode } from 'react';\nimport type { LucideIcon } from 'lucide-react';\n\nexport interface NavItem {\n href: string;\n label: string;\n badge?: number;\n icon?: LucideIcon;\n}\n\ninterface AppHeaderProps {\n /** Optional site name. */\n siteName?: string;\n homeHref: string;\n nav: NavItem[];\n userPrimary?: string;\n userSecondary?: string;\n logout: () => Promise<unknown>;\n postLogoutPath: string;\n profileHref?: string;\n userAvatarUrl?: string | null;\n accountNav?: NavItem[];\n /** Overrides the hardcoded \"Partners\" brand text. */\n brand?: string;\n /** Overrides the hardcoded \"/betterinternship-logo.png\" logo path. */\n logoPath?: string;\n /** Extra controls rendered next to the nav (desktop) and inside the drawer (mobile). */\n actions?: ReactNode;\n /**\n * Inline search control rendered in the header's center region on desktop\n * (`md` and up only). Purely a layout slot — the consumer owns all search\n * state and behavior. For mobile, pair with `onSearchClick`.\n */\n search?: ReactNode;\n /**\n * When set, renders a search icon button on mobile immediately left of the\n * hamburger. Typically opens a full-screen search overlay owned by the\n * consumer.\n */\n onSearchClick?: () => void;\n}\n\nfunction labelIcon(label: string): LucideIcon {\n const map: Record<string, LucideIcon> = {\n Partners: Handshake,\n Invites: Mail,\n Invitations: Mail,\n Accounts: Users,\n 'Activity Log': History,\n 'MOA Templates': FileText,\n Universities: GraduationCap,\n Companies: Building2,\n 'Company Reviews': SearchCheck,\n 'Request MOA': FileSignature,\n Dashboard: LayoutDashboard,\n };\n return map[label] ?? Handshake;\n}\n\nexport function AppHeader({\n siteName,\n homeHref,\n nav,\n userPrimary,\n userSecondary,\n logout: logoutFn,\n postLogoutPath,\n profileHref,\n userAvatarUrl,\n accountNav = [],\n brand = 'Partners',\n logoPath = '/betterinternship-logo.png',\n actions,\n search,\n onSearchClick,\n}: AppHeaderProps) {\n const pathname = usePathname() ?? '';\n const router = useRouter();\n const queryClient = useQueryClient();\n const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n\n useEffect(() => {\n setIsDrawerOpen(false);\n }, [pathname]);\n\n useEffect(() => {\n document.body.style.overflow = isDrawerOpen ? 'hidden' : '';\n return () => {\n document.body.style.overflow = '';\n };\n }, [isDrawerOpen]);\n\n const logout = useMutation({\n mutationFn: logoutFn,\n onSettled: () => {\n queryClient.clear();\n router.replace(postLogoutPath);\n },\n });\n\n const isActive = (href: string) =>\n pathname === href || pathname.startsWith(`${href}/`);\n\n return (\n <header className=\"bg-background/70 sticky top-0 z-40 border-b py-2 backdrop-blur\">\n <div className=\"mx-auto flex h-16 items-center justify-between gap-2 px-4 sm:px-6 lg:px-8\">\n {/* Brand */}\n <Link\n href={homeHref}\n className=\"block shrink-0 border-none text-black! outline-none focus:outline-none\"\n >\n <div className=\"flex items-center gap-2\">\n <Image\n src={logoPath}\n alt=\"\"\n width={25}\n height={25}\n className=\"flex-none\"\n />\n <div className=\"flex items-center\">\n <h1 className=\"font-display text-lg font-bold text-gray-900\">\n {brand}\n </h1>\n {siteName && (\n <>\n <span className=\"mx-2.5 text-gray-300\" aria-hidden=\"true\">\n |\n </span>\n <span className=\"font-display text-gray-500\">{siteName}</span>\n </>\n )}\n </div>\n </div>\n </Link>\n\n {/* Desktop center: inline search slot. The empty div doubles as the\n spacer that keeps the right cluster right-aligned when no search\n is passed. */}\n <div className=\"hidden min-w-0 flex-1 md:flex md:items-center md:px-4\">\n {search}\n </div>\n\n {/* Desktop right side: nav buttons + user */}\n <div className=\"hidden items-center justify-end gap-2 md:flex\">\n {nav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Button\n key={item.href}\n variant=\"ghost\"\n className={cn(\n 'relative h-auto min-w-0 flex-col items-center justify-center gap-1 rounded-[0.33em] px-3 py-1',\n isActive(item.href)\n ? 'text-primary'\n : 'opacity-80 hover:bg-gray-100 hover:opacity-100',\n )}\n onClick={() => router.push(item.href)}\n >\n <Icon className=\"h-6! w-6!\" strokeWidth={1.7} />\n <span className=\"text-xs\">{item.label}</span>\n {!!item.badge && (\n <span className=\"absolute -top-0.5 right-5.5 inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900\">\n {item.badge}\n </span>\n )}\n </Button>\n );\n })}\n\n {actions}\n\n {/* User dropdown */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n className={cn(\n 'group h-auto w-20 flex-col items-center justify-center gap-1 rounded-[0.33em] px-2 py-1',\n (profileHref && isActive(profileHref)) ||\n accountNav.some((item) => isActive(item.href))\n ? 'text-primary'\n : 'opacity-80 hover:bg-gray-100 hover:opacity-100',\n )}\n >\n <div className=\"flex h-6 w-6 items-center justify-center overflow-hidden rounded-full bg-gray-100\">\n {userAvatarUrl ? (\n <img\n src={userAvatarUrl}\n alt=\"\"\n className=\"h-full w-full object-contain\"\n />\n ) : (\n <UserRound className=\"h-5 w-5 text-gray-500\" />\n )}\n </div>\n <div className=\"flex items-center gap-0.5\">\n <span className=\"text-xs\">Account</span>\n <ChevronDown className=\"h-3! w-3! transition-transform group-data-[state=open]:rotate-180\" />\n </div>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-max min-w-44\">\n {userPrimary && (\n <div className=\"px-2 py-1.5\">\n <div className=\"text-center text-sm font-medium\">\n {userPrimary}\n </div>\n {userSecondary && (\n <div className=\"text-muted-foreground text-center text-xs\">\n {userSecondary}\n </div>\n )}\n </div>\n )}\n <DropdownMenuSeparator />\n {profileHref && (\n <DropdownMenuItem asChild>\n <Link href={profileHref}>\n <UserRound className=\"h-4 w-4\" />\n Profile\n </Link>\n </DropdownMenuItem>\n )}\n {accountNav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <DropdownMenuItem key={item.href} asChild>\n <Link href={item.href}>\n <Icon className=\"h-4 w-4\" />\n {item.label}\n </Link>\n </DropdownMenuItem>\n );\n })}\n {(profileHref || accountNav.length > 0) && (\n <DropdownMenuSeparator />\n )}\n <DropdownMenuItem\n variant=\"destructive\"\n disabled={logout.isPending}\n onClick={() => logout.mutate()}\n >\n <LogOut className=\"h-4 w-4\" />\n {logout.isPending ? 'Logging out...' : 'Sign Out'}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* Mobile: search trigger + hamburger */}\n <div className=\"flex items-center gap-1 md:hidden\">\n {onSearchClick && (\n <button\n type=\"button\"\n aria-label=\"Search\"\n className=\"inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50\"\n onClick={onSearchClick}\n >\n <Search className=\"h-5 w-5\" />\n </button>\n )}\n <button\n type=\"button\"\n aria-label={isDrawerOpen ? 'Close menu' : 'Open menu'}\n className=\"inline-flex h-10 w-10 items-center justify-center rounded-md border border-gray-300 hover:bg-gray-50\"\n onClick={() => setIsDrawerOpen(!isDrawerOpen)}\n >\n {isDrawerOpen ? (\n <X className=\"h-5 w-5\" />\n ) : (\n <Menu className=\"h-5 w-5\" />\n )}\n </button>\n </div>\n </div>\n\n {/* Mobile right drawer */}\n {isDrawerOpen && (\n <div\n className=\"fixed inset-0 z-[30] duration-200 md:hidden\"\n onClick={() => setIsDrawerOpen(false)}\n />\n )}\n\n <div\n className={cn(\n 'fixed top-0 right-0 z-[31] h-[100svh] w-full max-w-[92%] border-l border-gray-200 bg-white shadow-xl sm:max-w-[420px] md:hidden',\n 'transition-transform duration-250 ease-out',\n isDrawerOpen ? 'translate-x-0' : 'translate-x-full',\n )}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Mobile menu\"\n >\n <div className=\"flex h-full flex-col\">\n <div className=\"mt-1 flex items-center justify-between border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Image\n src={logoPath}\n alt=\"\"\n width={25}\n height={25}\n className=\"h-6 w-6 rounded object-contain\"\n />\n <span className=\"text-sm font-semibold\">{brand}</span>\n <span className=\"rounded border border-gray-200 bg-gray-50 px-1 py-0 text-[10px] font-medium text-gray-400 leading-none\">\n {portal}\n </span>\n </div>\n <button\n type=\"button\"\n aria-label=\"Close menu\"\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-gray-100\"\n onClick={() => setIsDrawerOpen(false)}\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n {userPrimary && (\n <div className=\"flex items-center gap-2 pb-2\">\n <UserRound className=\"h-5 w-5 text-gray-500\" />\n <span className=\"text-sm font-semibold text-gray-900\">\n {userPrimary}\n </span>\n </div>\n )}\n\n <Separator className=\"my-4\" />\n\n {actions && <div className=\"mb-2\">{actions}</div>}\n\n <nav className=\"space-y-1\">\n {nav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Link\n key={item.href}\n href={item.href}\n className=\"block w-full\"\n >\n <button className=\"flex w-full items-center justify-between rounded-md border border-transparent px-3 py-2 text-sm transition-colors hover:border-gray-200 hover:bg-gray-50\">\n <div className=\"flex items-center gap-2\">\n <Icon className=\"h-4 w-4 text-gray-500\" />\n <span>{item.label}</span>\n {!!item.badge && (\n <span className=\"inline-flex h-4 w-4 items-center justify-center rounded-full bg-amber-400 text-[10px] font-bold leading-none text-amber-900\">\n !\n </span>\n )}\n </div>\n <ChevronRight className=\"h-4 w-4 text-gray-300\" />\n </button>\n </Link>\n );\n })}\n </nav>\n </div>\n\n <div className=\"mt-auto border-t px-4 py-3 space-y-1\">\n {profileHref && (\n <Link href={profileHref} className=\"block w-full\">\n <button className=\"flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors hover:bg-gray-50\">\n <UserRound className=\"h-4 w-4\" />\n Profile\n </button>\n </Link>\n )}\n {accountNav.map((item) => {\n const Icon = item.icon ?? labelIcon(item.label);\n return (\n <Link key={item.href} href={item.href} className=\"block w-full\">\n <button className=\"flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors hover:bg-gray-50\">\n <Icon className=\"h-4 w-4\" />\n {item.label}\n </button>\n </Link>\n );\n })}\n <button\n onClick={() => logout.mutate()}\n disabled={logout.isPending}\n className=\"flex w-full items-center justify-center gap-2 rounded-md py-2 font-medium text-red-600 transition-colors hover:bg-red-50\"\n >\n <LogOut className=\"h-4 w-4\" />\n {logout.isPending ? 'Logging out...' : 'Sign Out'}\n </button>\n </div>\n </div>\n </div>\n </header>\n );\n}\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":";;;;;;;;;;;;AA4EA,SAAS,SAAS,CAAC,KAAa,EAAA;AAC9B,IAAA,MAAM,GAAG,GAA+B;AACtC,QAAA,QAAQ,EAAE,SAAS;AACnB,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,WAAW,EAAE,IAAI;AACjB,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,cAAc,EAAE,OAAO;AACvB,QAAA,eAAe,EAAE,QAAQ;AACzB,QAAA,YAAY,EAAE,aAAa;AAC3B,QAAA,SAAS,EAAE,SAAS;AACpB,QAAA,iBAAiB,EAAE,WAAW;AAC9B,QAAA,aAAa,EAAE,aAAa;AAC5B,QAAA,SAAS,EAAE,eAAe;KAC3B;AACD,IAAA,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS;AAChC;SAEgB,SAAS,CAAC,EACxB,QAAQ,EACR,QAAQ,EACR,GAAG,EACH,WAAW,EACX,aAAa,EACb,MAAM,EAAE,QAAQ,EAChB,cAAc,EACd,WAAW,EACX,aAAa,EACb,UAAU,GAAG,EAAE,EACf,KAAK,GAAG,UAAU,EAClB,QAAQ,GAAG,4BAA4B,EACvC,OAAO,EACP,MAAM,EACN,aAAa,GACE,EAAA;AACf,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE,IAAI,EAAE;AACpC,IAAA,MAAM,MAAM,GAAG,SAAS,EAAE;AAC1B,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE;IACpC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IAEvD,SAAS,CAAC,MAAK;QACb,eAAe,CAAC,KAAK,CAAC;AACxB,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEd,SAAS,CAAC,MAAK;AACb,QAAA,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,EAAE;AAC3D,QAAA,OAAO,MAAK;YACV,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE;AACnC,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,WAAW,CAAC;AACzB,QAAA,UAAU,EAAE,QAAQ;QACpB,SAAS,EAAE,MAAK;YACd,WAAW,CAAC,KAAK,EAAE;AACnB,YAAA,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;QAChC,CAAC;AACF,KAAA,CAAC;AAEF,IAAA,MAAM,QAAQ,GAAG,CAAC,IAAY,KAC5B,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA,CAAA,CAAG,CAAC;IAEtD,QACEA,IAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,gEAAgE,aAChFA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,2EAA2E,EAAA,QAAA,EAAA,CAExFC,GAAA,CAAC,IAAI,EAAA,EACH,IAAI,EAAE,QAAQ,EACd,SAAS,EAAC,wEAAwE,EAAA,QAAA,EAElFD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,yBAAyB,aACtCC,GAAA,CAAC,KAAK,EAAA,EACJ,GAAG,EAAE,QAAQ,EACb,GAAG,EAAC,EAAE,EACN,KAAK,EAAE,EAAE,EACT,MAAM,EAAE,EAAE,EACV,SAAS,EAAC,WAAW,EAAA,CACrB,EACFD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAAA,CAChCC,GAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,8CAA8C,EAAA,QAAA,EACzD,KAAK,EAAA,CACH,EACJ,QAAQ,KACPD,IAAA,CAAAE,QAAA,EAAA,EAAA,QAAA,EAAA,CACED,cAAM,SAAS,EAAC,sBAAsB,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EAAA,GAAA,EAAA,CAElD,EACPA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAE,QAAQ,GAAQ,CAAA,EAAA,CAC7D,CACJ,CAAA,EAAA,CACG,CAAA,EAAA,CACF,EAAA,CACD,EAKPA,aAAK,SAAS,EAAC,uDAAuD,EAAA,QAAA,EACnE,MAAM,EAAA,CACH,EAGND,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,+CAA+C,EAAA,QAAA,EAAA,CAC3D,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;AAChB,gCAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;AAC/C,gCAAA,QACEA,IAAA,CAAC,MAAM,IAEL,OAAO,EAAC,OAAO,EACf,SAAS,EAAE,EAAE,CACX,+FAA+F,EAC/F,QAAQ,CAAC,IAAI,CAAC,IAAI;AAChB,0CAAE;AACF,0CAAE,gDAAgD,CACrD,EACD,OAAO,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAA,QAAA,EAAA,CAErCC,GAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAC,WAAW,EAAC,WAAW,EAAE,GAAG,GAAI,EAChDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,SAAS,EAAA,QAAA,EAAE,IAAI,CAAC,KAAK,EAAA,CAAQ,EAC5C,CAAC,CAAC,IAAI,CAAC,KAAK,KACXA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,yJAAyJ,EAAA,QAAA,EACtK,IAAI,CAAC,KAAK,EAAA,CACN,CACR,CAAA,EAAA,EAhBI,IAAI,CAAC,IAAI,CAiBP;AAEb,4BAAA,CAAC,CAAC,EAED,OAAO,EAGRD,KAAC,YAAY,EAAA,EAAA,QAAA,EAAA,CACXC,GAAA,CAAC,mBAAmB,EAAA,EAAC,OAAO,EAAA,IAAA,EAAA,QAAA,EAC1BD,IAAA,CAAC,MAAM,EAAA,EACL,OAAO,EAAC,OAAO,EACf,SAAS,EAAE,EAAE,CACX,yFAAyF,EACzF,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC;AACnC,gDAAA,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;AAC7C,kDAAE;AACF,kDAAE,gDAAgD,CACrD,EAAA,QAAA,EAAA,CAEDC,aAAK,SAAS,EAAC,mFAAmF,EAAA,QAAA,EAC/F,aAAa,IACZA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,aAAa,EAClB,GAAG,EAAC,EAAE,EACN,SAAS,EAAC,8BAA8B,EAAA,CACxC,KAEFA,GAAA,CAAC,SAAS,EAAA,EAAC,SAAS,EAAC,uBAAuB,EAAA,CAAG,CAChD,GACG,EACND,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,2BAA2B,EAAA,QAAA,EAAA,CACxCC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,SAAS,EAAA,QAAA,EAAA,SAAA,EAAA,CAAe,EACxCA,GAAA,CAAC,WAAW,EAAA,EAAC,SAAS,EAAC,mEAAmE,EAAA,CAAG,CAAA,EAAA,CACzF,CAAA,EAAA,CACC,EAAA,CACW,EACtBD,IAAA,CAAC,mBAAmB,EAAA,EAAC,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,gBAAgB,EAAA,QAAA,EAAA,CACxD,WAAW,KACVA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,aAAa,EAAA,QAAA,EAAA,CAC1BC,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAC7C,WAAW,EAAA,CACR,EACL,aAAa,KACZA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,2CAA2C,EAAA,QAAA,EACvD,aAAa,EAAA,CACV,CACP,CAAA,EAAA,CACG,CACP,EACDA,GAAA,CAAC,qBAAqB,EAAA,EAAA,CAAG,EACxB,WAAW,KACVA,GAAA,CAAC,gBAAgB,EAAA,EAAC,OAAO,EAAA,IAAA,EAAA,QAAA,EACvBD,IAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAE,WAAW,EAAA,QAAA,EAAA,CACrBC,GAAA,CAAC,SAAS,EAAA,EAAC,SAAS,EAAC,SAAS,EAAA,CAAG,eAE5B,EAAA,CACU,CACpB,EACA,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;AACvB,gDAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;AAC/C,gDAAA,QACEA,GAAA,CAAC,gBAAgB,EAAA,EAAiB,OAAO,EAAA,IAAA,EAAA,QAAA,EACvCD,IAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAA,QAAA,EAAA,CACnBC,GAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAC,SAAS,EAAA,CAAG,EAC3B,IAAI,CAAC,KAAK,CAAA,EAAA,CACN,IAJc,IAAI,CAAC,IAAI,CAKb;AAEvB,4CAAA,CAAC,CAAC,EACD,CAAC,WAAW,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,MACpCA,GAAA,CAAC,qBAAqB,EAAA,EAAA,CAAG,CAC1B,EACDD,IAAA,CAAC,gBAAgB,EAAA,EACf,OAAO,EAAC,aAAa,EACrB,QAAQ,EAAE,MAAM,CAAC,SAAS,EAC1B,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,EAAA,QAAA,EAAA,CAE9BC,GAAA,CAAC,MAAM,EAAA,EAAC,SAAS,EAAC,SAAS,GAAG,EAC7B,MAAM,CAAC,SAAS,GAAG,gBAAgB,GAAG,UAAU,CAAA,EAAA,CAChC,IACC,CAAA,EAAA,CACT,CAAA,EAAA,CACX,EAGND,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mCAAmC,aAC/C,aAAa,KACZC,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,QAAQ,EACnB,SAAS,EAAC,sGAAsG,EAChH,OAAO,EAAE,aAAa,EAAA,QAAA,EAEtBA,GAAA,CAAC,MAAM,EAAA,EAAC,SAAS,EAAC,SAAS,EAAA,CAAG,GACvB,CACV,EACDA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EAAA,YAAA,EACD,YAAY,GAAG,YAAY,GAAG,WAAW,EACrD,SAAS,EAAC,sGAAsG,EAChH,OAAO,EAAE,MAAM,eAAe,CAAC,CAAC,YAAY,CAAC,EAAA,QAAA,EAE5C,YAAY,IACXA,IAAC,CAAC,EAAA,EAAC,SAAS,EAAC,SAAS,GAAG,KAEzBA,GAAA,CAAC,IAAI,IAAC,SAAS,EAAC,SAAS,EAAA,CAAG,CAC7B,EAAA,CACM,CAAA,EAAA,CACL,IACF,EAGL,YAAY,KACXA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,6CAA6C,EACvD,OAAO,EAAE,MAAM,eAAe,CAAC,KAAK,CAAC,EAAA,CACrC,CACH,EAEDA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,iIAAiI,EACjI,4CAA4C,EAC5C,YAAY,GAAG,eAAe,GAAG,kBAAkB,CACpD,EACD,IAAI,EAAC,QAAQ,gBACF,MAAM,EAAA,YAAA,EACN,aAAa,EAAA,QAAA,EAExBD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sBAAsB,EAAA,QAAA,EAAA,CACnCA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,2DAA2D,aACxEA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,yBAAyB,EAAA,QAAA,EAAA,CACtCC,GAAA,CAAC,KAAK,IACJ,GAAG,EAAE,QAAQ,EACb,GAAG,EAAC,EAAE,EACN,KAAK,EAAE,EAAE,EACT,MAAM,EAAE,EAAE,EACV,SAAS,EAAC,gCAAgC,EAAA,CAC1C,EACFA,cAAM,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAE,KAAK,GAAQ,EACtDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,wGAAwG,YACrH,MAAM,EAAA,CACF,IACH,EACNA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,YAAY,EACvB,SAAS,EAAC,gGAAgG,EAC1G,OAAO,EAAE,MAAM,eAAe,CAAC,KAAK,CAAC,YAErCA,GAAA,CAAC,CAAC,IAAC,SAAS,EAAC,SAAS,EAAA,CAAG,GAClB,CAAA,EAAA,CACL,EAEND,cAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACxC,WAAW,KACVA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,8BAA8B,aAC3CC,GAAA,CAAC,SAAS,IAAC,SAAS,EAAC,uBAAuB,EAAA,CAAG,EAC/CA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,qCAAqC,EAAA,QAAA,EAClD,WAAW,EAAA,CACP,CAAA,EAAA,CACH,CACP,EAEDA,IAAC,SAAS,EAAA,EAAC,SAAS,EAAC,MAAM,GAAG,EAE7B,OAAO,IAAIA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,MAAM,YAAE,OAAO,EAAA,CAAO,EAEjDA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,WAAW,EAAA,QAAA,EACvB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;AAChB,wCAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;AAC/C,wCAAA,QACEA,GAAA,CAAC,IAAI,EAAA,EAEH,IAAI,EAAE,IAAI,CAAC,IAAI,EACf,SAAS,EAAC,cAAc,EAAA,QAAA,EAExBD,IAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,0JAA0J,EAAA,QAAA,EAAA,CAC1KA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,yBAAyB,EAAA,QAAA,EAAA,CACtCC,GAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAC,uBAAuB,GAAG,EAC1CA,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAO,IAAI,CAAC,KAAK,EAAA,CAAQ,EACxB,CAAC,CAAC,IAAI,CAAC,KAAK,KACXA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,6HAA6H,EAAA,QAAA,EAAA,GAAA,EAAA,CAEtI,CACR,CAAA,EAAA,CACG,EACNA,GAAA,CAAC,YAAY,EAAA,EAAC,SAAS,EAAC,uBAAuB,EAAA,CAAG,CAAA,EAAA,CAC3C,EAAA,EAfJ,IAAI,CAAC,IAAI,CAgBT;oCAEX,CAAC,CAAC,GACE,CAAA,EAAA,CACF,EAEND,cAAK,SAAS,EAAC,sCAAsC,EAAA,QAAA,EAAA,CAClD,WAAW,KACVC,GAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAC,cAAc,EAAA,QAAA,EAC/CD,iBAAQ,SAAS,EAAC,gGAAgG,EAAA,QAAA,EAAA,CAChHC,GAAA,CAAC,SAAS,EAAA,EAAC,SAAS,EAAC,SAAS,EAAA,CAAG,eAE1B,EAAA,CACJ,CACR,EACA,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;AACvB,oCAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;AAC/C,oCAAA,QACEA,GAAA,CAAC,IAAI,EAAA,EAAiB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAC,cAAc,EAAA,QAAA,EAC7DD,IAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAC,gGAAgG,EAAA,QAAA,EAAA,CAChHC,GAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAC,SAAS,GAAG,EAC3B,IAAI,CAAC,KAAK,IACJ,EAAA,EAJA,IAAI,CAAC,IAAI,CAKb;gCAEX,CAAC,CAAC,EACFD,IAAA,CAAA,QAAA,EAAA,EACE,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,EAC9B,QAAQ,EAAE,MAAM,CAAC,SAAS,EAC1B,SAAS,EAAC,0HAA0H,EAAA,QAAA,EAAA,CAEpIC,GAAA,CAAC,MAAM,EAAA,EAAC,SAAS,EAAC,SAAS,EAAA,CAAG,EAC7B,MAAM,CAAC,SAAS,GAAG,gBAAgB,GAAG,UAAU,CAAA,EAAA,CAC1C,IACL,CAAA,EAAA,CACF,EAAA,CACF,CAAA,EAAA,CACC;AAEb;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"status-notice.js","sources":["../../../src/components/ui/status-notice.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { cn } from \"@/utils\";\n\ntype StatusNoticeVariant = \"primary\" | \"warning\" | \"destructive\";\n\nconst variantClasses: Record<\n StatusNoticeVariant,\n { container: string; icon: string }\n> = {\n primary: {\n container:\n \"border-primary/25 bg-primary/[0.035] transition-colors hover:bg-primary/[0.06]\",\n icon: \"bg-primary/5 text-primary\",\n },\n warning: {\n container:\n \"border-warning/30 bg-warning/10 transition-colors hover:bg-warning/15\",\n icon: \"bg-warning/10 text-warning\",\n },\n destructive: {\n container:\n \"border-destructive/30 bg-destructive/5 transition-colors hover:bg-destructive/10\",\n icon: \"bg-destructive/10 text-destructive\",\n },\n};\n\nfunction StatusNotice({\n icon: Icon,\n media,\n title,\n description,\n action,\n actionClassName,\n variant = \"primary\",\n compact = false,\n className,\n ...props\n}: ComponentProps<\"div\"> & {\n icon?: LucideIcon;\n media?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n actionClassName?: string;\n variant?: StatusNoticeVariant;\n compact?: boolean;\n}) {\n const styles = variantClasses[variant];\n\n return (\n <div\n data-slot=\"status-notice\"\n className={cn(\n \"group/status-notice flex flex-col rounded-[0.33em] border\",\n compact\n ? \"items-start gap-3 p-3 sm:flex-row sm:items-start sm:gap-2\"\n : \"gap-4 px-4 py-4 sm:flex-row sm:items-stretch sm:gap-3 sm:px-5\",\n styles.container,\n className,\n )}\n {...props}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-1 items-start gap-3 sm:items-stretch sm:gap-3\",\n compact && \"gap-2 sm:items-start sm:gap-2\",\n )}\n >\n <span\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-[0.33em]\",\n compact ? \"size-8\" : \"size-10 sm:self-center\",\n styles.icon,\n )}\n >\n {media ??\n (Icon && (\n <Icon\n className={compact ? \"size-4\" : \"size-5\"}\n aria-hidden=\"true\"\n />\n ))}\n </span>\n <div className=\"min-w-0 flex-1 space-y-0.5\">\n <p className=\"text-sm font-medium text-gray-900\">{title}</p>\n {description && (\n <div className=\"text-muted-foreground text-sm\">{description}</div>\n )}\n </div>\n </div>\n {action && (\n <div\n className={cn(\n \"w-full shrink-0 sm:w-auto sm:self-center\",\n actionClassName,\n )}\n >\n {action}\n </div>\n )}\n </div>\n );\n}\n\nexport { StatusNotice, type StatusNoticeVariant };\n"],"names":["_jsxs","_jsx"],"mappings":";;;AAMA,MAAM,cAAc,GAGhB;AACF,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,gFAAgF;AAClF,QAAA,IAAI,EAAE,2BAA2B;AAClC,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,uEAAuE;AACzE,QAAA,IAAI,EAAE,4BAA4B;AACnC,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,SAAS,EACP,kFAAkF;AACpF,QAAA,IAAI,EAAE,oCAAoC;AAC3C,KAAA;CACF;AAED,SAAS,YAAY,CAAC,EACpB,IAAI,EAAE,IAAI,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,MAAM,EACN,eAAe,EACf,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,SAAS,EACT,GAAG,KAAK,EAUT,EAAA;AACC,IAAA,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;IAEtC,QACEA,IAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CACX,2DAA2D,EAC3D;AACE,cAAE;cACA,+DAA+D,EACnE,MAAM,CAAC,SAAS,EAChB,SAAS,CACV,EAAA,GACG,KAAK,EAAA,QAAA,EAAA,CAETA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,iEAAiE,EACjE,OAAO,IAAI,+BAA+B,CAC3C,aAEDC,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,OAAO,GAAG,QAAQ,GAAG,wBAAwB,EAC7C,MAAM,CAAC,IAAI,CACZ,EAAA,QAAA,EAEA,KAAK;AACJ,6BAAC,IAAI,KACHA,GAAA,CAAC,IAAI,EAAA,EACH,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAA,aAAA,EAC5B,MAAM,EAAA,CAClB,CACH,CAAC,GACC,EACPD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACzCC,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAE,KAAK,EAAA,CAAK,EAC3D,WAAW,KACVA,aAAK,SAAS,EAAC,+BAA+B,EAAA,QAAA,EAAE,WAAW,EAAA,CAAO,CACnE,CAAA,EAAA,CACG,IACF,EACL,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,0CAA0C,EAC1C,eAAe,CAChB,YAEA,MAAM,EAAA,CACH,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
1
+ {"version":3,"file":"status-notice.js","sources":["../../../src/components/ui/status-notice.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\r\nimport type { LucideIcon } from \"lucide-react\";\r\nimport { cn } from \"@/utils\";\r\n\r\ntype StatusNoticeVariant = \"primary\" | \"warning\" | \"destructive\";\r\n\r\nconst variantClasses: Record<\r\n StatusNoticeVariant,\r\n { container: string; icon: string }\r\n> = {\r\n primary: {\r\n container:\r\n \"border-primary/25 bg-primary/[0.035] transition-colors hover:bg-primary/[0.06]\",\r\n icon: \"bg-primary/5 text-primary\",\r\n },\r\n warning: {\r\n container:\r\n \"border-warning/30 bg-warning/10 transition-colors hover:bg-warning/15\",\r\n icon: \"bg-warning/10 text-warning\",\r\n },\r\n destructive: {\r\n container:\r\n \"border-destructive/30 bg-destructive/5 transition-colors hover:bg-destructive/10\",\r\n icon: \"bg-destructive/10 text-destructive\",\r\n },\r\n};\r\n\r\nfunction StatusNotice({\r\n icon: Icon,\r\n media,\r\n title,\r\n description,\r\n action,\r\n actionClassName,\r\n variant = \"primary\",\r\n compact = false,\r\n className,\r\n ...props\r\n}: ComponentProps<\"div\"> & {\r\n icon?: LucideIcon;\r\n media?: ReactNode;\r\n title: ReactNode;\r\n description?: ReactNode;\r\n action?: ReactNode;\r\n actionClassName?: string;\r\n variant?: StatusNoticeVariant;\r\n compact?: boolean;\r\n}) {\r\n const styles = variantClasses[variant];\r\n\r\n return (\r\n <div\r\n data-slot=\"status-notice\"\r\n className={cn(\r\n \"group/status-notice flex flex-col rounded-[0.33em] border\",\r\n compact\r\n ? \"items-start gap-3 p-3 sm:flex-row sm:items-start sm:gap-2\"\r\n : \"gap-4 px-4 py-4 sm:flex-row sm:items-stretch sm:gap-3 sm:px-5\",\r\n styles.container,\r\n className,\r\n )}\r\n {...props}\r\n >\r\n <div\r\n className={cn(\r\n \"flex min-w-0 flex-1 items-start gap-3 sm:items-stretch sm:gap-3\",\r\n compact && \"gap-2 sm:items-start sm:gap-2\",\r\n )}\r\n >\r\n <span\r\n className={cn(\r\n \"flex shrink-0 items-center justify-center rounded-[0.33em]\",\r\n compact ? \"size-8\" : \"size-10 sm:self-center\",\r\n styles.icon,\r\n )}\r\n >\r\n {media ??\r\n (Icon && (\r\n <Icon\r\n className={compact ? \"size-4\" : \"size-5\"}\r\n aria-hidden=\"true\"\r\n />\r\n ))}\r\n </span>\r\n <div className=\"min-w-0 flex-1 space-y-0.5\">\r\n <p className=\"text-sm font-medium text-gray-900\">{title}</p>\r\n {description && (\r\n <div className=\"text-muted-foreground text-sm\">{description}</div>\r\n )}\r\n </div>\r\n </div>\r\n {action && (\r\n <div\r\n className={cn(\r\n \"w-full shrink-0 sm:w-auto sm:self-center\",\r\n actionClassName,\r\n )}\r\n >\r\n {action}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nexport { StatusNotice, type StatusNoticeVariant };\r\n"],"names":["_jsxs","_jsx"],"mappings":";;;AAMA,MAAM,cAAc,GAGhB;AACF,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,gFAAgF;AAClF,QAAA,IAAI,EAAE,2BAA2B;AAClC,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,SAAS,EACP,uEAAuE;AACzE,QAAA,IAAI,EAAE,4BAA4B;AACnC,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,SAAS,EACP,kFAAkF;AACpF,QAAA,IAAI,EAAE,oCAAoC;AAC3C,KAAA;CACF;AAED,SAAS,YAAY,CAAC,EACpB,IAAI,EAAE,IAAI,EACV,KAAK,EACL,KAAK,EACL,WAAW,EACX,MAAM,EACN,eAAe,EACf,OAAO,GAAG,SAAS,EACnB,OAAO,GAAG,KAAK,EACf,SAAS,EACT,GAAG,KAAK,EAUT,EAAA;AACC,IAAA,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;IAEtC,QACEA,IAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CACX,2DAA2D,EAC3D;AACE,cAAE;cACA,+DAA+D,EACnE,MAAM,CAAC,SAAS,EAChB,SAAS,CACV,EAAA,GACG,KAAK,EAAA,QAAA,EAAA,CAETA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,iEAAiE,EACjE,OAAO,IAAI,+BAA+B,CAC3C,aAEDC,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,4DAA4D,EAC5D,OAAO,GAAG,QAAQ,GAAG,wBAAwB,EAC7C,MAAM,CAAC,IAAI,CACZ,EAAA,QAAA,EAEA,KAAK;AACJ,6BAAC,IAAI,KACHA,GAAA,CAAC,IAAI,EAAA,EACH,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAA,aAAA,EAC5B,MAAM,EAAA,CAClB,CACH,CAAC,GACC,EACPD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACzCC,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAE,KAAK,EAAA,CAAK,EAC3D,WAAW,KACVA,aAAK,SAAS,EAAC,+BAA+B,EAAA,QAAA,EAAE,WAAW,EAAA,CAAO,CACnE,CAAA,EAAA,CACG,IACF,EACL,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,0CAA0C,EAC1C,eAAe,CAChB,YAEA,MAAM,EAAA,CACH,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/utils';\n\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\n return (\n <div\n data-slot=\"table-container\"\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\n >\n <table\n data-slot=\"table\"\n className={cn('w-full caption-bottom text-sm', className)}\n {...props}\n />\n </div>\n );\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn('[&_tr]:border-b', className)}\n {...props}\n />\n );\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\n return (\n <tbody\n data-slot=\"table-body\"\n className={cn('[&_tr:last-child]:border-0', className)}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn(\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\n return (\n <th\n data-slot=\"table-head\"\n className={cn(\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn(\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCaption({\n className,\n ...props\n}: React.ComponentProps<'caption'>) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn('text-muted-foreground mt-4 text-sm', className)}\n {...props}\n />\n );\n}\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
1
+ {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\r\n\r\nimport { cn } from '@/utils';\r\n\r\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\r\n return (\r\n <div\r\n data-slot=\"table-container\"\r\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\r\n >\r\n <table\r\n data-slot=\"table\"\r\n className={cn('w-full caption-bottom text-sm', className)}\r\n {...props}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\r\n return (\r\n <thead\r\n data-slot=\"table-header\"\r\n className={cn('[&_tr]:border-b', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\r\n return (\r\n <tbody\r\n data-slot=\"table-body\"\r\n className={cn('[&_tr:last-child]:border-0', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\r\n return (\r\n <tfoot\r\n data-slot=\"table-footer\"\r\n className={cn(\r\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\r\n return (\r\n <tr\r\n data-slot=\"table-row\"\r\n className={cn(\r\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\r\n return (\r\n <th\r\n data-slot=\"table-head\"\r\n className={cn(\r\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\r\n return (\r\n <td\r\n data-slot=\"table-cell\"\r\n className={cn(\r\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCaption({\r\n className,\r\n ...props\r\n}: React.ComponentProps<'caption'>) {\r\n return (\r\n <caption\r\n data-slot=\"table-caption\"\r\n className={cn('text-muted-foreground mt-4 text-sm', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nexport {\r\n Table,\r\n TableHeader,\r\n TableBody,\r\n TableFooter,\r\n TableHead,\r\n TableRow,\r\n TableCell,\r\n TableCaption,\r\n};\r\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMQJob.js","sources":["../../src/hooks/useMQJob.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useRef } from 'react';\nimport { useQueries, useQuery, Query } from '@tanstack/react-query';\n\nexport type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';\n\nexport interface MQJob<T = unknown> {\n id: string;\n type: string;\n status: MQJobStatus;\n progress?: { total: number; done: number; failed: number };\n result?: T;\n error?: string;\n}\n\ninterface MQJobsConfig {\n /**\n * Fetches the current state of a job. The package knows no URL and no\n * response envelope — the consuming app owns both (plan §5.2). Reject/throw\n * on a transport or not-found failure; React Query's own retry handles it.\n */\n poll: (jobId: string) => Promise<MQJob>;\n}\n\nconst MQJobsContext = createContext<MQJobsConfig | null>(null);\n\n/** Mount once near the root, alongside the app's other data providers. */\nexport const MQJobsProvider = ({\n poll,\n children,\n}: MQJobsConfig & { children: React.ReactNode }) => (\n <MQJobsContext.Provider value={{ poll }}>{children}</MQJobsContext.Provider>\n);\n\nconst useMQJobsConfig = (caller: string): MQJobsConfig => {\n const ctx = useContext(MQJobsContext);\n if (!ctx)\n throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);\n return ctx;\n};\n\nconst BASE_INTERVAL_MS = 2000;\nconst MAX_INTERVAL_MS = 10000;\n\n/** Capped backoff keyed per job id, so each job restarts its own count. */\nconst nextInterval = (\n attempts: { current: Record<string, number> },\n key: string,\n status: MQJobStatus | undefined,\n): number | false => {\n if (status === 'done' || status === 'failed') return false;\n const attempt = attempts.current[key] ?? 0;\n attempts.current[key] = attempt + 1;\n return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);\n};\n\nconst summarize = <T,>(job: MQJob<T> | undefined) => ({\n job,\n status: job?.status,\n result: job?.result,\n error: job?.error,\n isPending: !job || job.status === 'queued' || job.status === 'processing',\n isDone: job?.status === 'done',\n isFailed: job?.status === 'failed',\n});\n\n/**\n * Polls a single `internal.mq_jobs` row to completion. Replaces\n * `useClientProcess` for anything queued through the broker: no\n * callback-URL dance, the result comes back inline on the job itself once\n * `status` is terminal.\n */\nexport function useMQJob<T = unknown>(jobId?: string | null) {\n const { poll } = useMQJobsConfig('useMQJob');\n const attempts = useRef<Record<string, number>>({});\n\n const query = useQuery<MQJob<T>>({\n queryKey: ['.__mq_job', jobId],\n // `poll`'s result field is caller-typed via `T`; the transport itself\n // doesn't know or care what shape a given job's result has.\n queryFn: () => poll(jobId as string) as Promise<MQJob<T>>,\n enabled: !!jobId,\n staleTime: Infinity,\n refetchOnWindowFocus: true,\n refetchIntervalInBackground: true,\n refetchInterval: (query: Query<MQJob<T>>) =>\n nextInterval(attempts, jobId ?? '', query.state.data?.status),\n });\n\n return summarize(query.data);\n}\n\n/**\n * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a\n * feature that can have several jobs in flight at once (e.g. a list of\n * pending/handled items). Built on `useQueries` directly rather than\n * composing `useMQJob` in a loop, since the number of tracked ids changes\n * over time and that would violate the rules of hooks.\n */\nexport function useMQJobs<T = unknown>(jobIds: readonly string[]) {\n const { poll } = useMQJobsConfig('useMQJobs');\n const attempts = useRef<Record<string, number>>({});\n\n const queries = useQueries({\n queries: jobIds.map((jobId) => ({\n queryKey: ['.__mq_job', jobId],\n queryFn: () => poll(jobId) as Promise<MQJob<T>>,\n staleTime: Infinity,\n refetchOnWindowFocus: true,\n refetchIntervalInBackground: true,\n refetchInterval: (query: Query<MQJob<T>>) =>\n nextInterval(attempts, jobId, query.state.data?.status),\n })),\n });\n\n return jobIds.map((jobId, index) => ({\n jobId,\n ...summarize(queries[index]?.data as MQJob<T> | undefined),\n }));\n}\n"],"names":[],"mappings":";;;;;AAyBA;AAEA;AACO;AAOP;AACE;AACA;AACE;AACF;AACF;AAEA;AACA;AAEA;AACA;AAKE;AAA8C;;;AAG9C;AACF;AAEA;;;;;AAKE;AACA;AACA;AACD;AAED;;;;;AAKG;AACG;;AAEJ;;AAGE;;;AAGA;;AAEA;AACA;AACA;;AAGD;AAED;AACF;AAEA;;;;;;AAMG;AACG;;AAEJ;;;AAII;AACA;AACA;AACA;AACA;AACA;AAED;AACF;;;;AAKA;AACH;;"}
1
+ {"version":3,"file":"useMQJob.js","sources":["../../src/hooks/useMQJob.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { createContext, useContext, useRef } from 'react';\r\nimport { useQueries, useQuery, Query } from '@tanstack/react-query';\r\n\r\nexport type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';\r\n\r\nexport interface MQJob<T = unknown> {\r\n id: string;\r\n type: string;\r\n status: MQJobStatus;\r\n progress?: { total: number; done: number; failed: number };\r\n result?: T;\r\n error?: string;\r\n}\r\n\r\ninterface MQJobsConfig {\r\n /**\r\n * Fetches the current state of a job. The package knows no URL and no\r\n * response envelope — the consuming app owns both (plan §5.2). Reject/throw\r\n * on a transport or not-found failure; React Query's own retry handles it.\r\n */\r\n poll: (jobId: string) => Promise<MQJob>;\r\n}\r\n\r\nconst MQJobsContext = createContext<MQJobsConfig | null>(null);\r\n\r\n/** Mount once near the root, alongside the app's other data providers. */\r\nexport const MQJobsProvider = ({\r\n poll,\r\n children,\r\n}: MQJobsConfig & { children: React.ReactNode }) => (\r\n <MQJobsContext.Provider value={{ poll }}>{children}</MQJobsContext.Provider>\r\n);\r\n\r\nconst useMQJobsConfig = (caller: string): MQJobsConfig => {\r\n const ctx = useContext(MQJobsContext);\r\n if (!ctx)\r\n throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);\r\n return ctx;\r\n};\r\n\r\nconst BASE_INTERVAL_MS = 2000;\r\nconst MAX_INTERVAL_MS = 10000;\r\n\r\n/** Capped backoff keyed per job id, so each job restarts its own count. */\r\nconst nextInterval = (\r\n attempts: { current: Record<string, number> },\r\n key: string,\r\n status: MQJobStatus | undefined,\r\n): number | false => {\r\n if (status === 'done' || status === 'failed') return false;\r\n const attempt = attempts.current[key] ?? 0;\r\n attempts.current[key] = attempt + 1;\r\n return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);\r\n};\r\n\r\nconst summarize = <T,>(job: MQJob<T> | undefined) => ({\r\n job,\r\n status: job?.status,\r\n result: job?.result,\r\n error: job?.error,\r\n isPending: !job || job.status === 'queued' || job.status === 'processing',\r\n isDone: job?.status === 'done',\r\n isFailed: job?.status === 'failed',\r\n});\r\n\r\n/**\r\n * Polls a single `internal.mq_jobs` row to completion. Replaces\r\n * `useClientProcess` for anything queued through the broker: no\r\n * callback-URL dance, the result comes back inline on the job itself once\r\n * `status` is terminal.\r\n */\r\nexport function useMQJob<T = unknown>(jobId?: string | null) {\r\n const { poll } = useMQJobsConfig('useMQJob');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const query = useQuery<MQJob<T>>({\r\n queryKey: ['.__mq_job', jobId],\r\n // `poll`'s result field is caller-typed via `T`; the transport itself\r\n // doesn't know or care what shape a given job's result has.\r\n queryFn: () => poll(jobId as string) as Promise<MQJob<T>>,\r\n enabled: !!jobId,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId ?? '', query.state.data?.status),\r\n });\r\n\r\n return summarize(query.data);\r\n}\r\n\r\n/**\r\n * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a\r\n * feature that can have several jobs in flight at once (e.g. a list of\r\n * pending/handled items). Built on `useQueries` directly rather than\r\n * composing `useMQJob` in a loop, since the number of tracked ids changes\r\n * over time and that would violate the rules of hooks.\r\n */\r\nexport function useMQJobs<T = unknown>(jobIds: readonly string[]) {\r\n const { poll } = useMQJobsConfig('useMQJobs');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const queries = useQueries({\r\n queries: jobIds.map((jobId) => ({\r\n queryKey: ['.__mq_job', jobId],\r\n queryFn: () => poll(jobId) as Promise<MQJob<T>>,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId, query.state.data?.status),\r\n })),\r\n });\r\n\r\n return jobIds.map((jobId, index) => ({\r\n jobId,\r\n ...summarize(queries[index]?.data as MQJob<T> | undefined),\r\n }));\r\n}\r\n"],"names":[],"mappings":";;;;;AAyBA;AAEA;AACO;AAOP;AACE;AACA;AACE;AACF;AACF;AAEA;AACA;AAEA;AACA;AAKE;AAA8C;;;AAG9C;AACF;AAEA;;;;;AAKE;AACA;AACA;AACD;AAED;;;;;AAKG;AACG;;AAEJ;;AAGE;;;AAGA;;AAEA;AACA;AACA;;AAGD;AAED;AACF;AAEA;;;;;;AAMG;AACG;;AAEJ;;;AAII;AACA;AACA;AACA;AACA;AACA;AAED;AACF;;;;AAKA;AACH;;"}
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}"],"names":[],"mappings":";;;AAGM,SAAU,EAAE,CAAC,GAAG,MAAoB,EAAA;AACxC,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}"],"names":[],"mappings":";;;AAGM,SAAU,EAAE,CAAC,GAAG,MAAoB,EAAA;AACxC,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B;;;;"}
package/package.json CHANGED
@@ -1,249 +1,249 @@
1
- {
2
- "name": "@betterinternship/components",
3
- "version": "2.7.0",
4
- "main": "dist/index.js",
5
- "module": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "rollup -c && tsc-alias",
9
- "test": "vitest run",
10
- "test:watch": "vitest",
11
- "prepare": "npm run build",
12
- "dev:playground": "npm --prefix playground run dev"
13
- },
14
- "publishConfig": {
15
- "access": "public"
16
- },
17
- "exports": {
18
- ".": {
19
- "import": "./dist/index.js",
20
- "types": "./dist/index.d.ts"
21
- },
22
- "./button": {
23
- "import": "./dist/components/ui/button.js",
24
- "types": "./dist/components/ui/button.d.ts"
25
- },
26
- "./accordion": {
27
- "import": "./dist/components/ui/accordion.js",
28
- "types": "./dist/components/ui/accordion.d.ts"
29
- },
30
- "./calendar": {
31
- "import": "./dist/components/ui/calendar.js",
32
- "types": "./dist/components/ui/calendar.d.ts"
33
- },
34
- "./input": {
35
- "import": "./dist/components/ui/input.js",
36
- "types": "./dist/components/ui/input.d.ts"
37
- },
38
- "./icons": {
39
- "import": "./dist/components/ui/icons.js",
40
- "types": "./dist/components/ui/icons.d.ts"
41
- },
42
- "./avatar": {
43
- "import": "./dist/components/ui/avatar.js",
44
- "types": "./dist/components/ui/avatar.d.ts"
45
- },
46
- "./badge": {
47
- "import": "./dist/components/ui/badge.js",
48
- "types": "./dist/components/ui/badge.d.ts"
49
- },
50
- "./card": {
51
- "import": "./dist/components/ui/card.js",
52
- "types": "./dist/components/ui/card.d.ts"
53
- },
54
- "./checkbox": {
55
- "import": "./dist/components/ui/checkbox.js",
56
- "types": "./dist/components/ui/checkbox.d.ts"
57
- },
58
- "./dialog": {
59
- "import": "./dist/components/ui/dialog.js",
60
- "types": "./dist/components/ui/dialog.d.ts"
61
- },
62
- "./label": {
63
- "import": "./dist/components/ui/label.js",
64
- "types": "./dist/components/ui/label.d.ts"
65
- },
66
- "./popover": {
67
- "import": "./dist/components/ui/popover.js",
68
- "types": "./dist/components/ui/popover.d.ts"
69
- },
70
- "./separator": {
71
- "import": "./dist/components/ui/separator.js",
72
- "types": "./dist/components/ui/separator.d.ts"
73
- },
74
- "./skeleton": {
75
- "import": "./dist/components/ui/skeleton.js",
76
- "types": "./dist/components/ui/skeleton.d.ts"
77
- },
78
- "./switch": {
79
- "import": "./dist/components/ui/switch.js",
80
- "types": "./dist/components/ui/switch.d.ts"
81
- },
82
- "./table": {
83
- "import": "./dist/components/ui/table.js",
84
- "types": "./dist/components/ui/table.d.ts"
85
- },
86
- "./textarea": {
87
- "import": "./dist/components/ui/textarea.js",
88
- "types": "./dist/components/ui/textarea.d.ts"
89
- },
90
- "./tooltip": {
91
- "import": "./dist/components/ui/tooltip.js",
92
- "types": "./dist/components/ui/tooltip.d.ts"
93
- },
94
- "./page-header": {
95
- "import": "./dist/components/ui/page-header.js",
96
- "types": "./dist/components/ui/page-header.d.ts"
97
- },
98
- "./status-notice": {
99
- "import": "./dist/components/ui/status-notice.js",
100
- "types": "./dist/components/ui/status-notice.d.ts"
101
- },
102
- "./app-header": {
103
- "import": "./dist/components/ui/app-header.js",
104
- "types": "./dist/components/ui/app-header.d.ts"
105
- },
106
- "./dropdown-menu": {
107
- "import": "./dist/components/ui/dropdown-menu.js",
108
- "types": "./dist/components/ui/dropdown-menu.d.ts"
109
- },
110
- "./theme.css": "./theme.css"
111
- },
112
- "repository": {
113
- "type": "git",
114
- "url": "git+https://github.com/BetterInternship/Components.git"
115
- },
116
- "keywords": [],
117
- "author": "",
118
- "license": "ISC",
119
- "bugs": {
120
- "url": "https://github.com/BetterInternship/Components/issues"
121
- },
122
- "homepage": "https://github.com/BetterInternship/Components#readme",
123
- "description": "",
124
- "peerDependencies": {
125
- "@radix-ui/react-accordion": "^1.2.11",
126
- "@radix-ui/react-alert-dialog": "^1.1.15",
127
- "@radix-ui/react-aspect-ratio": "^1.1.1",
128
- "@radix-ui/react-avatar": "^1.1.10",
129
- "@radix-ui/react-checkbox": "^1.3.2",
130
- "@radix-ui/react-collapsible": "^1.1.11",
131
- "@radix-ui/react-context-menu": "^2.2.4",
132
- "@radix-ui/react-dialog": "^1.1.14",
133
- "@radix-ui/react-dropdown-menu": "^2.1.15",
134
- "@radix-ui/react-hover-card": "^1.1.4",
135
- "@radix-ui/react-label": "^2.1.7",
136
- "@radix-ui/react-menubar": "^1.1.4",
137
- "@radix-ui/react-navigation-menu": "^1.2.3",
138
- "@radix-ui/react-popover": "^1.1.15",
139
- "@radix-ui/react-progress": "^1.1.7",
140
- "@radix-ui/react-radio-group": "^1.3.8",
141
- "@radix-ui/react-scroll-area": "^1.2.2",
142
- "@radix-ui/react-select": "^2.2.6",
143
- "@radix-ui/react-separator": "^1.1.7",
144
- "@radix-ui/react-slider": "^1.2.2",
145
- "@radix-ui/react-slot": "^1.2.3",
146
- "@radix-ui/react-switch": "^1.2.6",
147
- "@radix-ui/react-tabs": "^1.1.13",
148
- "@radix-ui/react-toast": "^1.2.4",
149
- "@radix-ui/react-toggle": "^1.1.1",
150
- "@radix-ui/react-toggle-group": "^1.1.1",
151
- "@radix-ui/react-tooltip": "^1.2.7",
152
- "@tanstack/react-query": "^5.0.0",
153
- "framer-motion": ">=11",
154
- "lucide-react": ">=0.454.0",
155
- "next": "^16.3.1",
156
- "react": "^19",
157
- "react-dom": "^19",
158
- "sonner": "^2.0.7"
159
- },
160
- "peerDependenciesMeta": {
161
- "react": {
162
- "optional": false
163
- },
164
- "sonner": {
165
- "optional": false
166
- },
167
- "react-dom": {
168
- "optional": false
169
- },
170
- "@tanstack/react-query": {
171
- "optional": false
172
- }
173
- },
174
- "devDependencies": {
175
- "@eslint/eslintrc": "^3.2.0",
176
- "@eslint/js": "^9.18.0",
177
- "framer-motion": "^13.1.1",
178
- "@radix-ui/react-accordion": "^1.2.11",
179
- "@radix-ui/react-alert-dialog": "^1.1.15",
180
- "@radix-ui/react-aspect-ratio": "^1.1.1",
181
- "@radix-ui/react-avatar": "^1.1.10",
182
- "@radix-ui/react-checkbox": "^1.3.2",
183
- "@radix-ui/react-collapsible": "^1.1.11",
184
- "@radix-ui/react-context-menu": "^2.2.4",
185
- "@radix-ui/react-dialog": "^1.1.14",
186
- "@radix-ui/react-dropdown-menu": "^2.1.15",
187
- "@radix-ui/react-hover-card": "^1.1.4",
188
- "@radix-ui/react-label": "^2.1.7",
189
- "@radix-ui/react-menubar": "^1.1.4",
190
- "@radix-ui/react-navigation-menu": "^1.2.3",
191
- "@radix-ui/react-popover": "^1.1.15",
192
- "@radix-ui/react-progress": "^1.1.7",
193
- "@radix-ui/react-radio-group": "^1.3.8",
194
- "@radix-ui/react-scroll-area": "^1.2.2",
195
- "@radix-ui/react-select": "^2.2.6",
196
- "@radix-ui/react-separator": "^1.1.7",
197
- "@radix-ui/react-slider": "^1.2.2",
198
- "@radix-ui/react-slot": "^1.2.3",
199
- "@radix-ui/react-switch": "^1.2.6",
200
- "@radix-ui/react-tabs": "^1.1.13",
201
- "@radix-ui/react-toast": "^1.2.4",
202
- "@radix-ui/react-toggle": "^1.1.1",
203
- "@radix-ui/react-toggle-group": "^1.1.1",
204
- "@radix-ui/react-tooltip": "^1.2.7",
205
- "@rollup/plugin-commonjs": "^29.0.0",
206
- "@rollup/plugin-node-resolve": "^16.0.3",
207
- "@rollup/plugin-typescript": "^12.3.0",
208
- "@tailwindcss/postcss": "^4.1.17",
209
- "@testing-library/jest-dom": "^7.0.1",
210
- "@testing-library/react": "^16.3.2",
211
- "@testing-library/user-event": "^14.6.3",
212
- "@types/react": "^19.2.7",
213
- "autoprefixer": "^10.4.22",
214
- "esbuild-css-modules-plugin": "^3.1.5",
215
- "esbuild-style-plugin": "^1.6.3",
216
- "eslint": "^9.18.0",
217
- "eslint-config-prettier": "^10.0.1",
218
- "eslint-plugin-prettier": "^5.2.2",
219
- "jsdom": "^29.1.1",
220
- "postcss": "^8.5.6",
221
- "postcss-cli": "^11.0.1",
222
- "prettier": "^3.4.2",
223
- "react": "^19",
224
- "react-dom": "^19",
225
- "rollup": "^4.53.3",
226
- "rollup-plugin-postcss": "^4.0.2",
227
- "rollup-plugin-preserve-directives": "^0.4.0",
228
- "rollup-plugin-typescript2": "^0.36.0",
229
- "sonner": "^2.0.7",
230
- "tailwindcss": "^4.1.17",
231
- "tsc-alias": "^1.8.16",
232
- "tw-animate-css": "^1.4.0",
233
- "typescript": "^5.9.3",
234
- "typescript-eslint": "^8.20.0",
235
- "vitest": "^4.1.10"
236
- },
237
- "files": [
238
- "dist",
239
- "theme.css"
240
- ],
241
- "dependencies": {
242
- "@daypicker/react": "^10.0.1",
243
- "@types/react-dom": "^19.2.4",
244
- "class-variance-authority": "^0.7.1",
245
- "clsx": "^2.1.1",
246
- "lucide-react": ">=0.454.0",
247
- "tailwind-merge": "^3.4.0"
248
- }
249
- }
1
+ {
2
+ "name": "@betterinternship/components",
3
+ "version": "2.8.1",
4
+ "main": "dist/index.js",
5
+ "module": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rollup -c && tsc-alias",
9
+ "test": "vitest run",
10
+ "test:watch": "vitest",
11
+ "prepare": "npm run build",
12
+ "dev:playground": "npm --prefix playground run dev"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ },
22
+ "./button": {
23
+ "import": "./dist/components/ui/button.js",
24
+ "types": "./dist/components/ui/button.d.ts"
25
+ },
26
+ "./accordion": {
27
+ "import": "./dist/components/ui/accordion.js",
28
+ "types": "./dist/components/ui/accordion.d.ts"
29
+ },
30
+ "./calendar": {
31
+ "import": "./dist/components/ui/calendar.js",
32
+ "types": "./dist/components/ui/calendar.d.ts"
33
+ },
34
+ "./input": {
35
+ "import": "./dist/components/ui/input.js",
36
+ "types": "./dist/components/ui/input.d.ts"
37
+ },
38
+ "./icons": {
39
+ "import": "./dist/components/ui/icons.js",
40
+ "types": "./dist/components/ui/icons.d.ts"
41
+ },
42
+ "./avatar": {
43
+ "import": "./dist/components/ui/avatar.js",
44
+ "types": "./dist/components/ui/avatar.d.ts"
45
+ },
46
+ "./badge": {
47
+ "import": "./dist/components/ui/badge.js",
48
+ "types": "./dist/components/ui/badge.d.ts"
49
+ },
50
+ "./card": {
51
+ "import": "./dist/components/ui/card.js",
52
+ "types": "./dist/components/ui/card.d.ts"
53
+ },
54
+ "./checkbox": {
55
+ "import": "./dist/components/ui/checkbox.js",
56
+ "types": "./dist/components/ui/checkbox.d.ts"
57
+ },
58
+ "./dialog": {
59
+ "import": "./dist/components/ui/dialog.js",
60
+ "types": "./dist/components/ui/dialog.d.ts"
61
+ },
62
+ "./label": {
63
+ "import": "./dist/components/ui/label.js",
64
+ "types": "./dist/components/ui/label.d.ts"
65
+ },
66
+ "./popover": {
67
+ "import": "./dist/components/ui/popover.js",
68
+ "types": "./dist/components/ui/popover.d.ts"
69
+ },
70
+ "./separator": {
71
+ "import": "./dist/components/ui/separator.js",
72
+ "types": "./dist/components/ui/separator.d.ts"
73
+ },
74
+ "./skeleton": {
75
+ "import": "./dist/components/ui/skeleton.js",
76
+ "types": "./dist/components/ui/skeleton.d.ts"
77
+ },
78
+ "./switch": {
79
+ "import": "./dist/components/ui/switch.js",
80
+ "types": "./dist/components/ui/switch.d.ts"
81
+ },
82
+ "./table": {
83
+ "import": "./dist/components/ui/table.js",
84
+ "types": "./dist/components/ui/table.d.ts"
85
+ },
86
+ "./textarea": {
87
+ "import": "./dist/components/ui/textarea.js",
88
+ "types": "./dist/components/ui/textarea.d.ts"
89
+ },
90
+ "./tooltip": {
91
+ "import": "./dist/components/ui/tooltip.js",
92
+ "types": "./dist/components/ui/tooltip.d.ts"
93
+ },
94
+ "./page-header": {
95
+ "import": "./dist/components/ui/page-header.js",
96
+ "types": "./dist/components/ui/page-header.d.ts"
97
+ },
98
+ "./status-notice": {
99
+ "import": "./dist/components/ui/status-notice.js",
100
+ "types": "./dist/components/ui/status-notice.d.ts"
101
+ },
102
+ "./app-header": {
103
+ "import": "./dist/components/ui/app-header.js",
104
+ "types": "./dist/components/ui/app-header.d.ts"
105
+ },
106
+ "./dropdown-menu": {
107
+ "import": "./dist/components/ui/dropdown-menu.js",
108
+ "types": "./dist/components/ui/dropdown-menu.d.ts"
109
+ },
110
+ "./theme.css": "./theme.css"
111
+ },
112
+ "repository": {
113
+ "type": "git",
114
+ "url": "git+https://github.com/BetterInternship/Components.git"
115
+ },
116
+ "keywords": [],
117
+ "author": "",
118
+ "license": "ISC",
119
+ "bugs": {
120
+ "url": "https://github.com/BetterInternship/Components/issues"
121
+ },
122
+ "homepage": "https://github.com/BetterInternship/Components#readme",
123
+ "description": "",
124
+ "peerDependencies": {
125
+ "@radix-ui/react-accordion": "^1.2.11",
126
+ "@radix-ui/react-alert-dialog": "^1.1.15",
127
+ "@radix-ui/react-aspect-ratio": "^1.1.1",
128
+ "@radix-ui/react-avatar": "^1.1.10",
129
+ "@radix-ui/react-checkbox": "^1.3.2",
130
+ "@radix-ui/react-collapsible": "^1.1.11",
131
+ "@radix-ui/react-context-menu": "^2.2.4",
132
+ "@radix-ui/react-dialog": "^1.1.14",
133
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
134
+ "@radix-ui/react-hover-card": "^1.1.4",
135
+ "@radix-ui/react-label": "^2.1.7",
136
+ "@radix-ui/react-menubar": "^1.1.4",
137
+ "@radix-ui/react-navigation-menu": "^1.2.3",
138
+ "@radix-ui/react-popover": "^1.1.15",
139
+ "@radix-ui/react-progress": "^1.1.7",
140
+ "@radix-ui/react-radio-group": "^1.3.8",
141
+ "@radix-ui/react-scroll-area": "^1.2.2",
142
+ "@radix-ui/react-select": "^2.2.6",
143
+ "@radix-ui/react-separator": "^1.1.7",
144
+ "@radix-ui/react-slider": "^1.2.2",
145
+ "@radix-ui/react-slot": "^1.2.3",
146
+ "@radix-ui/react-switch": "^1.2.6",
147
+ "@radix-ui/react-tabs": "^1.1.13",
148
+ "@radix-ui/react-toast": "^1.2.4",
149
+ "@radix-ui/react-toggle": "^1.1.1",
150
+ "@radix-ui/react-toggle-group": "^1.1.1",
151
+ "@radix-ui/react-tooltip": "^1.2.7",
152
+ "@tanstack/react-query": "^5.0.0",
153
+ "framer-motion": ">=11",
154
+ "lucide-react": ">=0.454.0",
155
+ "next": "^16.3.1",
156
+ "react": "^19",
157
+ "react-dom": "^19",
158
+ "sonner": "^2.0.7"
159
+ },
160
+ "peerDependenciesMeta": {
161
+ "react": {
162
+ "optional": false
163
+ },
164
+ "sonner": {
165
+ "optional": false
166
+ },
167
+ "react-dom": {
168
+ "optional": false
169
+ },
170
+ "@tanstack/react-query": {
171
+ "optional": false
172
+ }
173
+ },
174
+ "devDependencies": {
175
+ "@eslint/eslintrc": "^3.2.0",
176
+ "@eslint/js": "^9.18.0",
177
+ "framer-motion": "^13.1.1",
178
+ "@radix-ui/react-accordion": "^1.2.11",
179
+ "@radix-ui/react-alert-dialog": "^1.1.15",
180
+ "@radix-ui/react-aspect-ratio": "^1.1.1",
181
+ "@radix-ui/react-avatar": "^1.1.10",
182
+ "@radix-ui/react-checkbox": "^1.3.2",
183
+ "@radix-ui/react-collapsible": "^1.1.11",
184
+ "@radix-ui/react-context-menu": "^2.2.4",
185
+ "@radix-ui/react-dialog": "^1.1.14",
186
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
187
+ "@radix-ui/react-hover-card": "^1.1.4",
188
+ "@radix-ui/react-label": "^2.1.7",
189
+ "@radix-ui/react-menubar": "^1.1.4",
190
+ "@radix-ui/react-navigation-menu": "^1.2.3",
191
+ "@radix-ui/react-popover": "^1.1.15",
192
+ "@radix-ui/react-progress": "^1.1.7",
193
+ "@radix-ui/react-radio-group": "^1.3.8",
194
+ "@radix-ui/react-scroll-area": "^1.2.2",
195
+ "@radix-ui/react-select": "^2.2.6",
196
+ "@radix-ui/react-separator": "^1.1.7",
197
+ "@radix-ui/react-slider": "^1.2.2",
198
+ "@radix-ui/react-slot": "^1.2.3",
199
+ "@radix-ui/react-switch": "^1.2.6",
200
+ "@radix-ui/react-tabs": "^1.1.13",
201
+ "@radix-ui/react-toast": "^1.2.4",
202
+ "@radix-ui/react-toggle": "^1.1.1",
203
+ "@radix-ui/react-toggle-group": "^1.1.1",
204
+ "@radix-ui/react-tooltip": "^1.2.7",
205
+ "@rollup/plugin-commonjs": "^29.0.0",
206
+ "@rollup/plugin-node-resolve": "^16.0.3",
207
+ "@rollup/plugin-typescript": "^12.3.0",
208
+ "@tailwindcss/postcss": "^4.1.17",
209
+ "@testing-library/jest-dom": "^7.0.1",
210
+ "@testing-library/react": "^16.3.2",
211
+ "@testing-library/user-event": "^14.6.3",
212
+ "@types/react": "^19.2.7",
213
+ "autoprefixer": "^10.4.22",
214
+ "esbuild-css-modules-plugin": "^3.1.5",
215
+ "esbuild-style-plugin": "^1.6.3",
216
+ "eslint": "^9.18.0",
217
+ "eslint-config-prettier": "^10.0.1",
218
+ "eslint-plugin-prettier": "^5.2.2",
219
+ "jsdom": "^29.1.1",
220
+ "postcss": "^8.5.6",
221
+ "postcss-cli": "^11.0.1",
222
+ "prettier": "^3.4.2",
223
+ "react": "^19",
224
+ "react-dom": "^19",
225
+ "rollup": "^4.53.3",
226
+ "rollup-plugin-postcss": "^4.0.2",
227
+ "rollup-plugin-preserve-directives": "^0.4.0",
228
+ "rollup-plugin-typescript2": "^0.36.0",
229
+ "sonner": "^2.0.7",
230
+ "tailwindcss": "^4.1.17",
231
+ "tsc-alias": "^1.8.16",
232
+ "tw-animate-css": "^1.4.0",
233
+ "typescript": "^5.9.3",
234
+ "typescript-eslint": "^8.20.0",
235
+ "vitest": "^4.1.10"
236
+ },
237
+ "files": [
238
+ "dist",
239
+ "theme.css"
240
+ ],
241
+ "dependencies": {
242
+ "@daypicker/react": "^10.0.1",
243
+ "@types/react-dom": "^19.2.4",
244
+ "class-variance-authority": "^0.7.1",
245
+ "clsx": "^2.1.1",
246
+ "lucide-react": ">=0.454.0",
247
+ "tailwind-merge": "^3.4.0"
248
+ }
249
+ }