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-profileSource 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: latestlucide-react: latest

