{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "profile-header-extended-glass", "type": "registry:block", "title": "Profile Header Extended Glass", "description": "Formats ISO 8601 date to human-readable format", "dependencies": [ "lucide-react", "react" ], "registryDependencies": [ "cn" ], "files": [ { "path": "components/glass/sections/profile-header-extended-glass.tsx", "type": "registry:component", "content": "// ========================================\n// PROFILE HEADER EXTENDED GLASS COMPONENT\n// Extended user profile header with GitHub-compatible fields\n// Implements Issue #29 feature request\n// ========================================\n\nimport { forwardRef } from 'react';\nimport { Calendar, ExternalLink, FolderGit2, Users, User, MapPin, FileCode2 } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport { GlassCard } from '../ui/glass-card';\nimport { ProfileAvatarGlass } from '../specialized/profile-avatar-glass';\nimport { LanguageBarGlass, type LanguageData } from '../specialized/language-bar-glass';\nimport '@/glass-theme.css';\n\nexport interface ExtendedProfileStats {\n readonly repos?: number;\n readonly followers?: number;\n readonly following?: number;\n readonly gists?: number;\n}\n\nexport interface ExtendedProfileUser {\n /** Display name (can be null for users without a name set) */\n readonly name: string | null;\n /** Username/handle (e.g., \"octocat\") */\n readonly login: string;\n /** Avatar URL */\n readonly avatar: string;\n /** Profile URL */\n readonly url: string;\n /** Join date (ISO 8601 string or formatted string) */\n readonly createdAt: string;\n /** User biography/description */\n readonly bio?: string | null;\n /** User location */\n readonly location?: string | null;\n /** Profile stats */\n readonly stats?: ExtendedProfileStats;\n /** Programming languages distribution */\n readonly languages?: readonly LanguageData[];\n}\n\nexport interface ProfileHeaderExtendedGlassProps extends React.HTMLAttributes {\n /** User profile data */\n readonly user: ExtendedProfileUser;\n /** Whether to show the avatar with online status */\n readonly showStatus?: boolean;\n /** Avatar status when showStatus is true */\n readonly status?: 'online' | 'offline' | 'away' | 'busy';\n /** Custom action slot (replaces default external link behavior) */\n readonly actions?: React.ReactNode;\n /** Removes glass background, renders as plain div */\n readonly transparent?: boolean;\n}\n\n/**\n * Formats ISO 8601 date to human-readable format\n * @example \"2011-01-25T18:44:36Z\" -> \"January 25, 2011\"\n */\nfunction formatJoinDate(dateString: string): string {\n try {\n const date = new Date(dateString);\n if (isNaN(date.getTime())) {\n // If not a valid date, return as-is (might already be formatted)\n return dateString;\n }\n return date.toLocaleDateString('en-US', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n });\n } catch {\n return dateString;\n }\n}\n\n/**\n * Gets initials from a name string\n */\nfunction getInitials(name: string | null, login: string): string {\n if (name) {\n return name\n .split(' ')\n .map((n) => n[0])\n .join('')\n .toUpperCase()\n .slice(0, 2);\n }\n return login.slice(0, 2).toUpperCase();\n}\n\n/**\n * ProfileHeaderExtendedGlass - Extended profile header with GitHub-compatible fields\n *\n * Features:\n * - Full GitHub/GitLab user field support\n * - Avatar with optional status indicator\n * - Bio display\n * - Location with icon\n * - Extended stats (repos, followers, following, gists)\n * - Language distribution bar\n * - Custom actions slot\n *\n * @example\n * ```tsx\n * \n * ```\n */\nexport const ProfileHeaderExtendedGlass = forwardRef<\n HTMLDivElement,\n ProfileHeaderExtendedGlassProps\n>(\n (\n {\n user,\n showStatus = false,\n status = 'online',\n actions,\n transparent = false,\n className,\n ...props\n },\n ref\n ) => {\n const displayName = user.name || user.login;\n const stats = {\n repos: 0,\n followers: 0,\n following: 0,\n gists: 0,\n ...user.stats,\n };\n\n const content = (\n
\n {/* Top section: Avatar + Identity */}\n
\n {/* Avatar */}\n {user.avatar ? (\n \n ) : (\n \n )}\n\n {/* Identity section */}\n
\n {/* Name */}\n \n {displayName}\n \n\n {/* Username + Link */}\n \n \n @{user.login} \n \n
\n\n {/* Bio */}\n {user.bio && (\n

\n {user.bio}\n

\n )}\n\n {/* Location + Join date */}\n \n {user.location && (\n \n \n {user.location}\n \n )}\n \n \n Joined {formatJoinDate(user.createdAt)}\n \n
\n
\n\n {/* Actions slot */}\n {actions &&
{actions}
}\n \n\n {/* Stats row */}\n \n \n \n \n {stats.repos}\n \n repos\n \n \n \n \n {stats.followers}\n \n followers\n \n \n \n \n {stats.following}\n \n following\n \n {stats.gists > 0 && (\n \n \n \n {stats.gists}\n \n gists\n \n )}\n \n\n {/* Languages bar */}\n {user.languages && user.languages.length > 0 && (\n \n )}\n \n );\n\n if (transparent) {\n return (\n
\n {content}\n
\n );\n }\n\n return (\n \n {content}\n \n );\n }\n);\n\nProfileHeaderExtendedGlass.displayName = 'ProfileHeaderExtendedGlass';\n" } ], "categories": [ "sections" ] }