@janovix/blocks 1.0.0-rc.3 → 1.0.0-rc.5
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/README.md +605 -28
- package/dist/index.cjs +474 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +467 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -10,6 +10,8 @@ var SliderPrimitive = require('@radix-ui/react-slider');
|
|
|
10
10
|
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
11
11
|
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
12
12
|
var vaul = require('vaul');
|
|
13
|
+
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
14
|
+
var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
|
|
13
15
|
|
|
14
16
|
function _interopNamespace(e) {
|
|
15
17
|
if (e && e.__esModule) return e;
|
|
@@ -34,6 +36,8 @@ var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
|
34
36
|
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
|
|
35
37
|
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
|
|
36
38
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
39
|
+
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
|
|
40
|
+
var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
|
|
37
41
|
|
|
38
42
|
function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
|
|
39
43
|
return function handleEvent(event) {
|
|
@@ -9652,9 +9656,11 @@ function AvatarEditor({
|
|
|
9652
9656
|
const [dragStart, setDragStart] = React32.useState({ x: 0, y: 0 });
|
|
9653
9657
|
const [showGrid, setShowGrid] = React32.useState(initialShowGrid);
|
|
9654
9658
|
React32.useEffect(() => {
|
|
9655
|
-
if (imageSource
|
|
9659
|
+
if (imageSource) {
|
|
9656
9660
|
const img = new Image();
|
|
9657
|
-
|
|
9661
|
+
if (!imageSource.startsWith("data:")) {
|
|
9662
|
+
img.crossOrigin = "anonymous";
|
|
9663
|
+
}
|
|
9658
9664
|
img.onload = () => {
|
|
9659
9665
|
setImage(img);
|
|
9660
9666
|
setImageLoaded(true);
|
|
@@ -9842,6 +9848,7 @@ function AvatarEditor({
|
|
|
9842
9848
|
const handleTouchMove = React32.useCallback(
|
|
9843
9849
|
(e) => {
|
|
9844
9850
|
if (!isDragging) return;
|
|
9851
|
+
e.preventDefault();
|
|
9845
9852
|
const touch = e.touches[0];
|
|
9846
9853
|
setPosition({
|
|
9847
9854
|
x: touch.clientX - dragStart.x,
|
|
@@ -10424,14 +10431,13 @@ function DrawerDescription({
|
|
|
10424
10431
|
function useMediaQuery(query) {
|
|
10425
10432
|
const [matches, setMatches] = React32.useState(false);
|
|
10426
10433
|
React32.useEffect(() => {
|
|
10434
|
+
if (typeof window === "undefined") return;
|
|
10427
10435
|
const media = window.matchMedia(query);
|
|
10428
|
-
|
|
10429
|
-
setMatches(media.matches);
|
|
10430
|
-
}
|
|
10436
|
+
setMatches(media.matches);
|
|
10431
10437
|
const listener = () => setMatches(media.matches);
|
|
10432
10438
|
media.addEventListener("change", listener);
|
|
10433
10439
|
return () => media.removeEventListener("change", listener);
|
|
10434
|
-
}, [
|
|
10440
|
+
}, [query]);
|
|
10435
10441
|
return matches;
|
|
10436
10442
|
}
|
|
10437
10443
|
function AvatarEditorDialog({
|
|
@@ -10454,7 +10460,15 @@ function AvatarEditorDialog({
|
|
|
10454
10460
|
const [editedValue, setEditedValue] = React32.useState(value ?? null);
|
|
10455
10461
|
const [isSaving, setIsSaving] = React32.useState(false);
|
|
10456
10462
|
const [feedback, setFeedback] = React32.useState(null);
|
|
10463
|
+
const [mobileEditorSize, setMobileEditorSize] = React32.useState(editorSize);
|
|
10457
10464
|
const isMobile = useMediaQuery("(max-width: 640px)");
|
|
10465
|
+
React32.useEffect(() => {
|
|
10466
|
+
if (typeof window !== "undefined" && isMobile) {
|
|
10467
|
+
setMobileEditorSize(Math.min(editorSize + 40, window.innerWidth - 48));
|
|
10468
|
+
} else {
|
|
10469
|
+
setMobileEditorSize(editorSize);
|
|
10470
|
+
}
|
|
10471
|
+
}, [isMobile, editorSize]);
|
|
10458
10472
|
const handleOpenChange = React32.useCallback(
|
|
10459
10473
|
(open) => {
|
|
10460
10474
|
if (open) {
|
|
@@ -10529,7 +10543,6 @@ function AvatarEditorDialog({
|
|
|
10529
10543
|
]
|
|
10530
10544
|
}
|
|
10531
10545
|
);
|
|
10532
|
-
const mobileEditorSize = isMobile ? Math.min(editorSize + 40, window.innerWidth - 48) : editorSize;
|
|
10533
10546
|
const EditorContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
10534
10547
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10535
10548
|
AvatarEditor,
|
|
@@ -10614,6 +10627,453 @@ function AvatarEditorDialog({
|
|
|
10614
10627
|
] }) })
|
|
10615
10628
|
] });
|
|
10616
10629
|
}
|
|
10630
|
+
function Popover({
|
|
10631
|
+
...props
|
|
10632
|
+
}) {
|
|
10633
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { "data-slot": "popover", ...props });
|
|
10634
|
+
}
|
|
10635
|
+
function PopoverTrigger({
|
|
10636
|
+
...props
|
|
10637
|
+
}) {
|
|
10638
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
10639
|
+
}
|
|
10640
|
+
function PopoverContent({
|
|
10641
|
+
className,
|
|
10642
|
+
align = "center",
|
|
10643
|
+
sideOffset = 4,
|
|
10644
|
+
...props
|
|
10645
|
+
}) {
|
|
10646
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10647
|
+
PopoverPrimitive__namespace.Content,
|
|
10648
|
+
{
|
|
10649
|
+
"data-slot": "popover-content",
|
|
10650
|
+
align,
|
|
10651
|
+
sideOffset,
|
|
10652
|
+
className: cn(
|
|
10653
|
+
"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",
|
|
10654
|
+
className
|
|
10655
|
+
),
|
|
10656
|
+
...props
|
|
10657
|
+
}
|
|
10658
|
+
) });
|
|
10659
|
+
}
|
|
10660
|
+
function PopoverAnchor({
|
|
10661
|
+
...props
|
|
10662
|
+
}) {
|
|
10663
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Anchor, { "data-slot": "popover-anchor", ...props });
|
|
10664
|
+
}
|
|
10665
|
+
function ScrollArea({
|
|
10666
|
+
className,
|
|
10667
|
+
children,
|
|
10668
|
+
...props
|
|
10669
|
+
}) {
|
|
10670
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10671
|
+
ScrollAreaPrimitive__namespace.Root,
|
|
10672
|
+
{
|
|
10673
|
+
"data-slot": "scroll-area",
|
|
10674
|
+
className: cn("relative overflow-hidden", className),
|
|
10675
|
+
...props,
|
|
10676
|
+
children: [
|
|
10677
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10678
|
+
ScrollAreaPrimitive__namespace.Viewport,
|
|
10679
|
+
{
|
|
10680
|
+
"data-slot": "scroll-area-viewport",
|
|
10681
|
+
className: "h-full w-full rounded-[inherit]",
|
|
10682
|
+
children
|
|
10683
|
+
}
|
|
10684
|
+
),
|
|
10685
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
|
|
10686
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Corner, {})
|
|
10687
|
+
]
|
|
10688
|
+
}
|
|
10689
|
+
);
|
|
10690
|
+
}
|
|
10691
|
+
function ScrollBar({
|
|
10692
|
+
className,
|
|
10693
|
+
orientation = "vertical",
|
|
10694
|
+
...props
|
|
10695
|
+
}) {
|
|
10696
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10697
|
+
ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
|
|
10698
|
+
{
|
|
10699
|
+
"data-slot": "scroll-bar",
|
|
10700
|
+
orientation,
|
|
10701
|
+
className: cn(
|
|
10702
|
+
"flex touch-none select-none transition-colors",
|
|
10703
|
+
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
|
|
10704
|
+
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
|
10705
|
+
className
|
|
10706
|
+
),
|
|
10707
|
+
...props,
|
|
10708
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10709
|
+
ScrollAreaPrimitive__namespace.ScrollAreaThumb,
|
|
10710
|
+
{
|
|
10711
|
+
"data-slot": "scroll-thumb",
|
|
10712
|
+
className: "relative flex-1 rounded-full bg-border"
|
|
10713
|
+
}
|
|
10714
|
+
)
|
|
10715
|
+
}
|
|
10716
|
+
);
|
|
10717
|
+
}
|
|
10718
|
+
var sizeConfig = {
|
|
10719
|
+
sm: {
|
|
10720
|
+
button: "h-8 w-8",
|
|
10721
|
+
icon: "w-4 h-4",
|
|
10722
|
+
badge: "min-w-[16px] h-4 text-[10px] -top-1 -right-1",
|
|
10723
|
+
dot: "w-2.5 h-2.5 -top-0.5 -right-0.5"
|
|
10724
|
+
},
|
|
10725
|
+
md: {
|
|
10726
|
+
button: "h-9 w-9",
|
|
10727
|
+
icon: "w-5 h-5",
|
|
10728
|
+
badge: "min-w-[18px] h-[18px] text-[11px] -top-1 -right-1",
|
|
10729
|
+
dot: "w-3 h-3 -top-0.5 -right-0.5"
|
|
10730
|
+
},
|
|
10731
|
+
lg: {
|
|
10732
|
+
button: "h-10 w-10",
|
|
10733
|
+
icon: "w-6 h-6",
|
|
10734
|
+
badge: "min-w-[20px] h-5 text-xs -top-1.5 -right-1.5",
|
|
10735
|
+
dot: "w-3.5 h-3.5 -top-0.5 -right-0.5"
|
|
10736
|
+
}
|
|
10737
|
+
};
|
|
10738
|
+
var typeConfig = {
|
|
10739
|
+
info: {
|
|
10740
|
+
icon: lucideReact.Info,
|
|
10741
|
+
color: "text-blue-500",
|
|
10742
|
+
bg: "bg-blue-500/10"
|
|
10743
|
+
},
|
|
10744
|
+
success: {
|
|
10745
|
+
icon: lucideReact.CheckCircle,
|
|
10746
|
+
color: "text-green-500",
|
|
10747
|
+
bg: "bg-green-500/10"
|
|
10748
|
+
},
|
|
10749
|
+
warning: {
|
|
10750
|
+
icon: lucideReact.AlertTriangle,
|
|
10751
|
+
color: "text-amber-500",
|
|
10752
|
+
bg: "bg-amber-500/10"
|
|
10753
|
+
},
|
|
10754
|
+
error: {
|
|
10755
|
+
icon: lucideReact.XCircle,
|
|
10756
|
+
color: "text-red-500",
|
|
10757
|
+
bg: "bg-red-500/10"
|
|
10758
|
+
}
|
|
10759
|
+
};
|
|
10760
|
+
var dotColorConfig = {
|
|
10761
|
+
red: "bg-red-500",
|
|
10762
|
+
blue: "bg-blue-500",
|
|
10763
|
+
green: "bg-green-500",
|
|
10764
|
+
amber: "bg-amber-500",
|
|
10765
|
+
purple: "bg-purple-500",
|
|
10766
|
+
primary: "bg-primary"
|
|
10767
|
+
};
|
|
10768
|
+
var soundConfig = {
|
|
10769
|
+
chime: {
|
|
10770
|
+
frequencies: [880, 1100],
|
|
10771
|
+
durations: [0.1, 0.2],
|
|
10772
|
+
gain: 0.3
|
|
10773
|
+
},
|
|
10774
|
+
bell: {
|
|
10775
|
+
frequencies: [523, 659, 784],
|
|
10776
|
+
durations: [0.15, 0.15, 0.2],
|
|
10777
|
+
gain: 0.25
|
|
10778
|
+
},
|
|
10779
|
+
pop: {
|
|
10780
|
+
frequencies: [400, 600],
|
|
10781
|
+
durations: [0.05, 0.08],
|
|
10782
|
+
gain: 0.4
|
|
10783
|
+
},
|
|
10784
|
+
ding: {
|
|
10785
|
+
frequencies: [1200],
|
|
10786
|
+
durations: [0.15],
|
|
10787
|
+
gain: 0.2
|
|
10788
|
+
}
|
|
10789
|
+
};
|
|
10790
|
+
var pulseVariants = {
|
|
10791
|
+
ring: {
|
|
10792
|
+
animate: { scale: [1, 1.8], opacity: [0.6, 0] },
|
|
10793
|
+
transition: {
|
|
10794
|
+
duration: 1.2,
|
|
10795
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10796
|
+
ease: "easeOut"
|
|
10797
|
+
}
|
|
10798
|
+
},
|
|
10799
|
+
glow: {
|
|
10800
|
+
animate: { scale: [1, 1.3, 1], opacity: [0.8, 0.4, 0.8] },
|
|
10801
|
+
transition: {
|
|
10802
|
+
duration: 1.5,
|
|
10803
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10804
|
+
ease: "easeInOut"
|
|
10805
|
+
}
|
|
10806
|
+
},
|
|
10807
|
+
bounce: {
|
|
10808
|
+
animate: { scale: [1, 1.2, 1], y: [0, -2, 0] },
|
|
10809
|
+
transition: {
|
|
10810
|
+
duration: 0.6,
|
|
10811
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10812
|
+
ease: "easeInOut"
|
|
10813
|
+
}
|
|
10814
|
+
}
|
|
10815
|
+
};
|
|
10816
|
+
function formatTimeAgo(date) {
|
|
10817
|
+
const now = /* @__PURE__ */ new Date();
|
|
10818
|
+
const diffMs = now.getTime() - date.getTime();
|
|
10819
|
+
const diffSecs = Math.floor(diffMs / 1e3);
|
|
10820
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
10821
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
10822
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
10823
|
+
if (diffSecs < 60) return "just now";
|
|
10824
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
10825
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
10826
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
10827
|
+
return date.toLocaleDateString();
|
|
10828
|
+
}
|
|
10829
|
+
function playNotificationSound(soundType = "chime", soundUrl) {
|
|
10830
|
+
if (typeof window === "undefined" || soundType === "none") return;
|
|
10831
|
+
if (soundUrl) {
|
|
10832
|
+
const audio = new Audio(soundUrl);
|
|
10833
|
+
audio.volume = 0.5;
|
|
10834
|
+
audio.play().catch(() => {
|
|
10835
|
+
});
|
|
10836
|
+
return;
|
|
10837
|
+
}
|
|
10838
|
+
const config = soundConfig[soundType];
|
|
10839
|
+
if (!config) return;
|
|
10840
|
+
try {
|
|
10841
|
+
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
10842
|
+
let currentTime = audioContext.currentTime;
|
|
10843
|
+
config.frequencies.forEach((freq, i) => {
|
|
10844
|
+
const oscillator = audioContext.createOscillator();
|
|
10845
|
+
const gainNode = audioContext.createGain();
|
|
10846
|
+
oscillator.connect(gainNode);
|
|
10847
|
+
gainNode.connect(audioContext.destination);
|
|
10848
|
+
oscillator.frequency.setValueAtTime(freq, currentTime);
|
|
10849
|
+
gainNode.gain.setValueAtTime(config.gain, currentTime);
|
|
10850
|
+
gainNode.gain.exponentialRampToValueAtTime(
|
|
10851
|
+
0.01,
|
|
10852
|
+
currentTime + config.durations[i]
|
|
10853
|
+
);
|
|
10854
|
+
oscillator.start(currentTime);
|
|
10855
|
+
oscillator.stop(currentTime + config.durations[i]);
|
|
10856
|
+
currentTime += config.durations[i] * 0.7;
|
|
10857
|
+
});
|
|
10858
|
+
} catch {
|
|
10859
|
+
}
|
|
10860
|
+
}
|
|
10861
|
+
function NotificationsWidget({
|
|
10862
|
+
notifications,
|
|
10863
|
+
onMarkAsRead,
|
|
10864
|
+
onMarkAllAsRead,
|
|
10865
|
+
onDismiss,
|
|
10866
|
+
onClearAll,
|
|
10867
|
+
onNotificationClick,
|
|
10868
|
+
size: size4 = "md",
|
|
10869
|
+
maxVisible = 5,
|
|
10870
|
+
playSound = true,
|
|
10871
|
+
soundUrl,
|
|
10872
|
+
className,
|
|
10873
|
+
emptyMessage = "No notifications",
|
|
10874
|
+
title = "Notifications",
|
|
10875
|
+
dotColor = "red",
|
|
10876
|
+
showPulse = true,
|
|
10877
|
+
soundType = "chime",
|
|
10878
|
+
pulseStyle = "ring",
|
|
10879
|
+
soundCooldown = 2e3
|
|
10880
|
+
}) {
|
|
10881
|
+
const [isOpen, setIsOpen] = React32__namespace.useState(false);
|
|
10882
|
+
const [prevCount, setPrevCount] = React32__namespace.useState(0);
|
|
10883
|
+
const lastSoundPlayedRef = React32__namespace.useRef(0);
|
|
10884
|
+
const styles = sizeConfig[size4];
|
|
10885
|
+
const dotBgColor = dotColorConfig[dotColor];
|
|
10886
|
+
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
10887
|
+
const visibleNotifications = React32__namespace.useMemo(
|
|
10888
|
+
() => notifications.slice(0, maxVisible),
|
|
10889
|
+
[notifications, maxVisible]
|
|
10890
|
+
);
|
|
10891
|
+
const hasMore = notifications.length > maxVisible;
|
|
10892
|
+
React32__namespace.useEffect(() => {
|
|
10893
|
+
if (playSound && soundType !== "none" && unreadCount > prevCount && prevCount > 0) {
|
|
10894
|
+
const now = Date.now();
|
|
10895
|
+
if (now - lastSoundPlayedRef.current >= soundCooldown) {
|
|
10896
|
+
playNotificationSound(soundType, soundUrl);
|
|
10897
|
+
lastSoundPlayedRef.current = now;
|
|
10898
|
+
}
|
|
10899
|
+
}
|
|
10900
|
+
setPrevCount(unreadCount);
|
|
10901
|
+
}, [unreadCount, prevCount, soundType, soundUrl, soundCooldown, playSound]);
|
|
10902
|
+
React32__namespace.useEffect(() => {
|
|
10903
|
+
if (isOpen && onMarkAsRead) {
|
|
10904
|
+
visibleNotifications.forEach((notification) => {
|
|
10905
|
+
if (!notification.read) {
|
|
10906
|
+
onMarkAsRead(notification.id);
|
|
10907
|
+
}
|
|
10908
|
+
});
|
|
10909
|
+
}
|
|
10910
|
+
}, [isOpen, onMarkAsRead, visibleNotifications]);
|
|
10911
|
+
const handleNotificationClick = (notification) => {
|
|
10912
|
+
if (notification.href) {
|
|
10913
|
+
onNotificationClick?.(notification);
|
|
10914
|
+
}
|
|
10915
|
+
};
|
|
10916
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
10917
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10918
|
+
react.motion.button,
|
|
10919
|
+
{
|
|
10920
|
+
className: cn(
|
|
10921
|
+
"relative inline-flex items-center justify-center rounded-lg",
|
|
10922
|
+
"bg-muted/50 border border-border/50 hover:bg-muted/70 transition-colors",
|
|
10923
|
+
styles.button,
|
|
10924
|
+
className
|
|
10925
|
+
),
|
|
10926
|
+
whileTap: { scale: 0.95 },
|
|
10927
|
+
"aria-label": `Notifications${unreadCount > 0 ? ` (${unreadCount} unread)` : ""}`,
|
|
10928
|
+
children: [
|
|
10929
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: cn(styles.icon, "text-muted-foreground") }),
|
|
10930
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10931
|
+
react.motion.div,
|
|
10932
|
+
{
|
|
10933
|
+
initial: { scale: 0, opacity: 0 },
|
|
10934
|
+
animate: { scale: 1, opacity: 1 },
|
|
10935
|
+
exit: { scale: 0, opacity: 0 },
|
|
10936
|
+
className: cn(
|
|
10937
|
+
"absolute flex items-center justify-center rounded-full",
|
|
10938
|
+
dotBgColor,
|
|
10939
|
+
"text-white font-medium",
|
|
10940
|
+
unreadCount > 9 ? styles.badge : styles.dot,
|
|
10941
|
+
unreadCount > 9 && "px-1"
|
|
10942
|
+
),
|
|
10943
|
+
children: unreadCount > 9 ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: unreadCount > 99 ? "99+" : unreadCount }) : null
|
|
10944
|
+
}
|
|
10945
|
+
) }),
|
|
10946
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: unreadCount > 0 && showPulse && pulseStyle !== "none" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10947
|
+
react.motion.div,
|
|
10948
|
+
{
|
|
10949
|
+
initial: { scale: 1, opacity: 0.5 },
|
|
10950
|
+
animate: pulseVariants[pulseStyle].animate,
|
|
10951
|
+
transition: pulseVariants[pulseStyle].transition,
|
|
10952
|
+
className: cn("absolute rounded-full", dotBgColor, styles.dot)
|
|
10953
|
+
}
|
|
10954
|
+
) })
|
|
10955
|
+
]
|
|
10956
|
+
}
|
|
10957
|
+
) }),
|
|
10958
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10959
|
+
PopoverContent,
|
|
10960
|
+
{
|
|
10961
|
+
side: "bottom",
|
|
10962
|
+
align: "end",
|
|
10963
|
+
className: "w-80 p-0 overflow-hidden",
|
|
10964
|
+
children: [
|
|
10965
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
|
|
10966
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10967
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-sm", children: title }),
|
|
10968
|
+
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-0.5 text-xs font-medium rounded-full bg-primary/10 text-primary", children: [
|
|
10969
|
+
unreadCount,
|
|
10970
|
+
" new"
|
|
10971
|
+
] })
|
|
10972
|
+
] }),
|
|
10973
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: unreadCount > 0 && onMarkAllAsRead && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10974
|
+
Button,
|
|
10975
|
+
{
|
|
10976
|
+
variant: "ghost",
|
|
10977
|
+
size: "sm",
|
|
10978
|
+
className: "h-7 px-2 text-xs",
|
|
10979
|
+
onClick: () => onMarkAllAsRead(),
|
|
10980
|
+
children: [
|
|
10981
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "w-3.5 h-3.5 mr-1" }),
|
|
10982
|
+
"Mark all read"
|
|
10983
|
+
]
|
|
10984
|
+
}
|
|
10985
|
+
) })
|
|
10986
|
+
] }),
|
|
10987
|
+
notifications.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-4 text-center", children: [
|
|
10988
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 rounded-full bg-muted flex items-center justify-center mb-3", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: "w-6 h-6 text-muted-foreground" }) }),
|
|
10989
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
|
|
10990
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10991
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "h-[320px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border", children: visibleNotifications.map((notification) => {
|
|
10992
|
+
const config = typeConfig[notification.type || "info"];
|
|
10993
|
+
const Icon = config.icon;
|
|
10994
|
+
const hasLink = !!notification.href;
|
|
10995
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10996
|
+
react.motion.div,
|
|
10997
|
+
{
|
|
10998
|
+
initial: { opacity: 0, y: -10 },
|
|
10999
|
+
animate: { opacity: 1, y: 0 },
|
|
11000
|
+
className: cn(
|
|
11001
|
+
"relative flex gap-3 px-4 py-3 transition-colors group",
|
|
11002
|
+
hasLink && "cursor-pointer hover:bg-muted/50",
|
|
11003
|
+
!hasLink && "cursor-default",
|
|
11004
|
+
!notification.read && "bg-primary/5"
|
|
11005
|
+
),
|
|
11006
|
+
onClick: () => handleNotificationClick(notification),
|
|
11007
|
+
children: [
|
|
11008
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11009
|
+
"div",
|
|
11010
|
+
{
|
|
11011
|
+
className: cn(
|
|
11012
|
+
"flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
|
|
11013
|
+
config.bg
|
|
11014
|
+
),
|
|
11015
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: cn("w-4 h-4", config.color) })
|
|
11016
|
+
}
|
|
11017
|
+
),
|
|
11018
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11019
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11020
|
+
"p",
|
|
11021
|
+
{
|
|
11022
|
+
className: cn(
|
|
11023
|
+
"text-sm line-clamp-1",
|
|
11024
|
+
!notification.read ? "font-semibold" : "font-medium",
|
|
11025
|
+
hasLink && "group-hover:underline"
|
|
11026
|
+
),
|
|
11027
|
+
children: notification.title
|
|
11028
|
+
}
|
|
11029
|
+
) }),
|
|
11030
|
+
notification.message && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground line-clamp-2 mt-0.5", children: notification.message }),
|
|
11031
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground/70 mt-1", children: formatTimeAgo(notification.timestamp) })
|
|
11032
|
+
] }),
|
|
11033
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 flex items-start gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: onDismiss && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11034
|
+
Button,
|
|
11035
|
+
{
|
|
11036
|
+
variant: "ghost",
|
|
11037
|
+
size: "icon",
|
|
11038
|
+
className: "h-6 w-6 text-muted-foreground hover:text-destructive",
|
|
11039
|
+
onClick: (e) => {
|
|
11040
|
+
e.stopPropagation();
|
|
11041
|
+
onDismiss(notification.id);
|
|
11042
|
+
},
|
|
11043
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
11044
|
+
}
|
|
11045
|
+
) })
|
|
11046
|
+
]
|
|
11047
|
+
},
|
|
11048
|
+
notification.id
|
|
11049
|
+
);
|
|
11050
|
+
}) }) }),
|
|
11051
|
+
(hasMore || onClearAll) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/30", children: [
|
|
11052
|
+
hasMore && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
11053
|
+
"+",
|
|
11054
|
+
notifications.length - maxVisible,
|
|
11055
|
+
" more"
|
|
11056
|
+
] }),
|
|
11057
|
+
onClearAll && notifications.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11058
|
+
Button,
|
|
11059
|
+
{
|
|
11060
|
+
variant: "ghost",
|
|
11061
|
+
size: "sm",
|
|
11062
|
+
className: "h-7 px-2 text-xs text-muted-foreground hover:text-destructive",
|
|
11063
|
+
onClick: () => onClearAll(),
|
|
11064
|
+
children: [
|
|
11065
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-3 h-3 mr-1" }),
|
|
11066
|
+
"Clear all"
|
|
11067
|
+
]
|
|
11068
|
+
}
|
|
11069
|
+
)
|
|
11070
|
+
] })
|
|
11071
|
+
] })
|
|
11072
|
+
]
|
|
11073
|
+
}
|
|
11074
|
+
)
|
|
11075
|
+
] });
|
|
11076
|
+
}
|
|
10617
11077
|
|
|
10618
11078
|
exports.AvatarEditor = AvatarEditor;
|
|
10619
11079
|
exports.AvatarEditorDialog = AvatarEditorDialog;
|
|
@@ -10654,6 +11114,13 @@ exports.DropdownMenuSubContent = DropdownMenuSubContent2;
|
|
|
10654
11114
|
exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger2;
|
|
10655
11115
|
exports.DropdownMenuTrigger = DropdownMenuTrigger2;
|
|
10656
11116
|
exports.LanguageSwitcher = LanguageSwitcher;
|
|
11117
|
+
exports.NotificationsWidget = NotificationsWidget;
|
|
11118
|
+
exports.Popover = Popover;
|
|
11119
|
+
exports.PopoverAnchor = PopoverAnchor;
|
|
11120
|
+
exports.PopoverContent = PopoverContent;
|
|
11121
|
+
exports.PopoverTrigger = PopoverTrigger;
|
|
11122
|
+
exports.ScrollArea = ScrollArea;
|
|
11123
|
+
exports.ScrollBar = ScrollBar;
|
|
10657
11124
|
exports.Slider = Slider;
|
|
10658
11125
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
10659
11126
|
exports.Toggle = Toggle;
|