Glass Neon

Animated aurora gradient background with frosted-glass cards (backdrop-blur), bold display name with subtle text glow, and neon underline accents on hover. Renders one Spotify music embed at the top of the link stack.

Preview

Source

tsx
"use client";

import {
  Instagram,
  Twitter,
  Youtube,
  Mail,
  Globe,
  ShoppingBag,
  PlayCircle,
  Linkedin,
  Music2,
  ArrowUpRight,
  type LucideIcon,
} from "lucide-react";
import type { LinkIcon, LinksInBioData, RichBlock } from "../types";
import { defaultData } from "../defaultData";

const ICONS: Record<LinkIcon, LucideIcon> = {
  instagram: Instagram,
  twitter: Twitter,
  tiktok: Music2,
  youtube: Youtube,
  spotify: Music2,
  apple: Music2,
  linkedin: Linkedin,
  email: Mail,
  globe: Globe,
  shop: ShoppingBag,
  play: PlayCircle,
};

function MusicBlock({ block }: { block: Extract<RichBlock, { kind: "music" }> }) {
  return (
    <div className="overflow-hidden rounded-2xl border border-white/15 bg-white/[0.06] p-1 backdrop-blur-xl">
      <iframe
        title="Featured track"
        src={block.embedUrl}
        width="100%"
        height="152"
        frameBorder="0"
        allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
        loading="lazy"
        className="block w-full rounded-xl"
        style={{ colorScheme: "dark" }}
      />
    </div>
  );
}

export interface LinksInBioGlassNeonProps {
  data?: LinksInBioData;
}

export default function LinksInBioGlassNeon({
  data = defaultData,
}: LinksInBioGlassNeonProps) {
  const music = data.richBlocks?.find(
    (b): b is Extract<RichBlock, { kind: "music" }> => b.kind === "music"
  );

  return (
    <section
      className="relative min-h-screen w-full overflow-hidden px-4 py-14 sm:py-20"
      style={{
        background: "#08070d",
        fontFamily: "'Inter', system-ui, sans-serif",
        color: "#f7f6fb",
      }}
    >
      <style>{`
        @keyframes glassneon-aurora {
          0%   { transform: translate3d(-15%, -10%, 0) rotate(0deg); }
          50%  { transform: translate3d(15%, 10%, 0)  rotate(180deg); }
          100% { transform: translate3d(-15%, -10%, 0) rotate(360deg); }
        }
        @keyframes glassneon-aurora2 {
          0%   { transform: translate3d(20%, 15%, 0)  rotate(0deg); }
          50%  { transform: translate3d(-20%, -5%, 0) rotate(-180deg); }
          100% { transform: translate3d(20%, 15%, 0)  rotate(-360deg); }
        }
      `}</style>

      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 opacity-80 blur-3xl"
        style={{
          background:
            "conic-gradient(from 90deg at 30% 30%, #5a4cf2 0%, #ff5fa8 25%, #00e7c8 50%, #5a4cf2 75%, #ff5fa8 100%)",
          animation: "glassneon-aurora 22s ease-in-out infinite",
          willChange: "transform",
        }}
      />
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 opacity-60 blur-3xl"
        style={{
          background:
            "radial-gradient(60% 40% at 70% 70%, #ff7eb6 0%, transparent 60%), radial-gradient(40% 30% at 20% 80%, #00e7c8 0%, transparent 60%)",
          animation: "glassneon-aurora2 28s ease-in-out infinite",
          willChange: "transform",
        }}
      />
      <div aria-hidden className="absolute inset-0" style={{ background: "rgba(8,7,13,0.45)" }} />

      <div className="relative mx-auto w-full max-w-[440px]">
        <div className="rounded-3xl border border-white/15 bg-white/[0.06] p-7 backdrop-blur-xl">
          <div className="flex flex-col items-center text-center">
            <div className="rounded-full p-[2px]" style={{ background: "linear-gradient(135deg,#ff5fa8,#00e7c8)" }}>
              <img
                src={data.avatar}
                alt={data.name}
                width={104}
                height={104}
                loading="eager"
                className="h-26 w-26 rounded-full object-cover"
                style={{ height: "104px", width: "104px" }}
              />
            </div>

            <h1
              className="mt-5 text-2xl font-bold tracking-tight"
              style={{ textShadow: "0 0 18px rgba(255,127,209,0.45)" }}
            >
              {data.name}
              {data.verified && (
                <span className="ml-1.5 inline-block translate-y-[-2px] text-[#00e7c8]">✓</span>
              )}
            </h1>
            {data.handle && (
              <p className="mt-1 text-sm text-white/60">{data.handle}</p>
            )}
            {data.bio && (
              <p className="mt-3 max-w-[320px] text-sm leading-relaxed text-white/75">
                {data.bio}
              </p>
            )}
          </div>

          {music && (
            <div className="mt-6">
              <MusicBlock block={music} />
            </div>
          )}

          <div className="mt-6 space-y-3">
            {data.links.map((link) => {
              const Icon = link.icon ? ICONS[link.icon] : Globe;
              return (
                <a
                  key={link.label}
                  href={link.href}
                  className="group relative flex items-center justify-between gap-3 overflow-hidden rounded-xl border border-white/15 bg-white/[0.06] px-4 py-3 backdrop-blur-md transition-all hover:border-white/40 hover:bg-white/[0.10]"
                >
                  <div className="flex min-w-0 items-center gap-3">
                    <span
                      className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg"
                      style={{ background: "rgba(255,255,255,0.08)" }}
                    >
                      <Icon className="h-4 w-4 text-white" strokeWidth={1.6} />
                    </span>
                    <span className="truncate text-sm font-medium text-white">{link.label}</span>
                  </div>
                  <div className="flex items-center gap-2">
                    {link.badge && (
                      <span
                        className="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider"
                        style={{
                          background: "linear-gradient(135deg,#ff5fa8,#00e7c8)",
                          color: "#08070d",
                        }}
                      >
                        {link.badge}
                      </span>
                    )}
                    <ArrowUpRight className="h-4 w-4 text-white/60 transition-colors group-hover:text-white" />
                  </div>
                  <span
                    aria-hidden
                    className="absolute bottom-0 left-1/2 h-px w-0 -translate-x-1/2 transition-all duration-500 group-hover:w-[70%]"
                    style={{
                      background: "linear-gradient(90deg,transparent,#00e7c8,#ff5fa8,transparent)",
                      boxShadow: "0 0 12px #00e7c8, 0 0 20px #ff5fa8",
                    }}
                  />
                </a>
              );
            })}
          </div>

          {data.socials && data.socials.length > 0 && (
            <div className="mt-7 flex items-center justify-center gap-4 text-white/70">
              {data.socials.map((s, i) => {
                const Icon = ICONS[s.type] ?? Globe;
                return (
                  <a
                    key={i}
                    href={s.href}
                    aria-label={s.type}
                    className="rounded-full border border-white/15 bg-white/[0.05] p-2 backdrop-blur-md transition-colors hover:border-white/40 hover:text-white"
                  >
                    <Icon className="h-4 w-4" strokeWidth={1.6} />
                  </a>
                );
              })}
            </div>
          )}
        </div>

        <p className="mt-6 text-center text-[11px] uppercase tracking-[0.2em] text-white/40">
          Made with care
        </p>
      </div>
    </section>
  );
}
Claude Code Instructions

CLI Install

npx innovations add glass-neon

Where to use it

A bold, music-forward link-in-bio page with animated aurora gradients and frosted-glass cards. Hardcoded dark palette (does not follow site theme). Pass a typed 'data' prop (LinksInBioData from src/registry/links-in-bio/types.ts) to swap content. With no prop it renders sample data. Add a richBlocks entry with kind 'music' (provider: 'spotify' or 'apple', embedUrl: full embed URL) to feature a track or album above the link stack. In Astro: import LinksInBioGlassNeon from '../components/innovations/links-in-bio/glass-neon'; <LinksInBioGlassNeon client:load data={myProfile} /> In Next.js: import LinksInBioGlassNeon from '@/components/innovations/links-in-bio/glass-neon'; Best for: musicians, DJs, producers, nightlife brands. The aurora animation runs continuously; if you need to pause it for users with prefers-reduced-motion, wrap the animated divs accordingly.