@devalok/shilp-sutra 0.42.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +78 -0
- package/dist/_chunks/chat.js +164 -163
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +35 -33
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/oauth-button.js +102 -97
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/popover.js +1 -1
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/shared.js +1 -1
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/command-bar.js +1 -1
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +4 -4
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.d.ts +6 -0
- package/dist/composed/content-card.d.ts.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/error-boundary.js +1 -1
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-suggestion.js +1 -1
- package/dist/composed/extensions/emoji-suggestion.js.map +1 -1
- package/dist/composed/extensions/file-attachment.d.ts.map +1 -1
- package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js +147 -143
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.js +5 -2
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/page-header.js +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/audio-player.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +600 -591
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.d.ts.map +1 -1
- package/dist/composed/rich-text-editor.js +166 -164
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/shell/notification-center.d.ts.map +1 -1
- package/dist/shell/notification-center.js +102 -98
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/sidebar.d.ts +6 -0
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +142 -118
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +87 -84
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +9 -2
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/autocomplete.js +1 -1
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.js +1 -1
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/breadcrumb.js +2 -2
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts +82 -7
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +76 -110
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/color-input.js +1 -1
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.js +3 -3
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +2 -2
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dropdown-menu.js +11 -5
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/hover-card.js +1 -1
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +58 -56
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/menubar.js +12 -6
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -1
- package/dist/ui/select.js +6 -3
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sidebar.js +74 -74
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/split-button.js +1 -1
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +26 -3
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +183 -150
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.d.ts +46 -0
- package/dist/ui/stat-flash.d.ts.map +1 -0
- package/dist/ui/stat-flash.js +114 -0
- package/dist/ui/stat-flash.js.map +1 -0
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +5 -2
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/toast.js +2 -2
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/truncated-text.d.ts +37 -0
- package/dist/ui/truncated-text.d.ts.map +1 -0
- package/dist/ui/truncated-text.js +53 -0
- package/dist/ui/truncated-text.js.map +1 -0
- package/docs/components/ui/card.md +13 -4
- package/docs/components/ui/stat-card.md +18 -3
- package/docs/components/ui/stat-flash.md +44 -0
- package/docs/components/ui/truncated-text.md +49 -0
- package/llms-full.txt +125 -8
- package/make-kit/components/card.md +14 -4
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components-full.md +125 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-center.js","names":[],"sources":["../../src/shell/notification-center.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationCenter -- Popover-based notification panel.\n *\n * Props-driven: accepts notifications array and callbacks instead of\n * reading from Zustand stores or using Remix useNavigate.\n */\nimport { IconBell, IconChecks, IconInbox, IconX } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useCallback,useRef } from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from '../ui/icon'\nimport { formatRelativeTime } from '../ui/lib/date-utils'\nimport { durations } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport { Spinner } from '../ui/spinner'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationAction {\n /** Button label */\n label: string\n /** Visual style — 'primary' is filled, 'default' is ghost, 'danger' is red ghost */\n variant?: 'primary' | 'default' | 'danger'\n /** Called when the action button is clicked. Receives the notification id. */\n onClick: (id: string) => void\n}\n\nexport interface Notification {\n id: string\n title: string\n body?: string | null\n tier: 'INFO' | 'IMPORTANT' | 'CRITICAL'\n isRead: boolean\n createdAt: string\n entityType?: string | null\n entityId?: string | null\n projectId?: string | null\n project?: { title: string } | null\n /** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */\n actions?: NotificationAction[]\n}\n\nexport interface NotificationCenterProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** List of notifications to display */\n notifications?: Notification[]\n /** Count of unread notifications (derived from notifications if not provided) */\n unreadCount?: number\n /** Whether the popover is open (controlled mode) */\n open?: boolean\n /** Called when the popover open state changes */\n onOpenChange?: (open: boolean) => void\n /** Whether more notifications are loading */\n isLoading?: boolean\n /** Whether there are more notifications to fetch */\n hasMore?: boolean\n /** Called when the user scrolls near the bottom to load more */\n onFetchMore?: () => void\n /** Called to mark a single notification as read */\n onMarkRead?: (id: string) => void\n /** Called to mark all notifications as read */\n onMarkAllRead?: () => void\n /** Called when the user clicks a notification (e.g., navigate to entity) */\n onNavigate?: (path: string) => void\n /** Resolve a notification to a navigation path. Return null if no navigation. */\n getNotificationRoute?: (notification: Notification) => string | null\n /** Additional actions rendered in the header (e.g., settings button) */\n headerActions?: React.ReactNode\n /** Custom empty state to display when there are no notifications */\n emptyState?: React.ReactNode\n /** Content rendered below the notification list as a footer */\n footerSlot?: React.ReactNode\n /** Called when the user dismisses a notification. Renders an X button per row when provided. */\n onDismiss?: (id: string) => void\n /** Additional className for the popover content container */\n popoverClassName?: string\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n )\n}\n\nfunction getDateGroup(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date()\n yesterday.setDate(today.getDate() - 1)\n\n if (isSameDay(date, today)) return 'Today'\n if (isSameDay(date, yesterday)) return 'Yesterday'\n return 'Earlier'\n}\n\nconst TIER_COLORS: Record<string, string> = {\n INFO: 'bg-info-9',\n IMPORTANT: 'bg-warning-9',\n CRITICAL: 'bg-error-9',\n}\n\n// -----------------------------------------------------------------------\n// NotificationItem (internal)\n// -----------------------------------------------------------------------\n\nfunction NotificationItem({\n notification,\n onRead,\n onNavigate,\n getRoute,\n onDismiss,\n}: {\n notification: Notification\n onRead: (id: string) => void\n onNavigate: (path: string) => void\n getRoute: (notification: Notification) => string | null\n onDismiss?: (id: string) => void\n}) {\n const route = getRoute(notification)\n\n const handleClick = () => {\n if (!notification.isRead) {\n onRead(notification.id)\n }\n if (route) {\n onNavigate(route)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleClick()\n }\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n className={cn(\n 'group relative flex w-full cursor-pointer items-start gap-ds-04 px-ds-05 py-ds-04 text-left transition-colors duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised',\n !notification.isRead && 'bg-accent-1',\n )}\n >\n {/* Tier dot — doubles as read/unread marker */}\n <div className=\"mt-ds-02b flex shrink-0\">\n <span\n className={cn(\n 'h-[8px] w-[8px] rounded-pill transition-opacity duration-fast-02 ease-productive-standard',\n TIER_COLORS[notification.tier] || TIER_COLORS.INFO,\n notification.isRead ? 'opacity-20' : 'opacity-100',\n )}\n />\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <p\n className={cn(\n 'truncate text-ds-md text-surface-fg',\n !notification.isRead && 'font-semibold',\n )}\n >\n {notification.title}\n </p>\n {notification.body && (\n <p className=\"mt-ds-01 line-clamp-2 text-ds-sm text-surface-fg-subtle\">\n {notification.body}\n </p>\n )}\n <div className=\"mt-ds-02 flex items-center gap-ds-03\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {formatRelativeTime(notification.createdAt)}\n </span>\n {notification.project && (\n <>\n <span className=\"text-surface-fg-subtle\">\n ·\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {notification.project.title}\n </span>\n </>\n )}\n </div>\n\n {/* Inline actions */}\n {notification.actions && notification.actions.length > 0 && (\n <div className=\"mt-ds-03 flex items-center gap-ds-02\">\n {notification.actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n action.onClick(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n 'rounded-control px-ds-03 py-ds-01 text-ds-sm font-medium transition-colors duration-fast-02 ease-productive-standard',\n action.variant === 'primary'\n ? 'bg-accent-9 text-accent-fg hover:bg-accent-10'\n : action.variant === 'danger'\n ? 'text-error-11 hover:bg-error-3'\n : 'text-surface-fg-muted hover:bg-surface-raised-hover',\n )}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={`Dismiss notification: ${notification.title}`}\n onClick={(e) => {\n e.stopPropagation()\n onDismiss(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className=\"absolute right-ds-03 top-ds-03 hidden rounded-control-inner p-ds-01 text-surface-fg-subtle transition-[color,background-color,opacity] duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted group-hover:flex group-focus-within:flex\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </div>\n )\n}\n\n// -----------------------------------------------------------------------\n// NotificationCenter\n// -----------------------------------------------------------------------\n\nconst NotificationCenter = React.forwardRef<HTMLButtonElement, NotificationCenterProps>(\n (\n {\n notifications = [],\n unreadCount: unreadCountProp,\n open,\n onOpenChange,\n isLoading = false,\n hasMore = false,\n onFetchMore,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n getNotificationRoute,\n onDismiss,\n headerActions,\n emptyState,\n footerSlot,\n popoverClassName,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = useRef<HTMLDivElement>(null)\n const prefersReducedMotion = useReducedMotion()\n const isMobile = useIsMobile()\n\n const unreadCount =\n unreadCountProp ?? notifications.filter((n) => !n.isRead).length\n\n const getRoute = getNotificationRoute ?? (() => null)\n\n const handleNavigate = useCallback(\n (path: string) => {\n onOpenChange?.(false)\n onNavigate?.(path)\n },\n [onNavigate, onOpenChange],\n )\n\n const handleMarkRead = useCallback(\n (id: string) => {\n onMarkRead?.(id)\n },\n [onMarkRead],\n )\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el || isLoading || !hasMore) return\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {\n onFetchMore?.()\n }\n }, [isLoading, hasMore, onFetchMore])\n\n // Group notifications by date\n const grouped = notifications.reduce<Record<string, Notification[]>>(\n (acc, n) => {\n const group = getDateGroup(n.createdAt)\n if (!acc[group]) acc[group] = []\n acc[group].push(n)\n return acc\n },\n {},\n )\n\n const groupOrder = ['Today', 'Yesterday', 'Earlier']\n\n // -- Shared panel content (used in both Popover and Sheet) --\n const panelContent = (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <div className=\"flex items-center gap-ds-03\">\n {/* On mobile the SheetTitle provides the accessible heading; on desktop use h3 */}\n {!isMobile && (\n <h3 className=\"text-ds-md font-semibold text-surface-fg\">\n Notifications\n </h3>\n )}\n {unreadCount > 0 && (\n <span className=\"flex h-5 min-w-5 items-center justify-center rounded-pill bg-accent-2 px-ds-02b text-ds-sm font-semibold text-accent-11\">\n {unreadCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-ds-03\">\n {unreadCount > 0 && onMarkAllRead && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"flex items-center gap-ds-02 text-ds-sm text-surface-fg-subtle transition-colors hover:text-accent-11\"\n >\n <Icon icon={IconChecks} size=\"sm\" />\n Mark all read\n </button>\n )}\n {headerActions}\n </div>\n </div>\n\n {/* Notification list */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n className={cn('overflow-y-auto', isMobile ? 'max-h-[60vh]' : 'max-h-[420px]')}\n >\n {notifications.length === 0 ? (\n emptyState || (\n <div className=\"flex flex-col items-center justify-center px-ds-05 py-ds-09\">\n <div className=\"flex h-ds-lg w-ds-lg items-center justify-center rounded-pill bg-surface-raised\">\n <Icon icon={IconInbox} size=\"lg\" className=\"text-surface-fg-subtle\" />\n </div>\n <p className=\"mt-ds-04 text-ds-md text-surface-fg-subtle\">\n No notifications yet\n </p>\n <p className=\"mt-ds-02 text-ds-sm text-surface-fg-subtle\">\n You're all caught up!\n </p>\n </div>\n )\n ) : (\n groupOrder.map((group) => {\n const items = grouped[group]\n if (!items || items.length === 0) return null\n return (\n <div key={group}>\n <div className=\"sticky top-0 z-raised bg-surface-overlay px-ds-05 py-ds-02b\">\n <span className=\"text-ds-sm font-medium text-surface-fg-subtle\">\n {group}\n </span>\n </div>\n {items.map((notification, index) => (\n <motion.div\n key={notification.id}\n initial={prefersReducedMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={prefersReducedMotion ? { duration: 0 } : { delay: index * 0.03 }}\n >\n <NotificationItem\n notification={notification}\n onRead={handleMarkRead}\n onNavigate={handleNavigate}\n getRoute={getRoute}\n onDismiss={onDismiss}\n />\n </motion.div>\n ))}\n </div>\n )\n })\n )}\n\n {isLoading && (\n <div className=\"flex items-center justify-center py-ds-05\">\n <Spinner />\n </div>\n )}\n </div>\n {footerSlot && (\n <div className=\"border-t border-surface-border-strong px-ds-05 py-ds-03\">\n {footerSlot}\n </div>\n )}\n </>\n )\n\n // -- Trigger button (shared between both modes) --\n const triggerButton = (\n <button\n {...props}\n ref={ref}\n aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : 'Notifications'}\n className={cn(\n 'relative flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised text-surface-fg-muted transition-colors ease-productive-standard hover:bg-surface-raised-hover',\n className,\n )}\n >\n <Icon icon={IconBell} size=\"sm\" />\n {unreadCount > 0 && (\n <motion.span\n initial={{ rotate: 0 }}\n animate={prefersReducedMotion ? undefined : { rotate: [0, -3, 3, -1, 1, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { duration: durations.slow01, ease: 'easeInOut' }}\n className=\"absolute -right-ds-01 -top-ds-01 flex h-4 min-w-4 items-center justify-center rounded-pill bg-accent-9 px-ds-02 text-ds-xs font-semibold text-accent-fg\"\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.span>\n )}\n </button>\n )\n\n // -- Mobile: render in a bottom Sheet --\n if (isMobile) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <SheetTrigger asChild>\n {triggerButton}\n </SheetTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <SheetContent side=\"bottom\" className={cn('p-0', popoverClassName)} responsive={false}>\n <SheetTitle className=\"px-ds-05 pt-ds-04 text-ds-md font-semibold text-surface-fg\">\n Notifications\n </SheetTitle>\n {panelContent}\n </SheetContent>\n </Sheet>\n )\n }\n\n // -- Desktop: render in a Popover --\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n {triggerButton}\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <PopoverContent\n className={cn(\n 'w-[380px] rounded-overlay-lg border border-surface-border-strong bg-surface-overlay p-0 shadow-floating',\n popoverClassName,\n )}\n sideOffset={8}\n align=\"end\"\n >\n {panelContent}\n </PopoverContent>\n </Popover>\n )\n },\n)\nNotificationCenter.displayName = 'NotificationCenter'\n\nexport { NotificationCenter }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"notification-center.js","names":[],"sources":["../../src/shell/notification-center.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationCenter -- Popover-based notification panel.\n *\n * Props-driven: accepts notifications array and callbacks instead of\n * reading from Zustand stores or using Remix useNavigate.\n */\nimport { IconBell, IconChecks, IconInbox, IconX } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useCallback,useRef } from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { formatRelativeTime } from '../ui/lib/date-utils'\nimport { durations } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport { Spinner } from '../ui/spinner'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { TruncatedText } from '../ui/truncated-text'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationAction {\n /** Button label */\n label: string\n /** Visual style — 'primary' is filled, 'default' is ghost, 'danger' is red ghost */\n variant?: 'primary' | 'default' | 'danger'\n /** Called when the action button is clicked. Receives the notification id. */\n onClick: (id: string) => void\n}\n\nexport interface Notification {\n id: string\n title: string\n body?: string | null\n tier: 'INFO' | 'IMPORTANT' | 'CRITICAL'\n isRead: boolean\n createdAt: string\n entityType?: string | null\n entityId?: string | null\n projectId?: string | null\n project?: { title: string } | null\n /** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */\n actions?: NotificationAction[]\n}\n\nexport interface NotificationCenterProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** List of notifications to display */\n notifications?: Notification[]\n /** Count of unread notifications (derived from notifications if not provided) */\n unreadCount?: number\n /** Whether the popover is open (controlled mode) */\n open?: boolean\n /** Called when the popover open state changes */\n onOpenChange?: (open: boolean) => void\n /** Whether more notifications are loading */\n isLoading?: boolean\n /** Whether there are more notifications to fetch */\n hasMore?: boolean\n /** Called when the user scrolls near the bottom to load more */\n onFetchMore?: () => void\n /** Called to mark a single notification as read */\n onMarkRead?: (id: string) => void\n /** Called to mark all notifications as read */\n onMarkAllRead?: () => void\n /** Called when the user clicks a notification (e.g., navigate to entity) */\n onNavigate?: (path: string) => void\n /** Resolve a notification to a navigation path. Return null if no navigation. */\n getNotificationRoute?: (notification: Notification) => string | null\n /** Additional actions rendered in the header (e.g., settings button) */\n headerActions?: React.ReactNode\n /** Custom empty state to display when there are no notifications */\n emptyState?: React.ReactNode\n /** Content rendered below the notification list as a footer */\n footerSlot?: React.ReactNode\n /** Called when the user dismisses a notification. Renders an X button per row when provided. */\n onDismiss?: (id: string) => void\n /** Additional className for the popover content container */\n popoverClassName?: string\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n )\n}\n\nfunction getDateGroup(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date()\n yesterday.setDate(today.getDate() - 1)\n\n if (isSameDay(date, today)) return 'Today'\n if (isSameDay(date, yesterday)) return 'Yesterday'\n return 'Earlier'\n}\n\nconst TIER_COLORS: Record<string, string> = {\n INFO: 'bg-info-9',\n IMPORTANT: 'bg-warning-9',\n CRITICAL: 'bg-error-9',\n}\n\n// -----------------------------------------------------------------------\n// NotificationItem (internal)\n// -----------------------------------------------------------------------\n\nfunction NotificationItem({\n notification,\n onRead,\n onNavigate,\n getRoute,\n onDismiss,\n}: {\n notification: Notification\n onRead: (id: string) => void\n onNavigate: (path: string) => void\n getRoute: (notification: Notification) => string | null\n onDismiss?: (id: string) => void\n}) {\n const route = getRoute(notification)\n\n const handleClick = () => {\n if (!notification.isRead) {\n onRead(notification.id)\n }\n if (route) {\n onNavigate(route)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleClick()\n }\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n className={cn(\n 'group relative flex w-full cursor-pointer items-start gap-ds-04 px-ds-05 py-ds-04 text-left transition-colors duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised',\n !notification.isRead && 'bg-accent-1',\n )}\n >\n {/* Tier dot — doubles as read/unread marker */}\n <div className=\"mt-ds-02b flex shrink-0\">\n <span\n className={cn(\n 'h-[8px] w-[8px] rounded-pill transition-opacity duration-fast-02 ease-productive-standard',\n TIER_COLORS[notification.tier] || TIER_COLORS.INFO,\n notification.isRead ? 'opacity-20' : 'opacity-100',\n )}\n />\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <TruncatedText\n as=\"p\"\n className={cn(\n 'text-ds-md text-surface-fg',\n !notification.isRead && 'font-semibold',\n )}\n >\n {notification.title}\n </TruncatedText>\n {notification.body && (\n <p className=\"mt-ds-01 line-clamp-2 text-ds-sm text-surface-fg-subtle\">\n {notification.body}\n </p>\n )}\n <div className=\"mt-ds-02 flex items-center gap-ds-03\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {formatRelativeTime(notification.createdAt)}\n </span>\n {notification.project && (\n <>\n <span className=\"text-surface-fg-subtle\">\n ·\n </span>\n <TruncatedText className=\"text-ds-sm text-surface-fg-subtle\">\n {notification.project.title}\n </TruncatedText>\n </>\n )}\n </div>\n\n {/* Inline actions */}\n {notification.actions && notification.actions.length > 0 && (\n <div className=\"mt-ds-03 flex items-center gap-ds-02\">\n {notification.actions.map((action) => (\n <Button\n key={action.label}\n size=\"sm\"\n variant={action.variant === 'primary' ? 'solid' : 'ghost'}\n color={action.variant === 'danger' ? 'error' : 'accent'}\n onClick={(e) => {\n e.stopPropagation()\n action.onClick(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {action.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={`Dismiss notification: ${notification.title}`}\n onClick={(e) => {\n e.stopPropagation()\n onDismiss(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className=\"absolute right-ds-03 top-ds-03 hidden rounded-control-inner p-ds-01 text-surface-fg-subtle transition-[color,background-color,opacity] duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted group-hover:flex group-focus-within:flex\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </div>\n )\n}\n\n// -----------------------------------------------------------------------\n// NotificationCenter\n// -----------------------------------------------------------------------\n\nconst NotificationCenter = React.forwardRef<HTMLButtonElement, NotificationCenterProps>(\n (\n {\n notifications = [],\n unreadCount: unreadCountProp,\n open,\n onOpenChange,\n isLoading = false,\n hasMore = false,\n onFetchMore,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n getNotificationRoute,\n onDismiss,\n headerActions,\n emptyState,\n footerSlot,\n popoverClassName,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = useRef<HTMLDivElement>(null)\n const prefersReducedMotion = useReducedMotion()\n const isMobile = useIsMobile()\n\n const unreadCount =\n unreadCountProp ?? notifications.filter((n) => !n.isRead).length\n\n const getRoute = getNotificationRoute ?? (() => null)\n\n const handleNavigate = useCallback(\n (path: string) => {\n onOpenChange?.(false)\n onNavigate?.(path)\n },\n [onNavigate, onOpenChange],\n )\n\n const handleMarkRead = useCallback(\n (id: string) => {\n onMarkRead?.(id)\n },\n [onMarkRead],\n )\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el || isLoading || !hasMore) return\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {\n onFetchMore?.()\n }\n }, [isLoading, hasMore, onFetchMore])\n\n // Group notifications by date\n const grouped = notifications.reduce<Record<string, Notification[]>>(\n (acc, n) => {\n const group = getDateGroup(n.createdAt)\n if (!acc[group]) acc[group] = []\n acc[group].push(n)\n return acc\n },\n {},\n )\n\n const groupOrder = ['Today', 'Yesterday', 'Earlier']\n\n // -- Shared panel content (used in both Popover and Sheet) --\n const panelContent = (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <div className=\"flex items-center gap-ds-03\">\n {/* On mobile the SheetTitle provides the accessible heading; on desktop use h3 */}\n {!isMobile && (\n <h3 className=\"text-ds-md font-semibold text-surface-fg\">\n Notifications\n </h3>\n )}\n {unreadCount > 0 && (\n <span className=\"flex h-5 min-w-5 items-center justify-center rounded-pill bg-accent-2 px-ds-02b text-ds-sm font-semibold text-accent-11\">\n {unreadCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-ds-03\">\n {unreadCount > 0 && onMarkAllRead && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"flex items-center gap-ds-02 text-ds-sm text-surface-fg-subtle transition-colors hover:text-accent-11\"\n >\n <Icon icon={IconChecks} size=\"sm\" />\n Mark all read\n </button>\n )}\n {headerActions}\n </div>\n </div>\n\n {/* Notification list */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n className={cn('overflow-y-auto', isMobile ? 'max-h-[60vh]' : 'max-h-[420px]')}\n >\n {notifications.length === 0 ? (\n emptyState || (\n <div className=\"flex flex-col items-center justify-center px-ds-05 py-ds-09\">\n <div className=\"flex h-ds-lg w-ds-lg items-center justify-center rounded-pill bg-surface-raised\">\n <Icon icon={IconInbox} size=\"lg\" className=\"text-surface-fg-subtle\" />\n </div>\n <p className=\"mt-ds-04 text-ds-md text-surface-fg-subtle\">\n No notifications yet\n </p>\n <p className=\"mt-ds-02 text-ds-sm text-surface-fg-subtle\">\n You're all caught up!\n </p>\n </div>\n )\n ) : (\n groupOrder.map((group) => {\n const items = grouped[group]\n if (!items || items.length === 0) return null\n return (\n <div key={group}>\n <div className=\"sticky top-0 z-raised bg-surface-overlay px-ds-05 py-ds-02b\">\n <span className=\"text-ds-sm font-medium text-surface-fg-subtle\">\n {group}\n </span>\n </div>\n {items.map((notification, index) => (\n <motion.div\n key={notification.id}\n initial={prefersReducedMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={prefersReducedMotion ? { duration: 0 } : { delay: index * 0.03 }}\n >\n <NotificationItem\n notification={notification}\n onRead={handleMarkRead}\n onNavigate={handleNavigate}\n getRoute={getRoute}\n onDismiss={onDismiss}\n />\n </motion.div>\n ))}\n </div>\n )\n })\n )}\n\n {isLoading && (\n <div className=\"flex items-center justify-center py-ds-05\">\n <Spinner />\n </div>\n )}\n </div>\n {footerSlot && (\n <div className=\"border-t border-surface-border-strong px-ds-05 py-ds-03\">\n {footerSlot}\n </div>\n )}\n </>\n )\n\n // -- Trigger button (shared between both modes) --\n const triggerButton = (\n <button\n {...props}\n ref={ref}\n aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : 'Notifications'}\n className={cn(\n 'relative flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-pill border border-surface-border-strong bg-surface-raised text-surface-fg-muted transition-colors ease-productive-standard hover:bg-surface-raised-hover',\n className,\n )}\n >\n <Icon icon={IconBell} size=\"sm\" />\n {unreadCount > 0 && (\n <motion.span\n initial={{ rotate: 0 }}\n animate={prefersReducedMotion ? undefined : { rotate: [0, -3, 3, -1, 1, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { duration: durations.slow01, ease: 'easeInOut' }}\n className=\"absolute -right-ds-01 -top-ds-01 flex h-4 min-w-4 items-center justify-center rounded-pill bg-accent-9 px-ds-02 text-ds-xs font-semibold text-accent-fg\"\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.span>\n )}\n </button>\n )\n\n // -- Mobile: render in a bottom Sheet --\n if (isMobile) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <SheetTrigger asChild>\n {triggerButton}\n </SheetTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <SheetContent side=\"bottom\" className={cn('p-0', popoverClassName)} responsive={false}>\n <SheetTitle className=\"px-ds-05 pt-ds-04 text-ds-md font-semibold text-surface-fg\">\n Notifications\n </SheetTitle>\n {panelContent}\n </SheetContent>\n </Sheet>\n )\n }\n\n // -- Desktop: render in a Popover --\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n {triggerButton}\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <PopoverContent\n className={cn(\n 'w-[380px] rounded-overlay-lg bg-surface-overlay p-0 shadow-floating',\n popoverClassName,\n )}\n sideOffset={8}\n align=\"end\"\n >\n {panelContent}\n </PopoverContent>\n </Popover>\n )\n },\n)\nNotificationCenter.displayName = 'NotificationCenter'\n\nexport { NotificationCenter }\n"],"mappings":"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"}
|
package/dist/shell/sidebar.d.ts
CHANGED
|
@@ -101,6 +101,12 @@ export interface AppSidebarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
101
101
|
renderItem?: (item: NavItem, defaultRender: () => React.ReactNode) => React.ReactNode | null;
|
|
102
102
|
/** Additional className for the root sidebar element */
|
|
103
103
|
className?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Corner radius of nav items (composable). @default 'md' (control radius, ~6px).
|
|
106
|
+
* `'lg'` restores the previous rounder look; `'sm'` is tighter; `'pill'` is fully rounded.
|
|
107
|
+
* Sets the `--ds-sidebar-item-radius` CSS var, so you can also override it via `className`/`style`.
|
|
108
|
+
*/
|
|
109
|
+
navItemRadius?: 'sm' | 'md' | 'lg' | 'pill';
|
|
104
110
|
}
|
|
105
111
|
declare const AppSidebar: React.ForwardRefExoticComponent<AppSidebarProps & React.RefAttributes<HTMLDivElement>>;
|
|
106
112
|
export { AppSidebar };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar.tsx"],"names":[],"mappings":"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"}
|
package/dist/shell/sidebar.js
CHANGED
|
@@ -3,15 +3,17 @@ import { IconProvider as e } from "../ui/icon-context.js";
|
|
|
3
3
|
import { cn as t } from "../ui/lib/utils.js";
|
|
4
4
|
import { Avatar as n, AvatarFallback as r, AvatarImage as i } from "../ui/avatar.js";
|
|
5
5
|
import { t as a } from "../_chunks/normalize-icon.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { Button as o } from "../ui/button.js";
|
|
7
|
+
import { Collapsible as s, CollapsibleContent as c, CollapsibleTrigger as l } from "../ui/collapsible.js";
|
|
8
|
+
import { TruncatedText as u } from "../ui/truncated-text.js";
|
|
9
|
+
import { n as d } from "../_chunks/link-context.js";
|
|
10
|
+
import { Sidebar as f, SidebarContent as p, SidebarFooter as m, SidebarGroup as h, SidebarGroupAction as g, SidebarGroupContent as _, SidebarGroupLabel as v, SidebarHeader as y, SidebarMenu as b, SidebarMenuBadge as x, SidebarMenuButton as S, SidebarMenuItem as C, SidebarMenuSub as w, SidebarMenuSubButton as T, SidebarMenuSubItem as E, SidebarSeparator as D } from "../ui/sidebar.js";
|
|
9
11
|
import "./link-context.js";
|
|
10
|
-
import * as
|
|
11
|
-
import { Fragment as
|
|
12
|
+
import * as O from "react";
|
|
13
|
+
import { Fragment as k, jsx as A, jsxs as j } from "react/jsx-runtime";
|
|
12
14
|
//#region src/shell/sidebar.tsx
|
|
13
|
-
function
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
+
function M({ className: e }) {
|
|
16
|
+
return /* @__PURE__ */ A("svg", {
|
|
15
17
|
xmlns: "http://www.w3.org/2000/svg",
|
|
16
18
|
width: "16",
|
|
17
19
|
height: "16",
|
|
@@ -22,11 +24,11 @@ function A({ className: e }) {
|
|
|
22
24
|
strokeLinecap: "round",
|
|
23
25
|
strokeLinejoin: "round",
|
|
24
26
|
className: e,
|
|
25
|
-
children: /* @__PURE__ */
|
|
27
|
+
children: /* @__PURE__ */ A("path", { d: "m9 18 6-6-6-6" })
|
|
26
28
|
});
|
|
27
29
|
}
|
|
28
|
-
function
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
+
function N({ className: e }) {
|
|
31
|
+
return /* @__PURE__ */ j("svg", {
|
|
30
32
|
xmlns: "http://www.w3.org/2000/svg",
|
|
31
33
|
width: "16",
|
|
32
34
|
height: "16",
|
|
@@ -37,224 +39,246 @@ function j({ className: e }) {
|
|
|
37
39
|
strokeLinecap: "round",
|
|
38
40
|
strokeLinejoin: "round",
|
|
39
41
|
className: e,
|
|
40
|
-
children: [/* @__PURE__ */
|
|
42
|
+
children: [/* @__PURE__ */ A("path", { d: "M18 6 6 18" }), /* @__PURE__ */ A("path", { d: "m6 6 12 12" })]
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
var P = "relative gap-ds-04 rounded-[var(--ds-sidebar-item-radius,var(--radius-control))] px-ds-04 py-ds-03 transition-colors duration-fast-02", F = {
|
|
46
|
+
sm: "var(--radius-control-inner)",
|
|
47
|
+
md: "var(--radius-control)",
|
|
48
|
+
lg: "var(--radius-surface)",
|
|
49
|
+
pill: "var(--radius-pill)"
|
|
50
|
+
}, I = "bg-accent-2 text-accent-11 font-medium", L = "text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg";
|
|
51
|
+
function R({ item: n, isActive: r, isPathActive: i }) {
|
|
52
|
+
let o = d(), u = n.badge == null ? null : typeof n.badge == "number" && n.badge > 99 ? "99+" : String(n.badge);
|
|
46
53
|
if (n.children && n.children.length > 0) {
|
|
47
|
-
let
|
|
48
|
-
return /* @__PURE__ */
|
|
49
|
-
defaultOpen:
|
|
54
|
+
let d = n.children.some((e) => i(e.href, e.exact));
|
|
55
|
+
return /* @__PURE__ */ A(s, {
|
|
56
|
+
defaultOpen: d || r || (n.defaultOpen ?? !1),
|
|
50
57
|
className: "group/collapsible",
|
|
51
|
-
children: /* @__PURE__ */
|
|
58
|
+
children: /* @__PURE__ */ j(C, { children: [/* @__PURE__ */ j("div", {
|
|
52
59
|
className: "relative",
|
|
53
60
|
children: [
|
|
54
|
-
/* @__PURE__ */
|
|
61
|
+
/* @__PURE__ */ A(S, {
|
|
55
62
|
asChild: !0,
|
|
56
|
-
isActive: r ||
|
|
63
|
+
isActive: r || d,
|
|
57
64
|
tooltip: n.title,
|
|
58
|
-
className: t(
|
|
59
|
-
children: /* @__PURE__ */
|
|
65
|
+
className: t(P, r || d ? I : L),
|
|
66
|
+
children: /* @__PURE__ */ j(o, {
|
|
60
67
|
href: n.href,
|
|
61
68
|
"aria-label": n.title,
|
|
62
69
|
"aria-current": r ? "page" : void 0,
|
|
63
|
-
|
|
70
|
+
className: "min-w-0",
|
|
71
|
+
children: [/* @__PURE__ */ A("span", {
|
|
64
72
|
className: "[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0",
|
|
65
73
|
"aria-hidden": "true",
|
|
66
|
-
children: /* @__PURE__ */
|
|
74
|
+
children: /* @__PURE__ */ A(e, {
|
|
67
75
|
size: "md",
|
|
68
76
|
children: a(n.icon)
|
|
69
77
|
})
|
|
70
|
-
}), /* @__PURE__ */
|
|
71
|
-
className: "text-ds-base",
|
|
78
|
+
}), /* @__PURE__ */ A("span", {
|
|
79
|
+
className: "text-ds-base truncate",
|
|
72
80
|
children: n.title
|
|
73
81
|
})]
|
|
74
82
|
})
|
|
75
83
|
}),
|
|
76
|
-
|
|
77
|
-
/* @__PURE__ */
|
|
84
|
+
u && /* @__PURE__ */ A(x, { children: u }),
|
|
85
|
+
/* @__PURE__ */ A(l, {
|
|
78
86
|
asChild: !0,
|
|
79
|
-
children: /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ A("button", {
|
|
80
88
|
className: "absolute right-ds-02 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg group-data-[collapsible=icon]:hidden",
|
|
81
89
|
"aria-label": `Toggle ${n.title}`,
|
|
82
|
-
children: /* @__PURE__ */
|
|
90
|
+
children: /* @__PURE__ */ A(M, { className: "h-4 w-4 transition-transform duration-fast-02 ease-productive-standard group-data-[state=open]/collapsible:rotate-90" })
|
|
83
91
|
})
|
|
84
92
|
})
|
|
85
93
|
]
|
|
86
|
-
}), /* @__PURE__ */
|
|
94
|
+
}), /* @__PURE__ */ A(c, { children: /* @__PURE__ */ A(w, { children: n.children.map((t) => {
|
|
87
95
|
let n = i(t.href, t.exact);
|
|
88
|
-
return /* @__PURE__ */
|
|
96
|
+
return /* @__PURE__ */ A(E, { children: /* @__PURE__ */ A(T, {
|
|
89
97
|
asChild: !0,
|
|
90
98
|
isActive: n,
|
|
91
|
-
children: /* @__PURE__ */
|
|
99
|
+
children: /* @__PURE__ */ j(o, {
|
|
92
100
|
href: t.href,
|
|
93
101
|
"aria-current": n ? "page" : void 0,
|
|
94
|
-
|
|
102
|
+
className: "min-w-0",
|
|
103
|
+
children: [t.icon && /* @__PURE__ */ A("span", {
|
|
95
104
|
className: "[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0",
|
|
96
105
|
"aria-hidden": "true",
|
|
97
|
-
children: /* @__PURE__ */
|
|
106
|
+
children: /* @__PURE__ */ A(e, {
|
|
98
107
|
size: "sm",
|
|
99
108
|
children: a(t.icon)
|
|
100
109
|
})
|
|
101
|
-
}), /* @__PURE__ */
|
|
110
|
+
}), /* @__PURE__ */ A("span", {
|
|
111
|
+
className: "truncate",
|
|
112
|
+
children: t.title
|
|
113
|
+
})]
|
|
102
114
|
})
|
|
103
115
|
}) }, t.href);
|
|
104
116
|
}) }) })] })
|
|
105
117
|
});
|
|
106
118
|
}
|
|
107
|
-
return /* @__PURE__ */
|
|
119
|
+
return /* @__PURE__ */ j(C, { children: [/* @__PURE__ */ A(S, {
|
|
108
120
|
asChild: !0,
|
|
109
121
|
isActive: r,
|
|
110
122
|
tooltip: n.title,
|
|
111
|
-
className: t(
|
|
112
|
-
children: /* @__PURE__ */
|
|
123
|
+
className: t(P, r ? I : L),
|
|
124
|
+
children: /* @__PURE__ */ j(o, {
|
|
113
125
|
href: n.href,
|
|
114
126
|
"aria-label": n.title,
|
|
115
127
|
"aria-current": r ? "page" : void 0,
|
|
116
|
-
|
|
128
|
+
className: "min-w-0",
|
|
129
|
+
children: [/* @__PURE__ */ A("span", {
|
|
117
130
|
className: "[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0",
|
|
118
131
|
"aria-hidden": "true",
|
|
119
|
-
children: /* @__PURE__ */
|
|
132
|
+
children: /* @__PURE__ */ A(e, {
|
|
120
133
|
size: "md",
|
|
121
134
|
children: a(n.icon)
|
|
122
135
|
})
|
|
123
|
-
}), /* @__PURE__ */
|
|
124
|
-
className: "text-ds-base",
|
|
136
|
+
}), /* @__PURE__ */ A("span", {
|
|
137
|
+
className: "text-ds-base truncate",
|
|
125
138
|
children: n.title
|
|
126
139
|
})]
|
|
127
140
|
})
|
|
128
|
-
}),
|
|
141
|
+
}), u && /* @__PURE__ */ A(x, { children: u })] });
|
|
129
142
|
}
|
|
130
|
-
var
|
|
131
|
-
let
|
|
132
|
-
return /* @__PURE__ */
|
|
133
|
-
...
|
|
134
|
-
ref:
|
|
143
|
+
var z = O.forwardRef(({ currentPath: s = "/", user: c, navGroups: l = [], logo: x, headerSlot: S, preFooterSlot: C, preFooterClassName: w, footerLinks: T = [], footer: E, renderItem: M, className: P, navItemRadius: I, style: L, ...z }, B) => {
|
|
144
|
+
let V = d(), H = (e, t = !1) => t || e === "/" ? s === e : s.startsWith(e);
|
|
145
|
+
return /* @__PURE__ */ j(f, {
|
|
146
|
+
...z,
|
|
147
|
+
ref: B,
|
|
135
148
|
"aria-label": "Main navigation",
|
|
136
|
-
|
|
149
|
+
style: I ? {
|
|
150
|
+
"--ds-sidebar-item-radius": F[I],
|
|
151
|
+
...L
|
|
152
|
+
} : L,
|
|
153
|
+
className: t("z-raised hidden h-full flex-col border-r border-surface-border-strong bg-surface-raised md:flex", P),
|
|
137
154
|
children: [
|
|
138
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ A(y, {
|
|
139
156
|
className: "px-ds-06 py-ds-06",
|
|
140
|
-
children:
|
|
157
|
+
children: x ?? /* @__PURE__ */ A("span", {
|
|
141
158
|
className: "text-ds-lg font-semibold text-surface-fg",
|
|
142
159
|
children: "Logo"
|
|
143
160
|
})
|
|
144
161
|
}),
|
|
145
|
-
|
|
162
|
+
c && /* @__PURE__ */ j("div", {
|
|
146
163
|
className: "flex items-center gap-ds-04 px-ds-06 pb-ds-05",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ j(n, {
|
|
148
165
|
className: "h-ds-sm-plus w-ds-sm-plus",
|
|
149
|
-
children: [
|
|
150
|
-
src:
|
|
151
|
-
alt:
|
|
152
|
-
}) : null, /* @__PURE__ */
|
|
166
|
+
children: [c.image ? /* @__PURE__ */ A(i, {
|
|
167
|
+
src: c.image,
|
|
168
|
+
alt: c.name
|
|
169
|
+
}) : null, /* @__PURE__ */ A(r, {
|
|
153
170
|
className: "bg-surface-raised-hover text-surface-fg",
|
|
154
|
-
children:
|
|
171
|
+
children: c.name?.charAt(0).toUpperCase()
|
|
155
172
|
})]
|
|
156
|
-
}), /* @__PURE__ */
|
|
173
|
+
}), /* @__PURE__ */ j("div", {
|
|
157
174
|
className: "flex min-w-0 flex-col",
|
|
158
|
-
children: [/* @__PURE__ */
|
|
159
|
-
className: "
|
|
160
|
-
children:
|
|
161
|
-
}), /* @__PURE__ */
|
|
162
|
-
className: "
|
|
163
|
-
children:
|
|
175
|
+
children: [/* @__PURE__ */ A(u, {
|
|
176
|
+
className: "text-ds-md text-surface-fg",
|
|
177
|
+
children: c.name ?? ""
|
|
178
|
+
}), /* @__PURE__ */ A(u, {
|
|
179
|
+
className: "text-ds-sm text-surface-fg-subtle",
|
|
180
|
+
children: c.designation || c.role || ""
|
|
164
181
|
})]
|
|
165
182
|
})]
|
|
166
183
|
}),
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
|
|
169
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ A(D, {}),
|
|
185
|
+
S && /* @__PURE__ */ j(k, { children: [S, /* @__PURE__ */ A(D, {})] }),
|
|
186
|
+
/* @__PURE__ */ A(p, {
|
|
170
187
|
className: "no-scrollbar px-ds-04",
|
|
171
|
-
children:
|
|
172
|
-
/* @__PURE__ */
|
|
188
|
+
children: l.map((e, t) => /* @__PURE__ */ j("div", { children: [t > 0 && /* @__PURE__ */ A(D, {}), /* @__PURE__ */ j(h, { children: [
|
|
189
|
+
/* @__PURE__ */ A(v, {
|
|
173
190
|
className: "px-ds-04 text-ds-sm text-surface-fg-subtle",
|
|
174
191
|
children: e.label
|
|
175
192
|
}),
|
|
176
|
-
e.action && /* @__PURE__ */
|
|
193
|
+
e.action && /* @__PURE__ */ A(g, {
|
|
177
194
|
asChild: !0,
|
|
178
195
|
children: e.action
|
|
179
196
|
}),
|
|
180
|
-
/* @__PURE__ */
|
|
181
|
-
let t = () => /* @__PURE__ */
|
|
197
|
+
/* @__PURE__ */ A(_, { children: /* @__PURE__ */ A(b, { children: e.items.map((e) => {
|
|
198
|
+
let t = () => /* @__PURE__ */ A(R, {
|
|
182
199
|
item: e,
|
|
183
|
-
isActive:
|
|
184
|
-
isPathActive:
|
|
200
|
+
isActive: H(e.href, e.exact),
|
|
201
|
+
isPathActive: H
|
|
185
202
|
});
|
|
186
|
-
if (
|
|
187
|
-
let n =
|
|
188
|
-
if (n !== null) return /* @__PURE__ */ O
|
|
203
|
+
if (M) {
|
|
204
|
+
let n = M(e, t);
|
|
205
|
+
if (n !== null) return /* @__PURE__ */ A(O.Fragment, { children: n }, e.href);
|
|
189
206
|
}
|
|
190
|
-
return /* @__PURE__ */ O
|
|
207
|
+
return /* @__PURE__ */ A(O.Fragment, { children: t() }, e.href);
|
|
191
208
|
}) }) })
|
|
192
209
|
] })] }, e.label))
|
|
193
210
|
}),
|
|
194
|
-
|
|
195
|
-
className:
|
|
196
|
-
children:
|
|
211
|
+
C && /* @__PURE__ */ j(k, { children: [/* @__PURE__ */ A(D, {}), /* @__PURE__ */ A("div", {
|
|
212
|
+
className: w,
|
|
213
|
+
children: C
|
|
197
214
|
})] }),
|
|
198
|
-
|
|
215
|
+
E ? /* @__PURE__ */ j(m, {
|
|
199
216
|
className: "gap-ds-03 px-ds-06 py-ds-05",
|
|
200
217
|
children: [
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
className: "relative rounded-surface
|
|
204
|
-
children: [
|
|
205
|
-
onClick:
|
|
218
|
+
E.slot && /* @__PURE__ */ A("div", { children: E.slot }),
|
|
219
|
+
E.promo && /* @__PURE__ */ j("div", {
|
|
220
|
+
className: "relative rounded-surface bg-surface-raised p-ds-04 shadow-raised",
|
|
221
|
+
children: [E.promo.onDismiss && /* @__PURE__ */ A("button", {
|
|
222
|
+
onClick: E.promo.onDismiss,
|
|
206
223
|
"aria-label": "Dismiss",
|
|
207
224
|
className: "absolute right-ds-02 top-ds-02 flex h-5 w-5 items-center justify-center rounded-control text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg",
|
|
208
|
-
children: /* @__PURE__ */
|
|
209
|
-
}), /* @__PURE__ */
|
|
225
|
+
children: /* @__PURE__ */ A(N, { className: "h-3.5 w-3.5" })
|
|
226
|
+
}), /* @__PURE__ */ j("div", {
|
|
210
227
|
className: "flex flex-col gap-ds-03",
|
|
211
|
-
children: [
|
|
228
|
+
children: [E.promo.icon && /* @__PURE__ */ A("span", {
|
|
212
229
|
className: "text-accent-11 [&>svg]:h-ico-md [&>svg]:w-ico-md",
|
|
213
230
|
"aria-hidden": "true",
|
|
214
|
-
children: /* @__PURE__ */
|
|
231
|
+
children: /* @__PURE__ */ A(e, {
|
|
215
232
|
size: "md",
|
|
216
|
-
children: a(
|
|
233
|
+
children: a(E.promo.icon)
|
|
217
234
|
})
|
|
218
|
-
}), /* @__PURE__ */
|
|
235
|
+
}), /* @__PURE__ */ j("div", {
|
|
219
236
|
className: "flex min-w-0 flex-col gap-ds-03",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
221
|
-
className: "text-ds-sm text-surface-fg",
|
|
222
|
-
children:
|
|
223
|
-
}),
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
children: [/* @__PURE__ */ A("p", {
|
|
238
|
+
className: "text-ds-sm text-surface-fg line-clamp-2",
|
|
239
|
+
children: E.promo.text
|
|
240
|
+
}), E.promo.action && (E.promo.action.href ? /* @__PURE__ */ A(o, {
|
|
241
|
+
asChild: !0,
|
|
242
|
+
variant: "solid",
|
|
243
|
+
size: "sm",
|
|
244
|
+
className: "self-start",
|
|
245
|
+
children: /* @__PURE__ */ A(V, {
|
|
246
|
+
href: E.promo.action.href,
|
|
247
|
+
onClick: E.promo.action.onClick,
|
|
248
|
+
children: E.promo.action.label
|
|
249
|
+
})
|
|
250
|
+
}) : /* @__PURE__ */ A(o, {
|
|
251
|
+
variant: "solid",
|
|
252
|
+
size: "sm",
|
|
253
|
+
className: "self-start",
|
|
254
|
+
onClick: E.promo.action.onClick,
|
|
255
|
+
children: E.promo.action.label
|
|
232
256
|
}))]
|
|
233
257
|
})]
|
|
234
258
|
})]
|
|
235
259
|
}),
|
|
236
|
-
(
|
|
260
|
+
(E.links?.length || E.version) && /* @__PURE__ */ j("div", {
|
|
237
261
|
className: "flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle",
|
|
238
262
|
children: [
|
|
239
|
-
|
|
263
|
+
E.links?.map((e, t) => /* @__PURE__ */ j(O.Fragment, { children: [t > 0 && /* @__PURE__ */ A("span", { children: "·" }), /* @__PURE__ */ A(V, {
|
|
240
264
|
className: "transition-colors hover:text-accent-11",
|
|
241
265
|
href: e.href,
|
|
242
266
|
children: e.label
|
|
243
267
|
})] }, e.href)),
|
|
244
|
-
|
|
245
|
-
|
|
268
|
+
E.links?.length && E.version && /* @__PURE__ */ A("span", { children: "·" }),
|
|
269
|
+
E.version && (typeof E.version == "string" ? /* @__PURE__ */ A("span", { children: E.version }) : /* @__PURE__ */ A(V, {
|
|
246
270
|
className: "transition-colors hover:text-accent-11",
|
|
247
|
-
href:
|
|
248
|
-
children:
|
|
271
|
+
href: E.version.href,
|
|
272
|
+
children: E.version.label
|
|
249
273
|
}))
|
|
250
274
|
]
|
|
251
275
|
})
|
|
252
276
|
]
|
|
253
|
-
}) :
|
|
277
|
+
}) : T.length > 0 ? /* @__PURE__ */ A(m, {
|
|
254
278
|
className: "px-ds-06 py-ds-05",
|
|
255
|
-
children: /* @__PURE__ */
|
|
279
|
+
children: /* @__PURE__ */ A("div", {
|
|
256
280
|
className: "flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle",
|
|
257
|
-
children:
|
|
281
|
+
children: T.map((e, t) => /* @__PURE__ */ j(O.Fragment, { children: [t > 0 && /* @__PURE__ */ A("span", { children: "·" }), /* @__PURE__ */ A(V, {
|
|
258
282
|
className: "transition-colors hover:text-accent-11",
|
|
259
283
|
href: e.href,
|
|
260
284
|
children: e.label
|
|
@@ -264,6 +288,6 @@ var I = E.forwardRef(({ currentPath: o = "/", user: s, navGroups: c = [], logo:
|
|
|
264
288
|
]
|
|
265
289
|
});
|
|
266
290
|
});
|
|
267
|
-
|
|
291
|
+
z.displayName = "AppSidebar";
|
|
268
292
|
//#endregion
|
|
269
|
-
export {
|
|
293
|
+
export { z as AppSidebar };
|