kv-tube/frontend/app/components/LoadingSpinner.tsx
2026-03-26 13:11:20 +07:00

75 lines
2 KiB
TypeScript

'use client';
interface LoadingSpinnerProps {
size?: 'small' | 'medium' | 'large';
fullScreen?: boolean;
text?: string;
color?: 'primary' | 'white';
}
const sizeMap = {
small: { spinner: 24, border: 2 },
medium: { spinner: 36, border: 3 },
large: { spinner: 48, border: 4 },
};
export default function LoadingSpinner({
size = 'medium',
fullScreen = false,
text,
color = 'primary'
}: LoadingSpinnerProps) {
const { spinner, border } = sizeMap[size];
const spinnerColor = color === 'white' ? '#fff' : 'var(--yt-text-primary)';
const borderColor = color === 'white' ? 'rgba(255,255,255,0.2)' : 'var(--yt-border)';
const content = (
<div style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: '12px',
}}>
<div style={{
width: `${spinner}px`,
height: `${spinner}px`,
border: `${border}px solid ${borderColor}`,
borderTop: `${border}px solid ${spinnerColor}`,
borderRadius: '50%',
animation: 'spin 1s linear infinite',
}} />
{text && (
<span style={{
fontSize: '14px',
color: 'var(--yt-text-secondary)',
}}>
{text}
</span>
)}
<style jsx>{`
@keyframes spin {
to { transform: rotate(360deg); }
}
`}</style>
</div>
);
if (fullScreen) {
return (
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100vh',
backgroundColor: 'var(--yt-background)',
}}>
{content}
</div>
);
}
return content;
}