- Updated dependencies in bun.lock and package.json to specific versions for better stability. - Added a new Contact component to display contact methods with tooltips. - Introduced a Banner component for notifications with customizable actions. - Enhanced the Dialog, Checkbox, Button, Input, and Label components for better usability and styling. - Integrated react-snowfall for a snow effect in the main page. - Added a Discord SVG icon to the project.
123 lines
No EOL
3.1 KiB
TypeScript
123 lines
No EOL
3.1 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import { X } from "lucide-react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
function Grid({
|
|
cellSize = 12,
|
|
strokeWidth = 1,
|
|
patternOffset = [0, 0],
|
|
className,
|
|
}: {
|
|
cellSize?: number
|
|
strokeWidth?: number
|
|
patternOffset?: [number, number]
|
|
className?: string
|
|
}) {
|
|
const id = React.useId()
|
|
|
|
return (
|
|
<svg
|
|
className={cn(
|
|
"pointer-events-none absolute inset-0 text-black/10",
|
|
className,
|
|
)}
|
|
width="100%"
|
|
height="100%"
|
|
>
|
|
<defs>
|
|
<pattern
|
|
id={`grid-${id}`}
|
|
x={patternOffset[0] - 1}
|
|
y={patternOffset[1] - 1}
|
|
width={cellSize}
|
|
height={cellSize}
|
|
patternUnits="userSpaceOnUse"
|
|
>
|
|
<path
|
|
d={`M ${cellSize} 0 L 0 0 0 ${cellSize}`}
|
|
fill="transparent"
|
|
stroke="currentColor"
|
|
strokeWidth={strokeWidth}
|
|
/>
|
|
</pattern>
|
|
</defs>
|
|
<rect fill={`url(#grid-${id})`} width="100%" height="100%" />
|
|
</svg>
|
|
)
|
|
}
|
|
|
|
interface BannerProps {
|
|
show: boolean
|
|
onHide: () => void
|
|
icon?: React.ReactNode
|
|
title: React.ReactNode
|
|
action: {
|
|
label: string
|
|
onClick: () => void
|
|
}
|
|
learnMoreUrl?: string
|
|
}
|
|
|
|
export function Banner({
|
|
show,
|
|
onHide,
|
|
icon,
|
|
title,
|
|
action,
|
|
learnMoreUrl,
|
|
}: BannerProps) {
|
|
if (!show) return null
|
|
|
|
return (
|
|
<div className="relative isolate flex flex-col justify-between gap-3 overflow-hidden rounded-lg border border-green-600/15 bg-gradient-to-r from-lime-100/80 to-emerald-100/80 py-3 pl-4 pr-12 sm:flex-row sm:items-center sm:py-2">
|
|
<Grid
|
|
cellSize={13}
|
|
patternOffset={[0, -1]}
|
|
className="text-black/30 mix-blend-overlay [mask-image:linear-gradient(to_right,black,transparent)] md:[mask-image:linear-gradient(to_right,black_60%,transparent)]"
|
|
/>
|
|
|
|
<div className="flex items-center gap-3">
|
|
{icon && (
|
|
<div className="hidden rounded-full border border-green-600/50 bg-white/50 p-1 shadow-[inset_0_0_1px_1px_#fff] sm:block">
|
|
{icon}
|
|
</div>
|
|
)}
|
|
<p className="text-sm text-gray-900">
|
|
{title}
|
|
{learnMoreUrl && (
|
|
<>
|
|
{" "}
|
|
<a
|
|
href={learnMoreUrl}
|
|
target="_blank"
|
|
className="text-gray-700 underline transition-colors hover:text-black"
|
|
>
|
|
Learn more
|
|
</a>
|
|
</>
|
|
)}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex items-center sm:-my-1">
|
|
<button
|
|
type="button"
|
|
className="whitespace-nowrap rounded-md border border-green-700/50 px-3 py-1 text-sm text-gray-800 transition-colors hover:bg-green-500/10"
|
|
onClick={action.onClick}
|
|
>
|
|
{action.label}
|
|
</button>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
className="absolute inset-y-0 right-2.5 p-1 text-sm text-green-700 underline transition-colors hover:text-green-900"
|
|
onClick={onHide}
|
|
>
|
|
<X className="h-[18px] w-[18px]" />
|
|
</button>
|
|
</div>
|
|
)
|
|
} |