75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
'use client';
|
||
|
||
import React from 'react';
|
||
import clsx from 'clsx';
|
||
|
||
type LoadingSpinnerProps = {
|
||
showBackground?: boolean;
|
||
showBorder?: boolean;
|
||
/** kleiner Spinner ohne äußeres Layout – z.B. im Button */
|
||
inline?: boolean;
|
||
/** Größe des Spinners */
|
||
size?: 'sm' | 'md' | 'lg';
|
||
/** Zusätzliche Klassen (z.B. text-current) */
|
||
className?: string;
|
||
};
|
||
|
||
const sizeClasses = {
|
||
sm: 'size-4 border-2',
|
||
md: 'size-6 border-3',
|
||
lg: 'size-8 border-4',
|
||
};
|
||
|
||
export default function LoadingSpinner({
|
||
showBackground = false,
|
||
showBorder = false,
|
||
inline = false,
|
||
size = 'md',
|
||
className,
|
||
}: LoadingSpinnerProps) {
|
||
// INLINE: nur der Kreis – perfekt für Buttons/Labels
|
||
if (inline) {
|
||
return (
|
||
<span className={clsx('inline-flex items-center', className)}>
|
||
<span
|
||
className={clsx(
|
||
'animate-spin inline-block rounded-full border-current border-t-transparent',
|
||
sizeClasses[size]
|
||
)}
|
||
role="status"
|
||
aria-label="loading"
|
||
>
|
||
<span className="sr-only">Lädt...</span>
|
||
</span>
|
||
</span>
|
||
);
|
||
}
|
||
|
||
// BLOCK: dein bisheriges Layout
|
||
const outerClasses = [
|
||
'flex flex-col flex-1 justify-center items-center',
|
||
showBackground && 'bg-white shadow-2xs dark:bg-neutral-800 dark:shadow-neutral-700/70',
|
||
showBorder && 'border border-gray-200 dark:border-neutral-700',
|
||
]
|
||
.filter(Boolean)
|
||
.join(' ');
|
||
|
||
return (
|
||
<div className={outerClasses}>
|
||
<div className="flex justify-center items-center">
|
||
<div
|
||
className={clsx(
|
||
'animate-spin inline-block rounded-full border-current border-t-transparent',
|
||
'text-blue-600 dark:text-blue-500',
|
||
sizeClasses[size]
|
||
)}
|
||
role="status"
|
||
aria-label="loading"
|
||
>
|
||
<span className="sr-only">Lädt...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|