Remove npm legacy errors, created single source of truth for ESlint. updated analytics url. updated script background (#5498)

* Update ScriptAccordion and ScriptItem components for improved styling

* Add README.md for Proxmox VE Helper-Scripts Frontend

* Remove testing dependencies and related test files from the frontend project

* Update analytics URL in siteConfig to point to community-scripts.org

* Refactor ESLint configuration to have one source of truth and run "npm lint" to apply new changes

* Update lint script in package.json to remove npm

* Add 'next' option to ESLint configuration for improved compatibility

* Update package dependencies and versions in package.json and package-lock.json

* Refactor theme provider import and enhance calendar component for dynamic icon rendering

* rename sidebar, alerts and buttons

* rename description and interfaces files

* rename more files

* change folder name

* Refactor tooltip logic to improve updateable condition handling

* Enhance CommandMenu to prevent duplicate scripts across categories

* Remove test step from frontend CI/CD workflow
This commit is contained in:
Bram Suurd
2025-06-28 00:38:09 +02:00
committed by GitHub
parent d60911a063
commit 0067075ed1
91 changed files with 8049 additions and 4043 deletions

View File

@@ -1,7 +1,9 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import type { VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
@@ -16,8 +18,8 @@ const alertVariants = cva(
defaultVariants: {
variant: "default",
},
}
)
},
);
const Alert = React.forwardRef<
HTMLDivElement,
@@ -29,8 +31,8 @@ const Alert = React.forwardRef<
className={cn(alertVariants({ variant }), className)}
{...props}
/>
))
Alert.displayName = "Alert"
));
Alert.displayName = "Alert";
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
@@ -41,8 +43,8 @@ const AlertTitle = React.forwardRef<
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"
));
AlertTitle.displayName = "AlertTitle";
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
@@ -53,7 +55,7 @@ const AlertDescription = React.forwardRef<
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"
));
AlertDescription.displayName = "AlertDescription";
export { Alert, AlertTitle, AlertDescription }
export { Alert, AlertDescription, AlertTitle };

View File

@@ -1,4 +1,4 @@
import { ReactNode } from "react";
import type { ReactNode } from "react";
import { cn } from "@/lib/utils";
@@ -17,7 +17,7 @@ export default function AnimatedGradientText({
)}
>
<div
className={`absolute inset-0 block h-full w-full animate-gradient bg-gradient-to-r from-[#ffaa40]/50 via-[#9c40ff]/50 to-[#ffaa40]/50 bg-[length:var(--bg-size)_100%] p-[1px] [border-radius:inherit] ![mask-composite:subtract] [mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]`}
className="absolute inset-0 block h-full w-full animate-gradient bg-gradient-to-r from-[#ffaa40]/50 via-[#9c40ff]/50 to-[#ffaa40]/50 bg-[length:var(--bg-size)_100%] p-[1px] [border-radius:inherit] ![mask-composite:subtract] [mask:linear-gradient(#fff_0_0)_content-box,linear-gradient(#fff_0_0)]"
/>
{children}

View File

@@ -1,4 +1,6 @@
import { cva, type VariantProps } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
@@ -26,9 +28,7 @@ const badgeVariants = cva(
},
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
export type BadgeProps = {} & React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof badgeVariants>;
function Badge({ className, variant, ...props }: BadgeProps) {
return (

View File

@@ -1,8 +1,11 @@
import { cn } from "@/lib/utils";
import type { VariantProps } from "class-variance-authority";
import { Slot, Slottable } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
@@ -47,21 +50,19 @@ const buttonVariants = cva(
},
);
interface IconProps {
type IconProps = {
Icon: React.ElementType;
iconPlacement: "left" | "right";
}
};
interface IconRefProps {
type IconRefProps = {
Icon?: never;
iconPlacement?: undefined;
}
};
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
export type ButtonProps = {
asChild?: boolean;
}
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>;
export type ButtonIconProps = IconProps | IconRefProps;

View File

@@ -1,13 +1,13 @@
"use client"
"use client";
import * as React from "react"
import { ChevronLeft, ChevronRight } from "lucide-react"
import { DayPicker } from "react-day-picker"
import { ChevronLeft, ChevronRight } from "lucide-react";
import { DayPicker } from "react-day-picker";
import * as React from "react";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export type CalendarProps = React.ComponentProps<typeof DayPicker>
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
function Calendar({
className,
@@ -27,7 +27,7 @@ function Calendar({
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
@@ -39,7 +39,7 @@ function Calendar({
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
day: cn(
buttonVariants({ variant: "ghost" }),
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
"h-9 w-9 p-0 font-normal aria-selected:opacity-100",
),
day_range_end: "day-range-end",
day_selected:
@@ -54,13 +54,17 @@ function Calendar({
...classNames,
}}
components={{
IconLeft: ({ ...props }) => <ChevronLeft className="h-4 w-4" />,
IconRight: ({ ...props }) => <ChevronRight className="h-4 w-4" />,
Chevron: ({ ...props }) => {
if (props.orientation === "left") {
return <ChevronLeft className="h-4 w-4" />;
}
return <ChevronRight className="h-4 w-4" />;
},
}}
{...props}
/>
)
);
}
Calendar.displayName = "Calendar"
Calendar.displayName = "Calendar";
export { Calendar }
export { Calendar };

View File

@@ -1,8 +1,10 @@
"use client";
import { cn } from "@/lib/utils";
import { CheckIcon, ClipboardIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Card } from "./card";
export default function CodeCopyButton({
@@ -26,7 +28,7 @@ export default function CodeCopyButton({
setHasCopied(true);
let warning = localStorage.getItem("warning");
const warning = localStorage.getItem("warning");
if (warning === null) {
localStorage.setItem("warning", "1");
@@ -50,11 +52,13 @@ export default function CodeCopyButton({
className={cn("bg-muted px-3 py-4")}
title="Copy"
>
{hasCopied ? (
<CheckIcon className="h-4 w-4" />
) : (
<ClipboardIcon className="h-4 w-4" />
)}
{hasCopied
? (
<CheckIcon className="h-4 w-4" />
)
: (
<ClipboardIcon className="h-4 w-4" />
)}
</button>
</Card>
</div>

View File

@@ -1,14 +1,18 @@
"use client";
import { basePath } from "@/config/siteConfig";
import { cn } from "@/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import { Clipboard, Copy } from "lucide-react";
import Link from "next/link";
import * as React from "react";
import { toast } from "sonner";
import { Button } from "./button";
import Link from "next/link";
import { basePath } from "@/config/site-config";
import { cn } from "@/lib/utils";
import { Separator } from "./separator";
import { Button } from "./button";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
@@ -40,23 +44,24 @@ const buttonVariants = cva(
},
);
const handleCopy = (type: string, value: string) => {
function handleCopy(type: string, value: string) {
navigator.clipboard.writeText(value);
let amountOfScriptsCopied = localStorage.getItem("amountOfScriptsCopied");
if (amountOfScriptsCopied === null) {
localStorage.setItem("amountOfScriptsCopied", "1");
} else {
amountOfScriptsCopied = (parseInt(amountOfScriptsCopied) + 1).toString();
}
else {
amountOfScriptsCopied = (Number.parseInt(amountOfScriptsCopied) + 1).toString();
localStorage.setItem("amountOfScriptsCopied", amountOfScriptsCopied);
if (
parseInt(amountOfScriptsCopied) === 3 ||
parseInt(amountOfScriptsCopied) === 10 ||
parseInt(amountOfScriptsCopied) === 25 ||
parseInt(amountOfScriptsCopied) === 50 ||
parseInt(amountOfScriptsCopied) === 100
Number.parseInt(amountOfScriptsCopied) === 3
|| Number.parseInt(amountOfScriptsCopied) === 10
|| Number.parseInt(amountOfScriptsCopied) === 25
|| Number.parseInt(amountOfScriptsCopied) === 50
|| Number.parseInt(amountOfScriptsCopied) === 100
) {
setTimeout(() => {
toast.info(
@@ -86,17 +91,20 @@ const handleCopy = (type: string, value: string) => {
toast.success(
<div className="flex items-center gap-2">
<Clipboard className="h-4 w-4" />
<span>Copied {type} to clipboard</span>
<span>
Copied
{type}
{" "}
to clipboard
</span>
</div>,
);
};
}
export interface CodeBlockProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
export type CodeBlockProps = {
asChild?: boolean;
code: string;
}
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>;
const CodeBlock = React.forwardRef<HTMLDivElement, CodeBlockProps>(
({ className, variant, size, asChild = false, code }, ref) => {
@@ -121,7 +129,10 @@ const CodeBlock = React.forwardRef<HTMLDivElement, CodeBlockProps>(
)}
>
<p className="flex items-center gap-2">
{code} <Separator orientation="vertical" />{" "}
{code}
{" "}
<Separator orientation="vertical" />
{" "}
<Copy
className="cursor-pointer"
size={16}

View File

@@ -1,6 +1,7 @@
"use client";
import { type DialogProps } from "@radix-ui/react-dialog";
import type { DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import * as React from "react";
@@ -23,9 +24,9 @@ const Command = React.forwardRef<
));
Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
type CommandDialogProps = {} & DialogProps;
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
function CommandDialog({ children, ...props }: CommandDialogProps) {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0 shadow-lg">
@@ -35,7 +36,7 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
</DialogContent>
</Dialog>
);
};
}
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
@@ -126,10 +127,10 @@ const CommandItem = React.forwardRef<
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
function CommandShortcut({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
}: React.HTMLAttributes<HTMLSpanElement>) {
return (
<span
className={cn(
@@ -139,7 +140,7 @@ const CommandShortcut = ({
{...props}
/>
);
};
}
CommandShortcut.displayName = "CommandShortcut";
export {

View File

@@ -1,8 +1,9 @@
"use client";
import { cn } from "@/lib/utils";
import { CheckIcon, ClipboardIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Card } from "./card";
export default function CodeCopyButton({
@@ -26,7 +27,6 @@ export default function CodeCopyButton({
setHasCopied(true);
// toast.success(`copied ${type} to clipboard`, {
// icon: <ClipboardCheck className="h-4 w-4" />,
// });
@@ -42,11 +42,13 @@ export default function CodeCopyButton({
className={cn(" right-0 cursor-pointer bg-muted px-3 py-4")}
onClick={() => handleCopy("install command", children)}
>
{hasCopied ? (
<CheckIcon className="h-4 w-4" />
) : (
<ClipboardIcon className="h-4 w-4" />
)}
{hasCopied
? (
<CheckIcon className="h-4 w-4" />
)
: (
<ClipboardIcon className="h-4 w-4" />
)}
<span className="sr-only">Copy</span>
</div>
</Card>

View File

@@ -53,32 +53,36 @@ const DialogContent = React.forwardRef<
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({
function DialogHeader({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
}
DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({
function DialogFooter({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
}
DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef<

View File

@@ -37,8 +37,8 @@ const DropdownMenuSubTrigger = React.forwardRef<
<ChevronRight className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
));
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName;
DropdownMenuSubTrigger.displayName
= DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@@ -53,8 +53,8 @@ const DropdownMenuSubContent = React.forwardRef<
{...props}
/>
));
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName;
DropdownMenuSubContent.displayName
= DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@@ -113,8 +113,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
{children}
</DropdownMenuPrimitive.CheckboxItem>
));
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName;
DropdownMenuCheckboxItem.displayName
= DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@@ -168,17 +168,17 @@ const DropdownMenuSeparator = React.forwardRef<
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
function DropdownMenuShortcut({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
}: React.HTMLAttributes<HTMLSpanElement>) {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
);
};
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {

View File

@@ -2,8 +2,7 @@ import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
export type InputProps = {} & React.InputHTMLAttributes<HTMLInputElement>;
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {

View File

@@ -1,26 +1,28 @@
"use client"
"use client";
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
import type { VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import * as LabelPrimitive from "@radix-ui/react-label";
import { cva } 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<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
& VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
));
Label.displayName = LabelPrimitive.Root.displayName;
export { Label }
export { Label };

View File

@@ -53,7 +53,8 @@ const NavigationMenuTrigger = React.forwardRef<
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
{children}
{" "}
<ChevronDown
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
aria-hidden="true"
@@ -94,8 +95,8 @@ const NavigationMenuViewport = React.forwardRef<
/>
</div>
));
NavigationMenuViewport.displayName =
NavigationMenuPrimitive.Viewport.displayName;
NavigationMenuViewport.displayName
= NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
@@ -112,8 +113,8 @@ const NavigationMenuIndicator = React.forwardRef<
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
));
NavigationMenuIndicator.displayName =
NavigationMenuPrimitive.Indicator.displayName;
NavigationMenuIndicator.displayName
= NavigationMenuPrimitive.Indicator.displayName;
export {
NavigationMenu,

View File

@@ -30,10 +30,10 @@ export default function NumberTicker({
});
useEffect(() => {
isInView &&
setTimeout(() => {
motionValue.set(direction === "down" ? 0 : value);
}, delay * 1000);
isInView
&& setTimeout(() => {
motionValue.set(direction === "down" ? 0 : value);
}, delay * 1000);
}, [motionValue, isInView, delay, value, direction]);
useEffect(

View File

@@ -1,12 +1,13 @@
"use client";
import { cn } from "@/lib/utils";
import React, { useEffect, useRef, useState } from "react";
interface MousePosition {
import { cn } from "@/lib/utils";
type MousePosition = {
x: number;
y: number;
}
};
function MousePosition(): MousePosition {
const [mousePosition, setMousePosition] = useState<MousePosition>({
@@ -29,7 +30,7 @@ function MousePosition(): MousePosition {
return mousePosition;
}
interface ParticlesProps {
type ParticlesProps = {
className?: string;
quantity?: number;
staticity?: number;
@@ -39,18 +40,18 @@ interface ParticlesProps {
color?: string;
vx?: number;
vy?: number;
}
};
function hexToRgb(hex: string): number[] {
hex = hex.replace("#", "");
if (hex.length === 3) {
hex = hex
.split("")
.map((char) => char + char)
.map(char => char + char)
.join("");
}
const hexInt = parseInt(hex, 16);
const hexInt = Number.parseInt(hex, 16);
const red = (hexInt >> 16) & 255;
const green = (hexInt >> 8) & 255;
const blue = hexInt & 255;
@@ -150,7 +151,7 @@ const Particles: React.FC<ParticlesProps> = ({
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 targetAlpha = Number.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;
@@ -213,8 +214,8 @@ const Particles: React.FC<ParticlesProps> = ({
start2: number,
end2: number,
): number => {
const remapped =
((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
const remapped
= ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
return remapped > 0 ? remapped : 0;
};
@@ -229,7 +230,7 @@ const Particles: React.FC<ParticlesProps> = ({
canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
];
const closestEdge = edge.reduce((a, b) => Math.min(a, b));
const remapClosestEdge = parseFloat(
const remapClosestEdge = Number.parseFloat(
remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
);
if (remapClosestEdge > 1) {
@@ -237,26 +238,27 @@ const Particles: React.FC<ParticlesProps> = ({
if (circle.alpha > circle.targetAlpha) {
circle.alpha = circle.targetAlpha;
}
} else {
}
else {
circle.alpha = circle.targetAlpha * remapClosestEdge;
}
circle.x += circle.dx + vx;
circle.y += circle.dy + vy;
circle.translateX +=
(mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
ease;
circle.translateY +=
(mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
ease;
circle.translateX
+= (mouse.current.x / (staticity / circle.magnetism) - circle.translateX)
/ ease;
circle.translateY
+= (mouse.current.y / (staticity / circle.magnetism) - circle.translateY)
/ ease;
drawCircle(circle, true);
// circle gets out of the canvas
if (
circle.x < -circle.size ||
circle.x > canvasSize.current.w + circle.size ||
circle.y < -circle.size ||
circle.y > canvasSize.current.h + circle.size
circle.x < -circle.size
|| circle.x > canvasSize.current.w + circle.size
|| circle.y < -circle.size
|| circle.y > canvasSize.current.h + circle.size
) {
// remove the circle from the array
circles.current.splice(i, 1);

View File

@@ -1,13 +1,13 @@
"use client"
"use client";
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Popover = PopoverPrimitive.Root
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
@@ -20,12 +20,12 @@ const PopoverContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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",
className
className,
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent }
export { Popover, PopoverContent, PopoverTrigger };

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 { Check, ChevronDown, ChevronUp } from "lucide-react";
import * as SelectPrimitive from "@radix-ui/react-select";
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-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 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
));
SelectScrollDownButton.displayName
= SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
@@ -76,9 +76,9 @@ const SelectContent = React.forwardRef<
ref={ref}
className={cn(
"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
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,
)}
position={position}
{...props}
@@ -87,8 +87,8 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
position === "popper"
&& "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,18 +143,18 @@ 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,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectGroup,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectLabel,
SelectScrollDownButton,
}
SelectScrollUpButton,
SelectSeparator,
SelectTrigger,
SelectValue,
};

View File

@@ -1,7 +1,9 @@
"use client";
import type { VariantProps } from "class-variance-authority";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import { X } from "lucide-react";
import * as React from "react";
@@ -49,9 +51,7 @@ const sheetVariants = cva(
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
type SheetContentProps = {} & React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & VariantProps<typeof sheetVariants>;
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
@@ -74,32 +74,36 @@ const SheetContent = React.forwardRef<
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
function SheetHeader({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
}
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
function SheetFooter({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
}
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<

View File

@@ -1,11 +1,11 @@
"use client";
import { useTheme } from "next-themes";
import { Toaster as Sonner } from "sonner";
import { useTheme } from "next-themes";
type ToasterProps = React.ComponentProps<typeof Sonner>;
const Toaster = ({ ...props }: ToasterProps) => {
function Toaster({ ...props }: ToasterProps) {
const { theme = "system" } = useTheme();
return (
@@ -26,6 +26,6 @@ const Toaster = ({ ...props }: ToasterProps) => {
{...props}
/>
);
};
}
export { Toaster };

View File

@@ -1,10 +1,12 @@
import { basePath } from "@/config/siteConfig";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { useEffect, useState } from "react";
import { FaGithub, FaStar } from "react-icons/fa";
import { buttonVariants } from "./button";
import { useEffect, useState } from "react";
import Link from "next/link";
import { basePath } from "@/config/site-config";
import { cn } from "@/lib/utils";
import NumberTicker from "./number-ticker";
import { buttonVariants } from "./button";
export default function StarOnGithubButton() {
const [stars, setStars] = useState(0);
@@ -23,7 +25,8 @@ export default function StarOnGithubButton() {
const data = await res.json();
setStars(data.stargazers_count || stars);
}
} catch (error) {
}
catch (error) {
console.error("Error fetching stars:", error);
}
};
@@ -43,7 +46,8 @@ export default function StarOnGithubButton() {
<span className="absolute right-0 -mt-12 h-32 translate-x-12 rotate-12 bg-white opacity-10 transition-all duration-1000 ease-out group-hover:-translate-x-40" />
<div className="flex items-center">
<FaGithub className="size-4" />
<span className="ml-1">Star on GitHub</span>{" "}
<span className="ml-1">Star on GitHub</span>
{" "}
</div>
<div className="ml-2 flex items-center gap-1 text-sm md:flex">
<FaStar className="size-4 text-gray-500 transition-all duration-300 group-hover:text-yellow-300" />

View File

@@ -1,9 +1,9 @@
"use client"
"use client";
import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"
import * as SwitchPrimitives from "@radix-ui/react-switch";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
@@ -12,18 +12,18 @@ const Switch = React.forwardRef<
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName
));
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch }
export { Switch };

View File

@@ -1,6 +1,6 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Table = React.forwardRef<
HTMLTableElement,
@@ -13,16 +13,16 @@ const Table = React.forwardRef<
{...props}
/>
</div>
))
Table.displayName = "Table"
));
Table.displayName = "Table";
const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"
));
TableHeader.displayName = "TableHeader";
const TableBody = React.forwardRef<
HTMLTableSectionElement,
@@ -33,8 +33,8 @@ const TableBody = React.forwardRef<
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"
));
TableBody.displayName = "TableBody";
const TableFooter = React.forwardRef<
HTMLTableSectionElement,
@@ -44,12 +44,12 @@ const TableFooter = React.forwardRef<
ref={ref}
className={cn(
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className
className,
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"
));
TableFooter.displayName = "TableFooter";
const TableRow = React.forwardRef<
HTMLTableRowElement,
@@ -59,12 +59,12 @@ const TableRow = React.forwardRef<
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className
className,
)}
{...props}
/>
))
TableRow.displayName = "TableRow"
));
TableRow.displayName = "TableRow";
const TableHead = React.forwardRef<
HTMLTableCellElement,
@@ -74,12 +74,12 @@ const TableHead = React.forwardRef<
ref={ref}
className={cn(
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
className,
)}
{...props}
/>
))
TableHead.displayName = "TableHead"
));
TableHead.displayName = "TableHead";
const TableCell = React.forwardRef<
HTMLTableCellElement,
@@ -89,12 +89,12 @@ const TableCell = React.forwardRef<
ref={ref}
className={cn(
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
className,
)}
{...props}
/>
))
TableCell.displayName = "TableCell"
));
TableCell.displayName = "TableCell";
const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
@@ -105,16 +105,16 @@ const TableCaption = React.forwardRef<
className={cn("mt-4 text-sm text-muted-foreground", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"
));
TableCaption.displayName = "TableCaption";
export {
Table,
TableHeader,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
TableCell,
TableCaption,
}
};

View File

@@ -1,6 +1,6 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Textarea = React.forwardRef<
HTMLTextAreaElement,
@@ -10,13 +10,13 @@ const Textarea = React.forwardRef<
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base 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 md:text-sm",
className
className,
)}
ref={ref}
{...props}
/>
)
})
Textarea.displayName = "Textarea"
);
});
Textarea.displayName = "Textarea";
export { Textarea }
export { Textarea };

View File

@@ -2,21 +2,24 @@
import { MoonIcon, SunIcon } from "@radix-ui/react-icons";
import { useTheme } from "next-themes";
import { Button } from "./button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "./tooltip";
import { Button } from "./button";
export function ThemeToggle() {
const { setTheme, theme: currentTheme } = useTheme();
const handleChangeTheme = (theme: "light" | "dark") => {
if (theme === currentTheme) return;
if (theme === currentTheme)
return;
if (!document.startViewTransition) return setTheme(theme);
if (!document.startViewTransition)
return setTheme(theme);
document.startViewTransition(() => setTheme(theme));
};
@@ -31,8 +34,7 @@ export function ThemeToggle() {
className="px-2"
aria-label="Toggle theme"
onClick={() =>
handleChangeTheme(currentTheme === "dark" ? "light" : "dark")
}
handleChangeTheme(currentTheme === "dark" ? "light" : "dark")}
>
<SunIcon className="size-[1.2rem] text-neutral-800 dark:hidden dark:text-neutral-200" />
<MoonIcon className="hidden size-[1.2rem] text-neutral-800 dark:block dark:text-neutral-200" />

View File

@@ -1,15 +1,15 @@
"use client"
"use client";
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
@@ -20,11 +20,11 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 origin-[--radix-tooltip-content-transform-origin]",
className
className,
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };