Personal portfolio spotlight with profile portrait, narrative highlights, and animated social links (Base UI)
@uitripled/react-baseui/src/components/sections/glassmorphism-portfolio-block-baseui.tsx
"use client";
import { Button } from "@base-ui/react/button";
import { motion, Variants } from "framer-motion";
import type { LucideIcon } from "lucide-react";
import {
ArrowUpRight,
Dribbble,
Github,
Linkedin,
Twitter,
} from "lucide-react";
type Highlight = {
title: string;
description: string;
};
type SocialLink = {
label: string;
handle: string;
href: string;
icon: LucideIcon;
};
const highlights: Highlight[] = [
{
title: "Collaborations",
description:
"Linear, Framer, Gamma, Clearbit, and early-stage founders crafting premium launches.",
},
{
title: "Latest drop",
description:
"Aurora OS motion system · 47 reusable blueprints, adaptive tokens, and launch storyboard.",
},
{
title: "Availability",
description:
"2 advisory spots for Q1 · Remote friendly across EU & US time zones.",
},
];
const socialLinks: SocialLink[] = [
{
label: "Twitter",
handle: "@caspermotions",
href: "https://x.com/caspermotions",
icon: Twitter,
},
{
label: "LinkedIn",
handle: "Casper Lightman",
href: "https://linkedin.com/in/casperlightman",
icon: Linkedin,
},
{
label: "Dribbble",
handle: "caspermotion",
href: "https://dribbble.com/caspermotion",
icon: Dribbble,
},
{
label: "GitHub",
handle: "casper-studio",
href: "https://github.com/casper-studio",
icon: Github,
},
];
const listVariants: Variants = {
hidden: { opacity: 0, y: 16 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.4,
staggerChildren: 0.08,
},
},
};
const itemVariants: Variants = {
hidden: { opacity: 0, y: 12 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.35,
},
},
};
export function GlassmorphismPortfolioBlockBaseui() {
return (
<section className="relative min-h-screen overflow-hidden px-6 py-24 lg:py-32">
<div className="mx-auto max-w-6xl">
<motion.div
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.6, ease: "easeOut" }}
className="relative overflow-hidden rounded-3xl border border-border/50 bg-background/45 p-8 backdrop-blur-2xl md:p-12"
>
{/* Glass gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-br from-foreground/[0.05] via-transparent to-transparent pointer-events-none" />
<div className="relative grid gap-12 lg:grid-cols-2">
{/* Left column - Main content */}
<div className="space-y-8">
<span className="inline-flex items-center gap-2 rounded-full border border-border/50 bg-background/55 px-4 py-1.5 text-xs font-semibold uppercase tracking-[0.3em] text-foreground/70 backdrop-blur transition-colors hover:bg-background/70">
Portfolio Insight
</span>
<div className="space-y-4">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="text-2xl font-semibold tracking-tight text-foreground md:text-3xl"
>
Casper Lightman, Product Designer & Motion Director
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className="max-w-xl text-base leading-relaxed text-foreground/70 md:text-md"
>
Principal product designer pairing narrative motion with
premium SaaS brands. Casper leads founders and product teams
through expressive design systems that convert curiosity into
momentum.
</motion.p>
</div>
{/* Highlights grid */}
<div className="grid gap-4 sm:grid-cols-1">
{highlights.map((item, index) => (
<motion.div
key={item.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.4, delay: 0.1 * index }}
whileHover={{ y: -4 }}
className="group relative overflow-hidden rounded-2xl border border-border/40 bg-background/60 p-5 backdrop-blur transition-all hover:border-border/60 hover:shadow-lg"
>
<div className="absolute inset-0 bg-gradient-to-br from-foreground/[0.04] via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100 -z-10" />
<div className="relative space-y-2">
<p className="text-xs font-semibold uppercase tracking-[0.25em] text-foreground/40">
{item.title}
</p>
<p className="text-sm leading-relaxed text-foreground/70">
{item.description}
</p>
</div>
</motion.div>
))}
</div>
{/* CTA Buttons */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.3 }}
className="grid grid-cols-1 gap-4"
>
<Button
onClick={() =>
window.open("https://casper.studio/case-studies", "_blank")
}
className="inline-flex h-12 w-full items-center justify-center gap-2 rounded-full bg-primary px-8 text-sm font-medium uppercase tracking-[0.25em] text-primary-foreground transition-all hover:shadow-lg sm:w-auto"
>
View case studies
<ArrowUpRight className="h-4 w-4" />
</Button>
</motion.div>
</div>
{/* Right column - Profile card */}
<div className="relative">
<div className="absolute inset-0 rounded-[32px] bg-gradient-to-b from-primary/15 via-transparent to-transparent blur-3xl" />
<div className="relative flex h-full flex-col justify-between overflow-hidden rounded-[28px] border border-border/50 bg-background/60 p-8 backdrop-blur-xl">
<div className="flex flex-col items-center text-center">
{/* Avatar with glow */}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="relative mb-6"
>
<div className="absolute left-1/2 top-1/2 h-32 w-32 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary/20 blur-2xl" />
<img
src="https://images.unsplash.com/photo-1544723795-3fb6469f5b39?w=640&q=80"
alt="Casper Lightman"
className="relative h-32 w-32 rounded-full border border-border/40 object-cover shadow-[0_25px_60px_rgba(15,23,42,0.3)] dark:shadow-[0_25px_60px_rgba(0,0,0,0.6)]"
/>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className="space-y-1"
>
<h3 className="text-2xl font-semibold tracking-tight text-foreground">
Casper Lightman
</h3>
<p className="text-xs font-semibold uppercase tracking-[0.35em] text-foreground/45">
Product Designer · Motion Director
</p>
</motion.div>
<motion.p
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.3 }}
className="mt-4 max-w-sm text-sm leading-relaxed text-foreground/70"
>
Partnering with future-facing teams to choreograph
interfaces that feel cinematic yet effortless.
</motion.p>
</div>
{/* Social links */}
<motion.div
variants={listVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-80px" }}
className="mt-8 flex flex-col gap-3"
>
{socialLinks.map((social) => {
const Icon = social.icon;
return (
<motion.a
key={social.label}
variants={itemVariants}
href={social.href}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center justify-between rounded-2xl border border-border/40 bg-background/70 px-4 py-3 text-left transition-all hover:-translate-y-0.5 hover:border-border/60 hover:bg-background/80 hover:shadow-md"
whileHover={{ scale: 1.01 }}
whileTap={{ scale: 0.985 }}
>
<div className="flex items-center gap-3">
<span className="flex h-10 w-10 items-center justify-center rounded-full border border-border/40 bg-background/70 text-foreground/80 shadow-[0_10px_30px_rgba(15,23,42,0.2)] transition-all group-hover:shadow-[0_10px_30px_rgba(15,23,42,0.3)] dark:shadow-[0_10px_30px_rgba(0,0,0,0.4)] dark:group-hover:shadow-[0_10px_30px_rgba(0,0,0,0.5)]">
<Icon className="h-4 w-4" />
</span>
<div>
<p className="text-sm font-semibold text-foreground">
{social.label}
</p>
<p className="text-xs text-foreground/60">
{social.handle}
</p>
</div>
</div>
<ArrowUpRight className="h-4 w-4 text-foreground/40 transition-all group-hover:translate-x-0.5 group-hover:-translate-y-0.5 group-hover:text-foreground/70" />
</motion.a>
);
})}
</motion.div>
</div>
</div>
</div>
</motion.div>
</div>
</section>
);
}