feat: Add Table component for displaying tabular data

This commit is contained in:
Mauro Balades
2024-08-11 18:51:59 +02:00
parent 4de8fe0a93
commit c6424e3bff
5 changed files with 348 additions and 90 deletions

View File

@@ -0,0 +1,144 @@
'use client'
import type { CSSProperties, ReactElement, ReactNode } from 'react'
import { useEffect, useRef, useState } from 'react'
import { ny } from '@/lib/utils'
interface NeonColorsProps {
firstColor: string
secondColor: string
}
interface NeonGradientCardProps {
/**
* @default <div />
* @type ReactElement
* @description
* The component to be rendered as the card
*/
as?: ReactElement
/**
* @default ""
* @type string
* @description
* The className of the card
*/
className?: string
/**
* @default ""
* @type ReactNode
* @description
* The children of the card
*/
children?: ReactNode
/**
* @default 5
* @type number
* @description
* The size of the border in pixels
*/
borderSize?: number
/**
* @default 20
* @type number
* @description
* The size of the radius in pixels
*/
borderRadius?: number
/**
* @default "{ firstColor: '#ff00aa', secondColor: '#00FFF1' }"
* @type string
* @description
* The colors of the neon gradient
*/
neonColors?: NeonColorsProps
[key: string]: any
}
const NeonGradientCard: React.FC<NeonGradientCardProps> = ({
className,
children,
borderSize = 2,
borderRadius = 20,
neonColors = {
firstColor: '#ff00aa',
secondColor: '#00FFF1',
},
...props
}) => {
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 })
}
}
updateDimensions()
window.addEventListener('resize', updateDimensions)
return () => {
window.removeEventListener('resize', updateDimensions)
}
}, [])
useEffect(() => {
if (containerRef.current) {
const { offsetWidth, offsetHeight } = containerRef.current
setDimensions({ width: offsetWidth, height: offsetHeight })
}
}, [children])
return (
<div
ref={containerRef}
style={
{
'--border-size': `${borderSize}px`,
'--border-radius': `${borderRadius}px`,
'--neon-first-color': neonColors.firstColor,
'--neon-second-color': neonColors.secondColor,
'--card-width': `${dimensions.width}px`,
'--card-height': `${dimensions.height}px`,
'--card-content-radius': `${borderRadius - borderSize}px`,
'--pseudo-element-background-image': `linear-gradient(0deg, ${neonColors.firstColor}, ${neonColors.secondColor})`,
'--pseudo-element-width': `${dimensions.width + borderSize * 2}px`,
'--pseudo-element-height': `${dimensions.height + borderSize * 2}px`,
'--after-blur': `${dimensions.width / 3}px`,
} as CSSProperties
}
className={ny(
'relative z-10 size-full rounded-[var(--border-radius)]',
className,
)}
{...props}
>
<div
className={ny(
'relative size-full min-h-[inherit] rounded-[var(--card-content-radius)] bg-gray-100 p-6',
'before:absolute before:-left-[var(--border-size)] before:-top-[var(--border-size)] before:-z-10 before:block',
'before:h-[var(--pseudo-element-height)] before:w-[var(--pseudo-element-width)] before:rounded-[var(--border-radius)] before:content-[\'\']',
'before:bg-[linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color))] before:bg-[length:100%_200%]',
'before:animate-backgroundPositionSpin',
'after:absolute after:-left-[var(--border-size)] after:-top-[var(--border-size)] after:-z-10 after:block',
'after:h-[var(--pseudo-element-height)] after:w-[var(--pseudo-element-width)] after:rounded-[var(--border-radius)] after:blur-[var(--after-blur)] after:content-[\'\']',
'after:bg-[linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color))] after:bg-[length:100%_200%] after:opacity-80',
'after:animate-backgroundPositionSpin',
'dark:bg-neutral-900',
)}
>
{children}
</div>
</div>
)
}
export { NeonGradientCard }