style: clean up code formatting and remove trailing whitespace

refactor: reorganize imports and fix type imports
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-11 03:08:36 -03:00
1 parent d3704602fd
commit 47c04de6fe
232 files changed
+7140 -4798

No files matched your search

+2 -2
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
const Accordion = AccordionPrimitive.Root;
@@ -28,7 +28,7 @@ const AccordionTrigger = React.forwardRef<
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
className,
)}
{...props}
>
+7 -7
View File
@@ -1,12 +1,12 @@
import { ComponentPropsWithoutRef } from "react"
import type { ComponentPropsWithoutRef } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface AnimatedGradientTextProps
extends ComponentPropsWithoutRef<"div"> {
speed?: number
colorFrom?: string
colorTo?: string
speed?: number;
colorFrom?: string;
colorTo?: string;
}
export function AnimatedGradientText({
@@ -28,11 +28,11 @@ export function AnimatedGradientText({
}
className={cn(
`animate-gradient inline bg-gradient-to-r from-[var(--color-from)] via-[var(--color-to)] to-[var(--color-from)] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent`,
className
className,
)}
{...props}
>
{children}
</span>
)
);
}
+23 -23
View File
@@ -1,14 +1,14 @@
"use client"
"use client";
import { AnimatePresence, type MotionProps, motion } from "motion/react";
import React, {
ComponentPropsWithoutRef,
type ComponentPropsWithoutRef,
useEffect,
useMemo,
useState,
} from "react"
import { AnimatePresence, motion, MotionProps } from "motion/react"
} from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export function AnimatedListItem({ children }: { children: React.ReactNode }) {
const animations: MotionProps = {
@@ -16,42 +16,42 @@ export function AnimatedListItem({ children }: { children: React.ReactNode }) {
animate: { scale: 1, opacity: 1, originY: 0 },
exit: { scale: 0, opacity: 0 },
transition: { type: "spring", stiffness: 350, damping: 40 },
}
};
return (
<motion.div {...animations} layout className="mx-auto w-full">
{children}
</motion.div>
)
);
}
export interface AnimatedListProps extends ComponentPropsWithoutRef<"div"> {
children: React.ReactNode
delay?: number
children: React.ReactNode;
delay?: number;
}
export const AnimatedList = React.memo(
({ children, className, delay = 1000, ...props }: AnimatedListProps) => {
const [index, setIndex] = useState(0)
const [index, setIndex] = useState(0);
const childrenArray = useMemo(
() => React.Children.toArray(children),
[children]
)
[children],
);
useEffect(() => {
if (index < childrenArray.length - 1) {
const timeout = setTimeout(() => {
setIndex((prevIndex) => (prevIndex + 1) % childrenArray.length)
}, delay)
setIndex((prevIndex) => (prevIndex + 1) % childrenArray.length);
}, delay);
return () => clearTimeout(timeout)
return () => clearTimeout(timeout);
}
}, [index, delay, childrenArray.length])
}, [index, delay, childrenArray.length]);
const itemsToShow = useMemo(() => {
const result = childrenArray.slice(0, index + 1).reverse()
return result
}, [index, childrenArray])
const result = childrenArray.slice(0, index + 1).reverse();
return result;
}, [index, childrenArray]);
return (
<div
@@ -66,8 +66,8 @@ export const AnimatedList = React.memo(
))}
</AnimatePresence>
</div>
)
}
)
);
},
);
AnimatedList.displayName = "AnimatedList"
AnimatedList.displayName = "AnimatedList";
+10 -10
View File
@@ -1,9 +1,9 @@
"use client"
"use client";
import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Avatar({
className,
@@ -14,11 +14,11 @@ function Avatar({
data-slot="avatar"
className={cn(
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
className
className,
)}
{...props}
/>
)
);
}
function AvatarImage({
@@ -31,7 +31,7 @@ function AvatarImage({
className={cn("aspect-square size-full", className)}
{...props}
/>
)
);
}
function AvatarFallback({
@@ -43,11 +43,11 @@ function AvatarFallback({
data-slot="avatar-fallback"
className={cn(
"bg-muted flex size-full items-center justify-center rounded-full",
className
className,
)}
{...props}
/>
)
);
}
export { Avatar, AvatarImage, AvatarFallback }
export { Avatar, AvatarImage, AvatarFallback };
+9 -9
View File
@@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
@@ -22,8 +22,8 @@ const badgeVariants = cva(
defaultVariants: {
variant: "default",
},
}
)
},
);
function Badge({
className,
@@ -32,7 +32,7 @@ function Badge({
...props
}: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span"
const Comp = asChild ? Slot : "span";
return (
<Comp
@@ -40,7 +40,7 @@ function Badge({
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
);
}
export { Badge, badgeVariants }
export { Badge, badgeVariants };
+4 -5
View File
@@ -1,8 +1,7 @@
import { ComponentPropsWithoutRef, ReactNode } from "react";
import { ArrowRightIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils";
import type { ComponentPropsWithoutRef, ReactNode } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
interface BentoGridProps extends ComponentPropsWithoutRef<"div"> {
children: ReactNode;
@@ -26,7 +25,7 @@ const BentoGrid = ({ children, className, ...props }: BentoGridProps) => {
"grid w-full gap-6",
"grid-cols-1 md:grid-cols-3",
"auto-rows-[minmax(280px,auto)]",
className
className,
)}
style={{
gridTemplateColumns: "1fr 2fr",
@@ -60,7 +59,7 @@ const BentoCard = ({
// dark styles
"dark:bg-background dark:border-border/50",
"dark:shadow-sm dark:hover:shadow-xl",
className
className,
)}
{...props}
>
+25 -25
View File
@@ -1,31 +1,31 @@
"use client"
"use client";
import { useRef } from "react"
import {
AnimatePresence,
type MotionProps,
motion,
MotionProps,
type UseInViewOptions,
useInView,
UseInViewOptions,
Variants,
} from "motion/react"
type Variants,
} from "motion/react";
import { useRef } from "react";
type MarginType = UseInViewOptions["margin"]
type MarginType = UseInViewOptions["margin"];
interface BlurFadeProps extends MotionProps {
children: React.ReactNode
className?: string
children: React.ReactNode;
className?: string;
variant?: {
hidden: { y: number }
visible: { y: number }
}
duration?: number
delay?: number
offset?: number
direction?: "up" | "down" | "left" | "right"
inView?: boolean
inViewMargin?: MarginType
blur?: string
hidden: { y: number };
visible: { y: number };
};
duration?: number;
delay?: number;
offset?: number;
direction?: "up" | "down" | "left" | "right";
inView?: boolean;
inViewMargin?: MarginType;
blur?: string;
}
export function BlurFade({
@@ -41,9 +41,9 @@ export function BlurFade({
blur = "6px",
...props
}: BlurFadeProps) {
const ref = useRef(null)
const inViewResult = useInView(ref, { once: true, margin: inViewMargin })
const isInView = !inView || inViewResult
const ref = useRef(null);
const inViewResult = useInView(ref, { once: true, margin: inViewMargin });
const isInView = !inView || inViewResult;
const defaultVariants: Variants = {
hidden: {
[direction === "left" || direction === "right" ? "x" : "y"]:
@@ -56,8 +56,8 @@ export function BlurFade({
opacity: 1,
filter: `blur(0px)`,
},
}
const combinedVariants = variant || defaultVariants
};
const combinedVariants = variant || defaultVariants;
return (
<AnimatePresence>
<motion.div
@@ -77,5 +77,5 @@ export function BlurFade({
{children}
</motion.div>
</AnimatePresence>
)
);
}
+10 -10
View File
@@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
@@ -33,8 +33,8 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
}
)
},
);
function Button({
className,
@@ -44,9 +44,9 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";
return (
<Comp
@@ -54,7 +54,7 @@ function Button({
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
);
}
export { Button, buttonVariants }
export { Button, buttonVariants };
+13 -13
View File
@@ -1,6 +1,6 @@
import * as React from "react"
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
@@ -8,11 +8,11 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className
className,
)}
{...props}
/>
)
);
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
@@ -21,11 +21,11 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className
className,
)}
{...props}
/>
)
);
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
@@ -35,7 +35,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
className={cn("leading-none font-semibold", className)}
{...props}
/>
)
);
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
@@ -45,7 +45,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
)
);
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
@@ -54,11 +54,11 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
className,
)}
{...props}
/>
)
);
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
@@ -68,7 +68,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
className={cn("px-6", className)}
{...props}
/>
)
);
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
@@ -78,7 +78,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props}
/>
)
);
}
export {
@@ -89,4 +89,4 @@ export {
CardAction,
CardDescription,
CardContent,
}
};
+9 -10
View File
@@ -1,10 +1,10 @@
"use client"
"use client";
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
@@ -14,7 +14,7 @@ const Checkbox = React.forwardRef<
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
className,
)}
{...props}
>
@@ -24,8 +24,7 @@ const Checkbox = React.forwardRef<
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName
export { Checkbox }
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox };
+6 -6
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root;
@@ -22,7 +22,7 @@ const DialogOverlay = React.forwardRef<
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
className,
)}
{...props}
/>
@@ -39,7 +39,7 @@ const DialogContent = React.forwardRef<
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
className,
)}
{...props}
>
@@ -60,7 +60,7 @@ const DialogHeader = ({
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
className,
)}
{...props}
/>
@@ -74,7 +74,7 @@ const DialogFooter = ({
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
className,
)}
{...props}
/>
@@ -89,7 +89,7 @@ const DialogTitle = React.forwardRef<
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
className,
)}
{...props}
/>
+33 -32
View File
@@ -1,9 +1,10 @@
"use client"
"use client";
import React, { useEffect, useId, useRef, useState } from "react"
import { motion } from "motion/react"
import { motion } from "motion/react";
import type React from "react";
import { useEffect, useId, useRef, useState } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
/**
* DotPattern Component Props
@@ -19,16 +20,16 @@ import { cn } from "@/lib/utils"
* @param {boolean} [glow=false] - Whether dots should have a glowing animation effect
*/
interface DotPatternProps extends React.SVGProps<SVGSVGElement> {
width?: number
height?: number
x?: number
y?: number
cx?: number
cy?: number
cr?: number
className?: string
glow?: boolean
[key: string]: unknown
width?: number;
height?: number;
x?: number;
y?: number;
cx?: number;
cy?: number;
cr?: number;
className?: string;
glow?: boolean;
[key: string]: unknown;
}
/**
@@ -73,22 +74,22 @@ export function DotPattern({
glow = false,
...props
}: DotPatternProps) {
const id = useId()
const containerRef = useRef<SVGSVGElement>(null)
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const id = useId();
const containerRef = useRef<SVGSVGElement>(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const updateDimensions = () => {
if (containerRef.current) {
const { width, height } = containerRef.current.getBoundingClientRect()
setDimensions({ width, height })
const { width, height } = containerRef.current.getBoundingClientRect();
setDimensions({ width, height });
}
}
};
updateDimensions()
window.addEventListener("resize", updateDimensions)
return () => window.removeEventListener("resize", updateDimensions)
}, [])
updateDimensions();
window.addEventListener("resize", updateDimensions);
return () => window.removeEventListener("resize", updateDimensions);
}, []);
const dots = Array.from(
{
@@ -97,16 +98,16 @@ export function DotPattern({
Math.ceil(dimensions.height / height),
},
(_, i) => {
const col = i % Math.ceil(dimensions.width / width)
const row = Math.floor(i / Math.ceil(dimensions.width / width))
const col = i % Math.ceil(dimensions.width / width);
const row = Math.floor(i / Math.ceil(dimensions.width / width));
return {
x: col * width + cx,
y: row * height + cy,
delay: Math.random() * 5,
duration: Math.random() * 3 + 2,
}
}
)
};
},
);
return (
<svg
@@ -114,7 +115,7 @@ export function DotPattern({
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full text-neutral-400/80",
className
className,
)}
{...props}
>
@@ -124,7 +125,7 @@ export function DotPattern({
<stop offset="100%" stopColor="currentColor" stopOpacity="0" />
</radialGradient>
</defs>
{dots.map((dot, index) => (
{dots.map((dot, _index) => (
<motion.circle
key={`${dot.x}-${dot.y}`}
cx={dot.x}
@@ -154,5 +155,5 @@ export function DotPattern({
/>
))}
</svg>
)
);
}
+33 -38
View File
@@ -1,20 +1,15 @@
"use client"
"use client";
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function DropdownMenu({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
return (
<DropdownMenuPrimitive.Root
data-slot="dropdown-menu"
{...props}
/>
);
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
}
function DropdownMenuPortal({
@@ -22,7 +17,7 @@ function DropdownMenuPortal({
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
return (
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
)
);
}
function DropdownMenuTrigger({
@@ -33,7 +28,7 @@ function DropdownMenuTrigger({
data-slot="dropdown-menu-trigger"
{...props}
/>
)
);
}
function DropdownMenuContent({
@@ -48,12 +43,12 @@ function DropdownMenuContent({
sideOffset={sideOffset}
className={cn(
"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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
className
className,
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
)
);
}
function DropdownMenuGroup({
@@ -61,7 +56,7 @@ function DropdownMenuGroup({
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
return (
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
)
);
}
function DropdownMenuItem({
@@ -70,8 +65,8 @@ function DropdownMenuItem({
variant = "default",
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
variant?: "default" | "destructive"
inset?: boolean;
variant?: "default" | "destructive";
}) {
return (
<DropdownMenuPrimitive.Item
@@ -80,11 +75,11 @@ function DropdownMenuItem({
data-variant={variant}
className={cn(
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
{...props}
/>
)
);
}
function DropdownMenuCheckboxItem({
@@ -98,7 +93,7 @@ function DropdownMenuCheckboxItem({
data-slot="dropdown-menu-checkbox-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
checked={checked}
{...props}
@@ -110,7 +105,7 @@ function DropdownMenuCheckboxItem({
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
)
);
}
function DropdownMenuRadioGroup({
@@ -121,7 +116,7 @@ function DropdownMenuRadioGroup({
data-slot="dropdown-menu-radio-group"
{...props}
/>
)
);
}
function DropdownMenuRadioItem({
@@ -134,7 +129,7 @@ function DropdownMenuRadioItem({
data-slot="dropdown-menu-radio-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
{...props}
>
@@ -145,7 +140,7 @@ function DropdownMenuRadioItem({
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
)
);
}
function DropdownMenuLabel({
@@ -153,7 +148,7 @@ function DropdownMenuLabel({
inset,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
inset?: boolean;
}) {
return (
<DropdownMenuPrimitive.Label
@@ -161,11 +156,11 @@ function DropdownMenuLabel({
data-inset={inset}
className={cn(
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
className
className,
)}
{...props}
/>
)
);
}
function DropdownMenuSeparator({
@@ -178,7 +173,7 @@ function DropdownMenuSeparator({
className={cn("bg-border -mx-1 my-1 h-px", className)}
{...props}
/>
)
);
}
function DropdownMenuShortcut({
@@ -190,17 +185,17 @@ function DropdownMenuShortcut({
data-slot="dropdown-menu-shortcut"
className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest",
className
className,
)}
{...props}
/>
)
);
}
function DropdownMenuSub({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
}
function DropdownMenuSubTrigger({
@@ -209,7 +204,7 @@ function DropdownMenuSubTrigger({
children,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
inset?: boolean;
}) {
return (
<DropdownMenuPrimitive.SubTrigger
@@ -217,14 +212,14 @@ function DropdownMenuSubTrigger({
data-inset={inset}
className={cn(
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto size-4" />
</DropdownMenuPrimitive.SubTrigger>
)
);
}
function DropdownMenuSubContent({
@@ -236,11 +231,11 @@ function DropdownMenuSubContent({
data-slot="dropdown-menu-sub-content"
className={cn(
"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 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
className
className,
)}
{...props}
/>
)
);
}
export {
@@ -259,4 +254,4 @@ export {
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
}
};
+42 -42
View File
@@ -1,12 +1,12 @@
"use client"
"use client";
import { useEffect, useRef } from "react"
import createGlobe, { COBEOptions } from "cobe"
import { useMotionValue, useSpring } from "motion/react"
import createGlobe, { type COBEOptions } from "cobe";
import { useMotionValue, useSpring } from "motion/react";
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const MOVEMENT_DAMPING = 1400
const MOVEMENT_DAMPING = 1400;
const GLOBE_CONFIG: COBEOptions = {
width: 800,
@@ -34,87 +34,87 @@ const GLOBE_CONFIG: COBEOptions = {
{ location: [34.6937, 135.5022], size: 0.05 },
{ location: [41.0082, 28.9784], size: 0.06 },
],
}
};
export function Globe({
className,
config = GLOBE_CONFIG,
}: {
className?: string
config?: COBEOptions
className?: string;
config?: COBEOptions;
}) {
let phi = 0
let width = 0
const canvasRef = useRef<HTMLCanvasElement>(null)
const pointerInteracting = useRef<number | null>(null)
const pointerInteractionMovement = useRef(0)
let phi = 0;
let width = 0;
const canvasRef = useRef<HTMLCanvasElement>(null);
const pointerInteracting = useRef<number | null>(null);
const pointerInteractionMovement = useRef(0);
const r = useMotionValue(0)
const r = useMotionValue(0);
const rs = useSpring(r, {
mass: 1,
damping: 30,
stiffness: 100,
})
});
const updatePointerInteraction = (value: number | null) => {
pointerInteracting.current = value
pointerInteracting.current = value;
if (canvasRef.current) {
canvasRef.current.style.cursor = value !== null ? "grabbing" : "grab"
canvasRef.current.style.cursor = value !== null ? "grabbing" : "grab";
}
}
};
const updateMovement = (clientX: number) => {
if (pointerInteracting.current !== null) {
const delta = clientX - pointerInteracting.current
pointerInteractionMovement.current = delta
r.set(r.get() + delta / MOVEMENT_DAMPING)
const delta = clientX - pointerInteracting.current;
pointerInteractionMovement.current = delta;
r.set(r.get() + delta / MOVEMENT_DAMPING);
}
}
};
useEffect(() => {
const onResize = () => {
if (canvasRef.current) {
width = canvasRef.current.offsetWidth
width = canvasRef.current.offsetWidth;
}
}
};
window.addEventListener("resize", onResize)
onResize()
window.addEventListener("resize", onResize);
onResize();
const globe = createGlobe(canvasRef.current!, {
...config,
width: width * 2,
height: width * 2,
onRender: (state) => {
if (!pointerInteracting.current) phi += 0.005
state.phi = phi + rs.get()
state.width = width * 2
state.height = width * 2
if (!pointerInteracting.current) phi += 0.005;
state.phi = phi + rs.get();
state.width = width * 2;
state.height = width * 2;
},
})
});
setTimeout(() => (canvasRef.current!.style.opacity = "1"), 0)
setTimeout(() => (canvasRef.current?.style.opacity = "1"), 0);
return () => {
globe.destroy()
window.removeEventListener("resize", onResize)
}
}, [rs, config])
globe.destroy();
window.removeEventListener("resize", onResize);
};
}, [rs, config, phi, width]);
return (
<div
className={cn(
"absolute inset-0 mx-auto aspect-[1/1] w-full max-w-[600px]",
className
className,
)}
>
<canvas
className={cn(
"size-full opacity-0 transition-opacity duration-500 [contain:layout_paint_size]"
"size-full opacity-0 transition-opacity duration-500 [contain:layout_paint_size]",
)}
ref={canvasRef}
onPointerDown={(e) => {
pointerInteracting.current = e.clientX
updatePointerInteraction(e.clientX)
pointerInteracting.current = e.clientX;
updatePointerInteraction(e.clientX);
}}
onPointerUp={() => updatePointerInteraction(null)}
onPointerOut={() => updatePointerInteraction(null)}
@@ -124,5 +124,5 @@ export function Globe({
}
/>
</div>
)
);
}
+5 -5
View File
@@ -1,6 +1,6 @@
import * as React from "react"
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
@@ -11,11 +11,11 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className
className,
)}
{...props}
/>
)
);
}
export { Input }
export { Input };
+2 -3
View File
@@ -1,12 +1,12 @@
"use client";
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
);
const Label = React.forwardRef<
@@ -23,4 +23,3 @@ const Label = React.forwardRef<
Label.displayName = LabelPrimitive.Root.displayName;
export { Label };
+37 -36
View File
@@ -1,18 +1,19 @@
"use client"
"use client";
import React, { useCallback, useEffect } from "react"
import { motion, useMotionTemplate, useMotionValue } from "motion/react"
import { motion, useMotionTemplate, useMotionValue } from "motion/react";
import type React from "react";
import { useCallback, useEffect } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface MagicCardProps {
children?: React.ReactNode
className?: string
gradientSize?: number
gradientColor?: string
gradientOpacity?: number
gradientFrom?: string
gradientTo?: string
children?: React.ReactNode;
className?: string;
gradientSize?: number;
gradientColor?: string;
gradientOpacity?: number;
gradientFrom?: string;
gradientTo?: string;
}
export function MagicCard({
@@ -24,49 +25,49 @@ export function MagicCard({
gradientFrom = "#9E7AFF",
gradientTo = "#FE8BBB",
}: MagicCardProps) {
const mouseX = useMotionValue(-gradientSize)
const mouseY = useMotionValue(-gradientSize)
const mouseX = useMotionValue(-gradientSize);
const mouseY = useMotionValue(-gradientSize);
const reset = useCallback(() => {
mouseX.set(-gradientSize)
mouseY.set(-gradientSize)
}, [gradientSize, mouseX, mouseY])
mouseX.set(-gradientSize);
mouseY.set(-gradientSize);
}, [gradientSize, mouseX, mouseY]);
const handlePointerMove = useCallback(
(e: React.PointerEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect()
mouseX.set(e.clientX - rect.left)
mouseY.set(e.clientY - rect.top)
const rect = e.currentTarget.getBoundingClientRect();
mouseX.set(e.clientX - rect.left);
mouseY.set(e.clientY - rect.top);
},
[mouseX, mouseY]
)
[mouseX, mouseY],
);
useEffect(() => {
reset()
}, [reset])
reset();
}, [reset]);
useEffect(() => {
const handleGlobalPointerOut = (e: PointerEvent) => {
if (!e.relatedTarget) {
reset()
reset();
}
}
};
const handleVisibility = () => {
if (document.visibilityState !== "visible") {
reset()
reset();
}
}
};
window.addEventListener("pointerout", handleGlobalPointerOut)
window.addEventListener("blur", reset)
document.addEventListener("visibilitychange", handleVisibility)
window.addEventListener("pointerout", handleGlobalPointerOut);
window.addEventListener("blur", reset);
document.addEventListener("visibilitychange", handleVisibility);
return () => {
window.removeEventListener("pointerout", handleGlobalPointerOut)
window.removeEventListener("blur", reset)
document.removeEventListener("visibilitychange", handleVisibility)
}
}, [reset])
window.removeEventListener("pointerout", handleGlobalPointerOut);
window.removeEventListener("blur", reset);
document.removeEventListener("visibilitychange", handleVisibility);
};
}, [reset]);
return (
<div
@@ -99,5 +100,5 @@ export function MagicCard({
/>
<div className="relative">{children}</div>
</div>
)
);
}
+61 -61
View File
@@ -1,103 +1,103 @@
"use client"
"use client";
import { useCallback, useEffect, useRef } from "react"
import { useCallback, useEffect, useRef } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const morphTime = 1.5
const cooldownTime = 0.5
const morphTime = 1.5;
const cooldownTime = 0.5;
const useMorphingText = (texts: string[]) => {
const textIndexRef = useRef(0)
const morphRef = useRef(0)
const cooldownRef = useRef(0)
const timeRef = useRef(new Date())
const textIndexRef = useRef(0);
const morphRef = useRef(0);
const cooldownRef = useRef(0);
const timeRef = useRef(new Date());
const text1Ref = useRef<HTMLSpanElement>(null)
const text2Ref = useRef<HTMLSpanElement>(null)
const text1Ref = useRef<HTMLSpanElement>(null);
const text2Ref = useRef<HTMLSpanElement>(null);
const setStyles = useCallback(
(fraction: number) => {
const [current1, current2] = [text1Ref.current, text2Ref.current]
if (!current1 || !current2) return
const [current1, current2] = [text1Ref.current, text2Ref.current];
if (!current1 || !current2) return;
current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`
current2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`
current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
current2.style.opacity = `${fraction ** 0.4 * 100}%`;
const invertedFraction = 1 - fraction
const invertedFraction = 1 - fraction;
current1.style.filter = `blur(${Math.min(
8 / invertedFraction - 8,
100
)}px)`
current1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`
100,
)}px)`;
current1.style.opacity = `${invertedFraction ** 0.4 * 100}%`;
current1.textContent = texts[textIndexRef.current % texts.length]
current2.textContent = texts[(textIndexRef.current + 1) % texts.length]
current1.textContent = texts[textIndexRef.current % texts.length];
current2.textContent = texts[(textIndexRef.current + 1) % texts.length];
},
[texts]
)
[texts],
);
const doMorph = useCallback(() => {
morphRef.current -= cooldownRef.current
cooldownRef.current = 0
morphRef.current -= cooldownRef.current;
cooldownRef.current = 0;
let fraction = morphRef.current / morphTime
let fraction = morphRef.current / morphTime;
if (fraction > 1) {
cooldownRef.current = cooldownTime
fraction = 1
cooldownRef.current = cooldownTime;
fraction = 1;
}
setStyles(fraction)
setStyles(fraction);
if (fraction === 1) {
textIndexRef.current++
textIndexRef.current++;
}
}, [setStyles])
}, [setStyles]);
const doCooldown = useCallback(() => {
morphRef.current = 0
const [current1, current2] = [text1Ref.current, text2Ref.current]
morphRef.current = 0;
const [current1, current2] = [text1Ref.current, text2Ref.current];
if (current1 && current2) {
current2.style.filter = "none"
current2.style.opacity = "100%"
current1.style.filter = "none"
current1.style.opacity = "0%"
current2.style.filter = "none";
current2.style.opacity = "100%";
current1.style.filter = "none";
current1.style.opacity = "0%";
}
}, [])
}, []);
useEffect(() => {
let animationFrameId: number
let animationFrameId: number;
const animate = () => {
animationFrameId = requestAnimationFrame(animate)
animationFrameId = requestAnimationFrame(animate);
const newTime = new Date()
const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000
timeRef.current = newTime
const newTime = new Date();
const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000;
timeRef.current = newTime;
cooldownRef.current -= dt
cooldownRef.current -= dt;
if (cooldownRef.current <= 0) doMorph()
else doCooldown()
}
if (cooldownRef.current <= 0) doMorph();
else doCooldown();
};
animate()
animate();
return () => {
cancelAnimationFrame(animationFrameId)
}
}, [doMorph, doCooldown])
cancelAnimationFrame(animationFrameId);
};
}, [doMorph, doCooldown]);
return { text1Ref, text2Ref }
}
return { text1Ref, text2Ref };
};
interface MorphingTextProps {
className?: string
texts: string[]
className?: string;
texts: string[];
}
const Texts: React.FC<Pick<MorphingTextProps, "texts">> = ({ texts }) => {
const { text1Ref, text2Ref } = useMorphingText(texts)
const { text1Ref, text2Ref } = useMorphingText(texts);
return (
<>
<span
@@ -109,8 +109,8 @@ const Texts: React.FC<Pick<MorphingTextProps, "texts">> = ({ texts }) => {
ref={text2Ref}
/>
</>
)
}
);
};
const SvgFilters: React.FC = () => (
<svg
@@ -131,7 +131,7 @@ const SvgFilters: React.FC = () => (
</filter>
</defs>
</svg>
)
);
export const MorphingText: React.FC<MorphingTextProps> = ({
texts,
@@ -140,10 +140,10 @@ export const MorphingText: React.FC<MorphingTextProps> = ({
<div
className={cn(
"relative mx-auto h-16 w-full max-w-screen-md text-center font-sans text-[40pt] leading-none font-bold [filter:url(#threshold)_blur(0.6px)] md:h-24 lg:text-[6rem]",
className
className,
)}
>
<Texts texts={texts} />
<SvgFilters />
</div>
)
);
+24 -24
View File
@@ -1,9 +1,9 @@
import * as React from "react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { ChevronDownIcon } from "lucide-react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import { cva } from "class-variance-authority";
import { ChevronDownIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function NavigationMenu({
className,
@@ -11,7 +11,7 @@ function NavigationMenu({
viewport = true,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
viewport?: boolean
viewport?: boolean;
}) {
return (
<NavigationMenuPrimitive.Root
@@ -19,14 +19,14 @@ function NavigationMenu({
data-viewport={viewport}
className={cn(
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
className
className,
)}
{...props}
>
{children}
{viewport && <NavigationMenuViewport />}
</NavigationMenuPrimitive.Root>
)
);
}
function NavigationMenuList({
@@ -38,11 +38,11 @@ function NavigationMenuList({
data-slot="navigation-menu-list"
className={cn(
"group flex flex-1 list-none items-center justify-center gap-1",
className
className,
)}
{...props}
/>
)
);
}
function NavigationMenuItem({
@@ -55,12 +55,12 @@ function NavigationMenuItem({
className={cn("relative", className)}
{...props}
/>
)
);
}
const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
)
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1",
);
function NavigationMenuTrigger({
className,
@@ -79,7 +79,7 @@ function NavigationMenuTrigger({
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
)
);
}
function NavigationMenuContent({
@@ -92,11 +92,11 @@ function NavigationMenuContent({
className={cn(
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
className
className,
)}
{...props}
/>
)
);
}
function NavigationMenuViewport({
@@ -106,19 +106,19 @@ function NavigationMenuViewport({
return (
<div
className={cn(
"absolute top-full left-0 isolate z-50 flex justify-center"
"absolute top-full left-0 isolate z-50 flex justify-center",
)}
>
<NavigationMenuPrimitive.Viewport
data-slot="navigation-menu-viewport"
className={cn(
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
className
className,
)}
{...props}
/>
</div>
)
);
}
function NavigationMenuLink({
@@ -130,11 +130,11 @@ function NavigationMenuLink({
data-slot="navigation-menu-link"
className={cn(
"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
{...props}
/>
)
);
}
function NavigationMenuIndicator({
@@ -146,13 +146,13 @@ function NavigationMenuIndicator({
data-slot="navigation-menu-indicator"
className={cn(
"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
className
className,
)}
{...props}
>
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
</NavigationMenuPrimitive.Indicator>
)
);
}
export {
@@ -165,4 +165,4 @@ export {
NavigationMenuIndicator,
NavigationMenuViewport,
navigationMenuTriggerStyle,
}
};
+31 -31
View File
@@ -1,19 +1,19 @@
"use client"
"use client";
import {
CSSProperties,
ReactElement,
ReactNode,
type CSSProperties,
type ReactElement,
type ReactNode,
useEffect,
useRef,
useState,
} from "react"
} from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface NeonColorsProps {
firstColor: string
secondColor: string
firstColor: string;
secondColor: string;
}
interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -23,14 +23,14 @@ interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
* @description
* The component to be rendered as the card
* */
as?: ReactElement
as?: ReactElement;
/**
* @default ""
* @type string
* @description
* The className of the card
*/
className?: string
className?: string;
/**
* @default ""
@@ -38,7 +38,7 @@ interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
* @description
* The children of the card
* */
children?: ReactNode
children?: ReactNode;
/**
* @default 5
@@ -46,7 +46,7 @@ interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
* @description
* The size of the border in pixels
* */
borderSize?: number
borderSize?: number;
/**
* @default 20
@@ -54,7 +54,7 @@ interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
* @description
* The size of the radius in pixels
* */
borderRadius?: number
borderRadius?: number;
/**
* @default "{ firstColor: '#ff00aa', secondColor: '#00FFF1' }"
@@ -62,7 +62,7 @@ interface NeonGradientCardProps extends React.HTMLAttributes<HTMLDivElement> {
* @description
* The colors of the neon gradient
* */
neonColors?: NeonColorsProps
neonColors?: NeonColorsProps;
}
export const NeonGradientCard: React.FC<NeonGradientCardProps> = ({
@@ -76,31 +76,31 @@ export const NeonGradientCard: React.FC<NeonGradientCardProps> = ({
},
...props
}) => {
const containerRef = useRef<HTMLDivElement>(null)
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
const containerRef = useRef<HTMLDivElement>(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const updateDimensions = () => {
if (containerRef.current) {
const { offsetWidth, offsetHeight } = containerRef.current
setDimensions({ width: offsetWidth, height: offsetHeight })
const { offsetWidth, offsetHeight } = containerRef.current;
setDimensions({ width: offsetWidth, height: offsetHeight });
}
}
};
updateDimensions()
window.addEventListener("resize", updateDimensions)
updateDimensions();
window.addEventListener("resize", updateDimensions);
return () => {
window.removeEventListener("resize", updateDimensions)
}
}, [])
window.removeEventListener("resize", updateDimensions);
};
}, []);
useEffect(() => {
if (containerRef.current) {
const { offsetWidth, offsetHeight } = containerRef.current
setDimensions({ width: offsetWidth, height: offsetHeight })
const { offsetWidth, offsetHeight } = containerRef.current;
setDimensions({ width: offsetWidth, height: offsetHeight });
}
}, [children])
}, []);
return (
<div
@@ -122,7 +122,7 @@ export const NeonGradientCard: React.FC<NeonGradientCardProps> = ({
}
className={cn(
"relative z-10 size-full rounded-[var(--border-radius)]",
className
className,
)}
{...props}
>
@@ -138,11 +138,11 @@ export const NeonGradientCard: React.FC<NeonGradientCardProps> = ({
"after:bg-[linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color))] after:bg-[length:100%_200%] after:opacity-80",
"after:animate-background-position-spin",
"dark:bg-neutral-900",
"break-words"
"break-words",
)}
>
{children}
</div>
</div>
)
}
);
};
+22 -22
View File
@@ -1,16 +1,16 @@
"use client"
"use client";
import { ComponentPropsWithoutRef, useEffect, useRef } from "react"
import { useInView, useMotionValue, useSpring } from "motion/react"
import { useInView, useMotionValue, useSpring } from "motion/react";
import { type ComponentPropsWithoutRef, useEffect, useRef } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface NumberTickerProps extends ComponentPropsWithoutRef<"span"> {
value: number
startValue?: number
direction?: "up" | "down"
delay?: number
decimalPlaces?: number
value: number;
startValue?: number;
direction?: "up" | "down";
delay?: number;
decimalPlaces?: number;
}
export function NumberTicker({
@@ -22,22 +22,22 @@ export function NumberTicker({
decimalPlaces = 0,
...props
}: NumberTickerProps) {
const ref = useRef<HTMLSpanElement>(null)
const motionValue = useMotionValue(direction === "down" ? value : startValue)
const ref = useRef<HTMLSpanElement>(null);
const motionValue = useMotionValue(direction === "down" ? value : startValue);
const springValue = useSpring(motionValue, {
damping: 60,
stiffness: 100,
})
const isInView = useInView(ref, { once: true, margin: "0px" })
});
const isInView = useInView(ref, { once: true, margin: "0px" });
useEffect(() => {
if (isInView) {
const timer = setTimeout(() => {
motionValue.set(direction === "down" ? startValue : value)
}, delay * 1000)
return () => clearTimeout(timer)
motionValue.set(direction === "down" ? startValue : value);
}, delay * 1000);
return () => clearTimeout(timer);
}
}, [motionValue, isInView, delay, value, direction, startValue])
}, [motionValue, isInView, delay, value, direction, startValue]);
useEffect(
() =>
@@ -46,22 +46,22 @@ export function NumberTicker({
ref.current.textContent = Intl.NumberFormat("en-US", {
minimumFractionDigits: decimalPlaces,
maximumFractionDigits: decimalPlaces,
}).format(Number(latest.toFixed(decimalPlaces)))
}).format(Number(latest.toFixed(decimalPlaces)));
}
}),
[springValue, decimalPlaces]
)
[springValue, decimalPlaces],
);
return (
<span
ref={ref}
className={cn(
"inline-block tracking-wider text-black tabular-nums dark:text-white",
className
className,
)}
{...props}
>
{startValue}
</span>
)
);
}
+147 -146
View File
@@ -1,81 +1,82 @@
"use client"
"use client";
import React, {
ComponentPropsWithoutRef,
import type React from "react";
import {
type ComponentPropsWithoutRef,
useEffect,
useRef,
useState,
} from "react"
} from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface MousePosition {
x: number
y: number
x: number;
y: number;
}
function MousePosition(): MousePosition {
const [mousePosition, setMousePosition] = useState<MousePosition>({
x: 0,
y: 0,
})
});
useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
setMousePosition({ x: event.clientX, y: event.clientY })
}
setMousePosition({ x: event.clientX, y: event.clientY });
};
window.addEventListener("mousemove", handleMouseMove)
window.addEventListener("mousemove", handleMouseMove);
return () => {
window.removeEventListener("mousemove", handleMouseMove)
}
}, [])
window.removeEventListener("mousemove", handleMouseMove);
};
}, []);
return mousePosition
return mousePosition;
}
interface ParticlesProps extends ComponentPropsWithoutRef<"div"> {
className?: string
quantity?: number
staticity?: number
ease?: number
size?: number
refresh?: boolean
color?: string
vx?: number
vy?: number
className?: string;
quantity?: number;
staticity?: number;
ease?: number;
size?: number;
refresh?: boolean;
color?: string;
vx?: number;
vy?: number;
}
function hexToRgb(hex: string): number[] {
hex = hex.replace("#", "")
hex = hex.replace("#", "");
if (hex.length === 3) {
hex = hex
.split("")
.map((char) => char + char)
.join("")
.join("");
}
const hexInt = parseInt(hex, 16)
const red = (hexInt >> 16) & 255
const green = (hexInt >> 8) & 255
const blue = hexInt & 255
return [red, green, blue]
const hexInt = parseInt(hex, 16);
const red = (hexInt >> 16) & 255;
const green = (hexInt >> 8) & 255;
const blue = hexInt & 255;
return [red, green, blue];
}
type Circle = {
x: number
y: number
translateX: number
translateY: number
size: number
alpha: number
targetAlpha: number
dx: number
dy: number
magnetism: number
}
x: number;
y: number;
translateX: number;
translateY: number;
size: number;
alpha: number;
targetAlpha: number;
dx: number;
dy: number;
magnetism: number;
};
export const Particles: React.FC<ParticlesProps> = ({
className = "",
@@ -89,104 +90,104 @@ export const Particles: React.FC<ParticlesProps> = ({
vy = 0,
...props
}) => {
const canvasRef = useRef<HTMLCanvasElement>(null)
const canvasContainerRef = useRef<HTMLDivElement>(null)
const context = useRef<CanvasRenderingContext2D | null>(null)
const circles = useRef<Circle[]>([])
const mousePosition = MousePosition()
const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 })
const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 })
const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1
const rafID = useRef<number | null>(null)
const resizeTimeout = useRef<NodeJS.Timeout | null>(null)
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvasContainerRef = useRef<HTMLDivElement>(null);
const context = useRef<CanvasRenderingContext2D | null>(null);
const circles = useRef<Circle[]>([]);
const mousePosition = MousePosition();
const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;
const rafID = useRef<number | null>(null);
const resizeTimeout = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
if (canvasRef.current) {
context.current = canvasRef.current.getContext("2d")
context.current = canvasRef.current.getContext("2d");
}
initCanvas()
animate()
initCanvas();
animate();
const handleResize = () => {
if (resizeTimeout.current) {
clearTimeout(resizeTimeout.current)
clearTimeout(resizeTimeout.current);
}
resizeTimeout.current = setTimeout(() => {
initCanvas()
}, 200)
}
initCanvas();
}, 200);
};
window.addEventListener("resize", handleResize)
window.addEventListener("resize", handleResize);
return () => {
if (rafID.current != null) {
window.cancelAnimationFrame(rafID.current)
window.cancelAnimationFrame(rafID.current);
}
if (resizeTimeout.current) {
clearTimeout(resizeTimeout.current)
clearTimeout(resizeTimeout.current);
}
window.removeEventListener("resize", handleResize)
}
}, [color])
window.removeEventListener("resize", handleResize);
};
}, [animate, initCanvas]);
useEffect(() => {
onMouseMove()
}, [mousePosition.x, mousePosition.y])
onMouseMove();
}, [onMouseMove]);
useEffect(() => {
initCanvas()
}, [refresh])
initCanvas();
}, [initCanvas]);
const initCanvas = () => {
resizeCanvas()
drawParticles()
}
resizeCanvas();
drawParticles();
};
const onMouseMove = () => {
if (canvasRef.current) {
const rect = canvasRef.current.getBoundingClientRect()
const { w, h } = canvasSize.current
const x = mousePosition.x - rect.left - w / 2
const y = mousePosition.y - rect.top - h / 2
const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2
const rect = canvasRef.current.getBoundingClientRect();
const { w, h } = canvasSize.current;
const x = mousePosition.x - rect.left - w / 2;
const y = mousePosition.y - rect.top - h / 2;
const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;
if (inside) {
mouse.current.x = x
mouse.current.y = y
mouse.current.x = x;
mouse.current.y = y;
}
}
}
};
const resizeCanvas = () => {
if (canvasContainerRef.current && canvasRef.current && context.current) {
canvasSize.current.w = canvasContainerRef.current.offsetWidth
canvasSize.current.h = canvasContainerRef.current.offsetHeight
canvasSize.current.w = canvasContainerRef.current.offsetWidth;
canvasSize.current.h = canvasContainerRef.current.offsetHeight;
canvasRef.current.width = canvasSize.current.w * dpr
canvasRef.current.height = canvasSize.current.h * dpr
canvasRef.current.style.width = `${canvasSize.current.w}px`
canvasRef.current.style.height = `${canvasSize.current.h}px`
context.current.scale(dpr, dpr)
canvasRef.current.width = canvasSize.current.w * dpr;
canvasRef.current.height = canvasSize.current.h * dpr;
canvasRef.current.style.width = `${canvasSize.current.w}px`;
canvasRef.current.style.height = `${canvasSize.current.h}px`;
context.current.scale(dpr, dpr);
// Clear existing particles and create new ones with exact quantity
circles.current = []
circles.current = [];
for (let i = 0; i < quantity; i++) {
const circle = circleParams()
drawCircle(circle)
const circle = circleParams();
drawCircle(circle);
}
}
}
};
const circleParams = (): Circle => {
const x = Math.floor(Math.random() * canvasSize.current.w)
const y = Math.floor(Math.random() * canvasSize.current.h)
const translateX = 0
const translateY = 0
const pSize = Math.floor(Math.random() * 2) + size
const alpha = 0
const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1))
const dx = (Math.random() - 0.5) * 0.1
const dy = (Math.random() - 0.5) * 0.1
const magnetism = 0.1 + Math.random() * 4
const x = Math.floor(Math.random() * canvasSize.current.w);
const y = Math.floor(Math.random() * canvasSize.current.h);
const translateX = 0;
const translateY = 0;
const pSize = Math.floor(Math.random() * 2) + size;
const alpha = 0;
const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));
const dx = (Math.random() - 0.5) * 0.1;
const dy = (Math.random() - 0.5) * 0.1;
const magnetism = 0.1 + Math.random() * 4;
return {
x,
y,
@@ -198,26 +199,26 @@ export const Particles: React.FC<ParticlesProps> = ({
dx,
dy,
magnetism,
}
}
};
};
const rgb = hexToRgb(color)
const rgb = hexToRgb(color);
const drawCircle = (circle: Circle, update = false) => {
if (context.current) {
const { x, y, translateX, translateY, size, alpha } = circle
context.current.translate(translateX, translateY)
context.current.beginPath()
context.current.arc(x, y, size, 0, 2 * Math.PI)
context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`
context.current.fill()
context.current.setTransform(dpr, 0, 0, dpr, 0, 0)
const { x, y, translateX, translateY, size, alpha } = circle;
context.current.translate(translateX, translateY);
context.current.beginPath();
context.current.arc(x, y, size, 0, 2 * Math.PI);
context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`;
context.current.fill();
context.current.setTransform(dpr, 0, 0, dpr, 0, 0);
if (!update) {
circles.current.push(circle)
circles.current.push(circle);
}
}
}
};
const clearContext = () => {
if (context.current) {
@@ -225,34 +226,34 @@ export const Particles: React.FC<ParticlesProps> = ({
0,
0,
canvasSize.current.w,
canvasSize.current.h
)
canvasSize.current.h,
);
}
}
};
const drawParticles = () => {
clearContext()
const particleCount = quantity
clearContext();
const particleCount = quantity;
for (let i = 0; i < particleCount; i++) {
const circle = circleParams()
drawCircle(circle)
const circle = circleParams();
drawCircle(circle);
}
}
};
const remapValue = (
value: number,
start1: number,
end1: number,
start2: number,
end2: number
end2: number,
): number => {
const remapped =
((value - start1) * (end2 - start2)) / (end1 - start1) + start2
return remapped > 0 ? remapped : 0
}
((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
return remapped > 0 ? remapped : 0;
};
const animate = () => {
clearContext()
clearContext();
circles.current.forEach((circle: Circle, i: number) => {
// Handle the alpha value
const edge = [
@@ -260,29 +261,29 @@ export const Particles: React.FC<ParticlesProps> = ({
canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge
circle.y + circle.translateY - circle.size, // distance from top edge
canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
]
const closestEdge = edge.reduce((a, b) => Math.min(a, b))
];
const closestEdge = edge.reduce((a, b) => Math.min(a, b));
const remapClosestEdge = parseFloat(
remapValue(closestEdge, 0, 20, 0, 1).toFixed(2)
)
remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
);
if (remapClosestEdge > 1) {
circle.alpha += 0.02
circle.alpha += 0.02;
if (circle.alpha > circle.targetAlpha) {
circle.alpha = circle.targetAlpha
circle.alpha = circle.targetAlpha;
}
} else {
circle.alpha = circle.targetAlpha * remapClosestEdge
circle.alpha = circle.targetAlpha * remapClosestEdge;
}
circle.x += circle.dx + vx
circle.y += circle.dy + vy
circle.x += circle.dx + vx;
circle.y += circle.dy + vy;
circle.translateX +=
(mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
ease
ease;
circle.translateY +=
(mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
ease
ease;
drawCircle(circle, true)
drawCircle(circle, true);
// circle gets out of the canvas
if (
@@ -292,14 +293,14 @@ export const Particles: React.FC<ParticlesProps> = ({
circle.y > canvasSize.current.h + circle.size
) {
// remove the circle from the array
circles.current.splice(i, 1)
circles.current.splice(i, 1);
// create a new circle
const newCircle = circleParams()
drawCircle(newCircle)
const newCircle = circleParams();
drawCircle(newCircle);
}
})
rafID.current = window.requestAnimationFrame(animate)
}
});
rafID.current = window.requestAnimationFrame(animate);
};
return (
<div
@@ -310,5 +311,5 @@ export const Particles: React.FC<ParticlesProps> = ({
>
<canvas ref={canvasRef} className="size-full" />
</div>
)
}
);
};
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { Currency } from "@/types/currency";
import { formatPrice, formatPriceWithTc } from "@/lib/currency-utils";
import { cn } from "@/lib/utils";
import type { Currency } from "@/types/currency";
interface PriceDisplayProps {
value: number;
+29 -30
View File
@@ -1,16 +1,16 @@
"use client"
"use client";
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"
import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown, ChevronUp } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Select = SelectPrimitive.Root
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
@@ -20,7 +20,7 @@ const SelectTrigger = React.forwardRef<
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
className,
)}
{...props}
>
@@ -29,8 +29,8 @@ const SelectTrigger = React.forwardRef<
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
@@ -40,14 +40,14 @@ const SelectScrollUpButton = React.forwardRef<
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
className,
)}
{...props}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
@@ -57,15 +57,15 @@ const SelectScrollDownButton = React.forwardRef<
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
className,
)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
))
));
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName
SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
@@ -78,7 +78,7 @@ const SelectContent = React.forwardRef<
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
className,
)}
position={position}
{...props}
@@ -88,7 +88,7 @@ const SelectContent = React.forwardRef<
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
@@ -96,8 +96,8 @@ const SelectContent = React.forwardRef<
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
));
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
@@ -108,8 +108,8 @@ const SelectLabel = React.forwardRef<
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
@@ -119,7 +119,7 @@ const SelectItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
className,
)}
{...props}
>
@@ -131,8 +131,8 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
@@ -143,8 +143,8 @@ const SelectSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
@@ -157,5 +157,4 @@ export {
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}
};
+7 -7
View File
@@ -1,9 +1,9 @@
"use client"
"use client";
import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Separator({
className,
@@ -18,11 +18,11 @@ function Separator({
orientation={orientation}
className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
className
className,
)}
{...props}
/>
)
);
}
export { Separator }
export { Separator };
+19 -24
View File
@@ -1,36 +1,31 @@
"use client"
"use client";
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { XIcon } from "lucide-react"
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return (
<SheetPrimitive.Root
data-slot="sheet"
{...props}
/>
);
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
}
function SheetTrigger({
...props
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
}
function SheetClose({
...props
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
}
function SheetPortal({
...props
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
}
function SheetOverlay({
@@ -42,11 +37,11 @@ function SheetOverlay({
data-slot="sheet-overlay"
className={cn(
"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",
className
className,
)}
{...props}
/>
)
);
}
function SheetContent({
@@ -55,7 +50,7 @@ function SheetContent({
side = "right",
...props
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
side?: "top" | "right" | "bottom" | "left"
side?: "top" | "right" | "bottom" | "left";
}) {
return (
<SheetPortal>
@@ -72,7 +67,7 @@ function SheetContent({
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
side === "bottom" &&
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
className
className,
)}
{...props}
>
@@ -83,7 +78,7 @@ function SheetContent({
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
)
);
}
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
@@ -93,7 +88,7 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex flex-col gap-1.5 p-4", className)}
{...props}
/>
)
);
}
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
@@ -103,7 +98,7 @@ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
);
}
function SheetTitle({
@@ -116,7 +111,7 @@ function SheetTitle({
className={cn("text-foreground font-semibold", className)}
{...props}
/>
)
);
}
function SheetDescription({
@@ -129,7 +124,7 @@ function SheetDescription({
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
)
);
}
export {
@@ -141,4 +136,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
}
};
+21 -18
View File
@@ -1,15 +1,18 @@
import React, { ComponentPropsWithoutRef, CSSProperties } from "react"
import React, {
type ComponentPropsWithoutRef,
type CSSProperties,
} from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface ShimmerButtonProps extends ComponentPropsWithoutRef<"button"> {
shimmerColor?: string
shimmerSize?: string
borderRadius?: string
shimmerDuration?: string
background?: string
className?: string
children?: React.ReactNode
shimmerColor?: string;
shimmerSize?: string;
borderRadius?: string;
shimmerDuration?: string;
background?: string;
className?: string;
children?: React.ReactNode;
}
export const ShimmerButton = React.forwardRef<
@@ -27,7 +30,7 @@ export const ShimmerButton = React.forwardRef<
children,
...props
},
ref
ref,
) => {
return (
<button
@@ -44,7 +47,7 @@ export const ShimmerButton = React.forwardRef<
className={cn(
"group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden [border-radius:var(--radius)] border border-white/10 px-6 py-3 whitespace-nowrap text-white [background:var(--bg)]",
"transform-gpu transition-transform duration-300 ease-in-out active:translate-y-px",
className
className,
)}
ref={ref}
{...props}
@@ -53,7 +56,7 @@ export const ShimmerButton = React.forwardRef<
<div
className={cn(
"-z-30 blur-[2px]",
"[container-type:size] absolute inset-0 overflow-visible"
"[container-type:size] absolute inset-0 overflow-visible",
)}
>
{/* spark */}
@@ -78,19 +81,19 @@ export const ShimmerButton = React.forwardRef<
"group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",
// on click
"group-active:shadow-[inset_0_-10px_10px_#ffffff3f]"
"group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
)}
/>
{/* backdrop */}
<div
className={cn(
"absolute [inset:var(--cut)] -z-20 [border-radius:var(--radius)] [background:var(--bg)]"
"absolute [inset:var(--cut)] -z-20 [border-radius:var(--radius)] [background:var(--bg)]",
)}
/>
</button>
)
}
)
);
},
);
ShimmerButton.displayName = "ShimmerButton"
ShimmerButton.displayName = "ShimmerButton";
+8 -8
View File
@@ -1,25 +1,25 @@
"use client"
"use client";
import * as React from "react"
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface ShineBorderProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Width of the border in pixels
* @default 1
*/
borderWidth?: number
borderWidth?: number;
/**
* Duration of the animation in seconds
* @default 14
*/
duration?: number
duration?: number;
/**
* Color of the border, can be a single color or an array of colors
* @default "#000000"
*/
shineColor?: string | string[]
shineColor?: string | string[];
}
/**
@@ -55,9 +55,9 @@ export function ShineBorder({
}
className={cn(
"motion-safe:animate-shine pointer-events-none absolute inset-0 size-full rounded-[inherit] will-change-[background-position]",
className
className,
)}
{...props}
/>
)
);
}
-5
View File
@@ -13,8 +13,3 @@ function Skeleton({
}
export { Skeleton };
+11 -11
View File
@@ -1,9 +1,9 @@
"use client"
"use client";
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import * as TabsPrimitive from "@radix-ui/react-tabs";
import type * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Tabs({
className,
@@ -15,7 +15,7 @@ function Tabs({
className={cn("flex flex-col gap-2", className)}
{...props}
/>
)
);
}
function TabsList({
@@ -27,11 +27,11 @@ function TabsList({
data-slot="tabs-list"
className={cn(
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
className
className,
)}
{...props}
/>
)
);
}
function TabsTrigger({
@@ -43,11 +43,11 @@ function TabsTrigger({
data-slot="tabs-trigger"
className={cn(
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
className,
)}
{...props}
/>
)
);
}
function TabsContent({
@@ -60,7 +60,7 @@ function TabsContent({
className={cn("flex-1 outline-none", className)}
{...props}
/>
)
);
}
export { Tabs, TabsList, TabsTrigger, TabsContent }
export { Tabs, TabsList, TabsTrigger, TabsContent };
+2 -2
View File
@@ -10,13 +10,13 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
className,
)}
ref={ref}
{...props}
/>
);
}
},
);
Textarea.displayName = "Textarea";
+14 -14
View File
@@ -1,15 +1,15 @@
"use client"
"use client";
import { useEffect, useState } from "react"
import { AnimatePresence, motion, MotionProps } from "motion/react"
import { AnimatePresence, type MotionProps, motion } from "motion/react";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
interface WordRotateProps {
words: string[]
duration?: number
motionProps?: MotionProps
className?: string
words: string[];
duration?: number;
motionProps?: MotionProps;
className?: string;
}
export function WordRotate({
@@ -23,16 +23,16 @@ export function WordRotate({
},
className,
}: WordRotateProps) {
const [index, setIndex] = useState(0)
const [index, setIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setIndex((prevIndex) => (prevIndex + 1) % words.length)
}, duration)
setIndex((prevIndex) => (prevIndex + 1) % words.length);
}, duration);
// Clean up interval on unmount
return () => clearInterval(interval)
}, [words, duration])
return () => clearInterval(interval);
}, [words, duration]);
return (
<div className="overflow-hidden py-2">
@@ -46,5 +46,5 @@ export function WordRotate({
</motion.h1>
</AnimatePresence>
</div>
)
);
}