Files
gridpilot.gg/apps/website/ui/Heading.tsx
2026-01-17 02:32:34 +01:00

82 lines
2.4 KiB
TypeScript

import React, { ReactNode, ElementType } from 'react';
import { Stack } from './Stack';
import { Box, BoxProps } from './Box';
interface ResponsiveFontSize {
base?: string;
sm?: string;
md?: string;
lg?: string;
xl?: string;
'2xl'?: string;
}
interface HeadingProps extends Omit<BoxProps<'h1'>, 'children' | 'as' | 'fontSize'> {
level: 1 | 2 | 3 | 4 | 5 | 6;
children: ReactNode;
icon?: ReactNode;
id?: string;
groupHoverColor?: string;
truncate?: boolean;
fontSize?: string | ResponsiveFontSize;
weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
}
export function Heading({ level, children, icon, groupHoverColor, truncate, fontSize, weight, ...props }: HeadingProps) {
const Tag = `h${level}` as ElementType;
const levelClasses = {
1: 'text-3xl md:text-4xl font-bold text-white tracking-tight',
2: 'text-xl md:text-2xl font-bold text-white tracking-tight',
3: 'text-lg font-bold text-white tracking-tight',
4: 'text-base font-bold text-white tracking-tight',
5: 'text-sm font-bold text-white tracking-tight uppercase tracking-wider',
6: 'text-xs font-bold text-white tracking-tight uppercase tracking-widest',
};
const weightClasses = {
light: 'font-light',
normal: 'font-normal',
medium: 'font-medium',
semibold: 'font-semibold',
bold: 'font-bold'
};
const getFontSizeClasses = (value: string | ResponsiveFontSize | undefined) => {
if (value === undefined) return '';
if (typeof value === 'object') {
const classes = [];
if (value.base) classes.push(`text-${value.base}`);
if (value.sm) classes.push(`sm:text-${value.sm}`);
if (value.md) classes.push(`md:text-${value.md}`);
if (value.lg) classes.push(`lg:text-${value.lg}`);
if (value.xl) classes.push(`xl:text-${value.xl}`);
if (value['2xl']) classes.push(`2xl:text-${value['2xl']}`);
return classes.join(' ');
}
return `text-${value}`;
};
const content = icon ? (
<Stack direction="row" align="center" gap={2}>
{icon}
{children}
</Stack>
) : children;
const classes = [
levelClasses[level],
getFontSizeClasses(fontSize),
weight ? weightClasses[weight] : '',
groupHoverColor ? `group-hover:text-${groupHoverColor}` : '',
truncate ? 'truncate' : '',
props.className
].filter(Boolean).join(' ');
return (
<Box as={Tag} {...props} className={classes}>
{content}
</Box>
);
}