/** * DTFeatureLegend — Interactive grid of product feature icons with rotated labels. * * Matches dt-shopify-storefront UseCaseLegend: header bar with hover details, * rotated vertical labels (above for row 0, below for row 1), ? toggle, * bordered grid with dark cell backgrounds, and pulse-on-hover icons. * * CSS reference: feature-legend.css */ import { useState, type ReactNode, type CSSProperties } from 'react'; import type { DTVariant } from '@dangerousthings/tokens'; import { cx } from '../utils/cx'; import { getVariantClass } from '../utils/variantClasses'; export interface DTFeatureItem { key: string; name: string; icon: ReactNode; state: 'supported' | 'disabled' | 'unsupported'; /** Optional detail text shown in the header on hover */ detail?: string; } const stateClassMap: Record = { supported: 'dt-feature-supported', disabled: 'dt-feature-disabled', unsupported: 'dt-feature-unsupported', }; interface DTFeatureLegendProps { features: DTFeatureItem[]; title?: string; /** Header variant @default 'normal' */ variant?: DTVariant; /** Grid columns @default 5 */ columns?: number; /** Icon size in px @default 42 */ iconSize?: number; /** Show rotated labels initially @default true */ showLabels?: boolean; className?: string; style?: CSSProperties; } export function DTFeatureLegend({ features, title, variant = 'normal', columns = 5, iconSize = 42, showLabels: initialShowLabels = true, className, style, }: DTFeatureLegendProps) { const [showLabels, setShowLabels] = useState(initialShowLabels); const [hoveredFeature, setHoveredFeature] = useState(null); const hoveredItem = hoveredFeature ? features.find(f => f.key === hoveredFeature) : null; const rowCount = Math.ceil(features.length / columns); const hasBottomRow = rowCount >= 2; return (
{/* Header bar — title + hovered feature detail + ? toggle */} {title && (
{title}
{hoveredItem ? ( {hoveredItem.name}{hoveredItem.detail ? ': ' : ''} {hoveredItem.detail && {hoveredItem.detail}} ) : ( Hover a feature for details )}
)} {/* Icon grid with border */}
{features.map((feature, index) => { const row = Math.floor(index / columns); const labelPosition = rowCount >= 2 ? (row === 0 ? 'above' : 'below') : 'above'; return (
setHoveredFeature(feature.key)} onMouseLeave={() => setHoveredFeature(null)}> {/* Rotated vertical label — always in DOM, visibility via CSS */}
{feature.name}
{feature.icon}
); })}
); }