Profile Section Component

A component for displaying user profile information.

Default (with image and social links)

John Doe Profile

John Doe

> Full-stack developer

Compact (no image)

John Doe

Full-stack developer

Without social links

Jane Smith Profile

Jane Smith

> Designer & developer

Installation

pnpm dlx shadcn@latest add https://ui.vllnt.com/r/profile-section.json
bash

Usage

import { ProfileSection } from '@vllnt/ui'

export function ProfileSectionExample() {
return (
  <ProfileSection
    dict={{
      profile: {
        name: 'John Doe',
        tagline: 'Full-stack developer',
      },
    }}
    imageAlt="John Doe Profile"
    imageSource="/avatar.jpg"
    socialLinks={[
      { href: 'https://x.com/johndoe', label: 'X (Twitter)' },
      { href: 'https://github.com/johndoe', label: 'GitHub' },
    ]}
  />
)
}
tsx

Code

import Image from 'next/image'
import Link from 'next/link'

import { Button } from '../button/button'

type ProfileDict = {
  profile: {
    name: string
    tagline: string
  }
}

type SocialLink = {
  href: string
  label: string
}

type ProfileSectionProps = {
  compact?: boolean
  dict: ProfileDict
  imageAlt?: string
  imageSource?: string
  socialLinks?: SocialLink[]
}

export function ProfileSection({
  compact = false,
  dict,
  imageAlt,
  imageSource = '/profile.png',
  socialLinks,
}: ProfileSectionProps) {
  const displayImageAlt = imageAlt ?? `${dict.profile.name} Profile`
  const showImage = !compact && Boolean(imageSource)
  const showSocialLinks = !compact && Boolean(socialLinks && socialLinks.length > 0)

  return (
    <div className="text-center space-y-4">
      {showImage ? (
        <div className="relative w-24 h-24 mx-auto overflow-hidden rounded-md">
          <Image
            alt={displayImageAlt}
            className="w-full h-full object-cover rounded-md"
            height={96}
            priority={true}
            src={imageSource}
            width={96}
          />
        </div>
      ) : null}

      <div className="space-y-2">
        <h3 className={`font-semibold ${compact ? 'text-lg' : 'text-xl'}`}>{dict.profile.name}</h3>
        <p className="text-sm text-muted-foreground">
          {compact ? dict.profile.tagline : `> ${dict.profile.tagline}`}
        </p>
      </div>

      {showSocialLinks ? (
        <div className="flex flex-wrap justify-center items-center gap-2">
          {socialLinks?.map((link) => (
            <Link href={link.href} key={link.href} rel="noopener noreferrer" target="_blank">
              <Button className="w-32" size="sm" variant="outline">
                {link.label}
              </Button>
            </Link>
          ))}
        </div>
      ) : null}
    </div>
  )
}
typescript

Dependencies

  • next
  • next/image