// frontend\src\components\ui\Tabs.tsx 'use client' import * as React from 'react' import { ChevronDownIcon } from '@heroicons/react/16/solid' import clsx from 'clsx' export type TabIcon = React.ComponentType> export type TabItem = { id: string label: string count?: number | string icon?: TabIcon disabled?: boolean spinIcon?: boolean } export type TabsVariant = | 'underline' | 'underlineIcons' | 'pills' | 'pillsGray' | 'pillsBrand' | 'fullWidthUnderline' | 'barUnderline' | 'simple' type TabsProps = { tabs: TabItem[] value: string onChange: (id: string) => void className?: string ariaLabel?: string /** Siehe Variants aus pasted.txt */ variant?: TabsVariant /** * Optional: In der pasted.txt sind Badges teils erst ab md sichtbar. * Default: false (wie deine bisherige Komponente: immer sichtbar auf Desktop). */ hideCountUntilMd?: boolean } export default function Tabs({ tabs, value, onChange, className, ariaLabel = 'Ansicht auswählen', variant = 'underline', hideCountUntilMd = false, }: TabsProps) { if (!tabs?.length) return null const current = tabs.find((t) => t.id === value) ?? tabs[0] const mobileSelectClass = clsx( // entspricht den Beispielen (outline-1 + -outline-offset-1) 'col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-2 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 dark:text-gray-100 dark:outline-white/10 dark:*:bg-gray-800 dark:focus:outline-indigo-500', variant === 'pillsBrand' ? 'dark:bg-gray-800/50' : 'dark:bg-white/5' ) const countPillClass = (selected: boolean) => clsx( selected ? 'bg-indigo-100 text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-400' : 'bg-gray-100 text-gray-900 dark:bg-white/10 dark:text-gray-300', hideCountUntilMd ? 'ml-3 hidden rounded-full px-2.5 py-0.5 text-xs font-medium md:inline-block' : 'ml-3 rounded-full px-2.5 py-0.5 text-xs font-medium' ) const renderCount = (selected: boolean, tab: TabItem) => { if (tab.count === undefined) return null return {tab.count} } const renderDesktop = () => { switch (variant) { case 'underline': case 'underlineIcons': { return (
) } case 'pills': case 'pillsGray': case 'pillsBrand': { const active = variant === 'pills' ? 'bg-gray-100 text-gray-700 dark:bg-white/10 dark:text-gray-200' : variant === 'pillsGray' ? 'bg-gray-200 text-gray-800 dark:bg-white/10 dark:text-white' : 'bg-indigo-100 text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-300' const inactive = variant === 'pills' ? 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200' : variant === 'pillsGray' ? 'text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-white' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200' return ( ) } case 'fullWidthUnderline': { return (
) } case 'barUnderline': { return ( ) } case 'simple': { return ( ) } default: return null } } return (
{/* Mobile: Select + Chevron (wie Beispiele) */}
{/* Desktop */}
{renderDesktop()}
) }