geraete/components/ui/Skeleton.tsx
2025-11-14 17:03:26 +01:00

68 lines
2.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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>
);
}