68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
// components/ui/Skeleton.tsx
|
||
'use client';
|
||
|
||
import * as React from 'react';
|
||
|
||
function classNames(...classes: Array<string | boolean | null | undefined>) {
|
||
return classes.filter(Boolean).join(' ');
|
||
}
|
||
|
||
type SkeletonProps = {
|
||
/** Zusätzliche Klassen für den Wrapper */
|
||
className?: string;
|
||
/** Beschriftung für Screenreader – z.B. "Benutzer" */
|
||
primaryLabel?: string;
|
||
/** Zweite Zeile für Screenreader – z.B. "Profildaten werden geladen" */
|
||
secondaryLabel?: string;
|
||
};
|
||
|
||
/**
|
||
* Hilfsfunktion: wähle eine Tailwind-Breite basierend auf der Textlänge.
|
||
* Wenn kein Text -> keine Breitenklasse (keine Simulation).
|
||
*/
|
||
function getWidthClass(label?: string) {
|
||
const len = (label ?? '').length;
|
||
|
||
if (len === 0) return ''; // keine Breite, wenn kein Text
|
||
if (len <= 6) return 'w-16'; // kurz
|
||
if (len <= 12) return 'w-24'; // mittel
|
||
if (len <= 20) return 'w-32'; // länger
|
||
return 'w-40'; // sehr lang
|
||
}
|
||
|
||
/**
|
||
* Skeleton-Placeholder für das User-Menü (Avatar + Text).
|
||
* Es werden nur Balken gerendert, wenn auch Labels übergeben wurden.
|
||
*/
|
||
export function Skeleton({
|
||
className,
|
||
primaryLabel,
|
||
secondaryLabel,
|
||
}: SkeletonProps) {
|
||
const primaryWidthClass = getWidthClass(primaryLabel);
|
||
const secondaryWidthClass = getWidthClass(secondaryLabel);
|
||
|
||
const srText = [primaryLabel, secondaryLabel].filter(Boolean).join(' – ');
|
||
|
||
return (
|
||
<div className={classNames('flex animate-pulse items-center space-x-4', className)}>
|
||
{/* Nur für Screenreader, wenn überhaupt Text vorhanden */}
|
||
{srText && <span className="sr-only">{srText}</span>}
|
||
|
||
<div className="size-8 rounded-full bg-gray-200 dark:bg-gray-700" />
|
||
|
||
<div className="space-y-2">
|
||
{/* erste Zeile – nur wenn primaryLabel gesetzt ist */}
|
||
{primaryLabel && (
|
||
<div
|
||
className={classNames(
|
||
'h-2 rounded bg-gray-200 dark:bg-gray-700',
|
||
primaryWidthClass,
|
||
)}
|
||
/>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|