Menu

Minimal User Profile

A clean, glassmorphic user profile card with banner, stats, and social links.

Preview

Live interactive preview.

Installation

Add this component to your project using the CLI:

terminal
npx -y vui-registry-cli-v1@latest add minimal-user-profile

Source Code

minimal-user-profile.tsx
"use client"

import { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import { MapPin, Link as LinkIcon, ExternalLink, Check } from "lucide-react"

const PROJECTS = [
  { title: "Velocity UI", stack: "React", stars: "4.2k" },
  { title: "Astro Dashboard", stack: "Next.js", stars: "1.8k" },
  { title: "Lumina Icons", stack: "SVG", stars: "2.5k" },
]

export default function MinimalUserProfile() {
  const [isFollowing, setIsFollowing] = useState(false)

  return (
    <div className="flex items-center justify-center w-full p-6 font-sans">
      <motion.div
        initial={{ opacity: 0, y: 12 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.4, ease: "easeOut" }}
        className="w-full max-w-sm rounded-2xl border border-neutral-200 dark:border-white/10 bg-white dark:bg-neutral-900 overflow-hidden"
      >
        {/* Header strip */}
        <div className="h-20 bg-gradient-to-br from-neutral-100 to-neutral-50 dark:from-neutral-800 dark:to-neutral-900 border-b border-neutral-100 dark:border-white/5" />

        <div className="px-5 pb-6 -mt-10">
          {/* Avatar */}
          <div className="flex items-end justify-between mb-4">
            <div className="w-[72px] h-[72px] rounded-2xl border-2 border-white dark:border-neutral-900 overflow-hidden bg-neutral-100 dark:bg-neutral-800 shadow-sm">
              <img
                src="https://i.postimg.cc/3xgQH76g/Whats-App-Image-2026-02-19-at-8-23-43-PM.jpg"
                alt="Vikas Yadav"
                className="w-full h-full object-cover"
              />
            </div>
            <span className="mb-1 px-2 py-0.5 rounded-md text-[9px] font-bold uppercase tracking-widest bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 border border-emerald-500/20">
              Available
            </span>
          </div>

          {/* Identity */}
          <div className="mb-5">
            <h2 className="text-xl font-bold text-neutral-900 dark:text-white tracking-tight leading-none">
              Vikas Yadav
            </h2>
            <p className="text-[11px] font-semibold uppercase tracking-[0.15em] text-neutral-400 mt-1.5">
              Full-Stack Developer
            </p>
            <p className="text-xs text-neutral-500 mt-2 leading-relaxed">
              Building premium UI systems and design tooling at Velocity UI.
            </p>
          </div>

          {/* Meta row */}
          <div className="flex flex-wrap gap-3 mb-5 text-xs text-neutral-500">
            <span className="inline-flex items-center gap-1.5">
              <MapPin className="w-3 h-3" />
              Dehradun, India
            </span>
            <span className="inline-flex items-center gap-1.5 hover:text-emerald-600 dark:hover:text-emerald-400 transition-colors cursor-pointer">
              <LinkIcon className="w-3 h-3" />
              vikas.dev
            </span>
          </div>

          {/* Stats */}
          <div className="grid grid-cols-3 gap-2 mb-5 py-3 border-y border-neutral-100 dark:border-white/5">
            {[
              { label: "Followers", value: "24K" },
              { label: "Following", value: "152" },
              { label: "Projects", value: "48" },
            ].map((stat) => (
              <div key={stat.label} className="text-center">
                <div className="text-base font-bold text-neutral-900 dark:text-white tabular-nums">{stat.value}</div>
                <div className="text-[9px] font-bold uppercase tracking-widest text-neutral-400 mt-0.5">{stat.label}</div>
              </div>
            ))}
          </div>

          {/* CTA */}
          <motion.button
            type="button"
            onClick={() => setIsFollowing(!isFollowing)}
            whileTap={{ scale: 0.98 }}
            className={`w-full py-2.5 rounded-xl text-xs font-bold uppercase tracking-wider transition-all ${
              isFollowing
                ? "bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-200 border border-neutral-200 dark:border-white/10"
                : "bg-emerald-600 hover:bg-emerald-500 text-white shadow-sm shadow-emerald-500/20"
            }`}
          >
            <AnimatePresence mode="wait">
              {isFollowing ? (
                <motion.span key="following" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="inline-flex items-center gap-1.5">
                  <Check className="w-3.5 h-3.5" />
                  Following
                </motion.span>
              ) : (
                <motion.span key="follow" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
                  Follow
                </motion.span>
              )}
            </AnimatePresence>
          </motion.button>

          {/* Projects */}
          <div className="mt-6">
            <p className="text-[9px] font-bold uppercase tracking-[0.2em] text-neutral-400 mb-3">Selected Work</p>
            <div className="space-y-1">
              {PROJECTS.map((project, i) => (
                <motion.div
                  key={project.title}
                  initial={{ opacity: 0, x: -6 }}
                  animate={{ opacity: 1, x: 0 }}
                  transition={{ delay: 0.15 + i * 0.06 }}
                  className="flex items-center justify-between py-2.5 px-2 -mx-2 rounded-lg hover:bg-neutral-50 dark:hover:bg-white/[0.03] transition-colors group cursor-pointer"
                >
                  <div>
                    <p className="text-[13px] font-semibold text-neutral-800 dark:text-neutral-100">{project.title}</p>
                    <p className="text-[10px] text-neutral-400 uppercase tracking-wide">{project.stack}</p>
                  </div>
                  <div className="flex items-center gap-2">
                    <span className="text-[10px] font-medium text-neutral-400 tabular-nums">{project.stars}</span>
                    <ExternalLink className="w-3 h-3 text-neutral-300 group-hover:text-emerald-500 transition-colors" />
                  </div>
                </motion.div>
              ))}
            </div>
          </div>
        </div>
      </motion.div>
    </div>
  )
}

Dependencies

  • framer-motion: latest
  • lucide-react: latest