{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "year-card-glass", "type": "registry:block", "title": "Year Card Glass", "description": "@deprecated This prop is no longer used. Sparkline is now only shown in expanded view.", "dependencies": [ "lucide-react", "react" ], "registryDependencies": [ "cn", "variants" ], "files": [ { "path": "components/glass/composite/year-card-glass.tsx", "type": "registry:component", "content": "/* eslint-disable react-refresh/only-export-components */\n// ========================================\n// YEAR CARD GLASS COMPONENT\n// Year card with compound API for career timeline\n// Issue #15: shadcn/ui compatible compound component\n// ========================================\n\nimport { forwardRef, type CSSProperties, type ReactNode, useMemo } from 'react';\nimport { ChevronDown, ChevronUp } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport { BadgeGlass } from '../../ui/badge-glass';\nimport { ProgressGlass } from '../../specialized/progress-glass';\nimport { SparklineGlass } from '../../specialized/sparkline-glass';\nimport { ButtonGlass } from '../../ui/button-glass';\nimport { InteractiveCard } from '../../primitives';\nimport { InsightCardGlass } from '../../atomic/insight-card-glass';\nimport { YearCardContext, useYearCard, type YearCardContextValue } from './year-card-context';\nimport type { ProgressGradient } from '@/lib/variants/progress-glass-variants';\nimport '@/glass-theme.css';\n\n// ========================================\n// TYPES\n// ========================================\n\nexport interface YearCardGlassInsight {\n readonly variant?: 'default' | 'tip' | 'highlight' | 'warning' | 'stat' | 'growth' | 'decline';\n readonly emoji?: string;\n readonly text: string;\n readonly detail?: string;\n}\n\nexport interface YearCardGlassStat {\n readonly label: string;\n readonly value: string | number;\n readonly icon?: ReactNode;\n}\n\n/** Props for YearCardGlass.Root */\nexport interface YearCardRootProps extends Omit, 'onSelect'> {\n /** Whether the card is selected */\n isSelected?: boolean;\n /** Whether the card is expanded */\n isExpanded?: boolean;\n /** Callback when selection is triggered */\n onSelect?: () => void;\n /** Callback when expanded state changes */\n onExpandedChange?: (expanded: boolean) => void;\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.Header */\nexport interface YearCardHeaderProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.Year */\nexport interface YearCardYearProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.Badge */\nexport interface YearCardBadgeProps extends React.HTMLAttributes {\n emoji?: string;\n label: string;\n}\n\n/** Props for YearCardGlass.Value */\nexport interface YearCardValueProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.Progress */\nexport interface YearCardProgressProps {\n value: number;\n gradient?: ProgressGradient;\n className?: string;\n}\n\n/** Props for YearCardGlass.Sparkline */\nexport interface YearCardSparklineProps {\n data: readonly number[];\n labels?: readonly string[];\n showLabels?: boolean;\n height?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\n/** Props for YearCardGlass.ExpandedContent */\nexport interface YearCardExpandedContentProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.Stats */\nexport interface YearCardStatsProps extends React.HTMLAttributes {\n children: ReactNode;\n /** Number of columns (auto-calculated from children if not provided) */\n columns?: number;\n}\n\n/** Props for YearCardGlass.StatItem */\nexport interface YearCardStatItemProps extends React.HTMLAttributes {\n label: string;\n value: string | number;\n icon?: ReactNode;\n}\n\n/** Props for YearCardGlass.Insights */\nexport interface YearCardInsightsProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Props for YearCardGlass.InsightItem */\nexport interface YearCardInsightItemProps {\n variant?: 'default' | 'tip' | 'highlight' | 'warning' | 'stat' | 'growth' | 'decline';\n emoji?: string;\n text: string;\n detail?: string;\n className?: string;\n}\n\n/** Props for YearCardGlass.Action */\nexport interface YearCardActionProps extends React.HTMLAttributes {\n children: ReactNode;\n}\n\n/** Legacy props for backward compatibility */\nexport interface YearCardGlassLegacyProps extends React.HTMLAttributes {\n readonly year: string | number;\n readonly emoji: string;\n readonly label: string;\n readonly commits: string;\n readonly progress: number;\n readonly isExpanded?: boolean;\n readonly gradient?: ProgressGradient;\n readonly prs?: number;\n readonly repos?: number;\n readonly onShowYear?: () => void;\n readonly sparklineData?: readonly number[];\n readonly sparklineLabels?: readonly string[];\n readonly insights?: readonly YearCardGlassInsight[];\n readonly stats?: readonly YearCardGlassStat[];\n readonly actionLabel?: string;\n /**\n * @deprecated This prop is no longer used. Sparkline is now only shown in expanded view.\n */\n readonly showSparklineCollapsed?: boolean;\n readonly valueFormatter?: (commits: string) => string;\n readonly children?: ReactNode;\n}\n\n// ========================================\n// COMPOUND COMPONENTS\n// ========================================\n\n/** Root container with context provider */\nconst YearCardRoot = forwardRef(\n (\n {\n isSelected = false,\n isExpanded = false,\n onSelect,\n onExpandedChange,\n children,\n className,\n ...props\n },\n ref\n ) => {\n const contextValue = useMemo(\n () => ({ isSelected, isExpanded, onSelect, onExpandedChange }),\n [isSelected, isExpanded, onSelect, onExpandedChange]\n );\n\n const handleClick = (e: React.MouseEvent) => {\n onExpandedChange?.(!isExpanded);\n props.onClick?.(e);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onExpandedChange?.(!isExpanded);\n }\n props.onKeyDown?.(e);\n };\n\n return (\n \n \n {children}\n \n \n );\n }\n);\nYearCardRoot.displayName = 'YearCardGlass.Root';\n\n/** Header section */\nconst YearCardHeader = forwardRef(\n ({ children, className, ...props }, ref) => {\n const { isExpanded } = useYearCard();\n\n return (\n \n
{children}
\n
\n {isExpanded ? (\n \n ) : (\n \n )}\n
\n \n );\n }\n);\nYearCardHeader.displayName = 'YearCardGlass.Header';\n\n/** Year display */\nconst YearCardYear = forwardRef(\n ({ children, className, ...props }, ref) => (\n \n {children}\n \n )\n);\nYearCardYear.displayName = 'YearCardGlass.Year';\n\n/** Badge wrapper */\nconst YearCardBadge = forwardRef(\n ({ emoji, label, className, ...props }, ref) => (\n \n \n {emoji && `${emoji} `}\n {label}\n \n \n )\n);\nYearCardBadge.displayName = 'YearCardGlass.Badge';\n\n/** Value display (commits, etc.) */\nconst YearCardValue = forwardRef(\n ({ children, className, ...props }, ref) => (\n \n {children}\n \n )\n);\nYearCardValue.displayName = 'YearCardGlass.Value';\n\n/** Progress bar wrapper */\nconst YearCardProgress = forwardRef(\n ({ value, gradient = 'blue', className }, ref) => (\n
\n \n
\n )\n);\nYearCardProgress.displayName = 'YearCardGlass.Progress';\n\n/** Sparkline wrapper */\nconst YearCardSparkline = forwardRef(\n ({ data, labels, showLabels, height = 'sm', className }, ref) => {\n if (!data || data.length === 0) return null;\n\n return (\n
\n \n
\n );\n }\n);\nYearCardSparkline.displayName = 'YearCardGlass.Sparkline';\n\n/** Expanded content container - only renders when expanded */\nconst YearCardExpandedContent = forwardRef(\n ({ children, className, ...props }, ref) => {\n const { isExpanded } = useYearCard();\n\n if (!isExpanded) return null;\n\n const expandedStyles: CSSProperties = {\n background: 'var(--expanded-bg)',\n borderColor: 'var(--expanded-border)',\n };\n\n return (\n \n {children}\n \n );\n }\n);\nYearCardExpandedContent.displayName = 'YearCardGlass.ExpandedContent';\n\n/** Stats grid container */\nconst YearCardStats = forwardRef(\n ({ children, columns, className, ...props }, ref) => {\n // Count children for auto columns\n const childCount = Array.isArray(children) ? children.length : 1;\n const cols = columns ?? Math.min(childCount, 4);\n\n return (\n \n {children}\n \n );\n }\n);\nYearCardStats.displayName = 'YearCardGlass.Stats';\n\n/** Single stat item */\nconst YearCardStatItem = forwardRef(\n ({ label, value, icon, className, ...props }, ref) => {\n const metricCardStyles: CSSProperties = {\n background: 'var(--card-bg)',\n borderColor: 'var(--card-border)',\n };\n\n return (\n \n {icon &&
{icon}
}\n
{value}
\n
{label}
\n \n );\n }\n);\nYearCardStatItem.displayName = 'YearCardGlass.StatItem';\n\n/** Insights container */\nconst YearCardInsights = forwardRef(\n ({ children, className, ...props }, ref) => (\n
\n {children}\n
\n )\n);\nYearCardInsights.displayName = 'YearCardGlass.Insights';\n\n/** Single insight item */\nconst YearCardInsightItem = forwardRef(\n ({ variant, emoji, text, detail, className }, ref) => (\n
\n \n
\n )\n);\nYearCardInsightItem.displayName = 'YearCardGlass.InsightItem';\n\n/** Action button */\nconst YearCardAction = forwardRef(\n ({ children, className, onClick, ...props }, ref) => {\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onClick?.(e);\n };\n\n return (\n \n {children}\n \n );\n }\n);\nYearCardAction.displayName = 'YearCardGlass.Action';\n\n// ========================================\n// LEGACY COMPONENT (backward compatibility)\n// ========================================\n\nconst YearCardGlassLegacy = forwardRef(\n (\n {\n year,\n emoji,\n label,\n commits,\n progress,\n isExpanded = false,\n gradient = 'blue',\n prs = 0,\n repos = 0,\n onShowYear,\n sparklineData,\n sparklineLabels,\n insights,\n stats,\n actionLabel,\n // @deprecated - showSparklineCollapsed is no longer used, sparkline only shows in expanded view\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n showSparklineCollapsed: _showSparklineCollapsed,\n valueFormatter,\n children,\n className,\n onClick,\n // Exclude onSelect from props spread to avoid type conflict\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onSelect: _onSelect,\n ...props\n },\n ref\n ) => {\n // Format commits display\n const displayCommits = valueFormatter ? valueFormatter(commits) : commits;\n\n // Default stats if none provided\n const displayStats = stats || [\n { label: 'Commits', value: commits },\n { label: 'PRs', value: prs },\n { label: 'Repos', value: repos },\n ];\n\n // Default action label\n const buttonLabel = actionLabel || `Show repos from ${year}`;\n\n // Handle expand toggle via onClick\n const handleExpandedChange = () => {\n // Legacy API uses onClick for toggle\n };\n\n return (\n \n \n {year}\n \n {displayCommits}\n \n\n {/* Progress bar */}\n \n\n \n {/* Stats Grid */}\n \n {displayStats.map((stat, index) => (\n \n ))}\n \n\n {/* Sparkline with labels (only in expanded view) */}\n {sparklineData && sparklineData.length > 0 && (\n \n )}\n\n {/* Insights */}\n {insights && insights.length > 0 && (\n \n {insights.map((insight, index) => (\n \n ))}\n \n )}\n\n {/* Custom children content */}\n {children}\n\n {/* Show Year Button */}\n {onShowYear && {buttonLabel}}\n \n \n );\n }\n);\nYearCardGlassLegacy.displayName = 'YearCardGlass';\n\n// ========================================\n// EXPORTS\n// ========================================\n\n/**\n * YearCardGlass - Year card with compound API for career timeline\n *\n * @example Legacy API (backward compatible)\n * ```tsx\n * setExpanded(!expanded)}\n * />\n * ```\n *\n * @example Compound API (flexible)\n * ```tsx\n * setSelected('2024')}\n * isExpanded={expanded}\n * onExpandedChange={setExpanded}\n * >\n * \n * 2024\n * \n * 1,234 commits\n * \n * \n * \n * \n * \n * \n * \n * Show repos\n * \n * \n * ```\n */\nexport const YearCardGlass = Object.assign(YearCardGlassLegacy, {\n Root: YearCardRoot,\n Header: YearCardHeader,\n Year: YearCardYear,\n Badge: YearCardBadge,\n Value: YearCardValue,\n Progress: YearCardProgress,\n Sparkline: YearCardSparkline,\n ExpandedContent: YearCardExpandedContent,\n Stats: YearCardStats,\n StatItem: YearCardStatItem,\n Insights: YearCardInsights,\n InsightItem: YearCardInsightItem,\n Action: YearCardAction,\n});\n\n// Named exports for direct imports\nexport {\n YearCardRoot,\n YearCardHeader,\n YearCardYear,\n YearCardBadge,\n YearCardValue,\n YearCardProgress,\n YearCardSparkline,\n YearCardExpandedContent,\n YearCardStats,\n YearCardStatItem,\n YearCardInsights,\n YearCardInsightItem,\n YearCardAction,\n};\n\n// Re-export types and hooks\nexport { useYearCard, useYearCardOptional } from './year-card-context';\n" } ], "categories": [ "composite" ] }