@janovix/blocks 1.0.0-rc.2 → 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.cjs +1566 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -1
- package/dist/index.d.ts +160 -1
- package/dist/index.js +1532 -3
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,12 @@ var react = require('motion/react');
|
|
|
6
6
|
var React32 = require('react');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var ReactDOM = require('react-dom');
|
|
9
|
+
var SliderPrimitive = require('@radix-ui/react-slider');
|
|
10
|
+
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
11
|
+
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
12
|
+
var vaul = require('vaul');
|
|
13
|
+
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
14
|
+
var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
|
|
9
15
|
|
|
10
16
|
function _interopNamespace(e) {
|
|
11
17
|
if (e && e.__esModule) return e;
|
|
@@ -27,6 +33,11 @@ function _interopNamespace(e) {
|
|
|
27
33
|
|
|
28
34
|
var React32__namespace = /*#__PURE__*/_interopNamespace(React32);
|
|
29
35
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
36
|
+
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
|
|
37
|
+
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
|
|
38
|
+
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
39
|
+
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
|
|
40
|
+
var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
|
|
30
41
|
|
|
31
42
|
function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
|
|
32
43
|
return function handleEvent(event) {
|
|
@@ -9528,8 +9539,1553 @@ function LanguageSwitcher({
|
|
|
9528
9539
|
}
|
|
9529
9540
|
);
|
|
9530
9541
|
}
|
|
9542
|
+
function Slider({
|
|
9543
|
+
className,
|
|
9544
|
+
defaultValue,
|
|
9545
|
+
value,
|
|
9546
|
+
min: min2 = 0,
|
|
9547
|
+
max: max2 = 100,
|
|
9548
|
+
...props
|
|
9549
|
+
}) {
|
|
9550
|
+
const _values = React32__namespace.useMemo(
|
|
9551
|
+
() => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min2, max2],
|
|
9552
|
+
[value, defaultValue, min2, max2]
|
|
9553
|
+
);
|
|
9554
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9555
|
+
SliderPrimitive__namespace.Root,
|
|
9556
|
+
{
|
|
9557
|
+
"data-slot": "slider",
|
|
9558
|
+
defaultValue,
|
|
9559
|
+
value,
|
|
9560
|
+
min: min2,
|
|
9561
|
+
max: max2,
|
|
9562
|
+
className: cn(
|
|
9563
|
+
"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
9564
|
+
className
|
|
9565
|
+
),
|
|
9566
|
+
...props,
|
|
9567
|
+
children: [
|
|
9568
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9569
|
+
SliderPrimitive__namespace.Track,
|
|
9570
|
+
{
|
|
9571
|
+
"data-slot": "slider-track",
|
|
9572
|
+
className: cn(
|
|
9573
|
+
"bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
|
|
9574
|
+
),
|
|
9575
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9576
|
+
SliderPrimitive__namespace.Range,
|
|
9577
|
+
{
|
|
9578
|
+
"data-slot": "slider-range",
|
|
9579
|
+
className: cn(
|
|
9580
|
+
"bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
9581
|
+
)
|
|
9582
|
+
}
|
|
9583
|
+
)
|
|
9584
|
+
}
|
|
9585
|
+
),
|
|
9586
|
+
Array.from({ length: _values.length }, (_, index2) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
9587
|
+
SliderPrimitive__namespace.Thumb,
|
|
9588
|
+
{
|
|
9589
|
+
"data-slot": "slider-thumb",
|
|
9590
|
+
className: "border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
|
|
9591
|
+
},
|
|
9592
|
+
index2
|
|
9593
|
+
))
|
|
9594
|
+
]
|
|
9595
|
+
}
|
|
9596
|
+
);
|
|
9597
|
+
}
|
|
9598
|
+
var toggleVariants = cva(
|
|
9599
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
|
|
9600
|
+
{
|
|
9601
|
+
variants: {
|
|
9602
|
+
variant: {
|
|
9603
|
+
default: "bg-transparent",
|
|
9604
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
9605
|
+
},
|
|
9606
|
+
size: {
|
|
9607
|
+
default: "h-9 px-2 min-w-9",
|
|
9608
|
+
sm: "h-8 px-1.5 min-w-8",
|
|
9609
|
+
lg: "h-10 px-2.5 min-w-10"
|
|
9610
|
+
}
|
|
9611
|
+
},
|
|
9612
|
+
defaultVariants: {
|
|
9613
|
+
variant: "default",
|
|
9614
|
+
size: "default"
|
|
9615
|
+
}
|
|
9616
|
+
}
|
|
9617
|
+
);
|
|
9618
|
+
function Toggle({
|
|
9619
|
+
className,
|
|
9620
|
+
variant,
|
|
9621
|
+
size: size4,
|
|
9622
|
+
...props
|
|
9623
|
+
}) {
|
|
9624
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9625
|
+
TogglePrimitive__namespace.Root,
|
|
9626
|
+
{
|
|
9627
|
+
"data-slot": "toggle",
|
|
9628
|
+
className: cn(toggleVariants({ variant, size: size4, className })),
|
|
9629
|
+
...props
|
|
9630
|
+
}
|
|
9631
|
+
);
|
|
9632
|
+
}
|
|
9633
|
+
function AvatarEditor({
|
|
9634
|
+
value,
|
|
9635
|
+
onChange,
|
|
9636
|
+
size: size4 = 280,
|
|
9637
|
+
showGrid: initialShowGrid = false,
|
|
9638
|
+
outputSize = 256,
|
|
9639
|
+
outputFormat = "png",
|
|
9640
|
+
outputQuality = 0.92,
|
|
9641
|
+
className,
|
|
9642
|
+
controlSize = "default",
|
|
9643
|
+
defaultImage,
|
|
9644
|
+
initials: _initials
|
|
9645
|
+
}) {
|
|
9646
|
+
const canvasRef = React32.useRef(null);
|
|
9647
|
+
const fileInputRef = React32.useRef(null);
|
|
9648
|
+
const containerRef = React32.useRef(null);
|
|
9649
|
+
const imageSource = value ?? defaultImage;
|
|
9650
|
+
const [image, setImage] = React32.useState(null);
|
|
9651
|
+
const [imageLoaded, setImageLoaded] = React32.useState(false);
|
|
9652
|
+
const [zoom, setZoom] = React32.useState(1);
|
|
9653
|
+
const [rotation, setRotation] = React32.useState(0);
|
|
9654
|
+
const [position, setPosition] = React32.useState({ x: 0, y: 0 });
|
|
9655
|
+
const [isDragging, setIsDragging] = React32.useState(false);
|
|
9656
|
+
const [dragStart, setDragStart] = React32.useState({ x: 0, y: 0 });
|
|
9657
|
+
const [showGrid, setShowGrid] = React32.useState(initialShowGrid);
|
|
9658
|
+
React32.useEffect(() => {
|
|
9659
|
+
if (imageSource && !imageSource.startsWith("data:")) {
|
|
9660
|
+
const img = new Image();
|
|
9661
|
+
img.crossOrigin = "anonymous";
|
|
9662
|
+
img.onload = () => {
|
|
9663
|
+
setImage(img);
|
|
9664
|
+
setImageLoaded(true);
|
|
9665
|
+
setZoom(1);
|
|
9666
|
+
setRotation(0);
|
|
9667
|
+
setPosition({ x: 0, y: 0 });
|
|
9668
|
+
};
|
|
9669
|
+
img.src = imageSource;
|
|
9670
|
+
}
|
|
9671
|
+
}, [imageSource]);
|
|
9672
|
+
const generateOutput = React32.useCallback(() => {
|
|
9673
|
+
if (!image) return null;
|
|
9674
|
+
const outputCanvas = document.createElement("canvas");
|
|
9675
|
+
outputCanvas.width = outputSize;
|
|
9676
|
+
outputCanvas.height = outputSize;
|
|
9677
|
+
const ctx = outputCanvas.getContext("2d");
|
|
9678
|
+
if (!ctx) return null;
|
|
9679
|
+
ctx.imageSmoothingEnabled = true;
|
|
9680
|
+
ctx.imageSmoothingQuality = "high";
|
|
9681
|
+
if (outputFormat === "jpeg") {
|
|
9682
|
+
ctx.fillStyle = "#ffffff";
|
|
9683
|
+
ctx.fillRect(0, 0, outputSize, outputSize);
|
|
9684
|
+
}
|
|
9685
|
+
ctx.save();
|
|
9686
|
+
ctx.translate(outputSize / 2, outputSize / 2);
|
|
9687
|
+
ctx.rotate(rotation * Math.PI / 180);
|
|
9688
|
+
const scale = zoom;
|
|
9689
|
+
const imgAspect = image.width / image.height;
|
|
9690
|
+
let drawWidth, drawHeight;
|
|
9691
|
+
if (imgAspect > 1) {
|
|
9692
|
+
drawHeight = outputSize * scale;
|
|
9693
|
+
drawWidth = drawHeight * imgAspect;
|
|
9694
|
+
} else {
|
|
9695
|
+
drawWidth = outputSize * scale;
|
|
9696
|
+
drawHeight = drawWidth / imgAspect;
|
|
9697
|
+
}
|
|
9698
|
+
const positionScale = outputSize / size4;
|
|
9699
|
+
const scaledPosX = position.x * positionScale;
|
|
9700
|
+
const scaledPosY = position.y * positionScale;
|
|
9701
|
+
ctx.drawImage(
|
|
9702
|
+
image,
|
|
9703
|
+
-drawWidth / 2 + scaledPosX,
|
|
9704
|
+
-drawHeight / 2 + scaledPosY,
|
|
9705
|
+
drawWidth,
|
|
9706
|
+
drawHeight
|
|
9707
|
+
);
|
|
9708
|
+
ctx.restore();
|
|
9709
|
+
const mimeType = `image/${outputFormat}`;
|
|
9710
|
+
return outputCanvas.toDataURL(mimeType, outputQuality);
|
|
9711
|
+
}, [
|
|
9712
|
+
image,
|
|
9713
|
+
outputSize,
|
|
9714
|
+
outputFormat,
|
|
9715
|
+
outputQuality,
|
|
9716
|
+
zoom,
|
|
9717
|
+
rotation,
|
|
9718
|
+
position,
|
|
9719
|
+
size4
|
|
9720
|
+
]);
|
|
9721
|
+
React32.useEffect(() => {
|
|
9722
|
+
if (!canvasRef.current || !image || !imageLoaded) return;
|
|
9723
|
+
const canvas = canvasRef.current;
|
|
9724
|
+
const ctx = canvas.getContext("2d");
|
|
9725
|
+
if (!ctx) return;
|
|
9726
|
+
const displaySize = size4;
|
|
9727
|
+
canvas.width = displaySize;
|
|
9728
|
+
canvas.height = displaySize;
|
|
9729
|
+
ctx.clearRect(0, 0, displaySize, displaySize);
|
|
9730
|
+
ctx.fillStyle = "#1a1a2e";
|
|
9731
|
+
ctx.fillRect(0, 0, displaySize, displaySize);
|
|
9732
|
+
ctx.save();
|
|
9733
|
+
ctx.translate(displaySize / 2, displaySize / 2);
|
|
9734
|
+
ctx.rotate(rotation * Math.PI / 180);
|
|
9735
|
+
const scale = zoom;
|
|
9736
|
+
const imgAspect = image.width / image.height;
|
|
9737
|
+
let drawWidth, drawHeight;
|
|
9738
|
+
if (imgAspect > 1) {
|
|
9739
|
+
drawHeight = displaySize * scale;
|
|
9740
|
+
drawWidth = drawHeight * imgAspect;
|
|
9741
|
+
} else {
|
|
9742
|
+
drawWidth = displaySize * scale;
|
|
9743
|
+
drawHeight = drawWidth / imgAspect;
|
|
9744
|
+
}
|
|
9745
|
+
ctx.drawImage(
|
|
9746
|
+
image,
|
|
9747
|
+
-drawWidth / 2 + position.x,
|
|
9748
|
+
-drawHeight / 2 + position.y,
|
|
9749
|
+
drawWidth,
|
|
9750
|
+
drawHeight
|
|
9751
|
+
);
|
|
9752
|
+
ctx.restore();
|
|
9753
|
+
ctx.globalCompositeOperation = "destination-in";
|
|
9754
|
+
ctx.beginPath();
|
|
9755
|
+
ctx.arc(
|
|
9756
|
+
displaySize / 2,
|
|
9757
|
+
displaySize / 2,
|
|
9758
|
+
displaySize / 2 - 4,
|
|
9759
|
+
0,
|
|
9760
|
+
Math.PI * 2
|
|
9761
|
+
);
|
|
9762
|
+
ctx.fill();
|
|
9763
|
+
ctx.globalCompositeOperation = "source-over";
|
|
9764
|
+
ctx.strokeStyle = "hsl(var(--primary))";
|
|
9765
|
+
ctx.lineWidth = 3;
|
|
9766
|
+
ctx.beginPath();
|
|
9767
|
+
ctx.arc(
|
|
9768
|
+
displaySize / 2,
|
|
9769
|
+
displaySize / 2,
|
|
9770
|
+
displaySize / 2 - 2,
|
|
9771
|
+
0,
|
|
9772
|
+
Math.PI * 2
|
|
9773
|
+
);
|
|
9774
|
+
ctx.stroke();
|
|
9775
|
+
const dataUrl = generateOutput();
|
|
9776
|
+
if (dataUrl) {
|
|
9777
|
+
onChange?.(dataUrl);
|
|
9778
|
+
}
|
|
9779
|
+
}, [
|
|
9780
|
+
image,
|
|
9781
|
+
imageLoaded,
|
|
9782
|
+
zoom,
|
|
9783
|
+
rotation,
|
|
9784
|
+
position,
|
|
9785
|
+
size4,
|
|
9786
|
+
generateOutput,
|
|
9787
|
+
onChange
|
|
9788
|
+
]);
|
|
9789
|
+
const resetTransforms = React32.useCallback(() => {
|
|
9790
|
+
setZoom(1);
|
|
9791
|
+
setRotation(0);
|
|
9792
|
+
setPosition({ x: 0, y: 0 });
|
|
9793
|
+
}, []);
|
|
9794
|
+
const handleFileSelect = React32.useCallback(
|
|
9795
|
+
(e) => {
|
|
9796
|
+
const file = e.target.files?.[0];
|
|
9797
|
+
if (!file) return;
|
|
9798
|
+
const reader = new FileReader();
|
|
9799
|
+
reader.onload = (event) => {
|
|
9800
|
+
const img = new Image();
|
|
9801
|
+
img.crossOrigin = "anonymous";
|
|
9802
|
+
img.onload = () => {
|
|
9803
|
+
setImage(img);
|
|
9804
|
+
setImageLoaded(true);
|
|
9805
|
+
resetTransforms();
|
|
9806
|
+
};
|
|
9807
|
+
img.src = event.target?.result;
|
|
9808
|
+
};
|
|
9809
|
+
reader.readAsDataURL(file);
|
|
9810
|
+
},
|
|
9811
|
+
[resetTransforms]
|
|
9812
|
+
);
|
|
9813
|
+
const handleMouseDown = React32.useCallback(
|
|
9814
|
+
(e) => {
|
|
9815
|
+
if (!imageLoaded) return;
|
|
9816
|
+
setIsDragging(true);
|
|
9817
|
+
setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y });
|
|
9818
|
+
},
|
|
9819
|
+
[imageLoaded, position]
|
|
9820
|
+
);
|
|
9821
|
+
const handleMouseMove = React32.useCallback(
|
|
9822
|
+
(e) => {
|
|
9823
|
+
if (!isDragging) return;
|
|
9824
|
+
setPosition({
|
|
9825
|
+
x: e.clientX - dragStart.x,
|
|
9826
|
+
y: e.clientY - dragStart.y
|
|
9827
|
+
});
|
|
9828
|
+
},
|
|
9829
|
+
[isDragging, dragStart]
|
|
9830
|
+
);
|
|
9831
|
+
const handleMouseUp = React32.useCallback(() => {
|
|
9832
|
+
setIsDragging(false);
|
|
9833
|
+
}, []);
|
|
9834
|
+
const handleTouchStart = React32.useCallback(
|
|
9835
|
+
(e) => {
|
|
9836
|
+
if (!imageLoaded) return;
|
|
9837
|
+
const touch = e.touches[0];
|
|
9838
|
+
setIsDragging(true);
|
|
9839
|
+
setDragStart({
|
|
9840
|
+
x: touch.clientX - position.x,
|
|
9841
|
+
y: touch.clientY - position.y
|
|
9842
|
+
});
|
|
9843
|
+
},
|
|
9844
|
+
[imageLoaded, position]
|
|
9845
|
+
);
|
|
9846
|
+
const handleTouchMove = React32.useCallback(
|
|
9847
|
+
(e) => {
|
|
9848
|
+
if (!isDragging) return;
|
|
9849
|
+
const touch = e.touches[0];
|
|
9850
|
+
setPosition({
|
|
9851
|
+
x: touch.clientX - dragStart.x,
|
|
9852
|
+
y: touch.clientY - dragStart.y
|
|
9853
|
+
});
|
|
9854
|
+
},
|
|
9855
|
+
[isDragging, dragStart]
|
|
9856
|
+
);
|
|
9857
|
+
const handleDiscard = React32.useCallback(() => {
|
|
9858
|
+
setImage(null);
|
|
9859
|
+
setImageLoaded(false);
|
|
9860
|
+
resetTransforms();
|
|
9861
|
+
if (fileInputRef.current) {
|
|
9862
|
+
fileInputRef.current.value = "";
|
|
9863
|
+
}
|
|
9864
|
+
onChange?.(null);
|
|
9865
|
+
}, [resetTransforms, onChange]);
|
|
9866
|
+
const handleZoomIn = () => setZoom((z) => Math.min(z + 0.1, 3));
|
|
9867
|
+
const handleZoomOut = () => setZoom((z) => Math.max(z - 0.1, 0.5));
|
|
9868
|
+
const handleRotateLeft = () => setRotation((r2) => r2 - 15);
|
|
9869
|
+
const handleRotateRight = () => setRotation((r2) => r2 + 15);
|
|
9870
|
+
const isLarge = controlSize === "large";
|
|
9871
|
+
const buttonSize = isLarge ? "h-12 w-12" : "h-8 w-8";
|
|
9872
|
+
const iconSize = isLarge ? "w-6 h-6" : "w-4 h-4";
|
|
9873
|
+
const smallIconSize = isLarge ? "w-5 h-5" : "w-3 h-3";
|
|
9874
|
+
const textSize = isLarge ? "text-sm" : "text-xs";
|
|
9875
|
+
const uploadIconSize = isLarge ? "w-12 h-12" : "w-8 h-8";
|
|
9876
|
+
const uploadContainerSize = isLarge ? "w-24 h-24" : "w-16 h-16";
|
|
9877
|
+
const gapSize = isLarge ? "gap-6" : "gap-4";
|
|
9878
|
+
const controlGap = isLarge ? "gap-3" : "gap-2";
|
|
9879
|
+
const sliderHeight = isLarge ? "[&_[role=slider]]:h-6 [&_[role=slider]]:w-6" : "";
|
|
9880
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9881
|
+
"div",
|
|
9882
|
+
{
|
|
9883
|
+
className: cn("flex flex-col", gapSize, className),
|
|
9884
|
+
style: { width: size4 },
|
|
9885
|
+
children: [
|
|
9886
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9887
|
+
"div",
|
|
9888
|
+
{
|
|
9889
|
+
ref: containerRef,
|
|
9890
|
+
className: "relative bg-muted rounded-2xl overflow-hidden",
|
|
9891
|
+
style: { width: size4, height: size4 },
|
|
9892
|
+
children: [
|
|
9893
|
+
!imageLoaded && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9894
|
+
"button",
|
|
9895
|
+
{
|
|
9896
|
+
onClick: () => fileInputRef.current?.click(),
|
|
9897
|
+
className: cn(
|
|
9898
|
+
"absolute inset-0 z-10 flex flex-col items-center justify-center text-muted-foreground hover:text-foreground hover:bg-muted/80 transition-colors cursor-pointer",
|
|
9899
|
+
isLarge ? "gap-4" : "gap-3"
|
|
9900
|
+
),
|
|
9901
|
+
"aria-label": "Upload image",
|
|
9902
|
+
type: "button",
|
|
9903
|
+
children: [
|
|
9904
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9905
|
+
"div",
|
|
9906
|
+
{
|
|
9907
|
+
className: cn(
|
|
9908
|
+
"rounded-full bg-primary/10 flex items-center justify-center",
|
|
9909
|
+
uploadContainerSize
|
|
9910
|
+
),
|
|
9911
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: cn("text-primary", uploadIconSize) })
|
|
9912
|
+
}
|
|
9913
|
+
),
|
|
9914
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9915
|
+
"span",
|
|
9916
|
+
{
|
|
9917
|
+
className: cn("font-medium", isLarge ? "text-base" : "text-sm"),
|
|
9918
|
+
children: "Click to upload"
|
|
9919
|
+
}
|
|
9920
|
+
),
|
|
9921
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-muted-foreground", textSize), children: "PNG, JPG up to 10MB" })
|
|
9922
|
+
]
|
|
9923
|
+
}
|
|
9924
|
+
),
|
|
9925
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9926
|
+
"canvas",
|
|
9927
|
+
{
|
|
9928
|
+
ref: canvasRef,
|
|
9929
|
+
className: cn(
|
|
9930
|
+
"absolute inset-0",
|
|
9931
|
+
imageLoaded ? "cursor-move" : "pointer-events-none opacity-0"
|
|
9932
|
+
),
|
|
9933
|
+
style: { width: size4, height: size4 },
|
|
9934
|
+
onMouseDown: handleMouseDown,
|
|
9935
|
+
onMouseMove: handleMouseMove,
|
|
9936
|
+
onMouseUp: handleMouseUp,
|
|
9937
|
+
onMouseLeave: handleMouseUp,
|
|
9938
|
+
onTouchStart: handleTouchStart,
|
|
9939
|
+
onTouchMove: handleTouchMove,
|
|
9940
|
+
onTouchEnd: handleMouseUp
|
|
9941
|
+
}
|
|
9942
|
+
),
|
|
9943
|
+
showGrid && imageLoaded && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9944
|
+
"div",
|
|
9945
|
+
{
|
|
9946
|
+
className: "absolute inset-0 pointer-events-none",
|
|
9947
|
+
style: { width: size4, height: size4 },
|
|
9948
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size4, height: size4, className: "opacity-30", children: [
|
|
9949
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9950
|
+
"line",
|
|
9951
|
+
{
|
|
9952
|
+
x1: size4 / 3,
|
|
9953
|
+
y1: 0,
|
|
9954
|
+
x2: size4 / 3,
|
|
9955
|
+
y2: size4,
|
|
9956
|
+
stroke: "white",
|
|
9957
|
+
strokeWidth: "1"
|
|
9958
|
+
}
|
|
9959
|
+
),
|
|
9960
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9961
|
+
"line",
|
|
9962
|
+
{
|
|
9963
|
+
x1: size4 * 2 / 3,
|
|
9964
|
+
y1: 0,
|
|
9965
|
+
x2: size4 * 2 / 3,
|
|
9966
|
+
y2: size4,
|
|
9967
|
+
stroke: "white",
|
|
9968
|
+
strokeWidth: "1"
|
|
9969
|
+
}
|
|
9970
|
+
),
|
|
9971
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9972
|
+
"line",
|
|
9973
|
+
{
|
|
9974
|
+
x1: 0,
|
|
9975
|
+
y1: size4 / 3,
|
|
9976
|
+
x2: size4,
|
|
9977
|
+
y2: size4 / 3,
|
|
9978
|
+
stroke: "white",
|
|
9979
|
+
strokeWidth: "1"
|
|
9980
|
+
}
|
|
9981
|
+
),
|
|
9982
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9983
|
+
"line",
|
|
9984
|
+
{
|
|
9985
|
+
x1: 0,
|
|
9986
|
+
y1: size4 * 2 / 3,
|
|
9987
|
+
x2: size4,
|
|
9988
|
+
y2: size4 * 2 / 3,
|
|
9989
|
+
stroke: "white",
|
|
9990
|
+
strokeWidth: "1"
|
|
9991
|
+
}
|
|
9992
|
+
),
|
|
9993
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9994
|
+
"line",
|
|
9995
|
+
{
|
|
9996
|
+
x1: size4 / 2 - 10,
|
|
9997
|
+
y1: size4 / 2,
|
|
9998
|
+
x2: size4 / 2 + 10,
|
|
9999
|
+
y2: size4 / 2,
|
|
10000
|
+
stroke: "white",
|
|
10001
|
+
strokeWidth: "1"
|
|
10002
|
+
}
|
|
10003
|
+
),
|
|
10004
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10005
|
+
"line",
|
|
10006
|
+
{
|
|
10007
|
+
x1: size4 / 2,
|
|
10008
|
+
y1: size4 / 2 - 10,
|
|
10009
|
+
x2: size4 / 2,
|
|
10010
|
+
y2: size4 / 2 + 10,
|
|
10011
|
+
stroke: "white",
|
|
10012
|
+
strokeWidth: "1"
|
|
10013
|
+
}
|
|
10014
|
+
)
|
|
10015
|
+
] })
|
|
10016
|
+
}
|
|
10017
|
+
),
|
|
10018
|
+
imageLoaded && isDragging && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10019
|
+
"div",
|
|
10020
|
+
{
|
|
10021
|
+
className: cn(
|
|
10022
|
+
"absolute top-2 left-1/2 -translate-x-1/2 bg-black/60 rounded text-white flex items-center",
|
|
10023
|
+
isLarge ? "px-3 py-2 text-sm gap-2" : "px-2 py-1 text-xs gap-1"
|
|
10024
|
+
),
|
|
10025
|
+
children: [
|
|
10026
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Move, { className: smallIconSize }),
|
|
10027
|
+
"Dragging"
|
|
10028
|
+
]
|
|
10029
|
+
}
|
|
10030
|
+
)
|
|
10031
|
+
]
|
|
10032
|
+
}
|
|
10033
|
+
),
|
|
10034
|
+
imageLoaded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-4", isLarge && "space-y-5"), children: [
|
|
10035
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center", controlGap), children: [
|
|
10036
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10037
|
+
Button,
|
|
10038
|
+
{
|
|
10039
|
+
variant: "ghost",
|
|
10040
|
+
size: "icon",
|
|
10041
|
+
className: cn(buttonSize, "shrink-0"),
|
|
10042
|
+
onClick: handleZoomOut,
|
|
10043
|
+
"aria-label": "Zoom out",
|
|
10044
|
+
type: "button",
|
|
10045
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { className: iconSize })
|
|
10046
|
+
}
|
|
10047
|
+
),
|
|
10048
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10049
|
+
Slider,
|
|
10050
|
+
{
|
|
10051
|
+
value: [zoom],
|
|
10052
|
+
onValueChange: ([v]) => setZoom(v),
|
|
10053
|
+
min: 0.5,
|
|
10054
|
+
max: 3,
|
|
10055
|
+
step: 0.01,
|
|
10056
|
+
className: cn("flex-1", sliderHeight),
|
|
10057
|
+
"aria-label": "Zoom level"
|
|
10058
|
+
}
|
|
10059
|
+
),
|
|
10060
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10061
|
+
Button,
|
|
10062
|
+
{
|
|
10063
|
+
variant: "ghost",
|
|
10064
|
+
size: "icon",
|
|
10065
|
+
className: cn(buttonSize, "shrink-0"),
|
|
10066
|
+
onClick: handleZoomIn,
|
|
10067
|
+
"aria-label": "Zoom in",
|
|
10068
|
+
type: "button",
|
|
10069
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { className: iconSize })
|
|
10070
|
+
}
|
|
10071
|
+
)
|
|
10072
|
+
] }),
|
|
10073
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between", controlGap), children: [
|
|
10074
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10075
|
+
"div",
|
|
10076
|
+
{
|
|
10077
|
+
className: cn("flex items-center", isLarge ? "gap-2" : "gap-1"),
|
|
10078
|
+
children: [
|
|
10079
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10080
|
+
Button,
|
|
10081
|
+
{
|
|
10082
|
+
variant: "ghost",
|
|
10083
|
+
size: "icon",
|
|
10084
|
+
className: buttonSize,
|
|
10085
|
+
onClick: handleRotateLeft,
|
|
10086
|
+
"aria-label": "Rotate left 15 degrees",
|
|
10087
|
+
type: "button",
|
|
10088
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: iconSize })
|
|
10089
|
+
}
|
|
10090
|
+
),
|
|
10091
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10092
|
+
"span",
|
|
10093
|
+
{
|
|
10094
|
+
className: cn(
|
|
10095
|
+
"text-muted-foreground text-center tabular-nums",
|
|
10096
|
+
textSize,
|
|
10097
|
+
isLarge ? "w-16" : "w-12"
|
|
10098
|
+
),
|
|
10099
|
+
children: [
|
|
10100
|
+
rotation,
|
|
10101
|
+
"\xB0"
|
|
10102
|
+
]
|
|
10103
|
+
}
|
|
10104
|
+
),
|
|
10105
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10106
|
+
Button,
|
|
10107
|
+
{
|
|
10108
|
+
variant: "ghost",
|
|
10109
|
+
size: "icon",
|
|
10110
|
+
className: buttonSize,
|
|
10111
|
+
onClick: handleRotateRight,
|
|
10112
|
+
"aria-label": "Rotate right 15 degrees",
|
|
10113
|
+
type: "button",
|
|
10114
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: iconSize })
|
|
10115
|
+
}
|
|
10116
|
+
)
|
|
10117
|
+
]
|
|
10118
|
+
}
|
|
10119
|
+
),
|
|
10120
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10121
|
+
"div",
|
|
10122
|
+
{
|
|
10123
|
+
className: cn("flex items-center", isLarge ? "gap-2" : "gap-1"),
|
|
10124
|
+
children: [
|
|
10125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10126
|
+
Toggle,
|
|
10127
|
+
{
|
|
10128
|
+
pressed: showGrid,
|
|
10129
|
+
onPressedChange: setShowGrid,
|
|
10130
|
+
size: "sm",
|
|
10131
|
+
className: cn(buttonSize, "p-0"),
|
|
10132
|
+
"aria-label": "Toggle grid overlay",
|
|
10133
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Grid3X3, { className: iconSize })
|
|
10134
|
+
}
|
|
10135
|
+
),
|
|
10136
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10137
|
+
Button,
|
|
10138
|
+
{
|
|
10139
|
+
variant: "ghost",
|
|
10140
|
+
size: "icon",
|
|
10141
|
+
className: buttonSize,
|
|
10142
|
+
onClick: resetTransforms,
|
|
10143
|
+
"aria-label": "Reset all transforms",
|
|
10144
|
+
type: "button",
|
|
10145
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: iconSize })
|
|
10146
|
+
}
|
|
10147
|
+
),
|
|
10148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10149
|
+
Button,
|
|
10150
|
+
{
|
|
10151
|
+
variant: "ghost",
|
|
10152
|
+
size: "icon",
|
|
10153
|
+
className: buttonSize,
|
|
10154
|
+
onClick: () => fileInputRef.current?.click(),
|
|
10155
|
+
"aria-label": "Upload new image",
|
|
10156
|
+
type: "button",
|
|
10157
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: iconSize })
|
|
10158
|
+
}
|
|
10159
|
+
),
|
|
10160
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10161
|
+
Button,
|
|
10162
|
+
{
|
|
10163
|
+
variant: "ghost",
|
|
10164
|
+
size: "icon",
|
|
10165
|
+
className: cn(
|
|
10166
|
+
buttonSize,
|
|
10167
|
+
"text-destructive hover:text-destructive hover:bg-destructive/10"
|
|
10168
|
+
),
|
|
10169
|
+
onClick: handleDiscard,
|
|
10170
|
+
"aria-label": "Discard image",
|
|
10171
|
+
type: "button",
|
|
10172
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: iconSize })
|
|
10173
|
+
}
|
|
10174
|
+
)
|
|
10175
|
+
]
|
|
10176
|
+
}
|
|
10177
|
+
)
|
|
10178
|
+
] })
|
|
10179
|
+
] }),
|
|
10180
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10181
|
+
"input",
|
|
10182
|
+
{
|
|
10183
|
+
ref: fileInputRef,
|
|
10184
|
+
type: "file",
|
|
10185
|
+
accept: "image/*",
|
|
10186
|
+
onChange: handleFileSelect,
|
|
10187
|
+
className: "hidden",
|
|
10188
|
+
"aria-hidden": "true"
|
|
10189
|
+
}
|
|
10190
|
+
)
|
|
10191
|
+
]
|
|
10192
|
+
}
|
|
10193
|
+
);
|
|
10194
|
+
}
|
|
10195
|
+
function Dialog({
|
|
10196
|
+
...props
|
|
10197
|
+
}) {
|
|
10198
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
|
|
10199
|
+
}
|
|
10200
|
+
function DialogTrigger({
|
|
10201
|
+
...props
|
|
10202
|
+
}) {
|
|
10203
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
|
|
10204
|
+
}
|
|
10205
|
+
function DialogPortal({
|
|
10206
|
+
...props
|
|
10207
|
+
}) {
|
|
10208
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
|
|
10209
|
+
}
|
|
10210
|
+
function DialogClose({
|
|
10211
|
+
...props
|
|
10212
|
+
}) {
|
|
10213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
|
|
10214
|
+
}
|
|
10215
|
+
function DialogOverlay({
|
|
10216
|
+
className,
|
|
10217
|
+
...props
|
|
10218
|
+
}) {
|
|
10219
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10220
|
+
DialogPrimitive__namespace.Overlay,
|
|
10221
|
+
{
|
|
10222
|
+
"data-slot": "dialog-overlay",
|
|
10223
|
+
className: cn(
|
|
10224
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
10225
|
+
className
|
|
10226
|
+
),
|
|
10227
|
+
...props
|
|
10228
|
+
}
|
|
10229
|
+
);
|
|
10230
|
+
}
|
|
10231
|
+
function DialogContent({
|
|
10232
|
+
className,
|
|
10233
|
+
children,
|
|
10234
|
+
showCloseButton = true,
|
|
10235
|
+
...props
|
|
10236
|
+
}) {
|
|
10237
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
10238
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
10239
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10240
|
+
DialogPrimitive__namespace.Content,
|
|
10241
|
+
{
|
|
10242
|
+
"data-slot": "dialog-content",
|
|
10243
|
+
className: cn(
|
|
10244
|
+
"bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
|
|
10245
|
+
className
|
|
10246
|
+
),
|
|
10247
|
+
...props,
|
|
10248
|
+
children: [
|
|
10249
|
+
children,
|
|
10250
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10251
|
+
DialogPrimitive__namespace.Close,
|
|
10252
|
+
{
|
|
10253
|
+
"data-slot": "dialog-close",
|
|
10254
|
+
className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10255
|
+
children: [
|
|
10256
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
|
|
10257
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
10258
|
+
]
|
|
10259
|
+
}
|
|
10260
|
+
)
|
|
10261
|
+
]
|
|
10262
|
+
}
|
|
10263
|
+
)
|
|
10264
|
+
] });
|
|
10265
|
+
}
|
|
10266
|
+
function DialogHeader({ className, ...props }) {
|
|
10267
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10268
|
+
"div",
|
|
10269
|
+
{
|
|
10270
|
+
"data-slot": "dialog-header",
|
|
10271
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
10272
|
+
...props
|
|
10273
|
+
}
|
|
10274
|
+
);
|
|
10275
|
+
}
|
|
10276
|
+
function DialogFooter({ className, ...props }) {
|
|
10277
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10278
|
+
"div",
|
|
10279
|
+
{
|
|
10280
|
+
"data-slot": "dialog-footer",
|
|
10281
|
+
className: cn(
|
|
10282
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
10283
|
+
className
|
|
10284
|
+
),
|
|
10285
|
+
...props
|
|
10286
|
+
}
|
|
10287
|
+
);
|
|
10288
|
+
}
|
|
10289
|
+
function DialogTitle({
|
|
10290
|
+
className,
|
|
10291
|
+
...props
|
|
10292
|
+
}) {
|
|
10293
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10294
|
+
DialogPrimitive__namespace.Title,
|
|
10295
|
+
{
|
|
10296
|
+
"data-slot": "dialog-title",
|
|
10297
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
10298
|
+
...props
|
|
10299
|
+
}
|
|
10300
|
+
);
|
|
10301
|
+
}
|
|
10302
|
+
function DialogDescription({
|
|
10303
|
+
className,
|
|
10304
|
+
...props
|
|
10305
|
+
}) {
|
|
10306
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10307
|
+
DialogPrimitive__namespace.Description,
|
|
10308
|
+
{
|
|
10309
|
+
"data-slot": "dialog-description",
|
|
10310
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
10311
|
+
...props
|
|
10312
|
+
}
|
|
10313
|
+
);
|
|
10314
|
+
}
|
|
10315
|
+
function Drawer({
|
|
10316
|
+
...props
|
|
10317
|
+
}) {
|
|
10318
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Root, { "data-slot": "drawer", ...props });
|
|
10319
|
+
}
|
|
10320
|
+
function DrawerTrigger({
|
|
10321
|
+
...props
|
|
10322
|
+
}) {
|
|
10323
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Trigger, { "data-slot": "drawer-trigger", ...props });
|
|
10324
|
+
}
|
|
10325
|
+
function DrawerPortal({
|
|
10326
|
+
...props
|
|
10327
|
+
}) {
|
|
10328
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Portal, { "data-slot": "drawer-portal", ...props });
|
|
10329
|
+
}
|
|
10330
|
+
function DrawerClose({
|
|
10331
|
+
...props
|
|
10332
|
+
}) {
|
|
10333
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Close, { "data-slot": "drawer-close", ...props });
|
|
10334
|
+
}
|
|
10335
|
+
function DrawerOverlay({
|
|
10336
|
+
className,
|
|
10337
|
+
...props
|
|
10338
|
+
}) {
|
|
10339
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10340
|
+
vaul.Drawer.Overlay,
|
|
10341
|
+
{
|
|
10342
|
+
"data-slot": "drawer-overlay",
|
|
10343
|
+
className: cn(
|
|
10344
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
10345
|
+
className
|
|
10346
|
+
),
|
|
10347
|
+
...props
|
|
10348
|
+
}
|
|
10349
|
+
);
|
|
10350
|
+
}
|
|
10351
|
+
function DrawerContent({
|
|
10352
|
+
className,
|
|
10353
|
+
children,
|
|
10354
|
+
...props
|
|
10355
|
+
}) {
|
|
10356
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DrawerPortal, { "data-slot": "drawer-portal", children: [
|
|
10357
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerOverlay, {}),
|
|
10358
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10359
|
+
vaul.Drawer.Content,
|
|
10360
|
+
{
|
|
10361
|
+
"data-slot": "drawer-content",
|
|
10362
|
+
className: cn(
|
|
10363
|
+
"group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
|
|
10364
|
+
"data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
|
|
10365
|
+
"data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
|
|
10366
|
+
"data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
|
|
10367
|
+
"data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
|
|
10368
|
+
className
|
|
10369
|
+
),
|
|
10370
|
+
...props,
|
|
10371
|
+
children: [
|
|
10372
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }),
|
|
10373
|
+
children
|
|
10374
|
+
]
|
|
10375
|
+
}
|
|
10376
|
+
)
|
|
10377
|
+
] });
|
|
10378
|
+
}
|
|
10379
|
+
function DrawerHeader({ className, ...props }) {
|
|
10380
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10381
|
+
"div",
|
|
10382
|
+
{
|
|
10383
|
+
"data-slot": "drawer-header",
|
|
10384
|
+
className: cn(
|
|
10385
|
+
"flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left",
|
|
10386
|
+
className
|
|
10387
|
+
),
|
|
10388
|
+
...props
|
|
10389
|
+
}
|
|
10390
|
+
);
|
|
10391
|
+
}
|
|
10392
|
+
function DrawerFooter({ className, ...props }) {
|
|
10393
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10394
|
+
"div",
|
|
10395
|
+
{
|
|
10396
|
+
"data-slot": "drawer-footer",
|
|
10397
|
+
className: cn("mt-auto flex flex-col gap-2 p-4", className),
|
|
10398
|
+
...props
|
|
10399
|
+
}
|
|
10400
|
+
);
|
|
10401
|
+
}
|
|
10402
|
+
function DrawerTitle({
|
|
10403
|
+
className,
|
|
10404
|
+
...props
|
|
10405
|
+
}) {
|
|
10406
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10407
|
+
vaul.Drawer.Title,
|
|
10408
|
+
{
|
|
10409
|
+
"data-slot": "drawer-title",
|
|
10410
|
+
className: cn("text-foreground font-semibold", className),
|
|
10411
|
+
...props
|
|
10412
|
+
}
|
|
10413
|
+
);
|
|
10414
|
+
}
|
|
10415
|
+
function DrawerDescription({
|
|
10416
|
+
className,
|
|
10417
|
+
...props
|
|
10418
|
+
}) {
|
|
10419
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10420
|
+
vaul.Drawer.Description,
|
|
10421
|
+
{
|
|
10422
|
+
"data-slot": "drawer-description",
|
|
10423
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
10424
|
+
...props
|
|
10425
|
+
}
|
|
10426
|
+
);
|
|
10427
|
+
}
|
|
10428
|
+
function useMediaQuery(query) {
|
|
10429
|
+
const [matches, setMatches] = React32.useState(false);
|
|
10430
|
+
React32.useEffect(() => {
|
|
10431
|
+
const media = window.matchMedia(query);
|
|
10432
|
+
if (media.matches !== matches) {
|
|
10433
|
+
setMatches(media.matches);
|
|
10434
|
+
}
|
|
10435
|
+
const listener = () => setMatches(media.matches);
|
|
10436
|
+
media.addEventListener("change", listener);
|
|
10437
|
+
return () => media.removeEventListener("change", listener);
|
|
10438
|
+
}, [matches, query]);
|
|
10439
|
+
return matches;
|
|
10440
|
+
}
|
|
10441
|
+
function AvatarEditorDialog({
|
|
10442
|
+
value,
|
|
10443
|
+
onChange,
|
|
10444
|
+
onSave,
|
|
10445
|
+
displaySize = 120,
|
|
10446
|
+
editorSize = 280,
|
|
10447
|
+
outputSize = 256,
|
|
10448
|
+
placeholder: _placeholder = "Add Photo",
|
|
10449
|
+
editLabel = "Edit avatar",
|
|
10450
|
+
dialogTitle = "Edit Avatar",
|
|
10451
|
+
acceptText = "Accept",
|
|
10452
|
+
cancelText = "Cancel",
|
|
10453
|
+
successMessage = "Avatar saved successfully!",
|
|
10454
|
+
errorMessage = "Failed to save avatar. Please try again.",
|
|
10455
|
+
className
|
|
10456
|
+
}) {
|
|
10457
|
+
const [isOpen, setIsOpen] = React32.useState(false);
|
|
10458
|
+
const [editedValue, setEditedValue] = React32.useState(value ?? null);
|
|
10459
|
+
const [isSaving, setIsSaving] = React32.useState(false);
|
|
10460
|
+
const [feedback, setFeedback] = React32.useState(null);
|
|
10461
|
+
const isMobile = useMediaQuery("(max-width: 640px)");
|
|
10462
|
+
const handleOpenChange = React32.useCallback(
|
|
10463
|
+
(open) => {
|
|
10464
|
+
if (open) {
|
|
10465
|
+
setEditedValue(value ?? null);
|
|
10466
|
+
setFeedback(null);
|
|
10467
|
+
}
|
|
10468
|
+
setIsOpen(open);
|
|
10469
|
+
},
|
|
10470
|
+
[value]
|
|
10471
|
+
);
|
|
10472
|
+
const handleAccept = React32.useCallback(async () => {
|
|
10473
|
+
if (!editedValue) return;
|
|
10474
|
+
setIsSaving(true);
|
|
10475
|
+
setFeedback(null);
|
|
10476
|
+
try {
|
|
10477
|
+
if (onSave) {
|
|
10478
|
+
const result = await onSave(editedValue);
|
|
10479
|
+
if (result) {
|
|
10480
|
+
setFeedback({ type: "success", message: successMessage });
|
|
10481
|
+
setTimeout(() => {
|
|
10482
|
+
setIsOpen(false);
|
|
10483
|
+
setFeedback(null);
|
|
10484
|
+
}, 1500);
|
|
10485
|
+
} else {
|
|
10486
|
+
setFeedback({ type: "error", message: errorMessage });
|
|
10487
|
+
}
|
|
10488
|
+
} else {
|
|
10489
|
+
onChange?.(editedValue);
|
|
10490
|
+
setFeedback({ type: "success", message: successMessage });
|
|
10491
|
+
setTimeout(() => {
|
|
10492
|
+
setIsOpen(false);
|
|
10493
|
+
setFeedback(null);
|
|
10494
|
+
}, 1500);
|
|
10495
|
+
}
|
|
10496
|
+
} catch {
|
|
10497
|
+
setFeedback({ type: "error", message: errorMessage });
|
|
10498
|
+
} finally {
|
|
10499
|
+
setIsSaving(false);
|
|
10500
|
+
}
|
|
10501
|
+
}, [editedValue, onChange, onSave, successMessage, errorMessage]);
|
|
10502
|
+
const AvatarDisplay = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10503
|
+
"div",
|
|
10504
|
+
{
|
|
10505
|
+
className: cn("relative group", className),
|
|
10506
|
+
style: { width: displaySize, height: displaySize },
|
|
10507
|
+
children: [
|
|
10508
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10509
|
+
"div",
|
|
10510
|
+
{
|
|
10511
|
+
className: "w-full h-full rounded-full overflow-hidden bg-muted border-2 border-border flex items-center justify-center",
|
|
10512
|
+
style: { width: displaySize, height: displaySize },
|
|
10513
|
+
children: value ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10514
|
+
"img",
|
|
10515
|
+
{
|
|
10516
|
+
src: value || "/placeholder.svg",
|
|
10517
|
+
alt: "Avatar",
|
|
10518
|
+
className: "w-full h-full object-cover"
|
|
10519
|
+
}
|
|
10520
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-10 h-10" }) })
|
|
10521
|
+
}
|
|
10522
|
+
),
|
|
10523
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10524
|
+
"button",
|
|
10525
|
+
{
|
|
10526
|
+
onClick: () => handleOpenChange(true),
|
|
10527
|
+
className: "absolute bottom-0 right-0 w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center shadow-lg hover:bg-primary/90 transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2",
|
|
10528
|
+
"aria-label": editLabel,
|
|
10529
|
+
type: "button",
|
|
10530
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "w-4 h-4" })
|
|
10531
|
+
}
|
|
10532
|
+
)
|
|
10533
|
+
]
|
|
10534
|
+
}
|
|
10535
|
+
);
|
|
10536
|
+
const mobileEditorSize = isMobile ? Math.min(editorSize + 40, window.innerWidth - 48) : editorSize;
|
|
10537
|
+
const EditorContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
10538
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10539
|
+
AvatarEditor,
|
|
10540
|
+
{
|
|
10541
|
+
value: editedValue,
|
|
10542
|
+
onChange: setEditedValue,
|
|
10543
|
+
size: mobileEditorSize,
|
|
10544
|
+
outputSize,
|
|
10545
|
+
controlSize: isMobile ? "large" : "default"
|
|
10546
|
+
}
|
|
10547
|
+
),
|
|
10548
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: feedback && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10549
|
+
react.motion.div,
|
|
10550
|
+
{
|
|
10551
|
+
initial: { opacity: 0, y: -10 },
|
|
10552
|
+
animate: { opacity: 1, y: 0 },
|
|
10553
|
+
exit: { opacity: 0, y: -10 },
|
|
10554
|
+
className: cn(
|
|
10555
|
+
"flex items-center gap-2 rounded-lg font-medium",
|
|
10556
|
+
isMobile ? "px-5 py-3 text-base" : "px-4 py-2 text-sm",
|
|
10557
|
+
feedback.type === "success" ? "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400" : "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400"
|
|
10558
|
+
),
|
|
10559
|
+
children: [
|
|
10560
|
+
feedback.type === "success" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: isMobile ? "w-5 h-5" : "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: isMobile ? "w-5 h-5" : "w-4 h-4" }),
|
|
10561
|
+
feedback.message
|
|
10562
|
+
]
|
|
10563
|
+
}
|
|
10564
|
+
) })
|
|
10565
|
+
] });
|
|
10566
|
+
const FooterButtons = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10567
|
+
isMobile ? /* @__PURE__ */ jsxRuntime.jsx(DrawerClose, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10568
|
+
Button,
|
|
10569
|
+
{
|
|
10570
|
+
variant: "outline",
|
|
10571
|
+
disabled: isSaving,
|
|
10572
|
+
size: "lg",
|
|
10573
|
+
className: "flex-1 bg-transparent",
|
|
10574
|
+
children: cancelText
|
|
10575
|
+
}
|
|
10576
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", disabled: isSaving, children: cancelText }) }),
|
|
10577
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10578
|
+
Button,
|
|
10579
|
+
{
|
|
10580
|
+
onClick: handleAccept,
|
|
10581
|
+
disabled: !editedValue || isSaving || feedback?.type === "success",
|
|
10582
|
+
size: isMobile ? "lg" : "default",
|
|
10583
|
+
className: isMobile ? "flex-1" : "",
|
|
10584
|
+
children: isSaving ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10585
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10586
|
+
lucideReact.Loader2,
|
|
10587
|
+
{
|
|
10588
|
+
className: cn(
|
|
10589
|
+
"mr-2 animate-spin",
|
|
10590
|
+
isMobile ? "w-5 h-5" : "w-4 h-4"
|
|
10591
|
+
)
|
|
10592
|
+
}
|
|
10593
|
+
),
|
|
10594
|
+
"Saving..."
|
|
10595
|
+
] }) : feedback?.type === "success" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10596
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("mr-2", isMobile ? "w-5 h-5" : "w-4 h-4") }),
|
|
10597
|
+
"Saved!"
|
|
10598
|
+
] }) : acceptText
|
|
10599
|
+
}
|
|
10600
|
+
)
|
|
10601
|
+
] });
|
|
10602
|
+
if (isMobile) {
|
|
10603
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10604
|
+
AvatarDisplay,
|
|
10605
|
+
/* @__PURE__ */ jsxRuntime.jsx(Drawer, { open: isOpen, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DrawerContent, { className: "max-h-[96vh]", children: [
|
|
10606
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerHeader, { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx(DrawerTitle, { className: "text-xl", children: dialogTitle }) }),
|
|
10607
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pb-6 overflow-y-auto", children: EditorContent }),
|
|
10608
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerFooter, { className: "flex-row gap-3 px-6 pb-8", children: FooterButtons })
|
|
10609
|
+
] }) })
|
|
10610
|
+
] });
|
|
10611
|
+
}
|
|
10612
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10613
|
+
AvatarDisplay,
|
|
10614
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
10615
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: dialogTitle }) }),
|
|
10616
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-4", children: EditorContent }),
|
|
10617
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogFooter, { className: "gap-2 sm:gap-0", children: FooterButtons })
|
|
10618
|
+
] }) })
|
|
10619
|
+
] });
|
|
10620
|
+
}
|
|
10621
|
+
function Popover({
|
|
10622
|
+
...props
|
|
10623
|
+
}) {
|
|
10624
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { "data-slot": "popover", ...props });
|
|
10625
|
+
}
|
|
10626
|
+
function PopoverTrigger({
|
|
10627
|
+
...props
|
|
10628
|
+
}) {
|
|
10629
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
10630
|
+
}
|
|
10631
|
+
function PopoverContent({
|
|
10632
|
+
className,
|
|
10633
|
+
align = "center",
|
|
10634
|
+
sideOffset = 4,
|
|
10635
|
+
...props
|
|
10636
|
+
}) {
|
|
10637
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10638
|
+
PopoverPrimitive__namespace.Content,
|
|
10639
|
+
{
|
|
10640
|
+
"data-slot": "popover-content",
|
|
10641
|
+
align,
|
|
10642
|
+
sideOffset,
|
|
10643
|
+
className: cn(
|
|
10644
|
+
"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",
|
|
10645
|
+
className
|
|
10646
|
+
),
|
|
10647
|
+
...props
|
|
10648
|
+
}
|
|
10649
|
+
) });
|
|
10650
|
+
}
|
|
10651
|
+
function PopoverAnchor({
|
|
10652
|
+
...props
|
|
10653
|
+
}) {
|
|
10654
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Anchor, { "data-slot": "popover-anchor", ...props });
|
|
10655
|
+
}
|
|
10656
|
+
function ScrollArea({
|
|
10657
|
+
className,
|
|
10658
|
+
children,
|
|
10659
|
+
...props
|
|
10660
|
+
}) {
|
|
10661
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10662
|
+
ScrollAreaPrimitive__namespace.Root,
|
|
10663
|
+
{
|
|
10664
|
+
"data-slot": "scroll-area",
|
|
10665
|
+
className: cn("relative overflow-hidden", className),
|
|
10666
|
+
...props,
|
|
10667
|
+
children: [
|
|
10668
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10669
|
+
ScrollAreaPrimitive__namespace.Viewport,
|
|
10670
|
+
{
|
|
10671
|
+
"data-slot": "scroll-area-viewport",
|
|
10672
|
+
className: "h-full w-full rounded-[inherit]",
|
|
10673
|
+
children
|
|
10674
|
+
}
|
|
10675
|
+
),
|
|
10676
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollBar, {}),
|
|
10677
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollAreaPrimitive__namespace.Corner, {})
|
|
10678
|
+
]
|
|
10679
|
+
}
|
|
10680
|
+
);
|
|
10681
|
+
}
|
|
10682
|
+
function ScrollBar({
|
|
10683
|
+
className,
|
|
10684
|
+
orientation = "vertical",
|
|
10685
|
+
...props
|
|
10686
|
+
}) {
|
|
10687
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10688
|
+
ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
|
|
10689
|
+
{
|
|
10690
|
+
"data-slot": "scroll-bar",
|
|
10691
|
+
orientation,
|
|
10692
|
+
className: cn(
|
|
10693
|
+
"flex touch-none select-none transition-colors",
|
|
10694
|
+
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
|
|
10695
|
+
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
|
10696
|
+
className
|
|
10697
|
+
),
|
|
10698
|
+
...props,
|
|
10699
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10700
|
+
ScrollAreaPrimitive__namespace.ScrollAreaThumb,
|
|
10701
|
+
{
|
|
10702
|
+
"data-slot": "scroll-thumb",
|
|
10703
|
+
className: "relative flex-1 rounded-full bg-border"
|
|
10704
|
+
}
|
|
10705
|
+
)
|
|
10706
|
+
}
|
|
10707
|
+
);
|
|
10708
|
+
}
|
|
10709
|
+
var sizeConfig = {
|
|
10710
|
+
sm: {
|
|
10711
|
+
button: "h-8 w-8",
|
|
10712
|
+
icon: "w-4 h-4",
|
|
10713
|
+
badge: "min-w-[16px] h-4 text-[10px] -top-1 -right-1",
|
|
10714
|
+
dot: "w-2.5 h-2.5 -top-0.5 -right-0.5"
|
|
10715
|
+
},
|
|
10716
|
+
md: {
|
|
10717
|
+
button: "h-9 w-9",
|
|
10718
|
+
icon: "w-5 h-5",
|
|
10719
|
+
badge: "min-w-[18px] h-[18px] text-[11px] -top-1 -right-1",
|
|
10720
|
+
dot: "w-3 h-3 -top-0.5 -right-0.5"
|
|
10721
|
+
},
|
|
10722
|
+
lg: {
|
|
10723
|
+
button: "h-10 w-10",
|
|
10724
|
+
icon: "w-6 h-6",
|
|
10725
|
+
badge: "min-w-[20px] h-5 text-xs -top-1.5 -right-1.5",
|
|
10726
|
+
dot: "w-3.5 h-3.5 -top-0.5 -right-0.5"
|
|
10727
|
+
}
|
|
10728
|
+
};
|
|
10729
|
+
var typeConfig = {
|
|
10730
|
+
info: {
|
|
10731
|
+
icon: lucideReact.Info,
|
|
10732
|
+
color: "text-blue-500",
|
|
10733
|
+
bg: "bg-blue-500/10"
|
|
10734
|
+
},
|
|
10735
|
+
success: {
|
|
10736
|
+
icon: lucideReact.CheckCircle,
|
|
10737
|
+
color: "text-green-500",
|
|
10738
|
+
bg: "bg-green-500/10"
|
|
10739
|
+
},
|
|
10740
|
+
warning: {
|
|
10741
|
+
icon: lucideReact.AlertTriangle,
|
|
10742
|
+
color: "text-amber-500",
|
|
10743
|
+
bg: "bg-amber-500/10"
|
|
10744
|
+
},
|
|
10745
|
+
error: {
|
|
10746
|
+
icon: lucideReact.XCircle,
|
|
10747
|
+
color: "text-red-500",
|
|
10748
|
+
bg: "bg-red-500/10"
|
|
10749
|
+
}
|
|
10750
|
+
};
|
|
10751
|
+
var dotColorConfig = {
|
|
10752
|
+
red: "bg-red-500",
|
|
10753
|
+
blue: "bg-blue-500",
|
|
10754
|
+
green: "bg-green-500",
|
|
10755
|
+
amber: "bg-amber-500",
|
|
10756
|
+
purple: "bg-purple-500",
|
|
10757
|
+
primary: "bg-primary"
|
|
10758
|
+
};
|
|
10759
|
+
var soundConfig = {
|
|
10760
|
+
chime: {
|
|
10761
|
+
frequencies: [880, 1100],
|
|
10762
|
+
durations: [0.1, 0.2],
|
|
10763
|
+
gain: 0.3
|
|
10764
|
+
},
|
|
10765
|
+
bell: {
|
|
10766
|
+
frequencies: [523, 659, 784],
|
|
10767
|
+
durations: [0.15, 0.15, 0.2],
|
|
10768
|
+
gain: 0.25
|
|
10769
|
+
},
|
|
10770
|
+
pop: {
|
|
10771
|
+
frequencies: [400, 600],
|
|
10772
|
+
durations: [0.05, 0.08],
|
|
10773
|
+
gain: 0.4
|
|
10774
|
+
},
|
|
10775
|
+
ding: {
|
|
10776
|
+
frequencies: [1200],
|
|
10777
|
+
durations: [0.15],
|
|
10778
|
+
gain: 0.2
|
|
10779
|
+
}
|
|
10780
|
+
};
|
|
10781
|
+
var pulseVariants = {
|
|
10782
|
+
ring: {
|
|
10783
|
+
animate: { scale: [1, 1.8], opacity: [0.6, 0] },
|
|
10784
|
+
transition: {
|
|
10785
|
+
duration: 1.2,
|
|
10786
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10787
|
+
ease: "easeOut"
|
|
10788
|
+
}
|
|
10789
|
+
},
|
|
10790
|
+
glow: {
|
|
10791
|
+
animate: { scale: [1, 1.3, 1], opacity: [0.8, 0.4, 0.8] },
|
|
10792
|
+
transition: {
|
|
10793
|
+
duration: 1.5,
|
|
10794
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10795
|
+
ease: "easeInOut"
|
|
10796
|
+
}
|
|
10797
|
+
},
|
|
10798
|
+
bounce: {
|
|
10799
|
+
animate: { scale: [1, 1.2, 1], y: [0, -2, 0] },
|
|
10800
|
+
transition: {
|
|
10801
|
+
duration: 0.6,
|
|
10802
|
+
repeat: Number.POSITIVE_INFINITY,
|
|
10803
|
+
ease: "easeInOut"
|
|
10804
|
+
}
|
|
10805
|
+
}
|
|
10806
|
+
};
|
|
10807
|
+
function formatTimeAgo(date) {
|
|
10808
|
+
const now = /* @__PURE__ */ new Date();
|
|
10809
|
+
const diffMs = now.getTime() - date.getTime();
|
|
10810
|
+
const diffSecs = Math.floor(diffMs / 1e3);
|
|
10811
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
10812
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
10813
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
10814
|
+
if (diffSecs < 60) return "just now";
|
|
10815
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
10816
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
10817
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
10818
|
+
return date.toLocaleDateString();
|
|
10819
|
+
}
|
|
10820
|
+
function playNotificationSound(soundType = "chime", soundUrl) {
|
|
10821
|
+
if (typeof window === "undefined" || soundType === "none") return;
|
|
10822
|
+
if (soundUrl) {
|
|
10823
|
+
const audio = new Audio(soundUrl);
|
|
10824
|
+
audio.volume = 0.5;
|
|
10825
|
+
audio.play().catch(() => {
|
|
10826
|
+
});
|
|
10827
|
+
return;
|
|
10828
|
+
}
|
|
10829
|
+
const config = soundConfig[soundType];
|
|
10830
|
+
if (!config) return;
|
|
10831
|
+
try {
|
|
10832
|
+
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
10833
|
+
let currentTime = audioContext.currentTime;
|
|
10834
|
+
config.frequencies.forEach((freq, i) => {
|
|
10835
|
+
const oscillator = audioContext.createOscillator();
|
|
10836
|
+
const gainNode = audioContext.createGain();
|
|
10837
|
+
oscillator.connect(gainNode);
|
|
10838
|
+
gainNode.connect(audioContext.destination);
|
|
10839
|
+
oscillator.frequency.setValueAtTime(freq, currentTime);
|
|
10840
|
+
gainNode.gain.setValueAtTime(config.gain, currentTime);
|
|
10841
|
+
gainNode.gain.exponentialRampToValueAtTime(
|
|
10842
|
+
0.01,
|
|
10843
|
+
currentTime + config.durations[i]
|
|
10844
|
+
);
|
|
10845
|
+
oscillator.start(currentTime);
|
|
10846
|
+
oscillator.stop(currentTime + config.durations[i]);
|
|
10847
|
+
currentTime += config.durations[i] * 0.7;
|
|
10848
|
+
});
|
|
10849
|
+
} catch {
|
|
10850
|
+
}
|
|
10851
|
+
}
|
|
10852
|
+
function NotificationsWidget({
|
|
10853
|
+
notifications,
|
|
10854
|
+
onMarkAsRead,
|
|
10855
|
+
onMarkAllAsRead,
|
|
10856
|
+
onDismiss,
|
|
10857
|
+
onClearAll,
|
|
10858
|
+
onNotificationClick,
|
|
10859
|
+
size: size4 = "md",
|
|
10860
|
+
maxVisible = 5,
|
|
10861
|
+
playSound: _playSound = true,
|
|
10862
|
+
soundUrl,
|
|
10863
|
+
className,
|
|
10864
|
+
emptyMessage = "No notifications",
|
|
10865
|
+
title = "Notifications",
|
|
10866
|
+
dotColor = "red",
|
|
10867
|
+
showPulse = true,
|
|
10868
|
+
soundType = "chime",
|
|
10869
|
+
pulseStyle = "ring",
|
|
10870
|
+
soundCooldown = 2e3
|
|
10871
|
+
}) {
|
|
10872
|
+
const [isOpen, setIsOpen] = React32__namespace.useState(false);
|
|
10873
|
+
const [prevCount, setPrevCount] = React32__namespace.useState(0);
|
|
10874
|
+
const lastSoundPlayedRef = React32__namespace.useRef(0);
|
|
10875
|
+
const styles = sizeConfig[size4];
|
|
10876
|
+
const dotBgColor = dotColorConfig[dotColor];
|
|
10877
|
+
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
10878
|
+
const visibleNotifications = notifications.slice(0, maxVisible);
|
|
10879
|
+
const hasMore = notifications.length > maxVisible;
|
|
10880
|
+
React32__namespace.useEffect(() => {
|
|
10881
|
+
if (soundType !== "none" && unreadCount > prevCount && prevCount > 0) {
|
|
10882
|
+
const now = Date.now();
|
|
10883
|
+
if (now - lastSoundPlayedRef.current >= soundCooldown) {
|
|
10884
|
+
playNotificationSound(soundType, soundUrl);
|
|
10885
|
+
lastSoundPlayedRef.current = now;
|
|
10886
|
+
}
|
|
10887
|
+
}
|
|
10888
|
+
setPrevCount(unreadCount);
|
|
10889
|
+
}, [unreadCount, prevCount, soundType, soundUrl, soundCooldown]);
|
|
10890
|
+
React32__namespace.useEffect(() => {
|
|
10891
|
+
if (isOpen && onMarkAsRead) {
|
|
10892
|
+
visibleNotifications.forEach((notification) => {
|
|
10893
|
+
if (!notification.read) {
|
|
10894
|
+
onMarkAsRead(notification.id);
|
|
10895
|
+
}
|
|
10896
|
+
});
|
|
10897
|
+
}
|
|
10898
|
+
}, [isOpen, onMarkAsRead, visibleNotifications]);
|
|
10899
|
+
const handleNotificationClick = (notification) => {
|
|
10900
|
+
if (notification.href) {
|
|
10901
|
+
onNotificationClick?.(notification);
|
|
10902
|
+
}
|
|
10903
|
+
};
|
|
10904
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
10905
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10906
|
+
react.motion.button,
|
|
10907
|
+
{
|
|
10908
|
+
className: cn(
|
|
10909
|
+
"relative inline-flex items-center justify-center rounded-lg",
|
|
10910
|
+
"bg-muted/50 border border-border/50 hover:bg-muted/70 transition-colors",
|
|
10911
|
+
styles.button,
|
|
10912
|
+
className
|
|
10913
|
+
),
|
|
10914
|
+
whileTap: { scale: 0.95 },
|
|
10915
|
+
"aria-label": `Notifications${unreadCount > 0 ? ` (${unreadCount} unread)` : ""}`,
|
|
10916
|
+
children: [
|
|
10917
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: cn(styles.icon, "text-muted-foreground") }),
|
|
10918
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10919
|
+
react.motion.div,
|
|
10920
|
+
{
|
|
10921
|
+
initial: { scale: 0, opacity: 0 },
|
|
10922
|
+
animate: { scale: 1, opacity: 1 },
|
|
10923
|
+
exit: { scale: 0, opacity: 0 },
|
|
10924
|
+
className: cn(
|
|
10925
|
+
"absolute flex items-center justify-center rounded-full",
|
|
10926
|
+
dotBgColor,
|
|
10927
|
+
"text-white font-medium",
|
|
10928
|
+
unreadCount > 9 ? styles.badge : styles.dot,
|
|
10929
|
+
unreadCount > 9 && "px-1"
|
|
10930
|
+
),
|
|
10931
|
+
children: unreadCount > 9 ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: unreadCount > 99 ? "99+" : unreadCount }) : null
|
|
10932
|
+
}
|
|
10933
|
+
) }),
|
|
10934
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: unreadCount > 0 && showPulse && pulseStyle !== "none" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10935
|
+
react.motion.div,
|
|
10936
|
+
{
|
|
10937
|
+
initial: { scale: 1, opacity: 0.5 },
|
|
10938
|
+
animate: pulseVariants[pulseStyle].animate,
|
|
10939
|
+
transition: pulseVariants[pulseStyle].transition,
|
|
10940
|
+
className: cn("absolute rounded-full", dotBgColor, styles.dot)
|
|
10941
|
+
}
|
|
10942
|
+
) })
|
|
10943
|
+
]
|
|
10944
|
+
}
|
|
10945
|
+
) }),
|
|
10946
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10947
|
+
PopoverContent,
|
|
10948
|
+
{
|
|
10949
|
+
side: "bottom",
|
|
10950
|
+
align: "end",
|
|
10951
|
+
className: "w-80 p-0 overflow-hidden",
|
|
10952
|
+
children: [
|
|
10953
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
|
|
10954
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10955
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-sm", children: title }),
|
|
10956
|
+
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-2 py-0.5 text-xs font-medium rounded-full bg-primary/10 text-primary", children: [
|
|
10957
|
+
unreadCount,
|
|
10958
|
+
" new"
|
|
10959
|
+
] })
|
|
10960
|
+
] }),
|
|
10961
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: unreadCount > 0 && onMarkAllAsRead && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10962
|
+
Button,
|
|
10963
|
+
{
|
|
10964
|
+
variant: "ghost",
|
|
10965
|
+
size: "sm",
|
|
10966
|
+
className: "h-7 px-2 text-xs",
|
|
10967
|
+
onClick: () => onMarkAllAsRead(),
|
|
10968
|
+
children: [
|
|
10969
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "w-3.5 h-3.5 mr-1" }),
|
|
10970
|
+
"Mark all read"
|
|
10971
|
+
]
|
|
10972
|
+
}
|
|
10973
|
+
) })
|
|
10974
|
+
] }),
|
|
10975
|
+
notifications.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-4 text-center", children: [
|
|
10976
|
+
/* @__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" }) }),
|
|
10977
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
|
|
10978
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10979
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "h-[320px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border", children: visibleNotifications.map((notification) => {
|
|
10980
|
+
const config = typeConfig[notification.type || "info"];
|
|
10981
|
+
const Icon = config.icon;
|
|
10982
|
+
const hasLink = !!notification.href;
|
|
10983
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10984
|
+
react.motion.div,
|
|
10985
|
+
{
|
|
10986
|
+
initial: { opacity: 0, y: -10 },
|
|
10987
|
+
animate: { opacity: 1, y: 0 },
|
|
10988
|
+
className: cn(
|
|
10989
|
+
"relative flex gap-3 px-4 py-3 transition-colors group",
|
|
10990
|
+
hasLink && "cursor-pointer hover:bg-muted/50",
|
|
10991
|
+
!hasLink && "cursor-default",
|
|
10992
|
+
!notification.read && "bg-primary/5"
|
|
10993
|
+
),
|
|
10994
|
+
onClick: () => handleNotificationClick(notification),
|
|
10995
|
+
children: [
|
|
10996
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10997
|
+
"div",
|
|
10998
|
+
{
|
|
10999
|
+
className: cn(
|
|
11000
|
+
"flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
|
|
11001
|
+
config.bg
|
|
11002
|
+
),
|
|
11003
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: cn("w-4 h-4", config.color) })
|
|
11004
|
+
}
|
|
11005
|
+
),
|
|
11006
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11007
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11008
|
+
"p",
|
|
11009
|
+
{
|
|
11010
|
+
className: cn(
|
|
11011
|
+
"text-sm line-clamp-1",
|
|
11012
|
+
!notification.read ? "font-semibold" : "font-medium",
|
|
11013
|
+
hasLink && "group-hover:underline"
|
|
11014
|
+
),
|
|
11015
|
+
children: notification.title
|
|
11016
|
+
}
|
|
11017
|
+
) }),
|
|
11018
|
+
notification.message && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground line-clamp-2 mt-0.5", children: notification.message }),
|
|
11019
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground/70 mt-1", children: formatTimeAgo(notification.timestamp) })
|
|
11020
|
+
] }),
|
|
11021
|
+
/* @__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(
|
|
11022
|
+
Button,
|
|
11023
|
+
{
|
|
11024
|
+
variant: "ghost",
|
|
11025
|
+
size: "icon",
|
|
11026
|
+
className: "h-6 w-6 text-muted-foreground hover:text-destructive",
|
|
11027
|
+
onClick: (e) => {
|
|
11028
|
+
e.stopPropagation();
|
|
11029
|
+
onDismiss(notification.id);
|
|
11030
|
+
},
|
|
11031
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
11032
|
+
}
|
|
11033
|
+
) })
|
|
11034
|
+
]
|
|
11035
|
+
},
|
|
11036
|
+
notification.id
|
|
11037
|
+
);
|
|
11038
|
+
}) }) }),
|
|
11039
|
+
(hasMore || onClearAll) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/30", children: [
|
|
11040
|
+
hasMore && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
11041
|
+
"+",
|
|
11042
|
+
notifications.length - maxVisible,
|
|
11043
|
+
" more"
|
|
11044
|
+
] }),
|
|
11045
|
+
onClearAll && notifications.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11046
|
+
Button,
|
|
11047
|
+
{
|
|
11048
|
+
variant: "ghost",
|
|
11049
|
+
size: "sm",
|
|
11050
|
+
className: "h-7 px-2 text-xs text-muted-foreground hover:text-destructive",
|
|
11051
|
+
onClick: () => onClearAll(),
|
|
11052
|
+
children: [
|
|
11053
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-3 h-3 mr-1" }),
|
|
11054
|
+
"Clear all"
|
|
11055
|
+
]
|
|
11056
|
+
}
|
|
11057
|
+
)
|
|
11058
|
+
] })
|
|
11059
|
+
] })
|
|
11060
|
+
]
|
|
11061
|
+
}
|
|
11062
|
+
)
|
|
11063
|
+
] });
|
|
11064
|
+
}
|
|
9531
11065
|
|
|
11066
|
+
exports.AvatarEditor = AvatarEditor;
|
|
11067
|
+
exports.AvatarEditorDialog = AvatarEditorDialog;
|
|
9532
11068
|
exports.Button = Button;
|
|
11069
|
+
exports.Dialog = Dialog;
|
|
11070
|
+
exports.DialogClose = DialogClose;
|
|
11071
|
+
exports.DialogContent = DialogContent;
|
|
11072
|
+
exports.DialogDescription = DialogDescription;
|
|
11073
|
+
exports.DialogFooter = DialogFooter;
|
|
11074
|
+
exports.DialogHeader = DialogHeader;
|
|
11075
|
+
exports.DialogOverlay = DialogOverlay;
|
|
11076
|
+
exports.DialogPortal = DialogPortal;
|
|
11077
|
+
exports.DialogTitle = DialogTitle;
|
|
11078
|
+
exports.DialogTrigger = DialogTrigger;
|
|
11079
|
+
exports.Drawer = Drawer;
|
|
11080
|
+
exports.DrawerClose = DrawerClose;
|
|
11081
|
+
exports.DrawerContent = DrawerContent;
|
|
11082
|
+
exports.DrawerDescription = DrawerDescription;
|
|
11083
|
+
exports.DrawerFooter = DrawerFooter;
|
|
11084
|
+
exports.DrawerHeader = DrawerHeader;
|
|
11085
|
+
exports.DrawerOverlay = DrawerOverlay;
|
|
11086
|
+
exports.DrawerPortal = DrawerPortal;
|
|
11087
|
+
exports.DrawerTitle = DrawerTitle;
|
|
11088
|
+
exports.DrawerTrigger = DrawerTrigger;
|
|
9533
11089
|
exports.DropdownMenu = DropdownMenu2;
|
|
9534
11090
|
exports.DropdownMenuCheckboxItem = DropdownMenuCheckboxItem2;
|
|
9535
11091
|
exports.DropdownMenuContent = DropdownMenuContent2;
|
|
@@ -9546,12 +11102,22 @@ exports.DropdownMenuSubContent = DropdownMenuSubContent2;
|
|
|
9546
11102
|
exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger2;
|
|
9547
11103
|
exports.DropdownMenuTrigger = DropdownMenuTrigger2;
|
|
9548
11104
|
exports.LanguageSwitcher = LanguageSwitcher;
|
|
11105
|
+
exports.NotificationsWidget = NotificationsWidget;
|
|
11106
|
+
exports.Popover = Popover;
|
|
11107
|
+
exports.PopoverAnchor = PopoverAnchor;
|
|
11108
|
+
exports.PopoverContent = PopoverContent;
|
|
11109
|
+
exports.PopoverTrigger = PopoverTrigger;
|
|
11110
|
+
exports.ScrollArea = ScrollArea;
|
|
11111
|
+
exports.ScrollBar = ScrollBar;
|
|
11112
|
+
exports.Slider = Slider;
|
|
9549
11113
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
11114
|
+
exports.Toggle = Toggle;
|
|
9550
11115
|
exports.Tooltip = Tooltip2;
|
|
9551
11116
|
exports.TooltipContent = TooltipContent2;
|
|
9552
11117
|
exports.TooltipProvider = TooltipProvider2;
|
|
9553
11118
|
exports.TooltipTrigger = TooltipTrigger2;
|
|
9554
11119
|
exports.buttonVariants = buttonVariants;
|
|
9555
11120
|
exports.cn = cn;
|
|
11121
|
+
exports.toggleVariants = toggleVariants;
|
|
9556
11122
|
//# sourceMappingURL=index.cjs.map
|
|
9557
11123
|
//# sourceMappingURL=index.cjs.map
|