feat(frontend): add Skeleton primitive with scanline-shimmer
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type SkeletonVariant = "default" | "text" | "circle" | "row";
|
||||
|
||||
type SkeletonProps = {
|
||||
className?: string;
|
||||
variant?: SkeletonVariant;
|
||||
width?: string | number;
|
||||
height?: string | number;
|
||||
};
|
||||
|
||||
const variantClass: Record<SkeletonVariant, string> = {
|
||||
default: "rounded-md",
|
||||
text: "rounded-sm h-3 w-full",
|
||||
circle: "rounded-full",
|
||||
row: "rounded-md h-9 w-full",
|
||||
};
|
||||
|
||||
/**
|
||||
* Hairline loading primitive.
|
||||
* Voice: not a generic gray pulse — a 1px hairline ring with a slow
|
||||
* horizontal scanline that sweeps the surface, like a precision
|
||||
* instrument's sensor arm.
|
||||
*/
|
||||
export function Skeleton({
|
||||
className,
|
||||
variant = "default",
|
||||
width,
|
||||
height,
|
||||
}: SkeletonProps) {
|
||||
const style: React.CSSProperties = {
|
||||
...(width !== undefined ? { width } : null),
|
||||
...(height !== undefined ? { height } : null),
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative overflow-hidden bg-muted/30",
|
||||
"ring-1 ring-inset ring-border/40",
|
||||
variantClass[variant],
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
aria-busy="true"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-y-0 left-0 w-1/2 animate-shimmer"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(90deg, transparent 0%, hsl(var(--muted-foreground) / 0.08) 50%, transparent 100%)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user