'use client'; import React, { forwardRef } from 'react'; import { cn, Surface, CheckIcon, surfaceClasses, useEffectiveSurface, } from '../common'; import { tone as toneTokens, type ToneKey } from '../tokens'; import { PixelStarRating } from './PixelStarRating'; type QuoteSize = 'compact' | 'normal' | 'long'; type Variant = 'card' | 'quote' | 'slider'; const quoteSizeMap: Record = { compact: 'min-h-[5em]', normal: 'min-h-[7em]', long: 'min-h-[9em]', }; export interface PixelTestimonialCardProps extends React.HTMLAttributes { quote: string; name: string; role?: string; company?: string; avatar?: { src?: string; name: string; tone?: ToneKey }; stars?: number; verified?: boolean; tone?: ToneKey; variant?: Variant; quoteSize?: QuoteSize; actions?: React.ReactNode; surface?: Surface; } function initialsFor(name: string): string { const parts = name.trim().split(/\s+/).filter(Boolean); if (parts.length === 0) return '?'; if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); } export const PixelTestimonialCard = forwardRef( function PixelTestimonialCard( { quote, name, role, company, avatar, stars, verified = false, tone = 'neutral', variant = 'card', quoteSize = 'normal', actions, surface: surfaceProp, className, ...rest }, ref, ) { const surface = useEffectiveSurface(surfaceProp); const s = surfaceClasses(surface); const t = toneTokens[tone]; const avatarTone = toneTokens[avatar?.tone ?? tone]; const isCard = variant === 'card'; const Article = 'article' as 'article'; const roleCompany = [role, company].filter(Boolean).join(' ยท '); return (
} className={cn( 'relative grid grid-rows-[auto_1fr_auto_auto] gap-3 p-5', isCard && s.border, isCard && s.radiusLg, isCard && 'border-retro-border bg-retro-surface/40', s.font, className, )} {...rest} >
{typeof stars === 'number' && stars > 0 ? ( ) : null}
{verified && ( VERIFIED )}
“{quote}”
{actions ?
{actions}
: null}
{avatar?.src ? ( // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text {avatar.name} ) : ( {initialsFor(avatar?.name ?? name)} )}
{name} {roleCompany && ( {roleCompany} )}
{/* hint: tone tokens kept reachable so variant="card" highlight extensions can wire glow later */}
); }, ); PixelTestimonialCard.displayName = 'PixelTestimonialCard';