Skip to main content
The Profile Card component showcases personal information, including a profile image with an animated gradient border and a personal statement section.

Overview

Location: src/app/components/sections/ProfileCard.tsx The Profile Card is a prominent component in the portfolio grid layout, occupying 2 columns and 6 rows. It features an animated background gradient effect and displays the developer’s image, name, role, and bio.

Component Structure

export default function ProfileCard() {
  return (
    <div
      className="relative col-span-2 row-span-6 bg-spotify-light-dark rounded-xl p-4 max-md:p-3"
      id="#profile"
    >
      <div className="flex flex-col gap-7 max-md:gap-5">
        <BackgroundGradient containerClassName="rounded-[40px] place-self-center">
          <Image
            src="/luan_real.jpg"
            alt="Luan Nguyen"
            width={400}
            height={400}
            className="rounded-[25px] object-cover"
            priority
          />
        </BackgroundGradient>

        <PersonalStatement />
      </div>
    </div>
  );
}

Features

Animated Gradient Border

The profile image is wrapped in a BackgroundGradient component that creates an animated multi-color gradient border effect:
<BackgroundGradient containerClassName="rounded-[40px] place-self-center">
  <Image
    src="/luan_real.jpg"
    alt="Luan Nguyen"
    width={400}
    height={400}
    className="rounded-[25px] object-cover"
    priority
  />
</BackgroundGradient>
The priority prop on the Image component ensures the profile photo loads immediately for better perceived performance.

Personal Statement Section

The PersonalStatement subcomponent displays detailed information:
function PersonalStatement() {
  return (
    <div className="flex flex-col gap-3 px-4">
      <div className="space-y-1.5">
        <h1 className="text-3xl font-semibold">Luan Nguyen</h1>
        <p className="text-spotify-gray text-sm">
          Engineer • Researcher • Designer
        </p>
      </div>
      <h4 className="text-sm">
        Welcome. I hope your visit is short and beautiful, and that something
        here stays with you.
        <br /><br />
        I'm currently working as a software engineer intern on the
        broadcast engineering team at{" "}
        <a href="https://www.fox.com/" className="text-spotify-green underline">
          FOX.
        </a>
        {/* Additional content */}
      </h4>
    </div>
  );
}

Content Sections

Name
string
Developer name displayed as h1 heading
Role
string
Professional roles: “Engineer • Researcher • Designer”
Welcome Message
text
Personal greeting and introduction
Current Position
text with link
Current employment information with company link
Interests
text
Technical interests and focus areas (systems and AI infrastructure)
Call-to-action linking to blog posts

Background Gradient Component

The BackgroundGradient UI component provides the animated border effect: Location: src/app/components/ui/background-gradient.tsx

Props Interface

interface BackgroundGradientProps {
  children?: React.ReactNode;
  className?: string;
  containerClassName?: string;
  animate?: boolean;
}

Gradient Configuration

The gradient uses a radial gradient combination:
background: radial-gradient(circle farthest-side at 0 100%, #00ccb1, transparent),
            radial-gradient(circle farthest-side at 100% 0, #7b61ff, transparent),
            radial-gradient(circle farthest-side at 100% 100%, #ffc414, transparent),
            radial-gradient(circle farthest-side at 0 0, #1ca0fb, #141316);
Colors in the gradient:
  • Teal: #00ccb1
  • Purple: #7b61ff
  • Yellow: #ffc414
  • Blue: #1ca0fb

Animation

The gradient animates its background position in an infinite loop:
const variants = {
  initial: {
    backgroundPosition: "0 50%",
  },
  animate: {
    backgroundPosition: ["0, 50%", "100% 50%", "0 50%"],
  },
};

<motion.div
  variants={animate ? variants : undefined}
  initial={animate ? "initial" : undefined}
  animate={animate ? "animate" : undefined}
  transition={{
    duration: 5,
    repeat: Infinity,
    repeatType: "reverse",
  }}
  style={{
    backgroundSize: animate ? "400% 400%" : undefined,
  }}
/>
The animation creates a smooth, flowing effect that draws attention to the profile image without being distracting.

Grid Layout

Desktop Layout

.profile-card {
  grid-column: span 2;  /* Takes 2 columns */
  grid-row: span 6;     /* Takes 6 rows */
}

Mobile Responsive

  • Tablet/Mobile: Collapses to single column
  • Padding: Reduces from p-4 to p-3 on mobile
  • Gap: Reduces from gap-7 to gap-5 on mobile

Styling Details

Color Usage

/* Background */
bg-spotify-light-dark  /* #121212 */

/* Text colors */
text-spotify-gray      /* #282828 - for role description */
text-spotify-green     /* #1DB954 - for links */
text-white             /* Default text */

Border Radius

  • Card: rounded-xl (12px)
  • Gradient container: rounded-[40px]
  • Image: rounded-[25px]
The layered border radius creates depth and visual hierarchy, with the gradient container being the outermost rounded element.

Image Optimization

The component uses Next.js Image optimization:
<Image
  src="/luan_real.jpg"
  alt="Luan Nguyen"
  width={400}
  height={400}
  className="rounded-[25px] object-cover"
  priority
/>
priority
boolean
Loads image immediately on page load (no lazy loading)
object-cover
string
Ensures image fills the container while maintaining aspect ratio

Dependencies

{
  "next/image": "Optimized image component",
  "framer-motion": "Animation library for gradient effect",
  "../ui/background-gradient": "Custom animated gradient wrapper"
}

Accessibility

  • Semantic HTML structure with proper heading hierarchy
  • Alt text for profile image
  • Descriptive link text for external links
  • Proper anchor tags with rel="noopener noreferrer" for security

Build docs developers (and LLMs) love