'use client';
import { forwardRef, HTMLAttributes, useEffect, useState } from 'react';
export interface ScrollIndicatorProps extends HTMLAttributes {
text?: string;
showArrow?: boolean;
showPercentage?: boolean;
variant?: 'default' | 'blood' | 'minimal';
position?: 'right' | 'left';
trackHeight?: number;
}
const variantStyles: Record = {
default: {
track: 'bg-stone-700',
thumb: 'bg-amber-500 shadow-[0_0_10px_rgba(201,162,39,0.3)]',
text: 'text-stone-500',
},
blood: {
track: 'bg-red-500/20',
thumb: 'bg-red-500 shadow-[0_0_10px_rgba(255,0,64,0.5)]',
text: 'text-gray-500',
},
minimal: {
track: 'bg-stone-700',
thumb: 'bg-amber-500',
text: 'text-stone-500',
},
};
export const ScrollIndicator = forwardRef(
({ text = 'SCROLL', showArrow = false, showPercentage = false, variant = 'default', position = 'right', trackHeight = 100, className, ...props }, ref) => {
const [scrollProgress, setScrollProgress] = useState(0);
useEffect(() => {
const handleScroll = () => {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
setScrollProgress(Math.min(100, Math.max(0, progress)));
};
window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll();
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const colors = variantStyles[variant];
const thumbTop = (scrollProgress / 100) * (trackHeight - 20);
const isMinimal = variant === 'minimal';
return (
{showArrow && (
↓
)}
{text && !isMinimal && (
{text}
)}
{showPercentage && (
{Math.round(scrollProgress)}%
)}
);
}
);
ScrollIndicator.displayName = 'ScrollIndicator';
export default ScrollIndicator;