Velocity UI
Loading…
Menu

Minimal User Profile

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

Installation

Add this component to your project using the CLI:

terminal
npx vui-registry-cli-v1 add minimal-user-profile

Source Code

minimal-user-profile.tsx
"use client"

import { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import { 
  Music, 
  Heart, 
  Share2, 
  MoreHorizontal, 
  MapPin, 
  Link as LinkIcon,
  Twitter,
  Instagram,
  Github
} from "lucide-react"

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

  return (
    <div className="flex items-center justify-center min-h-[600px] w-full bg-neutral-100 dark:bg-neutral-950 p-8 font-sans">
      <motion.div 
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.5 }}
        className="relative w-full max-w-[380px] rounded-[2.5rem] bg-white/80 dark:bg-neutral-900/80 backdrop-blur-xl border border-white/40 dark:border-white/5 shadow-2xl overflow-hidden"
      >
        {/* Banner Image */}
        <div className="h-32 w-full relative overflow-hidden">
          <div className="absolute inset-0 bg-gradient-to-b from-transparent to-black/20 z-10" />
          <motion.img 
            initial={{ scale: 1.1 }}
            animate={{ scale: 1 }}
            transition={{ duration: 1.5 }}
            src="https://i1.sndcdn.com/artworks-000132598634-ui94jo-t1080x1080.jpg" 
            alt="Banner" 
            className="w-full h-full object-cover blur-sm opacity-80"
          />
        </div>

        {/* Profile Content */}
        <div className="px-6 pb-8 relative z-20">
          {/* Avatar */}
          <div className="relative -mt-16 mb-4 flex justify-between items-end">
            <motion.div 
              initial={{ scale: 0 }}
              animate={{ scale: 1 }}
              transition={{ type: "spring", stiffness: 260, damping: 20, delay: 0.1 }}
              className="w-28 h-28 rounded-full border-4 border-white dark:border-neutral-900 overflow-hidden shadow-lg bg-white dark:bg-neutral-800"
            >
              <img 
                src="https://i1.sndcdn.com/artworks-000132598634-ui94jo-t1080x1080.jpg" 
                alt="Profile" 
                className="w-full h-full object-cover"
              />
            </motion.div>
            
            <div className="flex gap-2 mb-2">
              <motion.button
                whileHover={{ scale: 1.1 }}
                whileTap={{ scale: 0.9 }}
                className="p-2.5 rounded-full bg-white/50 dark:bg-white/5 backdrop-blur-md border border-white/20 dark:border-white/10 text-neutral-600 dark:text-neutral-300 hover:bg-white dark:hover:bg-white/10 transition-colors"
              >
                <Share2 className="w-4 h-4" />
              </motion.button>
              <motion.button
                whileHover={{ scale: 1.1 }}
                whileTap={{ scale: 0.9 }}
                className="p-2.5 rounded-full bg-white/50 dark:bg-white/5 backdrop-blur-md border border-white/20 dark:border-white/10 text-neutral-600 dark:text-neutral-300 hover:bg-white dark:hover:bg-white/10 transition-colors"
              >
                <MoreHorizontal className="w-4 h-4" />
              </motion.button>
            </div>
          </div>

          {/* User Info */}
          <div className="space-y-1 mb-6">
            <div className="flex items-center gap-2">
              <h2 className="text-2xl font-bold text-neutral-800 dark:text-neutral-100">
                One Direction
              </h2>
              <span className="px-2 py-0.5 rounded-full text-[10px] font-medium bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/20">
                Artist
              </span>
            </div>
            <p className="text-sm text-neutral-500 dark:text-neutral-400">@onedirection</p>
            
            <div className="flex flex-wrap gap-4 pt-2 text-xs text-neutral-500 dark:text-neutral-400">
              <div className="flex items-center gap-1">
                <MapPin className="w-3 h-3" />
                London, UK
              </div>
              <div className="flex items-center gap-1 hover:text-blue-500 transition-colors cursor-pointer">
                <LinkIcon className="w-3 h-3" />
                onedirection.com
              </div>
            </div>
          </div>

          {/* Stats */}
          <div className="grid grid-cols-3 gap-4 mb-6 py-4 border-y border-neutral-200/60 dark:border-white/5">
            {[
              { label: "Followers", value: "32.5M" },
              { label: "Following", value: "128" },
              { label: "Tracks", value: "84" }
            ].map((stat, i) => (
              <motion.div 
                key={stat.label}
                initial={{ opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.2 + (i * 0.1) }}
                className="text-center"
              >
                <div className="text-lg font-bold text-neutral-800 dark:text-neutral-100">
                  {stat.value}
                </div>
                <div className="text-[10px] uppercase tracking-wider text-neutral-500 dark:text-neutral-400">
                  {stat.label}
                </div>
              </motion.div>
            ))}
          </div>

          {/* Action Button */}
          <motion.button
            onClick={() => setIsFollowing(!isFollowing)}
            whileHover={{ scale: 1.02 }}
            whileTap={{ scale: 0.98 }}
            className={`w-full py-3 rounded-xl font-semibold text-sm transition-all duration-300 relative overflow-hidden group ${
              isFollowing 
                ? "bg-neutral-100 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200 border border-neutral-200 dark:border-neutral-700" 
                : "text-white shadow-lg shadow-blue-500/25"
            }`}
          >
            {!isFollowing && (
              <div className="absolute inset-0 bg-gradient-to-r from-blue-600 to-indigo-600 transition-transform duration-300 group-hover:scale-105" />
            )}
            <span className="relative flex items-center justify-center gap-2">
              {isFollowing ? (
                "Following"
              ) : (
                <>
                  <Heart className="w-4 h-4 fill-white/20" />
                  Follow
                </>
              )}
            </span>
          </motion.button>

          {/* Recent Tracks Mini-List */}
          <div className="mt-8 space-y-4">
            <h3 className="text-xs font-semibold uppercase tracking-wider text-neutral-400 dark:text-neutral-500 mb-3">
              Popular Tracks
            </h3>
            {[
              { title: "Steal My Girl", plays: "845M" },
              { title: "Night Changes", plays: "920M" },
              { title: "Story of My Life", plays: "1.2B" }
            ].map((track, i) => (
              <motion.div
                key={track.title}
                initial={{ opacity: 0, x: -20 }}
                animate={{ opacity: 1, x: 0 }}
                transition={{ delay: 0.3 + (i * 0.1) }}
                className="flex items-center justify-between group cursor-pointer"
              >
                <div className="flex items-center gap-3">
                  <div className="w-8 h-8 rounded-lg bg-neutral-100 dark:bg-neutral-800 flex items-center justify-center text-neutral-400 group-hover:text-blue-500 group-hover:bg-blue-500/10 transition-colors">
                    <Music className="w-4 h-4" />
                  </div>
                  <div className="flex flex-col">
                    <span className="text-sm font-medium text-neutral-700 dark:text-neutral-200 group-hover:text-blue-500 transition-colors">
                      {track.title}
                    </span>
                    <span className="text-[10px] text-neutral-400">
                      {track.plays} plays
                    </span>
                  </div>
                </div>
                <div className="w-8 h-8 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
                   <div className="w-1 h-1 rounded-full bg-neutral-400 mx-0.5" />
                   <div className="w-1 h-1 rounded-full bg-neutral-400 mx-0.5" />
                   <div className="w-1 h-1 rounded-full bg-neutral-400 mx-0.5" />
                </div>
              </motion.div>
            ))}
          </div>
        </div>
      </motion.div>
    </div>
  )
}

Dependencies

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