Files
e-tib.com/components/ui/Heading.tsx
Marc Mintel 275a857554
Some checks failed
Build & Deploy / 🔍 Prepare (push) Failing after 4s
Build & Deploy / 🧪 QA (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
fix: ui component updates and project formatting
2026-06-17 15:38:56 +02:00

94 lines
3.3 KiB
TypeScript

import React from 'react';
import { cn } from './utils';
export type HeadingVariant = 'primary' | 'neutral' | 'white' | 'dark';
export type HeadingSize = 'hero' | 'section' | 'subsection' | 'card' | 'small' | '1' | '2' | '3' | '4' | '5' | '6';
interface HeadingProps {
level?: 1 | 2 | 3 | 4 | 5 | 6;
size?: HeadingSize;
variant?: HeadingVariant;
align?: 'left' | 'center' | 'right';
subtitle?: React.ReactNode;
children: React.ReactNode;
className?: string;
subtitleClassName?: string;
badgeStyle?: 'industrial' | 'simple';
}
export function Heading({
level = 2,
size,
variant = 'dark',
align = 'left',
subtitle,
children,
className,
subtitleClassName,
badgeStyle = 'industrial'
}: HeadingProps) {
const Tag = `h${level}` as any;
const effectiveSize = size || String(level) as HeadingSize;
const sizes: Record<string, string> = {
'hero': 'font-heading text-3xl md:text-5xl lg:text-6xl font-black tracking-tight !leading-[0.9]',
'section': 'font-heading text-3xl md:text-4xl lg:text-5xl font-extrabold tracking-tight !leading-[0.95]',
'subsection': 'font-heading text-xl md:text-3xl lg:text-4xl font-bold tracking-tight leading-tight',
'card': 'text-xl md:text-2xl font-bold leading-snug',
'small': 'text-lg font-semibold leading-snug',
// Legacy support
'1': 'text-2xl md:text-4xl lg:text-5xl font-bold leading-[0.9] tracking-tight',
'2': 'text-xl md:text-3xl lg:text-4xl font-bold leading-[0.95] tracking-tight',
'3': 'text-lg md:text-2xl lg:text-3xl font-bold leading-tight tracking-tight',
'4': 'text-lg md:text-xl lg:text-2xl font-bold leading-snug',
'5': 'text-base md:text-lg font-bold leading-normal',
'6': 'text-base md:text-lg font-semibold leading-normal',
};
const variants = {
primary: 'text-primary',
neutral: 'text-text-primary',
white: 'text-white',
dark: 'text-neutral-dark',
};
const alignments = {
left: 'text-left',
center: 'text-center mx-auto',
right: 'text-right',
};
return (
<div className={cn('mb-6 md:mb-8', alignments[align], className)}>
{subtitle && badgeStyle === 'industrial' && (
<span className={cn(
"inline-flex items-center space-x-2 px-3 py-1.5 rounded-full mb-6 border shadow-sm text-xs font-bold uppercase tracking-widest",
variant === 'white' ? 'bg-white/10 text-white border-white/20' : 'bg-primary/5 text-primary border-primary/20',
subtitleClassName
)}>
<span className="relative flex h-2 w-2">
<span className={cn("animate-ping absolute inline-flex h-full w-full rounded-full opacity-75", variant === 'white' ? 'bg-white' : 'bg-primary')}></span>
<span className={cn("relative inline-flex rounded-full h-2 w-2", variant === 'white' ? 'bg-white' : 'bg-primary')}></span>
</span>
<span>{subtitle}</span>
</span>
)}
{subtitle && badgeStyle === 'simple' && (
<span className={cn(
"inline-block font-bold tracking-widest uppercase text-xs md:text-sm mb-3 md:mb-4 animate-fade-in",
variant === 'white' ? 'text-white/80' : 'text-accent',
subtitleClassName
)}>
{subtitle}
</span>
)}
<Tag className={cn(sizes[effectiveSize], variants[variant])}>
{children}
</Tag>
</div>
);
}