diff --git a/apps/website/components/drivers/DriverCard.tsx b/apps/website/components/drivers/DriverCard.tsx index 606120996..21c121ccc 100644 --- a/apps/website/components/drivers/DriverCard.tsx +++ b/apps/website/components/drivers/DriverCard.tsx @@ -2,8 +2,10 @@ import { DriverIdentity } from '@/ui/DriverIdentity'; import { ProfileCard } from '@/ui/ProfileCard'; -import { StatGrid } from '@/ui/StatGrid'; import { Badge } from '@/ui/Badge'; +import { Grid } from '@/ui/Grid'; +import { Stack } from '@/ui/Stack'; +import { Text } from '@/ui/Text'; import { Flag, Trophy, Medal } from 'lucide-react'; interface DriverCardProps { @@ -23,12 +25,6 @@ interface DriverCardProps { } export function DriverCard({ driver, onClick }: DriverCardProps) { - const stats = [ - { label: 'Races', value: driver.racesCompleted, intent: 'low', icon: Flag }, - { label: 'Wins', value: driver.wins, intent: 'primary', icon: Trophy }, - { label: 'Podiums', value: driver.podiums, intent: 'warning', icon: Medal }, - ]; - return ( onClick(driver.id)} @@ -50,16 +46,20 @@ export function DriverCard({ driver, onClick }: DriverCardProps) { } stats={ - ({ - label: s.label, - value: s.value, - intent: s.intent as any, - icon: s.icon - }))} - columns={3} - variant="box" - /> + + + Races + {driver.racesCompleted} + + + Wins + {driver.wins} + + + Podiums + {driver.podiums} + + } /> ); diff --git a/apps/website/components/home/CtaSection.tsx b/apps/website/components/home/CtaSection.tsx index 1c13ef31f..4c76f077c 100644 --- a/apps/website/components/home/CtaSection.tsx +++ b/apps/website/components/home/CtaSection.tsx @@ -9,6 +9,7 @@ import { Group } from '@/ui/Group'; import { Box } from '@/ui/Box'; import { Panel } from '@/ui/Panel'; import { Stack } from '@/ui/Stack'; +import { Icon } from '@/ui/Icon'; import { Trophy } from 'lucide-react'; /** @@ -17,23 +18,23 @@ import { Trophy } from 'lucide-react'; */ export function CtaSection() { return ( -
+
- - - - - + + + - - Ready to elevate your league? - - - Join the growing ecosystem of professional sim racing leagues. - Start for free and scale as your community grows. - - + + + Ready to elevate your league? + + + Join the growing ecosystem of professional sim racing leagues. + Start for free and scale as your community grows. + + + diff --git a/apps/website/components/home/StewardingPreview.tsx b/apps/website/components/home/StewardingPreview.tsx index 7fb70780a..f18074761 100644 --- a/apps/website/components/home/StewardingPreview.tsx +++ b/apps/website/components/home/StewardingPreview.tsx @@ -11,6 +11,7 @@ import { Group } from '@/ui/Group'; import { Stack } from '@/ui/Stack'; import { Grid } from '@/ui/Grid'; import { Box } from '@/ui/Box'; +import { Icon } from '@/ui/Icon'; import { Gavel, Clock, User, MessageSquare } from 'lucide-react'; interface StewardingPreviewProps { @@ -38,15 +39,15 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { const teamName = team?.name || 'Alex Miller'; return ( -
- - - Structured Stewarding +
+ + + Structured Stewarding Protests are part of racing. Managing them shouldn't be a second job. GridPilot provides a dedicated workflow for drivers to report incidents and for you to resolve them with precision. - + @@ -66,7 +67,7 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { - + Protestor {teamName} @@ -76,7 +77,7 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { - + Defendant David Chen @@ -86,7 +87,7 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { - + Session Info Lap 1, 00:42.150 @@ -97,7 +98,7 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { - + Description @@ -110,11 +111,11 @@ export function StewardingPreview({ race, team }: StewardingPreviewProps) { - + - +
); } diff --git a/apps/website/components/home/ValuePillars.tsx b/apps/website/components/home/ValuePillars.tsx index 43bd13e0e..42d2f497c 100644 --- a/apps/website/components/home/ValuePillars.tsx +++ b/apps/website/components/home/ValuePillars.tsx @@ -31,19 +31,17 @@ export function ValuePillars() { ]; return ( -
- - - {pillars.map((pillar) => ( - - ))} - - +
+ + {pillars.map((pillar) => ( + + ))} +
); } diff --git a/apps/website/components/landing/FeatureGrid.tsx b/apps/website/components/landing/FeatureGrid.tsx index 9d63695ce..562b1fd70 100644 --- a/apps/website/components/landing/FeatureGrid.tsx +++ b/apps/website/components/landing/FeatureGrid.tsx @@ -99,7 +99,7 @@ function FeatureCard({ feature, index }: { feature: typeof features[0], index: n export function FeatureGrid() { return ( -
+
diff --git a/apps/website/components/leaderboards/RankingRow.tsx b/apps/website/components/leaderboards/RankingRow.tsx index 0bab065be..811875487 100644 --- a/apps/website/components/leaderboards/RankingRow.tsx +++ b/apps/website/components/leaderboards/RankingRow.tsx @@ -63,7 +63,7 @@ export function RankingRow({ {nationality} - + {SkillLevelDisplay.getLabel(skillLevel)} @@ -76,7 +76,7 @@ export function RankingRow({ {racesCompleted} - + Races @@ -84,7 +84,7 @@ export function RankingRow({ {RatingDisplay.format(rating)} - + Rating @@ -92,7 +92,7 @@ export function RankingRow({ {wins} - + Wins diff --git a/apps/website/components/leaderboards/TeamRankingRow.tsx b/apps/website/components/leaderboards/TeamRankingRow.tsx index 1ac7432ec..90f725360 100644 --- a/apps/website/components/leaderboards/TeamRankingRow.tsx +++ b/apps/website/components/leaderboards/TeamRankingRow.tsx @@ -61,7 +61,7 @@ export function TeamRankingRow({ {races} - + Races @@ -69,7 +69,7 @@ export function TeamRankingRow({ {rating} - + Rating @@ -77,7 +77,7 @@ export function TeamRankingRow({ {wins} - + Wins diff --git a/apps/website/components/teams/TeamCard.tsx b/apps/website/components/teams/TeamCard.tsx index d0494fbfe..e6f576641 100644 --- a/apps/website/components/teams/TeamCard.tsx +++ b/apps/website/components/teams/TeamCard.tsx @@ -105,15 +105,15 @@ export function TeamCard({ {/* Technical Stats Grid - Engineered Look */} - Rating + Rating {data.ratingLabel} - Wins + Wins {data.winsLabel} - Races + Races {data.racesLabel} diff --git a/apps/website/templates/DriverProfileTemplate.tsx b/apps/website/templates/DriverProfileTemplate.tsx index e40073b58..9752f531b 100644 --- a/apps/website/templates/DriverProfileTemplate.tsx +++ b/apps/website/templates/DriverProfileTemplate.tsx @@ -50,7 +50,7 @@ export function DriverProfileTemplate({ }: DriverProfileTemplateProps) { if (isLoading) { return ( - + Loading driver profile... @@ -61,7 +61,7 @@ export function DriverProfileTemplate({ if (error || !viewData?.currentDriver) { return ( - + {error || 'Driver not found'} - } - /> - - - + + Leaderboard + + } /> - - - onSearchChange(e.target.value)} - icon={Search} - variant="search" - /> - + + - {filteredDrivers.length > 0 ? ( - - {filteredDrivers.map(driver => ( - onSearchChange(e.target.value)} + icon={Search} + variant="search" + /> + + {filteredDrivers.length > 0 ? ( + + {filteredDrivers.map(driver => ( + + ))} + + ) : ( + - ))} - - ) : ( - - )} + )} + +
); } diff --git a/apps/website/templates/HomeTemplate.tsx b/apps/website/templates/HomeTemplate.tsx index b0dbbdc22..0973bba59 100644 --- a/apps/website/templates/HomeTemplate.tsx +++ b/apps/website/templates/HomeTemplate.tsx @@ -42,31 +42,33 @@ interface HomeTemplateProps { export function HomeTemplate({ viewData }: HomeTemplateProps) { return (
- {/* Hero Section - Admin Focus */} - + + {/* Hero Section - Admin Focus */} + - {/* Admin Pain/Solution Strip */} - + {/* Admin Pain/Solution Strip */} + - {/* Core Admin Features */} - + {/* Core Admin Features */} + - {/* Stewarding Workflow Preview */} - + {/* Stewarding Workflow Preview */} + - {/* League Identity Showcase */} - + {/* League Identity Showcase */} + - {/* Migration Offer */} - + {/* Migration Offer */} + - {/* Final CTA */} - + {/* Final CTA */} + +
); } diff --git a/apps/website/templates/LeaderboardsTemplate.tsx b/apps/website/templates/LeaderboardsTemplate.tsx index a01db7d54..436859028 100644 --- a/apps/website/templates/LeaderboardsTemplate.tsx +++ b/apps/website/templates/LeaderboardsTemplate.tsx @@ -42,71 +42,69 @@ export function LeaderboardsTemplate({ .slice(0, 5); return ( -
- - - - - - - } - /> +
+ + + + + + } + /> - {/* Top 10 2026 up top */} - + {/* Top 10 2026 up top */} + - - ({ - ...t, - logoUrl: t.logoUrl || '' - }))} - onTeamClick={onTeamClick} - onNavigateToTeams={onNavigateToTeams} + + ({ + ...t, + logoUrl: t.logoUrl || '' + }))} + onTeamClick={onTeamClick} + onNavigateToTeams={onNavigateToTeams} + /> + + + - - - - - - - - + + + +
); } diff --git a/apps/website/templates/LeaguesTemplate.tsx b/apps/website/templates/LeaguesTemplate.tsx index 3bf874c05..61ca62097 100644 --- a/apps/website/templates/LeaguesTemplate.tsx +++ b/apps/website/templates/LeaguesTemplate.tsx @@ -8,6 +8,8 @@ import { Input } from '@/ui/Input'; import { Button } from '@/ui/Button'; import { Group } from '@/ui/Group'; import { Container } from '@/ui/Container'; +import { Stack } from '@/ui/Stack'; +import { Surface } from '@/ui/Surface'; import { Text } from '@/ui/Text'; import { Icon } from '@/ui/Icon'; import { Section } from '@/ui/Section'; @@ -71,7 +73,7 @@ export function LeaguesTemplate({ onClearFilters, }: LeaguesTemplateProps) { return ( -
+
{/* Header Section */} } + icon={} > Create League } /> - {/* Stats Overview */} - + + {/* Stats Overview */} - - {/* Control Bar */} - - - ({ - id: c.id, - label: c.label, - icon: - }))} - activeId={activeCategory} - onChange={(id) => onCategoryChange(id as CategoryId)} - /> - - } - > - ) => onSearchChange(e.target.value)} - icon={} - size="sm" - width="300px" - /> - + {/* Control Bar */} + + + ({ + id: c.id, + label: c.label, + icon: + }))} + activeId={activeCategory} + onChange={(id) => onCategoryChange(id as CategoryId)} + /> + + } + > + ) => onSearchChange(e.target.value)} + icon={} + size="sm" + /> + - {/* Results */} - + {/* Results */} {filteredLeagues.length > 0 ? ( {filteredLeagues.map((league) => ( @@ -154,23 +153,23 @@ export function LeaguesTemplate({ ))} ) : ( -
- + + - + No results found Adjust filters to find matching infrastructure. - + - -
+ + )} -
+
); } diff --git a/apps/website/templates/ProfileLayoutShellTemplate.tsx b/apps/website/templates/ProfileLayoutShellTemplate.tsx index faba9017d..aea4bdbaa 100644 --- a/apps/website/templates/ProfileLayoutShellTemplate.tsx +++ b/apps/website/templates/ProfileLayoutShellTemplate.tsx @@ -13,7 +13,7 @@ interface ProfileLayoutShellTemplateProps { export function ProfileLayoutShellTemplate({ viewData, children }: ProfileLayoutShellTemplateProps) { return ( - + diff --git a/apps/website/templates/RaceDetailTemplate.tsx b/apps/website/templates/RaceDetailTemplate.tsx index fae1effa4..989d9bbca 100644 --- a/apps/website/templates/RaceDetailTemplate.tsx +++ b/apps/website/templates/RaceDetailTemplate.tsx @@ -117,7 +117,7 @@ export function RaceDetailTemplate({ }: RaceDetailTemplateProps) { if (isLoading) { return ( - + @@ -134,7 +134,7 @@ export function RaceDetailTemplate({ if (error || !viewData || !viewData.race) { return ( - + Race Not Found @@ -174,7 +174,7 @@ export function RaceDetailTemplate({ onBack={onBack} /> - + {userResult && ( + Loading results... @@ -56,7 +56,7 @@ export function RaceResultsTemplate({ if (error && !viewData.raceTrack) { return ( - + {error?.message || 'Race not found'} @@ -93,7 +93,7 @@ export function RaceResultsTemplate({ onBack={onBack} /> - + {importSuccess && ( diff --git a/apps/website/templates/RaceStewardingTemplate.tsx b/apps/website/templates/RaceStewardingTemplate.tsx index 7154e3965..13b57e373 100644 --- a/apps/website/templates/RaceStewardingTemplate.tsx +++ b/apps/website/templates/RaceStewardingTemplate.tsx @@ -46,7 +46,7 @@ export function RaceStewardingTemplate({ if (isLoading) { return ( - + Loading stewarding data... @@ -56,7 +56,7 @@ export function RaceStewardingTemplate({ if (!viewData?.race) { return ( - + Race Not Found @@ -94,7 +94,7 @@ export function RaceStewardingTemplate({ onBack={onBack} /> - + diff --git a/apps/website/templates/RacesIndexTemplate.tsx b/apps/website/templates/RacesIndexTemplate.tsx index 1673cea9a..a40ccb155 100644 --- a/apps/website/templates/RacesIndexTemplate.tsx +++ b/apps/website/templates/RacesIndexTemplate.tsx @@ -9,7 +9,9 @@ import { NextUpRacePanel } from '@/components/races/NextUpRacePanel'; import { RacesDayGroup } from '@/components/races/RacesDayGroup'; import { RacesEmptyState } from '@/components/races/RacesEmptyState'; import { RaceFilterModal } from '@/components/races/RaceFilterModal'; -import { PageHeader } from '@/components/shared/PageHeader'; +import { PageHeader } from '@/ui/PageHeader'; +import { Stack } from '@/ui/Stack'; +import { Flag } from 'lucide-react'; import type { RacesViewData, RaceViewData } from '@/lib/view-data/RacesViewData'; export interface RacesIndexTemplateProps { @@ -45,22 +47,21 @@ export function RacesIndexTemplate({ const hasRaces = viewData.racesByDate.length > 0; return ( -
+
- {/* 1. Status Rail: Live sessions first */} - + + {/* 1. Status Rail: Live sessions first */} - - {/* 2. Command Bar: Fast filters */} - + {/* 2. Command Bar: Fast filters */} setShowFilterModal(true)} /> - - {/* 3. Next Up: High signal panel */} - {timeFilter === 'upcoming' && viewData.nextUpRace && ( - + {/* 3. Next Up: High signal panel */} + {timeFilter === 'upcoming' && viewData.nextUpRace && ( - - )} + )} - {/* 4. Browse by Day: Grouped schedule */} - {hasRaces ? ( - - {viewData.racesByDate.map((group) => ( - + {/* 4. Browse by Day: Grouped schedule */} + {hasRaces ? ( + + {viewData.racesByDate.map((group) => ( - - ))} - - ) : ( - - )} + ))} + + ) : ( + + )} + + + + {/* Header */} + {/* Breadcrumb */} diff --git a/apps/website/templates/SponsorSettingsTemplate.tsx b/apps/website/templates/SponsorSettingsTemplate.tsx index 61092baa7..42a189544 100644 --- a/apps/website/templates/SponsorSettingsTemplate.tsx +++ b/apps/website/templates/SponsorSettingsTemplate.tsx @@ -82,7 +82,7 @@ export function SponsorSettingsTemplate({ saving, }: SponsorSettingsTemplateProps) { return ( - + - }> + }> Danger Zone diff --git a/apps/website/templates/TeamRankingsTemplate.tsx b/apps/website/templates/TeamRankingsTemplate.tsx index 795f16550..a2bb30027 100644 --- a/apps/website/templates/TeamRankingsTemplate.tsx +++ b/apps/website/templates/TeamRankingsTemplate.tsx @@ -26,7 +26,7 @@ export function TeamRankingsTemplate({ onBackToLeaderboards, }: TeamRankingsTemplateProps): React.ReactElement { return ( - + { @@ -63,21 +66,32 @@ export function TeamsTemplate({ }, [teams, filteredTeams, searchQuery]); return ( -
- - - +
+ + Leaderboard + + } + /> + + - - {clusters.length > 0 ? ( - - {clusters.map((cluster, index) => ( - + {clusters.length > 0 ? ( + + {clusters.map((cluster) => ( @@ -89,21 +103,21 @@ export function TeamsTemplate({ /> ))} - - ))} - - ) : ( - - )} + ))} + + ) : ( + + )} +
); } diff --git a/apps/website/ui/Card.tsx b/apps/website/ui/Card.tsx index 87eeb8108..5f8f9e739 100644 --- a/apps/website/ui/Card.tsx +++ b/apps/website/ui/Card.tsx @@ -7,37 +7,60 @@ export interface CardProps { variant?: 'default' | 'muted' | 'outline' | 'glass' | 'dark' | 'precision' | 'bordered' | 'elevated' | 'rarity-common' | 'rarity-rare' | 'rarity-epic' | 'rarity-legendary'; title?: string | ReactNode; footer?: ReactNode; - padding?: Spacing | number | any; - className?: string; - style?: React.CSSProperties; - bg?: string; - p?: number; + padding?: 'none' | 'sm' | 'md' | 'lg' | number; onClick?: () => void; - responsiveColSpan?: { lg: number }; - overflow?: string; - rounded?: string | boolean; - borderLeft?: boolean; - borderColor?: string; - center?: boolean; - transition?: string | boolean; - hoverBorderColor?: string; - border?: boolean; - position?: string; - mb?: number; - display?: string; - alignItems?: string; - gap?: number; + fullHeight?: boolean; + /** @deprecated Use semantic props instead. */ + className?: string; + /** @deprecated Use semantic props instead. */ + style?: React.CSSProperties; + /** @deprecated Use semantic props instead. */ + p?: number; + /** @deprecated Use semantic props instead. */ py?: number; + /** @deprecated Use semantic props instead. */ + mb?: number; + /** @deprecated Use semantic props instead. */ + bg?: string; + /** @deprecated Use semantic props instead. */ + borderColor?: string; + /** @deprecated Use semantic props instead. */ + hoverBorderColor?: string; + /** @deprecated Use semantic props instead. */ + border?: boolean; + /** @deprecated Use semantic props instead. */ + position?: string; + /** @deprecated Use semantic props instead. */ + overflow?: string; + /** @deprecated Use semantic props instead. */ + center?: boolean; + /** @deprecated Use semantic props instead. */ + rounded?: string | boolean; + /** @deprecated Use semantic props instead. */ + transition?: string | boolean; + /** @deprecated Use semantic props instead. */ + group?: boolean; + /** @deprecated Use semantic props instead. */ + responsiveColSpan?: { lg: number }; + /** @deprecated Use semantic props instead. */ backgroundColor?: string; - group?: boolean | any; - w?: string | any; - justifyContent?: string | any; - fullHeight?: boolean | any; + /** @deprecated Use semantic props instead. */ + w?: string | number; + /** @deprecated Use semantic props instead. */ + display?: string; + /** @deprecated Use semantic props instead. */ + alignItems?: string; + /** @deprecated Use semantic props instead. */ + gap?: number; + /** @deprecated Use semantic props instead. */ + borderLeft?: boolean; + /** @deprecated Use semantic props instead. */ + justifyContent?: string; } /** * Card - Redesigned for "Modern Precision" theme. - * Includes extensive compatibility props to prevent app-wide breakage. + * Enforces semantic props. */ export const Card = forwardRef(({ children, @@ -45,28 +68,31 @@ export const Card = forwardRef(({ title, footer, padding = 'md', - className, - style, - bg, - p, onClick, - responsiveColSpan, - overflow, - rounded, - borderLeft, + fullHeight, + className, + style: styleProp, + p, + py, + mb, + bg, borderColor, - center, - transition, hoverBorderColor, border, position, - mb, + overflow, + center, + rounded, + transition, + group, + responsiveColSpan, + backgroundColor, + w, display, alignItems, gap, - py, - backgroundColor, - fullHeight, + borderLeft, + justifyContent, }, ref) => { const variantClasses = { default: 'bg-[var(--ui-color-bg-surface)] border-[var(--ui-color-border-default)] shadow-sm', @@ -83,61 +109,69 @@ export const Card = forwardRef(({ 'rarity-legendary': 'bg-orange-500/10 border-orange-500/50', }; - const paddingClasses = { + const paddingClasses: Record = { none: 'p-0', sm: 'p-2', md: 'p-4', lg: 'p-8', }; - const getPaddingClass = (pad: any) => { - if (typeof pad === 'string') return `p-${pad}`; - return ''; // Handled in style - }; + const classes = [ + 'border', + variantClasses[variant as keyof typeof variantClasses] || variantClasses.default, + typeof padding === 'string' ? (paddingClasses[padding] || paddingClasses.md) : '', + onClick ? 'cursor-pointer hover:border-[var(--ui-color-border-bright)] transition-all duration-200' : '', + fullHeight ? 'h-full flex flex-col' : '', + group ? 'group' : '', + rounded === true ? 'rounded-full' : (typeof rounded === 'string' ? `rounded-${rounded}` : 'rounded-none'), + className, + ].filter(Boolean).join(' '); - const combinedStyle: React.CSSProperties = { - ...style, + const style: React.CSSProperties = { + ...(typeof padding === 'number' ? { padding: `${padding * 0.25}rem` } : {}), + ...(p !== undefined ? { padding: `${p * 0.25}rem` } : {}), + ...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}), + ...(mb !== undefined ? { marginBottom: `${mb * 0.25}rem` } : {}), ...(bg ? { backgroundColor: bg.startsWith('bg-') ? undefined : bg } : {}), ...(backgroundColor ? { backgroundColor } : {}), - ...(p !== undefined ? { padding: typeof p === 'number' ? `${p * 0.25}rem` : undefined } : {}), - ...(py !== undefined ? { paddingTop: typeof py === 'number' ? `${py * 0.25}rem` : undefined, paddingBottom: typeof py === 'number' ? `${py * 0.25}rem` : undefined } : {}), - ...(typeof padding === 'number' ? { padding: `${padding * 0.25}rem` } : {}), - ...(responsiveColSpan?.lg ? { gridColumn: `span ${responsiveColSpan.lg} / span ${responsiveColSpan.lg}` } : {}), - ...(overflow ? { overflow } : {}), ...(borderColor ? { borderColor: borderColor.startsWith('border-') ? undefined : borderColor } : {}), - ...(borderLeft ? { borderLeft: `4px solid ${borderColor || 'var(--ui-color-intent-primary)'}` } : {}), + ...(hoverBorderColor ? { '--hover-border-color': hoverBorderColor } as any : {}), + ...(border === false ? { border: 'none' } : {}), + ...(position ? { position: position as any } : {}), + ...(overflow ? { overflow } : {}), ...(center ? { display: 'flex', alignItems: 'center', justifyContent: 'center' } : {}), ...(typeof transition === 'string' ? { transition } : {}), - ...(position ? { position: position as any } : {}), - ...(mb !== undefined ? { marginBottom: `${mb * 0.25}rem` } : {}), + ...(responsiveColSpan?.lg ? { gridColumn: `span ${responsiveColSpan.lg} / span ${responsiveColSpan.lg}` } : {}), + ...(w !== undefined ? { width: w } : {}), ...(display ? { display } : {}), ...(alignItems ? { alignItems } : {}), + ...(justifyContent ? { justifyContent } : {}), ...(gap !== undefined ? { gap: `${gap * 0.25}rem` } : {}), - ...(border === false ? { border: 'none' } : {}), - ...(fullHeight ? { height: '100%' } : {}), + ...(borderLeft ? { borderLeft: `4px solid var(--ui-color-intent-primary)` } : {}), + ...(styleProp || {}), }; return (
0 ? style : undefined} > {title && ( -
+
{typeof title === 'string' ? ( {title} ) : title}
)} -
+
{children}
{footer && ( -
+
{footer}
)} diff --git a/apps/website/ui/Container.tsx b/apps/website/ui/Container.tsx index bb9768a3e..cab089ee0 100644 --- a/apps/website/ui/Container.tsx +++ b/apps/website/ui/Container.tsx @@ -2,28 +2,27 @@ import { ReactNode } from 'react'; export interface ContainerProps { children: ReactNode; - size?: 'sm' | 'md' | 'lg' | 'xl' | 'full' | any; - padding?: 'none' | 'sm' | 'md' | 'lg' | any; - py?: number | any; - position?: 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky' | any; - zIndex?: number | any; - paddingX?: number | any; - fullWidth?: boolean | any; + size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'; + padding?: 'none' | 'sm' | 'md' | 'lg'; + spacing?: 'none' | 'sm' | 'md' | 'lg' | 'xl'; + position?: 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'; + zIndex?: number; + /** @deprecated Use semantic props instead. */ + py?: number; } /** * Container - Redesigned for "Modern Precision" theme. - * Includes compatibility props to prevent app-wide breakage. + * Enforces semantic props. */ export const Container = ({ children, size = 'lg', padding = 'md', - py, + spacing = 'none', position, zIndex, - paddingX, - fullWidth, + py, }: ContainerProps) => { const sizeMap = { sm: 'max-w-[40rem]', @@ -40,17 +39,23 @@ export const Container = ({ lg: 'px-8', }; + const spacingMap = { + none: 'py-0', + sm: 'py-4', + md: 'py-8', + lg: 'py-12', + xl: 'py-16', + }; + const combinedStyle: React.CSSProperties = { - ...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}), - ...(paddingX !== undefined ? { paddingLeft: `${paddingX * 0.25}rem`, paddingRight: `${paddingX * 0.25}rem` } : {}), ...(position ? { position } : {}), ...(zIndex !== undefined ? { zIndex } : {}), - ...(fullWidth ? { width: '100%' } : {}), + ...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}), }; return (
{children} diff --git a/apps/website/ui/DurationField.tsx b/apps/website/ui/DurationField.tsx index f01725012..54bd65ad6 100644 --- a/apps/website/ui/DurationField.tsx +++ b/apps/website/ui/DurationField.tsx @@ -33,7 +33,7 @@ export const DurationField = ({ return ( - + {label} diff --git a/apps/website/ui/FeatureItem.tsx b/apps/website/ui/FeatureItem.tsx index f2c59b9d2..b7269470a 100644 --- a/apps/website/ui/FeatureItem.tsx +++ b/apps/website/ui/FeatureItem.tsx @@ -6,6 +6,8 @@ import { Text } from './Text'; import { LucideIcon } from 'lucide-react'; import { IconContainer } from './IconContainer'; +import { Icon } from './Icon'; + interface FeatureItemProps { title: string; description: string; @@ -16,12 +18,12 @@ interface FeatureItemProps { * FeatureItem - A semantic UI component for a single feature/pillar. * Allowed to use Stack primitive. */ -export function FeatureItem({ title, description, icon: Icon }: FeatureItemProps) { +export function FeatureItem({ title, description, icon }: FeatureItemProps) { return ( - + diff --git a/apps/website/ui/FormSection.tsx b/apps/website/ui/FormSection.tsx index ed3de19f3..9c84f8b56 100644 --- a/apps/website/ui/FormSection.tsx +++ b/apps/website/ui/FormSection.tsx @@ -16,7 +16,7 @@ export const FormSection = ({ return ( - + {title} {description && ( diff --git a/apps/website/ui/Heading.tsx b/apps/website/ui/Heading.tsx index 31f49ae3b..70682a9e7 100644 --- a/apps/website/ui/Heading.tsx +++ b/apps/website/ui/Heading.tsx @@ -6,28 +6,41 @@ export interface HeadingProps { weight?: 'normal' | 'medium' | 'semibold' | 'bold'; align?: 'left' | 'center' | 'right'; uppercase?: boolean; - intent?: 'primary' | 'telemetry' | 'warning' | 'critical' | 'default' | any; - className?: string; - style?: CSSProperties; - mb?: number | any; - marginBottom?: number | any; - mt?: number | any; - marginTop?: number | any; - color?: string; - fontSize?: string | { base: string; sm?: string; md: string; lg?: string; xl?: string }; - letterSpacing?: string; + intent?: 'primary' | 'telemetry' | 'warning' | 'critical' | 'default'; truncate?: boolean; - size?: string; icon?: ReactNode; id?: string; - lineHeight?: string | any; - groupHoverColor?: string | any; - transition?: boolean | any; + /** @deprecated Use semantic props instead. */ + className?: string; + /** @deprecated Use semantic props instead. */ + style?: CSSProperties; + /** @deprecated Use semantic props instead. */ + mb?: number | string; + /** @deprecated Use semantic props instead. */ + marginBottom?: number | string; + /** @deprecated Use semantic props instead. */ + mt?: number | string; + /** @deprecated Use semantic props instead. */ + marginTop?: number | string; + /** @deprecated Use semantic props instead. */ + color?: string; + /** @deprecated Use semantic props instead. */ + fontSize?: string | { base: string; sm?: string; md: string; lg?: string; xl?: string }; + /** @deprecated Use semantic props instead. */ + letterSpacing?: string; + /** @deprecated Use semantic props instead. */ + size?: string; + /** @deprecated Use semantic props instead. */ + groupHoverColor?: string; + /** @deprecated Use semantic props instead. */ + lineHeight?: string | number; + /** @deprecated Use semantic props instead. */ + transition?: boolean; } /** * Heading - Redesigned for "Modern Precision" theme. - * Includes extensive compatibility props to prevent app-wide breakage. + * Enforces semantic props. */ export const Heading = forwardRef(({ children, @@ -36,8 +49,11 @@ export const Heading = forwardRef(({ align = 'left', uppercase = false, intent = 'default', + truncate, + icon, + id, className, - style, + style: styleProp, mb, marginBottom, mt, @@ -45,9 +61,10 @@ export const Heading = forwardRef(({ color, fontSize, letterSpacing, - truncate, size, - icon, + groupHoverColor, + lineHeight, + transition, }, ref) => { const Tag = `h${level}` as const; @@ -76,8 +93,7 @@ export const Heading = forwardRef(({ }; const getResponsiveFontSize = (fs: HeadingProps['fontSize']) => { - if (!fs) return ''; - if (typeof fs === 'string') return ''; // Handled in style + if (!fs || typeof fs === 'string') return ''; const classes = []; if (fs.base) classes.push(`text-${fs.base}`); if (fs.sm) classes.push(`sm:text-${fs.sm}`); @@ -94,22 +110,25 @@ export const Heading = forwardRef(({ align === 'center' ? 'text-center' : (align === 'right' ? 'text-right' : 'text-left'), uppercase ? 'uppercase tracking-widest' : '', truncate ? 'truncate' : '', + transition ? 'transition-all duration-200' : '', + color?.startsWith('text-') ? color : '', className, ].join(' '); const combinedStyle: React.CSSProperties = { - ...style, ...(mb !== undefined ? { marginBottom: typeof mb === 'number' ? `${mb * 0.25}rem` : mb } : {}), ...(marginBottom !== undefined ? { marginBottom: typeof marginBottom === 'number' ? `${marginBottom * 0.25}rem` : marginBottom } : {}), ...(mt !== undefined ? { marginTop: typeof mt === 'number' ? `${mt * 0.25}rem` : mt } : {}), ...(marginTop !== undefined ? { marginTop: typeof marginTop === 'number' ? `${marginTop * 0.25}rem` : marginTop } : {}), - ...(color ? { color } : {}), + ...(color && !color.startsWith('text-') ? { color } : {}), ...(letterSpacing ? { letterSpacing } : {}), ...(typeof fontSize === 'string' ? { fontSize } : {}), + ...(lineHeight ? { lineHeight } : {}), + ...(styleProp || {}), }; return ( - + 0 ? combinedStyle : undefined} id={id}>
{icon} {children} diff --git a/apps/website/ui/InfoItem.tsx b/apps/website/ui/InfoItem.tsx index 5135d9b14..6c940b03a 100644 --- a/apps/website/ui/InfoItem.tsx +++ b/apps/website/ui/InfoItem.tsx @@ -22,10 +22,10 @@ export const InfoItem = ({ - + {label} - + {value} diff --git a/apps/website/ui/LandingHero.tsx b/apps/website/ui/LandingHero.tsx index 2a91f2408..2ae792502 100644 --- a/apps/website/ui/LandingHero.tsx +++ b/apps/website/ui/LandingHero.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Section } from './Section'; import { Container } from './Container'; -import { Box } from './Box'; +import { Stack } from './Stack'; import { Glow } from './Glow'; import { Heading } from './Heading'; import { Text } from './Text'; @@ -37,7 +37,7 @@ export function LandingHero({ - + {subtitle} @@ -68,7 +68,7 @@ export function LandingHero({ {secondaryAction.label} - +
); diff --git a/apps/website/ui/LandingItems.tsx b/apps/website/ui/LandingItems.tsx index 2d218f4f4..da21de081 100644 --- a/apps/website/ui/LandingItems.tsx +++ b/apps/website/ui/LandingItems.tsx @@ -24,7 +24,7 @@ export const LandingItem = ({
- + {title} diff --git a/apps/website/ui/LeagueCard.tsx b/apps/website/ui/LeagueCard.tsx index 0f8f10b7d..6bf6bb5de 100644 --- a/apps/website/ui/LeagueCard.tsx +++ b/apps/website/ui/LeagueCard.tsx @@ -21,7 +21,7 @@ export const LeagueCard = ({ children, onClick, coverUrl, logo, badges }: League diff --git a/apps/website/ui/NotificationContent.tsx b/apps/website/ui/NotificationContent.tsx index e72f5d7ce..31085823b 100644 --- a/apps/website/ui/NotificationContent.tsx +++ b/apps/website/ui/NotificationContent.tsx @@ -11,7 +11,7 @@ export interface NotificationStatProps { export const NotificationStat = ({ label, value, intent = 'low' }: NotificationStatProps) => ( - {label} + {label} {value} ); @@ -27,7 +27,7 @@ export const NotificationDeadline = ({ label, deadline, icon }: NotificationDead {label} - {deadline} + {deadline} ); diff --git a/apps/website/ui/PageHeader.tsx b/apps/website/ui/PageHeader.tsx index f3c276d77..e658e3678 100644 --- a/apps/website/ui/PageHeader.tsx +++ b/apps/website/ui/PageHeader.tsx @@ -31,26 +31,26 @@ export function PageHeader({ justifyContent="space-between" gap={6} borderBottom="1px solid var(--ui-color-border-muted)" - paddingBottom={8} + paddingBottom={6} > - + {icon ? ( ) : ( )} - {title} - + {title} + {description && ( - + {description} )} {action && ( - + {action} )} diff --git a/apps/website/ui/ProfileCard.tsx b/apps/website/ui/ProfileCard.tsx index a84d0aeff..fbb64d7e3 100644 --- a/apps/website/ui/ProfileCard.tsx +++ b/apps/website/ui/ProfileCard.tsx @@ -16,7 +16,7 @@ export const ProfileCard = ({ identity, stats, actions, variant = 'default', onC variant={variant} padding="md" onClick={onClick} - className="h-full flex flex-col gap-6 transition-all duration-200 hover:border-[var(--ui-color-border-bright)]" + fullHeight > diff --git a/apps/website/ui/Section.tsx b/apps/website/ui/Section.tsx index 4830786eb..a5dbfd0be 100644 --- a/apps/website/ui/Section.tsx +++ b/apps/website/ui/Section.tsx @@ -4,13 +4,12 @@ import { Box } from './Box'; export interface SectionProps { children: ReactNode; variant?: 'default' | 'dark' | 'muted'; - padding?: 'none' | 'sm' | 'md' | 'lg'; + padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl'; id?: string; minHeight?: string; - py?: number; fullWidth?: boolean; maxWidth?: string; - /** @deprecated DO NOT USE. Use semantic props instead. */ + /** @deprecated Use semantic props instead. */ className?: string; } @@ -20,10 +19,9 @@ export const Section = ({ padding = 'md', id, minHeight, - py, - className, fullWidth = false, - maxWidth = '80rem' + maxWidth = '80rem', + className, }: SectionProps) => { const variantClasses = { default: 'bg-[var(--ui-color-bg-base)]', @@ -36,18 +34,18 @@ export const Section = ({ sm: 'py-8', md: 'py-16', lg: 'py-24', + xl: 'py-32', }; const classes = [ variantClasses[variant], - py !== undefined ? '' : paddingClasses[padding], + paddingClasses[padding], className, ].join(' '); return (
{fullWidth ? ( children diff --git a/apps/website/ui/StatItem.tsx b/apps/website/ui/StatItem.tsx index a4cab7615..9f3291c47 100644 --- a/apps/website/ui/StatItem.tsx +++ b/apps/website/ui/StatItem.tsx @@ -16,7 +16,7 @@ export const StatItem = ({ }: StatItemProps) => { return ( - {label} + {label} {value} ); diff --git a/apps/website/ui/Text.tsx b/apps/website/ui/Text.tsx index ebc1d9035..c1f1a6953 100644 --- a/apps/website/ui/Text.tsx +++ b/apps/website/ui/Text.tsx @@ -5,69 +5,106 @@ export type TextSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' export interface TextProps { children: ReactNode; - variant?: 'high' | 'med' | 'low' | 'primary' | 'success' | 'warning' | 'critical' | 'telemetry' | 'inherit' | any; - size?: TextSize | { base: TextSize; sm?: TextSize; md?: TextSize; lg?: TextSize; xl?: TextSize } | any; - weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold' | any; + variant?: 'high' | 'med' | 'low' | 'primary' | 'success' | 'warning' | 'critical' | 'telemetry' | 'inherit'; + size?: TextSize | { base: TextSize; sm?: TextSize; md?: TextSize; lg?: TextSize; xl?: TextSize }; + weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold'; as?: ElementType; - align?: 'left' | 'center' | 'right' | any; + align?: 'left' | 'center' | 'right'; mono?: boolean; + font?: 'sans' | 'mono'; uppercase?: boolean; - leading?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose' | any; + leading?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose'; block?: boolean; truncate?: boolean; - mt?: number | any; - mb?: number | any; - ml?: number | any; - mr?: number | any; - marginTop?: number | any; - marginBottom?: number | any; - font?: 'sans' | 'mono' | string; - color?: string; - letterSpacing?: string; - lineHeight?: string | number; - flexGrow?: number; - flexShrink?: number; - lineClamp?: number; - display?: string | ResponsiveValue; - opacity?: number; maxWidth?: string | number; - maxHeight?: string | number; - overflow?: string; - whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-line' | 'pre-wrap'; - mx?: string | number; - pl?: number; - px?: number; - py?: number; - paddingX?: number; - paddingY?: number; - textAlign?: string; - groupHoverTextColor?: string; - transition?: boolean; - borderLeft?: boolean; - borderStyle?: string; - borderColor?: string; - ariaLabel?: string; - hoverVariant?: string; - fontSize?: string | any; - italic?: boolean; - animate?: string; - capitalize?: boolean; - alignItems?: string; - gap?: number; - cursor?: string; - width?: string | number; - height?: string | number; - htmlFor?: string; - transform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | string; - /** @deprecated DO NOT USE. Use semantic props instead. */ + lineClamp?: number; + letterSpacing?: 'tight' | 'normal' | 'wide' | 'widest' | string; + id?: string; + /** @deprecated Use semantic props (variant, intent) instead. */ + color?: string; + /** @deprecated Use semantic props instead. */ className?: string; - /** @deprecated DO NOT USE. Use semantic props instead. */ + /** @deprecated Use semantic props instead. */ style?: CSSProperties; + /** @deprecated Use semantic props instead. */ + marginBottom?: number | string | ResponsiveValue; + /** @deprecated Use semantic props instead. */ + marginTop?: number | string | ResponsiveValue; + /** @deprecated Use semantic props instead. */ + mb?: number | string | ResponsiveValue; + /** @deprecated Use semantic props instead. */ + mt?: number | string | ResponsiveValue; + /** @deprecated Use semantic props instead. */ + ml?: number | string; + /** @deprecated Use semantic props instead. */ + mr?: number | string; + /** @deprecated Use semantic props instead. */ + mx?: string | number; + /** @deprecated Use semantic props instead. */ + px?: number | string; + /** @deprecated Use semantic props instead. */ + py?: number | string; + /** @deprecated Use semantic props instead. */ + textAlign?: 'left' | 'center' | 'right'; + /** @deprecated Use semantic props instead. */ + flexGrow?: number; + /** @deprecated Use semantic props instead. */ + maxHeight?: string | number; + /** @deprecated Use semantic props instead. */ + overflow?: string; + /** @deprecated Use semantic props instead. */ + opacity?: number; + /** @deprecated Use semantic props instead. */ + groupHoverTextColor?: string; + /** @deprecated Use semantic props instead. */ + lineHeight?: string | number; + /** @deprecated Use semantic props instead. */ + transform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | string; + /** @deprecated Use semantic props instead. */ + animate?: string; + /** @deprecated Use semantic props instead. */ + transition?: boolean; + /** @deprecated Use semantic props instead. */ + display?: string | ResponsiveValue; + /** @deprecated Use semantic props instead. */ + alignItems?: string; + /** @deprecated Use semantic props instead. */ + gap?: number; + /** @deprecated Use semantic props instead. */ + italic?: boolean; + /** @deprecated Use semantic props instead. */ + fontSize?: string | any; + /** @deprecated Use semantic props instead. */ + borderLeft?: boolean; + /** @deprecated Use semantic props instead. */ + borderColor?: string; + /** @deprecated Use semantic props instead. */ + pl?: number; + /** @deprecated Use semantic props instead. */ + borderStyle?: string; + /** @deprecated Use semantic props instead. */ + paddingX?: number; + /** @deprecated Use semantic props instead. */ + whiteSpace?: string; + /** @deprecated Use semantic props instead. */ + htmlFor?: string; + /** @deprecated Use semantic props instead. */ + width?: string | number; + /** @deprecated Use semantic props instead. */ + height?: string | number; + /** @deprecated Use semantic props instead. */ + flexShrink?: number; + /** @deprecated Use semantic props instead. */ + capitalize?: boolean; + /** @deprecated Use semantic props instead. */ + hoverVariant?: string; + /** @deprecated Use semantic props instead. */ + cursor?: string; } /** * Text - Redesigned for "Modern Precision" theme. - * Includes extensive compatibility props to prevent app-wide breakage. + * Enforces semantic props. */ export const Text = forwardRef(({ children, @@ -77,56 +114,55 @@ export const Text = forwardRef(({ as = 'p', align = 'left', mono = false, + font, uppercase = false, leading = 'normal', block = false, truncate = false, + maxWidth, + lineClamp, + letterSpacing, + id, + color, className, - style, - mt, + style: styleProp, + marginBottom, + marginTop, mb, + mt, ml, mr, - marginTop, - marginBottom, - font, - color, - letterSpacing, - lineHeight, - flexGrow, - flexShrink, - lineClamp, - display, - opacity, - maxWidth, - maxHeight, - overflow, - whiteSpace, mx, - pl, px, py, - paddingX, - paddingY, textAlign, + flexGrow, + maxHeight, + overflow, + opacity, groupHoverTextColor, - transition, - borderLeft, - borderStyle, - borderColor, - ariaLabel, - hoverVariant, - fontSize, - italic, + lineHeight, + transform, animate, - capitalize, + transition, + display, alignItems, gap, - cursor, + italic, + fontSize, + borderLeft, + borderColor, + pl, + borderStyle, + paddingX, + whiteSpace, + htmlFor, width, height, - htmlFor, - transform, + flexShrink, + capitalize, + hoverVariant, + cursor, }, ref) => { const variantClasses = { high: 'text-[var(--ui-color-text-high)]', @@ -181,79 +217,99 @@ export const Text = forwardRef(({ loose: 'leading-loose', }; - const getResponsiveClasses = (prefix: string, value: any | ResponsiveValue | undefined) => { + const letterSpacingClasses: Record = { + tight: 'tracking-tight', + normal: 'tracking-normal', + wide: 'tracking-wide', + widest: 'tracking-widest', + }; + + const getResponsiveSpacing = (prefix: string, value: any) => { if (value === undefined) return ''; if (typeof value === 'object') { const classes = []; - if (value.base !== undefined) classes.push(prefix ? `${prefix}-${value.base}` : String(value.base)); - if (value.sm !== undefined) classes.push(prefix ? `sm:${prefix}-${value.sm}` : `sm:${value.sm}`); - if (value.md !== undefined) classes.push(prefix ? `md:${prefix}-${value.md}` : `md:${value.md}`); - if (value.lg !== undefined) classes.push(prefix ? `lg:${prefix}-${value.lg}` : `lg:${value.lg}`); - if (value.xl !== undefined) classes.push(prefix ? `xl:${prefix}-${value.xl}` : `xl:${value.xl}`); + if (value.base !== undefined) classes.push(`${prefix}-${value.base}`); + if (value.sm !== undefined) classes.push(`sm:${prefix}-${value.sm}`); + if (value.md !== undefined) classes.push(`md:${prefix}-${value.md}`); + if (value.lg !== undefined) classes.push(`lg:${prefix}-${value.lg}`); + if (value.xl !== undefined) classes.push(`xl:${prefix}-${value.xl}`); return classes.join(' '); } - return prefix ? `${prefix}-${value}` : String(value); + return ''; // Handled in style + }; + + const getResponsiveDisplay = (d: any) => { + if (!d) return ''; + if (typeof d === 'string') return d.includes(':') ? d : `flex`; // Fallback + const classes = []; + if (d.base) classes.push(d.base); + if (d.sm) classes.push(`sm:${d.sm}`); + if (d.md) classes.push(`md:${d.md}`); + if (d.lg) classes.push(`lg:${d.lg}`); + if (d.xl) classes.push(`xl:${d.xl}`); + return classes.join(' '); }; const classes = [ variantClasses[variant as keyof typeof variantClasses] || '', getResponsiveSize(size), weightClasses[weight as keyof typeof weightClasses] || '', - align === 'center' || textAlign === 'center' ? 'text-center' : (align === 'right' || textAlign === 'right' ? 'text-right' : 'text-left'), + (align === 'center' || textAlign === 'center') ? 'text-center' : ((align === 'right' || textAlign === 'right') ? 'text-right' : 'text-left'), (mono || font === 'mono') ? 'font-mono' : 'font-sans', - uppercase ? 'uppercase tracking-widest' : '', + uppercase ? 'uppercase' : '', + letterSpacing ? (letterSpacingClasses[letterSpacing] || '') : (uppercase ? 'tracking-widest' : ''), leadingClasses[leading as keyof typeof leadingClasses] || '', block ? 'block' : 'inline', truncate ? 'truncate' : '', - getResponsiveClasses('display', display), - transition ? 'transition-all duration-200' : '', + getResponsiveSpacing('mb', mb || marginBottom), + getResponsiveSpacing('mt', mt || marginTop), + getResponsiveDisplay(display), italic ? 'italic' : '', animate === 'pulse' ? 'animate-pulse' : '', + transition ? 'transition-all duration-200' : '', capitalize ? 'capitalize' : '', color?.startsWith('text-') ? color : '', className, ].filter(Boolean).join(' '); - const combinedStyle: React.CSSProperties = { - ...style, - ...(typeof display === 'string' ? { display } : {}), - ...(alignItems ? { alignItems } : {}), - ...(gap !== undefined ? { gap: `${gap * 0.25}rem` } : {}), - ...(cursor ? { cursor } : {}), - ...(width !== undefined ? { width } : {}), - ...(height !== undefined ? { height } : {}), - ...(opacity !== undefined ? { opacity } : {}), + const style: React.CSSProperties = { ...(maxWidth !== undefined ? { maxWidth } : {}), ...(maxHeight !== undefined ? { maxHeight } : {}), ...(overflow !== undefined ? { overflow } : {}), - ...(whiteSpace !== undefined ? { whiteSpace } : {}), - ...(mx === 'auto' ? { marginLeft: 'auto', marginRight: 'auto' } : {}), - ...(pl !== undefined ? { paddingLeft: `${pl * 0.25}rem` } : {}), - ...(px !== undefined ? { paddingLeft: `${px * 0.25}rem`, paddingRight: `${px * 0.25}rem` } : {}), - ...(py !== undefined ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}), - ...(paddingX !== undefined ? { paddingLeft: `${paddingX * 0.25}rem`, paddingRight: `${paddingX * 0.25}rem` } : {}), - ...(paddingY !== undefined ? { paddingTop: `${paddingY * 0.25}rem`, paddingBottom: `${paddingY * 0.25}rem` } : {}), - ...(mt !== undefined ? { marginTop: typeof mt === 'number' ? `${mt * 0.25}rem` : mt } : {}), - ...(mb !== undefined ? { marginBottom: typeof mb === 'number' ? `${mb * 0.25}rem` : mb } : {}), - ...(ml !== undefined ? { marginLeft: typeof ml === 'number' ? `${ml * 0.25}rem` : ml } : {}), - ...(mr !== undefined ? { marginRight: typeof mr === 'number' ? `${mr * 0.25}rem` : mr } : {}), - ...(marginTop !== undefined ? { marginTop: typeof marginTop === 'number' ? `${marginTop * 0.25}rem` : marginTop } : {}), - ...(marginBottom !== undefined ? { marginBottom: typeof marginBottom === 'number' ? `${marginBottom * 0.25}rem` : marginBottom } : {}), - ...(color ? { color: color.startsWith('text-') ? undefined : color } : {}), - ...(letterSpacing ? { letterSpacing } : {}), - ...(lineHeight ? { lineHeight } : {}), ...(flexGrow !== undefined ? { flexGrow } : {}), ...(flexShrink !== undefined ? { flexShrink } : {}), + ...(opacity !== undefined ? { opacity } : {}), ...(lineClamp !== undefined ? { display: '-webkit-box', WebkitLineClamp: lineClamp, WebkitBoxOrient: 'vertical', overflow: 'hidden' } : {}), - ...(borderLeft ? { borderLeft: `1px solid ${borderColor || 'var(--ui-color-border-default)'}` } : {}), - ...(fontSize ? { fontSize } : {}), + ...(color && !color.startsWith('text-') ? { color } : {}), + ...(typeof mb === 'number' || typeof mb === 'string' ? { marginBottom: typeof mb === 'number' ? `${mb * 0.25}rem` : mb } : {}), + ...(typeof marginBottom === 'number' || typeof marginBottom === 'string' ? { marginBottom: typeof marginBottom === 'number' ? `${marginBottom * 0.25}rem` : marginBottom } : {}), + ...(typeof mt === 'number' || typeof mt === 'string' ? { marginTop: typeof mt === 'number' ? `${mt * 0.25}rem` : mt } : {}), + ...(typeof marginTop === 'number' || typeof marginTop === 'string' ? { marginTop: typeof marginTop === 'number' ? `${marginTop * 0.25}rem` : marginTop } : {}), + ...(ml !== undefined ? { marginLeft: typeof ml === 'number' ? `${ml * 0.25}rem` : ml } : {}), + ...(mr !== undefined ? { marginRight: typeof mr === 'number' ? `${mr * 0.25}rem` : mr } : {}), + ...(mx === 'auto' ? { marginLeft: 'auto', marginRight: 'auto' } : {}), + ...(px !== undefined ? { paddingLeft: typeof px === 'number' ? `${px * 0.25}rem` : px, paddingRight: typeof px === 'number' ? `${px * 0.25}rem` : px } : {}), + ...(py !== undefined ? { paddingTop: typeof py === 'number' ? `${py * 0.25}rem` : py, paddingBottom: typeof py === 'number' ? `${py * 0.25}rem` : py } : {}), + ...(pl !== undefined ? { paddingLeft: typeof pl === 'number' ? `${pl * 0.25}rem` : pl } : {}), + ...(paddingX !== undefined ? { paddingLeft: typeof paddingX === 'number' ? `${paddingX * 0.25}rem` : paddingX, paddingRight: typeof paddingX === 'number' ? `${paddingX * 0.25}rem` : paddingX } : {}), + ...(letterSpacing && !letterSpacingClasses[letterSpacing] ? { letterSpacing } : {}), + ...(lineHeight ? { lineHeight } : {}), ...(transform ? { textTransform: transform as any } : {}), + ...(alignItems ? { alignItems } : {}), + ...(gap !== undefined ? { gap: `${gap * 0.25}rem` } : {}), + ...(cursor ? { cursor } : {}), + ...(fontSize && typeof fontSize === 'string' ? { fontSize } : {}), + ...(borderLeft ? { borderLeft: `1px solid ${borderColor || 'var(--ui-color-border-default)'}` } : {}), + ...(whiteSpace ? { whiteSpace: whiteSpace as any } : {}), + ...(width !== undefined ? { width } : {}), + ...(height !== undefined ? { height } : {}), + ...(styleProp || {}), }; const Tag = as || 'p'; return ( - + 0 ? style : undefined} id={id} htmlFor={htmlFor}> {children} );