@janovix/blocks 1.0.0-rc.3 → 1.0.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -8,6 +8,8 @@ import * as SliderPrimitive from '@radix-ui/react-slider';
8
8
  import * as TogglePrimitive from '@radix-ui/react-toggle';
9
9
  import * as DialogPrimitive from '@radix-ui/react-dialog';
10
10
  import { Drawer as Drawer$1 } from 'vaul';
11
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
12
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
11
13
  import { ClassValue } from 'clsx';
12
14
 
13
15
  type ThemeSwitcherLabels = {
@@ -132,6 +134,61 @@ interface AvatarEditorDialogProps {
132
134
  }
133
135
  declare function AvatarEditorDialog({ value, onChange, onSave, displaySize, editorSize, outputSize, placeholder: _placeholder, editLabel, dialogTitle, acceptText, cancelText, successMessage, errorMessage, className, }: AvatarEditorDialogProps): react_jsx_runtime.JSX.Element;
134
136
 
137
+ /**
138
+ * NotificationsWidget - A compact notification bell for navigation bars
139
+ *
140
+ * @description
141
+ * Displays a bell icon with unread count badge, plays sound on new notifications,
142
+ * and shows a popover with recent notifications that can be marked as read or dismissed.
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * <NotificationsWidget
147
+ * notifications={notifications}
148
+ * onMarkAsRead={(id) => markAsRead(id)}
149
+ * onMarkAllAsRead={() => markAllAsRead()}
150
+ * onDismiss={(id) => dismiss(id)}
151
+ * onClearAll={() => clearAll()}
152
+ * playSound={true}
153
+ * />
154
+ * ```
155
+ */
156
+ type NotificationType = "info" | "success" | "warning" | "error";
157
+ interface Notification {
158
+ id: string;
159
+ title: string;
160
+ message?: string;
161
+ type?: NotificationType;
162
+ timestamp: Date;
163
+ read?: boolean;
164
+ href?: string;
165
+ }
166
+ type WidgetSize = "sm" | "md" | "lg";
167
+ type DotColor = "red" | "blue" | "green" | "amber" | "purple" | "primary";
168
+ type SoundType = "chime" | "bell" | "pop" | "ding" | "none";
169
+ type PulseStyle = "ring" | "glow" | "bounce" | "none";
170
+ interface NotificationsWidgetProps {
171
+ notifications: Notification[];
172
+ onMarkAsRead?: (id: string) => void;
173
+ onMarkAllAsRead?: () => void;
174
+ onDismiss?: (id: string) => void;
175
+ onClearAll?: () => void;
176
+ onNotificationClick?: (notification: Notification) => void;
177
+ size?: WidgetSize;
178
+ maxVisible?: number;
179
+ playSound?: boolean;
180
+ soundUrl?: string;
181
+ className?: string;
182
+ emptyMessage?: string;
183
+ title?: string;
184
+ dotColor?: DotColor;
185
+ showPulse?: boolean;
186
+ soundType?: SoundType;
187
+ pulseStyle?: PulseStyle;
188
+ soundCooldown?: number;
189
+ }
190
+ declare function NotificationsWidget({ notifications, onMarkAsRead, onMarkAllAsRead, onDismiss, onClearAll, onNotificationClick, size, maxVisible, playSound: _playSound, soundUrl, className, emptyMessage, title, dotColor, showPulse, soundType, pulseStyle, soundCooldown, }: NotificationsWidgetProps): react_jsx_runtime.JSX.Element;
191
+
135
192
  declare const buttonVariants: (props?: ({
136
193
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
137
194
  size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
@@ -200,6 +257,14 @@ declare function DrawerFooter({ className, ...props }: React.ComponentProps<"div
200
257
  declare function DrawerTitle({ className, ...props }: React.ComponentProps<typeof Drawer$1.Title>): react_jsx_runtime.JSX.Element;
201
258
  declare function DrawerDescription({ className, ...props }: React.ComponentProps<typeof Drawer$1.Description>): react_jsx_runtime.JSX.Element;
202
259
 
260
+ declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): react_jsx_runtime.JSX.Element;
261
+ declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>): react_jsx_runtime.JSX.Element;
262
+ declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): react_jsx_runtime.JSX.Element;
263
+ declare function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>): react_jsx_runtime.JSX.Element;
264
+
265
+ declare function ScrollArea({ className, children, ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>): react_jsx_runtime.JSX.Element;
266
+ declare function ScrollBar({ className, orientation, ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>): react_jsx_runtime.JSX.Element;
267
+
203
268
  declare function cn(...inputs: ClassValue[]): string;
204
269
 
205
- export { AvatarEditor, AvatarEditorDialog, type AvatarEditorDialogProps, type AvatarEditorProps, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type Language, LanguageSwitcher, type LanguageSwitcherLabels, type LanguageSwitcherProps, Slider, ThemeSwitcher, type ThemeSwitcherLabels, type ThemeSwitcherProps, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buttonVariants, cn, toggleVariants };
270
+ export { AvatarEditor, AvatarEditorDialog, type AvatarEditorDialogProps, type AvatarEditorProps, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type Language, LanguageSwitcher, type LanguageSwitcherLabels, type LanguageSwitcherProps, type Notification, type NotificationType, NotificationsWidget, type NotificationsWidgetProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ScrollArea, ScrollBar, Slider, ThemeSwitcher, type ThemeSwitcherLabels, type ThemeSwitcherProps, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buttonVariants, cn, toggleVariants };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,8 @@ import * as SliderPrimitive from '@radix-ui/react-slider';
8
8
  import * as TogglePrimitive from '@radix-ui/react-toggle';
9
9
  import * as DialogPrimitive from '@radix-ui/react-dialog';
10
10
  import { Drawer as Drawer$1 } from 'vaul';
11
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
12
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
11
13
  import { ClassValue } from 'clsx';
12
14
 
13
15
  type ThemeSwitcherLabels = {
@@ -132,6 +134,61 @@ interface AvatarEditorDialogProps {
132
134
  }
133
135
  declare function AvatarEditorDialog({ value, onChange, onSave, displaySize, editorSize, outputSize, placeholder: _placeholder, editLabel, dialogTitle, acceptText, cancelText, successMessage, errorMessage, className, }: AvatarEditorDialogProps): react_jsx_runtime.JSX.Element;
134
136
 
137
+ /**
138
+ * NotificationsWidget - A compact notification bell for navigation bars
139
+ *
140
+ * @description
141
+ * Displays a bell icon with unread count badge, plays sound on new notifications,
142
+ * and shows a popover with recent notifications that can be marked as read or dismissed.
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * <NotificationsWidget
147
+ * notifications={notifications}
148
+ * onMarkAsRead={(id) => markAsRead(id)}
149
+ * onMarkAllAsRead={() => markAllAsRead()}
150
+ * onDismiss={(id) => dismiss(id)}
151
+ * onClearAll={() => clearAll()}
152
+ * playSound={true}
153
+ * />
154
+ * ```
155
+ */
156
+ type NotificationType = "info" | "success" | "warning" | "error";
157
+ interface Notification {
158
+ id: string;
159
+ title: string;
160
+ message?: string;
161
+ type?: NotificationType;
162
+ timestamp: Date;
163
+ read?: boolean;
164
+ href?: string;
165
+ }
166
+ type WidgetSize = "sm" | "md" | "lg";
167
+ type DotColor = "red" | "blue" | "green" | "amber" | "purple" | "primary";
168
+ type SoundType = "chime" | "bell" | "pop" | "ding" | "none";
169
+ type PulseStyle = "ring" | "glow" | "bounce" | "none";
170
+ interface NotificationsWidgetProps {
171
+ notifications: Notification[];
172
+ onMarkAsRead?: (id: string) => void;
173
+ onMarkAllAsRead?: () => void;
174
+ onDismiss?: (id: string) => void;
175
+ onClearAll?: () => void;
176
+ onNotificationClick?: (notification: Notification) => void;
177
+ size?: WidgetSize;
178
+ maxVisible?: number;
179
+ playSound?: boolean;
180
+ soundUrl?: string;
181
+ className?: string;
182
+ emptyMessage?: string;
183
+ title?: string;
184
+ dotColor?: DotColor;
185
+ showPulse?: boolean;
186
+ soundType?: SoundType;
187
+ pulseStyle?: PulseStyle;
188
+ soundCooldown?: number;
189
+ }
190
+ declare function NotificationsWidget({ notifications, onMarkAsRead, onMarkAllAsRead, onDismiss, onClearAll, onNotificationClick, size, maxVisible, playSound: _playSound, soundUrl, className, emptyMessage, title, dotColor, showPulse, soundType, pulseStyle, soundCooldown, }: NotificationsWidgetProps): react_jsx_runtime.JSX.Element;
191
+
135
192
  declare const buttonVariants: (props?: ({
136
193
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
137
194
  size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
@@ -200,6 +257,14 @@ declare function DrawerFooter({ className, ...props }: React.ComponentProps<"div
200
257
  declare function DrawerTitle({ className, ...props }: React.ComponentProps<typeof Drawer$1.Title>): react_jsx_runtime.JSX.Element;
201
258
  declare function DrawerDescription({ className, ...props }: React.ComponentProps<typeof Drawer$1.Description>): react_jsx_runtime.JSX.Element;
202
259
 
260
+ declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): react_jsx_runtime.JSX.Element;
261
+ declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>): react_jsx_runtime.JSX.Element;
262
+ declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): react_jsx_runtime.JSX.Element;
263
+ declare function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>): react_jsx_runtime.JSX.Element;
264
+
265
+ declare function ScrollArea({ className, children, ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>): react_jsx_runtime.JSX.Element;
266
+ declare function ScrollBar({ className, orientation, ...props }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>): react_jsx_runtime.JSX.Element;
267
+
203
268
  declare function cn(...inputs: ClassValue[]): string;
204
269
 
205
- export { AvatarEditor, AvatarEditorDialog, type AvatarEditorDialogProps, type AvatarEditorProps, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type Language, LanguageSwitcher, type LanguageSwitcherLabels, type LanguageSwitcherProps, Slider, ThemeSwitcher, type ThemeSwitcherLabels, type ThemeSwitcherProps, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buttonVariants, cn, toggleVariants };
270
+ export { AvatarEditor, AvatarEditorDialog, type AvatarEditorDialogProps, type AvatarEditorProps, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type Language, LanguageSwitcher, type LanguageSwitcherLabels, type LanguageSwitcherProps, type Notification, type NotificationType, NotificationsWidget, type NotificationsWidgetProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ScrollArea, ScrollBar, Slider, ThemeSwitcher, type ThemeSwitcherLabels, type ThemeSwitcherProps, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buttonVariants, cn, toggleVariants };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useTheme } from 'next-themes';
2
- import { CheckIcon, CircleIcon, ChevronRightIcon, Monitor, Sun, Moon, Languages, Upload, Move, ZoomOut, ZoomIn, RotateCcw, RotateCw, Grid3X3, RefreshCw, X, XIcon, User, Pencil, Check, Loader2 } from 'lucide-react';
2
+ import { CheckIcon, CircleIcon, ChevronRightIcon, Monitor, Sun, Moon, Languages, Upload, Move, ZoomOut, ZoomIn, RotateCcw, RotateCw, Grid3X3, RefreshCw, X, XIcon, User, Pencil, Check, Loader2, Bell, CheckCheck, XCircle, AlertTriangle, CheckCircle, Info, Trash2 } from 'lucide-react';
3
3
  import { AnimatePresence, motion } from 'motion/react';
4
4
  import * as React32 from 'react';
5
5
  import React32__default, { useLayoutEffect, useState, useCallback, useEffect, useRef } from 'react';
@@ -10,6 +10,8 @@ import * as SliderPrimitive from '@radix-ui/react-slider';
10
10
  import * as TogglePrimitive from '@radix-ui/react-toggle';
11
11
  import * as DialogPrimitive from '@radix-ui/react-dialog';
12
12
  import { Drawer as Drawer$1 } from 'vaul';
13
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
14
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
13
15
 
14
16
  function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
15
17
  return function handleEvent(event) {
@@ -10590,7 +10592,451 @@ function AvatarEditorDialog({
10590
10592
  ] }) })
10591
10593
  ] });
10592
10594
  }
10595
+ function Popover({
10596
+ ...props
10597
+ }) {
10598
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
10599
+ }
10600
+ function PopoverTrigger({
10601
+ ...props
10602
+ }) {
10603
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
10604
+ }
10605
+ function PopoverContent({
10606
+ className,
10607
+ align = "center",
10608
+ sideOffset = 4,
10609
+ ...props
10610
+ }) {
10611
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
10612
+ PopoverPrimitive.Content,
10613
+ {
10614
+ "data-slot": "popover-content",
10615
+ align,
10616
+ sideOffset,
10617
+ className: cn(
10618
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
10619
+ className
10620
+ ),
10621
+ ...props
10622
+ }
10623
+ ) });
10624
+ }
10625
+ function PopoverAnchor({
10626
+ ...props
10627
+ }) {
10628
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Anchor, { "data-slot": "popover-anchor", ...props });
10629
+ }
10630
+ function ScrollArea({
10631
+ className,
10632
+ children,
10633
+ ...props
10634
+ }) {
10635
+ return /* @__PURE__ */ jsxs(
10636
+ ScrollAreaPrimitive.Root,
10637
+ {
10638
+ "data-slot": "scroll-area",
10639
+ className: cn("relative overflow-hidden", className),
10640
+ ...props,
10641
+ children: [
10642
+ /* @__PURE__ */ jsx(
10643
+ ScrollAreaPrimitive.Viewport,
10644
+ {
10645
+ "data-slot": "scroll-area-viewport",
10646
+ className: "h-full w-full rounded-[inherit]",
10647
+ children
10648
+ }
10649
+ ),
10650
+ /* @__PURE__ */ jsx(ScrollBar, {}),
10651
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
10652
+ ]
10653
+ }
10654
+ );
10655
+ }
10656
+ function ScrollBar({
10657
+ className,
10658
+ orientation = "vertical",
10659
+ ...props
10660
+ }) {
10661
+ return /* @__PURE__ */ jsx(
10662
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
10663
+ {
10664
+ "data-slot": "scroll-bar",
10665
+ orientation,
10666
+ className: cn(
10667
+ "flex touch-none select-none transition-colors",
10668
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
10669
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
10670
+ className
10671
+ ),
10672
+ ...props,
10673
+ children: /* @__PURE__ */ jsx(
10674
+ ScrollAreaPrimitive.ScrollAreaThumb,
10675
+ {
10676
+ "data-slot": "scroll-thumb",
10677
+ className: "relative flex-1 rounded-full bg-border"
10678
+ }
10679
+ )
10680
+ }
10681
+ );
10682
+ }
10683
+ var sizeConfig = {
10684
+ sm: {
10685
+ button: "h-8 w-8",
10686
+ icon: "w-4 h-4",
10687
+ badge: "min-w-[16px] h-4 text-[10px] -top-1 -right-1",
10688
+ dot: "w-2.5 h-2.5 -top-0.5 -right-0.5"
10689
+ },
10690
+ md: {
10691
+ button: "h-9 w-9",
10692
+ icon: "w-5 h-5",
10693
+ badge: "min-w-[18px] h-[18px] text-[11px] -top-1 -right-1",
10694
+ dot: "w-3 h-3 -top-0.5 -right-0.5"
10695
+ },
10696
+ lg: {
10697
+ button: "h-10 w-10",
10698
+ icon: "w-6 h-6",
10699
+ badge: "min-w-[20px] h-5 text-xs -top-1.5 -right-1.5",
10700
+ dot: "w-3.5 h-3.5 -top-0.5 -right-0.5"
10701
+ }
10702
+ };
10703
+ var typeConfig = {
10704
+ info: {
10705
+ icon: Info,
10706
+ color: "text-blue-500",
10707
+ bg: "bg-blue-500/10"
10708
+ },
10709
+ success: {
10710
+ icon: CheckCircle,
10711
+ color: "text-green-500",
10712
+ bg: "bg-green-500/10"
10713
+ },
10714
+ warning: {
10715
+ icon: AlertTriangle,
10716
+ color: "text-amber-500",
10717
+ bg: "bg-amber-500/10"
10718
+ },
10719
+ error: {
10720
+ icon: XCircle,
10721
+ color: "text-red-500",
10722
+ bg: "bg-red-500/10"
10723
+ }
10724
+ };
10725
+ var dotColorConfig = {
10726
+ red: "bg-red-500",
10727
+ blue: "bg-blue-500",
10728
+ green: "bg-green-500",
10729
+ amber: "bg-amber-500",
10730
+ purple: "bg-purple-500",
10731
+ primary: "bg-primary"
10732
+ };
10733
+ var soundConfig = {
10734
+ chime: {
10735
+ frequencies: [880, 1100],
10736
+ durations: [0.1, 0.2],
10737
+ gain: 0.3
10738
+ },
10739
+ bell: {
10740
+ frequencies: [523, 659, 784],
10741
+ durations: [0.15, 0.15, 0.2],
10742
+ gain: 0.25
10743
+ },
10744
+ pop: {
10745
+ frequencies: [400, 600],
10746
+ durations: [0.05, 0.08],
10747
+ gain: 0.4
10748
+ },
10749
+ ding: {
10750
+ frequencies: [1200],
10751
+ durations: [0.15],
10752
+ gain: 0.2
10753
+ }
10754
+ };
10755
+ var pulseVariants = {
10756
+ ring: {
10757
+ animate: { scale: [1, 1.8], opacity: [0.6, 0] },
10758
+ transition: {
10759
+ duration: 1.2,
10760
+ repeat: Number.POSITIVE_INFINITY,
10761
+ ease: "easeOut"
10762
+ }
10763
+ },
10764
+ glow: {
10765
+ animate: { scale: [1, 1.3, 1], opacity: [0.8, 0.4, 0.8] },
10766
+ transition: {
10767
+ duration: 1.5,
10768
+ repeat: Number.POSITIVE_INFINITY,
10769
+ ease: "easeInOut"
10770
+ }
10771
+ },
10772
+ bounce: {
10773
+ animate: { scale: [1, 1.2, 1], y: [0, -2, 0] },
10774
+ transition: {
10775
+ duration: 0.6,
10776
+ repeat: Number.POSITIVE_INFINITY,
10777
+ ease: "easeInOut"
10778
+ }
10779
+ }
10780
+ };
10781
+ function formatTimeAgo(date) {
10782
+ const now = /* @__PURE__ */ new Date();
10783
+ const diffMs = now.getTime() - date.getTime();
10784
+ const diffSecs = Math.floor(diffMs / 1e3);
10785
+ const diffMins = Math.floor(diffSecs / 60);
10786
+ const diffHours = Math.floor(diffMins / 60);
10787
+ const diffDays = Math.floor(diffHours / 24);
10788
+ if (diffSecs < 60) return "just now";
10789
+ if (diffMins < 60) return `${diffMins}m ago`;
10790
+ if (diffHours < 24) return `${diffHours}h ago`;
10791
+ if (diffDays < 7) return `${diffDays}d ago`;
10792
+ return date.toLocaleDateString();
10793
+ }
10794
+ function playNotificationSound(soundType = "chime", soundUrl) {
10795
+ if (typeof window === "undefined" || soundType === "none") return;
10796
+ if (soundUrl) {
10797
+ const audio = new Audio(soundUrl);
10798
+ audio.volume = 0.5;
10799
+ audio.play().catch(() => {
10800
+ });
10801
+ return;
10802
+ }
10803
+ const config = soundConfig[soundType];
10804
+ if (!config) return;
10805
+ try {
10806
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
10807
+ let currentTime = audioContext.currentTime;
10808
+ config.frequencies.forEach((freq, i) => {
10809
+ const oscillator = audioContext.createOscillator();
10810
+ const gainNode = audioContext.createGain();
10811
+ oscillator.connect(gainNode);
10812
+ gainNode.connect(audioContext.destination);
10813
+ oscillator.frequency.setValueAtTime(freq, currentTime);
10814
+ gainNode.gain.setValueAtTime(config.gain, currentTime);
10815
+ gainNode.gain.exponentialRampToValueAtTime(
10816
+ 0.01,
10817
+ currentTime + config.durations[i]
10818
+ );
10819
+ oscillator.start(currentTime);
10820
+ oscillator.stop(currentTime + config.durations[i]);
10821
+ currentTime += config.durations[i] * 0.7;
10822
+ });
10823
+ } catch {
10824
+ }
10825
+ }
10826
+ function NotificationsWidget({
10827
+ notifications,
10828
+ onMarkAsRead,
10829
+ onMarkAllAsRead,
10830
+ onDismiss,
10831
+ onClearAll,
10832
+ onNotificationClick,
10833
+ size: size4 = "md",
10834
+ maxVisible = 5,
10835
+ playSound: _playSound = true,
10836
+ soundUrl,
10837
+ className,
10838
+ emptyMessage = "No notifications",
10839
+ title = "Notifications",
10840
+ dotColor = "red",
10841
+ showPulse = true,
10842
+ soundType = "chime",
10843
+ pulseStyle = "ring",
10844
+ soundCooldown = 2e3
10845
+ }) {
10846
+ const [isOpen, setIsOpen] = React32.useState(false);
10847
+ const [prevCount, setPrevCount] = React32.useState(0);
10848
+ const lastSoundPlayedRef = React32.useRef(0);
10849
+ const styles = sizeConfig[size4];
10850
+ const dotBgColor = dotColorConfig[dotColor];
10851
+ const unreadCount = notifications.filter((n) => !n.read).length;
10852
+ const visibleNotifications = notifications.slice(0, maxVisible);
10853
+ const hasMore = notifications.length > maxVisible;
10854
+ React32.useEffect(() => {
10855
+ if (soundType !== "none" && unreadCount > prevCount && prevCount > 0) {
10856
+ const now = Date.now();
10857
+ if (now - lastSoundPlayedRef.current >= soundCooldown) {
10858
+ playNotificationSound(soundType, soundUrl);
10859
+ lastSoundPlayedRef.current = now;
10860
+ }
10861
+ }
10862
+ setPrevCount(unreadCount);
10863
+ }, [unreadCount, prevCount, soundType, soundUrl, soundCooldown]);
10864
+ React32.useEffect(() => {
10865
+ if (isOpen && onMarkAsRead) {
10866
+ visibleNotifications.forEach((notification) => {
10867
+ if (!notification.read) {
10868
+ onMarkAsRead(notification.id);
10869
+ }
10870
+ });
10871
+ }
10872
+ }, [isOpen, onMarkAsRead, visibleNotifications]);
10873
+ const handleNotificationClick = (notification) => {
10874
+ if (notification.href) {
10875
+ onNotificationClick?.(notification);
10876
+ }
10877
+ };
10878
+ return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
10879
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
10880
+ motion.button,
10881
+ {
10882
+ className: cn(
10883
+ "relative inline-flex items-center justify-center rounded-lg",
10884
+ "bg-muted/50 border border-border/50 hover:bg-muted/70 transition-colors",
10885
+ styles.button,
10886
+ className
10887
+ ),
10888
+ whileTap: { scale: 0.95 },
10889
+ "aria-label": `Notifications${unreadCount > 0 ? ` (${unreadCount} unread)` : ""}`,
10890
+ children: [
10891
+ /* @__PURE__ */ jsx(Bell, { className: cn(styles.icon, "text-muted-foreground") }),
10892
+ /* @__PURE__ */ jsx(AnimatePresence, { children: unreadCount > 0 && /* @__PURE__ */ jsx(
10893
+ motion.div,
10894
+ {
10895
+ initial: { scale: 0, opacity: 0 },
10896
+ animate: { scale: 1, opacity: 1 },
10897
+ exit: { scale: 0, opacity: 0 },
10898
+ className: cn(
10899
+ "absolute flex items-center justify-center rounded-full",
10900
+ dotBgColor,
10901
+ "text-white font-medium",
10902
+ unreadCount > 9 ? styles.badge : styles.dot,
10903
+ unreadCount > 9 && "px-1"
10904
+ ),
10905
+ children: unreadCount > 9 ? /* @__PURE__ */ jsx("span", { children: unreadCount > 99 ? "99+" : unreadCount }) : null
10906
+ }
10907
+ ) }),
10908
+ /* @__PURE__ */ jsx(AnimatePresence, { children: unreadCount > 0 && showPulse && pulseStyle !== "none" && /* @__PURE__ */ jsx(
10909
+ motion.div,
10910
+ {
10911
+ initial: { scale: 1, opacity: 0.5 },
10912
+ animate: pulseVariants[pulseStyle].animate,
10913
+ transition: pulseVariants[pulseStyle].transition,
10914
+ className: cn("absolute rounded-full", dotBgColor, styles.dot)
10915
+ }
10916
+ ) })
10917
+ ]
10918
+ }
10919
+ ) }),
10920
+ /* @__PURE__ */ jsxs(
10921
+ PopoverContent,
10922
+ {
10923
+ side: "bottom",
10924
+ align: "end",
10925
+ className: "w-80 p-0 overflow-hidden",
10926
+ children: [
10927
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
10928
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10929
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold text-sm", children: title }),
10930
+ unreadCount > 0 && /* @__PURE__ */ jsxs("span", { className: "px-2 py-0.5 text-xs font-medium rounded-full bg-primary/10 text-primary", children: [
10931
+ unreadCount,
10932
+ " new"
10933
+ ] })
10934
+ ] }),
10935
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: unreadCount > 0 && onMarkAllAsRead && /* @__PURE__ */ jsxs(
10936
+ Button,
10937
+ {
10938
+ variant: "ghost",
10939
+ size: "sm",
10940
+ className: "h-7 px-2 text-xs",
10941
+ onClick: () => onMarkAllAsRead(),
10942
+ children: [
10943
+ /* @__PURE__ */ jsx(CheckCheck, { className: "w-3.5 h-3.5 mr-1" }),
10944
+ "Mark all read"
10945
+ ]
10946
+ }
10947
+ ) })
10948
+ ] }),
10949
+ notifications.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-4 text-center", children: [
10950
+ /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-3", children: /* @__PURE__ */ jsx(Bell, { className: "w-6 h-6 text-muted-foreground" }) }),
10951
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
10952
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
10953
+ /* @__PURE__ */ jsx(ScrollArea, { className: "h-[320px]", children: /* @__PURE__ */ jsx("div", { className: "divide-y divide-border", children: visibleNotifications.map((notification) => {
10954
+ const config = typeConfig[notification.type || "info"];
10955
+ const Icon = config.icon;
10956
+ const hasLink = !!notification.href;
10957
+ return /* @__PURE__ */ jsxs(
10958
+ motion.div,
10959
+ {
10960
+ initial: { opacity: 0, y: -10 },
10961
+ animate: { opacity: 1, y: 0 },
10962
+ className: cn(
10963
+ "relative flex gap-3 px-4 py-3 transition-colors group",
10964
+ hasLink && "cursor-pointer hover:bg-muted/50",
10965
+ !hasLink && "cursor-default",
10966
+ !notification.read && "bg-primary/5"
10967
+ ),
10968
+ onClick: () => handleNotificationClick(notification),
10969
+ children: [
10970
+ /* @__PURE__ */ jsx(
10971
+ "div",
10972
+ {
10973
+ className: cn(
10974
+ "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
10975
+ config.bg
10976
+ ),
10977
+ children: /* @__PURE__ */ jsx(Icon, { className: cn("w-4 h-4", config.color) })
10978
+ }
10979
+ ),
10980
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
10981
+ /* @__PURE__ */ jsx("div", { className: "flex items-start justify-between gap-2", children: /* @__PURE__ */ jsx(
10982
+ "p",
10983
+ {
10984
+ className: cn(
10985
+ "text-sm line-clamp-1",
10986
+ !notification.read ? "font-semibold" : "font-medium",
10987
+ hasLink && "group-hover:underline"
10988
+ ),
10989
+ children: notification.title
10990
+ }
10991
+ ) }),
10992
+ notification.message && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground line-clamp-2 mt-0.5", children: notification.message }),
10993
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground/70 mt-1", children: formatTimeAgo(notification.timestamp) })
10994
+ ] }),
10995
+ /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 flex items-start gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: onDismiss && /* @__PURE__ */ jsx(
10996
+ Button,
10997
+ {
10998
+ variant: "ghost",
10999
+ size: "icon",
11000
+ className: "h-6 w-6 text-muted-foreground hover:text-destructive",
11001
+ onClick: (e) => {
11002
+ e.stopPropagation();
11003
+ onDismiss(notification.id);
11004
+ },
11005
+ children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" })
11006
+ }
11007
+ ) })
11008
+ ]
11009
+ },
11010
+ notification.id
11011
+ );
11012
+ }) }) }),
11013
+ (hasMore || onClearAll) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/30", children: [
11014
+ hasMore && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
11015
+ "+",
11016
+ notifications.length - maxVisible,
11017
+ " more"
11018
+ ] }),
11019
+ onClearAll && notifications.length > 0 && /* @__PURE__ */ jsxs(
11020
+ Button,
11021
+ {
11022
+ variant: "ghost",
11023
+ size: "sm",
11024
+ className: "h-7 px-2 text-xs text-muted-foreground hover:text-destructive",
11025
+ onClick: () => onClearAll(),
11026
+ children: [
11027
+ /* @__PURE__ */ jsx(Trash2, { className: "w-3 h-3 mr-1" }),
11028
+ "Clear all"
11029
+ ]
11030
+ }
11031
+ )
11032
+ ] })
11033
+ ] })
11034
+ ]
11035
+ }
11036
+ )
11037
+ ] });
11038
+ }
10593
11039
 
10594
- export { AvatarEditor, AvatarEditorDialog, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu2 as DropdownMenu, DropdownMenuCheckboxItem2 as DropdownMenuCheckboxItem, DropdownMenuContent2 as DropdownMenuContent, DropdownMenuGroup2 as DropdownMenuGroup, DropdownMenuItem2 as DropdownMenuItem, DropdownMenuLabel2 as DropdownMenuLabel, DropdownMenuPortal2 as DropdownMenuPortal, DropdownMenuRadioGroup2 as DropdownMenuRadioGroup, DropdownMenuRadioItem2 as DropdownMenuRadioItem, DropdownMenuSeparator2 as DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub2 as DropdownMenuSub, DropdownMenuSubContent2 as DropdownMenuSubContent, DropdownMenuSubTrigger2 as DropdownMenuSubTrigger, DropdownMenuTrigger2 as DropdownMenuTrigger, LanguageSwitcher, Slider, ThemeSwitcher, Toggle, Tooltip2 as Tooltip, TooltipContent2 as TooltipContent, TooltipProvider2 as TooltipProvider, TooltipTrigger2 as TooltipTrigger, buttonVariants, cn, toggleVariants };
11040
+ export { AvatarEditor, AvatarEditorDialog, Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu2 as DropdownMenu, DropdownMenuCheckboxItem2 as DropdownMenuCheckboxItem, DropdownMenuContent2 as DropdownMenuContent, DropdownMenuGroup2 as DropdownMenuGroup, DropdownMenuItem2 as DropdownMenuItem, DropdownMenuLabel2 as DropdownMenuLabel, DropdownMenuPortal2 as DropdownMenuPortal, DropdownMenuRadioGroup2 as DropdownMenuRadioGroup, DropdownMenuRadioItem2 as DropdownMenuRadioItem, DropdownMenuSeparator2 as DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub2 as DropdownMenuSub, DropdownMenuSubContent2 as DropdownMenuSubContent, DropdownMenuSubTrigger2 as DropdownMenuSubTrigger, DropdownMenuTrigger2 as DropdownMenuTrigger, LanguageSwitcher, NotificationsWidget, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ScrollArea, ScrollBar, Slider, ThemeSwitcher, Toggle, Tooltip2 as Tooltip, TooltipContent2 as TooltipContent, TooltipProvider2 as TooltipProvider, TooltipTrigger2 as TooltipTrigger, buttonVariants, cn, toggleVariants };
10595
11041
  //# sourceMappingURL=index.js.map
10596
11042
  //# sourceMappingURL=index.js.map