Web InnoventixFreeCode

Profile Social

Original · free

social profile with follow

byWeb InnoventixReact + Tailwind
profilesocialprofiles
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/profile-social.json
profile-social.tsx
"use client";

import { useCallback, useEffect, useId, useRef, useState } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";

type SocialLink = {
  id: string;
  label: string;
  href: string;
  text: string;
  icon: "globe" | "mail" | "calendar";
};

type Mutual = {
  initials: string;
  name: string;
  tone: string;
};

const BASE_FOLLOWERS = 18402;
const BASE_LIKES = 342;

const LINKS: SocialLink[] = [
  {
    id: "site",
    label: "Open fieldnotes.email in a new tab",
    href: "https://example.com",
    text: "fieldnotes.email",
    icon: "globe",
  },
  {
    id: "mail",
    label: "Email Nadia Rahman",
    href: "mailto:hello@example.com",
    text: "hello@fieldnotes.email",
    icon: "mail",
  },
];

const MUTUALS: Mutual[] = [
  { initials: "PR", name: "Priya Raman", tone: "from-indigo-500 to-violet-500" },
  { initials: "DO", name: "Dan Okafor", tone: "from-emerald-500 to-sky-500" },
  { initials: "LM", name: "Lena Moreau", tone: "from-rose-500 to-amber-500" },
  { initials: "KT", name: "Kofi Tetteh", tone: "from-sky-500 to-indigo-500" },
];

const TOPICS = ["Decision-making", "Team process", "Writing", "Post-mortems"];

function formatCount(n: number): string {
  return n.toLocaleString("en-US");
}

function Icon({ name, className }: { name: SocialLink["icon"]; className: string }) {
  if (name === "globe") {
    return (
      <svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
        <circle cx="10" cy="10" r="7.25" />
        <path d="M2.9 10h14.2M10 2.75c1.9 2 2.85 4.4 2.85 7.25S11.9 15.25 10 17.25c-1.9-2-2.85-4.4-2.85-7.25S8.1 4.75 10 2.75z" />
      </svg>
    );
  }
  if (name === "mail") {
    return (
      <svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
        <rect x="2.75" y="4.75" width="14.5" height="10.5" rx="2" />
        <path d="M3.25 6.2l6.75 4.8 6.75-4.8" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
      <rect x="2.75" y="4.25" width="14.5" height="13" rx="2" />
      <path d="M2.75 8.25h14.5M6.5 2.75v3M13.5 2.75v3" strokeLinecap="round" />
    </svg>
  );
}

export default function ProfileSocial() {
  const reduced = useReducedMotion();
  const uid = useId();

  const [following, setFollowing] = useState(false);
  const [notify, setNotify] = useState(false);
  const [liked, setLiked] = useState(false);
  const [copied, setCopied] = useState(false);
  const [burst, setBurst] = useState(0);

  const copyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const burstTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (copyTimer.current) clearTimeout(copyTimer.current);
      if (burstTimer.current) clearTimeout(burstTimer.current);
    };
  }, []);

  const followers = following ? BASE_FOLLOWERS + 1 : BASE_FOLLOWERS;
  const likes = liked ? BASE_LIKES + 1 : BASE_LIKES;

  const toggleFollow = useCallback(() => {
    setFollowing((prev) => {
      const next = !prev;
      if (!next) setNotify(false);
      if (next) {
        setBurst((b) => b + 1);
        if (burstTimer.current) clearTimeout(burstTimer.current);
        burstTimer.current = setTimeout(() => setBurst(0), 1100);
      }
      return next;
    });
  }, []);

  const handleCopy = useCallback(() => {
    const url = "fieldnotes.email/@nadiarahman";
    const done = () => {
      setCopied(true);
      if (copyTimer.current) clearTimeout(copyTimer.current);
      copyTimer.current = setTimeout(() => setCopied(false), 2000);
    };
    if (typeof navigator !== "undefined" && navigator.clipboard) {
      navigator.clipboard.writeText(url).then(done).catch(done);
    } else {
      done();
    }
  }, []);

  return (
    <section className="relative w-full bg-slate-50 px-4 py-16 sm:px-6 sm:py-24 dark:bg-slate-950">
      <style>{`
        @keyframes psoc-orbit {
          from { transform: rotate(0deg); }
          to   { transform: rotate(360deg); }
        }
        @keyframes psoc-halo {
          0%, 100% { opacity: 0.55; transform: translate3d(0, 0, 0) scale(1); }
          50%      { opacity: 0.85; transform: translate3d(2%, -3%, 0) scale(1.08); }
        }
        @keyframes psoc-live {
          0%   { transform: scale(1); opacity: 0.6; }
          75%  { transform: scale(2.4); opacity: 0; }
          100% { transform: scale(2.4); opacity: 0; }
        }
        .psoc-orbit { animation: psoc-orbit 14s linear infinite; }
        .psoc-halo  { animation: psoc-halo 18s ease-in-out infinite; }
        .psoc-live  { animation: psoc-live 2.4s ease-out infinite; }
        @media (prefers-reduced-motion: reduce) {
          .psoc-orbit, .psoc-halo, .psoc-live { animation: none !important; }
        }
      `}</style>

      <div
        aria-hidden="true"
        className="psoc-halo pointer-events-none absolute left-1/2 top-8 h-72 w-[42rem] max-w-full -translate-x-1/2 rounded-full bg-[radial-gradient(50%_60%_at_30%_40%,#818cf8_0%,transparent_70%),radial-gradient(45%_55%_at_70%_50%,#34d399_0%,transparent_72%)] opacity-60 blur-3xl dark:opacity-30"
      />

      <div className="relative mx-auto w-full max-w-2xl">
        <article className="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-[0_1px_2px_rgba(15,23,42,0.04),0_12px_40px_-12px_rgba(15,23,42,0.12)] dark:border-slate-800 dark:bg-slate-900 dark:shadow-[0_12px_40px_-12px_rgba(0,0,0,0.6)]">
          <div className="px-5 pt-6 sm:px-8 sm:pt-8">
            <div className="flex items-start justify-between gap-4">
              <div className="flex min-w-0 items-center gap-4">
                <div className="relative shrink-0">
                  <div className="relative grid h-[4.5rem] w-[4.5rem] place-items-center rounded-full p-[2px] sm:h-20 sm:w-20">
                    <span
                      aria-hidden="true"
                      className="psoc-orbit absolute inset-0 rounded-full bg-[conic-gradient(from_0deg,#6366f1,#a78bfa,#34d399,#38bdf8,#6366f1)]"
                    />
                    <span className="relative grid h-full w-full place-items-center rounded-full bg-white dark:bg-slate-900">
                      <span className="grid h-[calc(100%-4px)] w-[calc(100%-4px)] place-items-center rounded-full bg-gradient-to-br from-slate-800 to-slate-600 text-lg font-semibold tracking-tight text-white sm:text-xl dark:from-slate-100 dark:to-slate-300 dark:text-slate-900">
                        NR
                      </span>
                    </span>
                  </div>
                  <span className="absolute bottom-0.5 right-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-white ring-2 ring-white dark:bg-slate-900 dark:ring-slate-900">
                    <span aria-hidden="true" className="psoc-live absolute h-2.5 w-2.5 rounded-full bg-emerald-400" />
                    <span className="relative h-2.5 w-2.5 rounded-full bg-emerald-500" />
                    <span className="sr-only">Active now</span>
                  </span>
                </div>

                <div className="min-w-0">
                  <div className="flex items-center gap-1.5">
                    <h2 className="truncate text-lg font-semibold tracking-tight text-slate-900 sm:text-xl dark:text-slate-50">
                      Nadia Rahman
                    </h2>
                    <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4 shrink-0 text-sky-500" fill="currentColor">
                      <path
                        fillRule="evenodd"
                        d="M10 1.6l2 1.5 2.5-.2.9 2.3 2.2 1.3-.7 2.4.7 2.4-2.2 1.3-.9 2.3-2.5-.2-2 1.5-2-1.5-2.5.2-.9-2.3L2.4 11l.7-2.4-.7-2.4 2.2-1.3.9-2.3 2.5.2 2-1.5zm3.2 6a.85.85 0 00-1.25-1.15l-2.85 2.95-1.1-1.15a.85.85 0 10-1.25 1.2l1.75 1.75a.85.85 0 001.25 0l3.45-3.6z"
                        clipRule="evenodd"
                      />
                    </svg>
                    <span className="sr-only">Verified writer</span>
                  </div>
                  <p className="mt-0.5 truncate text-sm text-slate-500 dark:text-slate-400">
                    @nadiarahman · Porto, Portugal
                  </p>
                </div>
              </div>

              <button
                type="button"
                onClick={handleCopy}
                aria-label="Copy link to this profile"
                className="grid h-9 w-9 shrink-0 place-items-center rounded-lg border border-slate-200 bg-white text-slate-500 transition-colors hover:bg-slate-50 hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100 dark:focus-visible:ring-offset-slate-900"
              >
                {copied ? (
                  <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4 text-emerald-500" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M4 10.5l4 4 8-9" />
                  </svg>
                ) : (
                  <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round">
                    <path d="M8.4 11.6a3 3 0 004.4.2l2.4-2.4a3 3 0 10-4.3-4.3l-1 1" />
                    <path d="M11.6 8.4a3 3 0 00-4.4-.2l-2.4 2.4a3 3 0 104.3 4.3l1-1" />
                  </svg>
                )}
              </button>
            </div>

            <p className="mt-5 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
              I write <span className="font-medium text-slate-900 dark:text-slate-100">Field Notes</span>, a weekly
              letter about how software teams actually make decisions — the meeting nobody minuted, the doc everyone
              skimmed, the trade-off that only shows up eighteen months later. Eight years of engineering management,
              written down honestly.
            </p>

            <ul className="mt-4 flex flex-wrap gap-1.5">
              {TOPICS.map((topic) => (
                <li
                  key={topic}
                  className="rounded-full border border-slate-200 bg-slate-50 px-2.5 py-1 text-xs font-medium text-slate-600 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-300"
                >
                  {topic}
                </li>
              ))}
            </ul>

            <div className="mt-5 flex flex-wrap items-center gap-x-5 gap-y-2 text-sm">
              {LINKS.map((link) => (
                <a
                  key={link.id}
                  href={link.href}
                  target="_blank"
                  rel="noopener"
                  aria-label={link.label}
                  className="inline-flex items-center gap-1.5 rounded-md text-slate-500 underline-offset-4 transition-colors hover:text-indigo-600 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:text-slate-400 dark:hover:text-indigo-400 dark:focus-visible:ring-offset-slate-900"
                >
                  <Icon name={link.icon} className="h-4 w-4" />
                  {link.text}
                </a>
              ))}
              <span className="inline-flex items-center gap-1.5 text-slate-500 dark:text-slate-400">
                <Icon name="calendar" className="h-4 w-4" />
                Joined March 2019
              </span>
            </div>
          </div>

          {/* Stats */}
          <div className="mt-6 grid grid-cols-3 border-y border-slate-200 dark:border-slate-800">
            <div className="border-r border-slate-200 px-4 py-4 text-center dark:border-slate-800">
              <p className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50">1,284</p>
              <p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
                Letters
              </p>
            </div>
            <div className="relative border-r border-slate-200 px-4 py-4 text-center dark:border-slate-800">
              <div className="relative flex h-6 items-center justify-center overflow-hidden">
                <AnimatePresence initial={false} mode="popLayout">
                  <motion.span
                    key={followers}
                    initial={reduced ? false : { y: 14, opacity: 0 }}
                    animate={{ y: 0, opacity: 1 }}
                    exit={reduced ? { opacity: 0 } : { y: -14, opacity: 0 }}
                    transition={reduced ? { duration: 0 } : { duration: 0.22, ease: "easeOut" }}
                    className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50"
                  >
                    {formatCount(followers)}
                  </motion.span>
                </AnimatePresence>
                <AnimatePresence>
                  {burst > 0 && !reduced && (
                    <motion.span
                      key={burst}
                      aria-hidden="true"
                      initial={{ opacity: 0, y: 4, scale: 0.8 }}
                      animate={{ opacity: 1, y: -18, scale: 1 }}
                      exit={{ opacity: 0, y: -26 }}
                      transition={{ duration: 0.9, ease: "easeOut" }}
                      className="pointer-events-none absolute right-3 top-0 text-xs font-bold text-emerald-500"
                    >
                      +1
                    </motion.span>
                  )}
                </AnimatePresence>
              </div>
              <p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
                Readers
              </p>
            </div>
            <div className="px-4 py-4 text-center">
              <p className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50">312</p>
              <p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
                Following
              </p>
            </div>
          </div>

          {/* Actions */}
          <div className="px-5 py-5 sm:px-8">
            <div className="flex items-center gap-2">
              <motion.button
                type="button"
                aria-pressed={following}
                onClick={toggleFollow}
                whileTap={reduced ? undefined : { scale: 0.97 }}
                transition={reduced ? { duration: 0 } : { type: "spring", stiffness: 500, damping: 30 }}
                className={[
                  "inline-flex h-11 flex-1 items-center justify-center gap-2 rounded-xl text-sm font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-900",
                  following
                    ? "bg-slate-100 text-slate-700 ring-1 ring-inset ring-slate-200 hover:bg-slate-200 focus-visible:ring-slate-400 dark:bg-slate-800 dark:text-slate-100 dark:ring-slate-700 dark:hover:bg-slate-700"
                    : "bg-indigo-600 text-white shadow-sm hover:bg-indigo-500 focus-visible:ring-indigo-500",
                ].join(" ")}
              >
                {following ? (
                  <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M4 10.5l4 4 8-9" />
                  </svg>
                ) : (
                  <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
                    <path d="M10 4.5v11M4.5 10h11" />
                  </svg>
                )}
                {following ? "Following" : "Follow"}
              </motion.button>

              <AnimatePresence initial={false}>
                {following && (
                  <motion.button
                    type="button"
                    aria-pressed={notify}
                    aria-label={notify ? "Turn off new letter alerts" : "Turn on new letter alerts"}
                    onClick={() => setNotify((v) => !v)}
                    initial={reduced ? false : { opacity: 0, width: 0, marginLeft: 0 }}
                    animate={{ opacity: 1, width: 44, marginLeft: 0 }}
                    exit={reduced ? { opacity: 0 } : { opacity: 0, width: 0, marginLeft: -8 }}
                    transition={reduced ? { duration: 0 } : { duration: 0.22, ease: "easeOut" }}
                    className={[
                      "grid h-11 shrink-0 place-items-center overflow-hidden rounded-xl border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-900",
                      notify
                        ? "border-transparent bg-amber-400 text-slate-900 hover:bg-amber-300 focus-visible:ring-amber-500"
                        : "border-slate-200 bg-white text-slate-500 hover:bg-slate-50 hover:text-slate-800 focus-visible:ring-indigo-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100",
                    ].join(" ")}
                  >
                    {notify ? (
                      <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="currentColor">
                        <path d="M10 2a4.5 4.5 0 00-4.5 4.5c0 3.2-.8 4.6-1.4 5.3-.4.4-.1 1.2.5 1.2h10.8c.6 0 .9-.8.5-1.2-.6-.7-1.4-2.1-1.4-5.3A4.5 4.5 0 0010 2zM8.2 15.2a1.9 1.9 0 003.6 0H8.2z" />
                      </svg>
                    ) : (
                      <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M5.8 6.9a4.2 4.2 0 018.4 0c0 3.1.8 4.5 1.4 5.2.3.4 0 1-.5 1H4.9c-.5 0-.8-.6-.5-1 .6-.7 1.4-2.1 1.4-5.2z" />
                        <path d="M8.4 15.4a1.8 1.8 0 003.2 0" />
                        <path d="M3.5 3.5l13 13" className="text-rose-400" />
                      </svg>
                    )}
                  </motion.button>
                )}
              </AnimatePresence>

              <a
                href="mailto:hello@example.com"
                className="inline-flex h-11 shrink-0 items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 text-sm font-semibold text-slate-700 transition-colors hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800 dark:focus-visible:ring-offset-slate-900"
              >
                <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M17 10a6.4 6.4 0 01-6.9 6.4A7 7 0 013 10.6 7 7 0 0110 3a7 7 0 017 7z" />
                  <path d="M6.5 13.5l1-3.5" />
                  <path d="M8 8.5l4.5-1.2-1.2 4.5" />
                </svg>
                Message
              </a>
            </div>

            <p aria-live="polite" className="sr-only">
              {following
                ? notify
                  ? "Following Nadia Rahman. Alerts on for new letters."
                  : "Following Nadia Rahman. Alerts off."
                : "Not following Nadia Rahman."}
              {copied ? " Profile link copied to clipboard." : ""}
            </p>

            {/* Mutuals */}
            <div className="mt-5 flex items-center gap-3">
              <ul className="flex shrink-0 -space-x-2" aria-hidden="true">
                {MUTUALS.map((m) => (
                  <li
                    key={m.initials}
                    className={`grid h-7 w-7 place-items-center rounded-full bg-gradient-to-br ${m.tone} text-[10px] font-semibold text-white ring-2 ring-white dark:ring-slate-900`}
                  >
                    {m.initials}
                  </li>
                ))}
              </ul>
              <p className="text-xs leading-relaxed text-slate-500 dark:text-slate-400">
                Followed by{" "}
                <span className="font-medium text-slate-700 dark:text-slate-200">Priya Raman</span>,{" "}
                <span className="font-medium text-slate-700 dark:text-slate-200">Dan Okafor</span> and 47 others you
                follow.
              </p>
            </div>
          </div>

          {/* Pinned letter */}
          <div className="border-t border-slate-200 bg-slate-50/70 px-5 py-5 sm:px-8 dark:border-slate-800 dark:bg-slate-950/40">
            <div className="flex items-center gap-1.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
              <svg viewBox="0 0 20 20" aria-hidden="true" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                <path d="M8 2.5h4l-.6 4.2 2.6 2.3H5.9l2.7-2.3L8 2.5z" />
                <path d="M10 9v8.5" />
              </svg>
              Pinned letter
            </div>

            <h3 className="mt-2 text-sm font-semibold text-slate-900 dark:text-slate-50">
              <a
                href="https://example.com"
                target="_blank"
                rel="noopener"
                id={`${uid}-pinned`}
                className="rounded-md underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-950"
              >
                Issue #211 — The reorg was decided in a hallway
              </a>
            </h3>
            <p className="mt-1.5 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
              Every org chart has an official story and a real one. This week: how to spot which decisions were made
              before the meeting, and why writing them down after the fact is not the same as making them in the open.
            </p>

            <div className="mt-3 flex items-center gap-3">
              <button
                type="button"
                aria-pressed={liked}
                aria-label={liked ? "Remove like from Issue 211" : "Like Issue 211"}
                onClick={() => setLiked((v) => !v)}
                className={[
                  "inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs font-semibold tabular-nums transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-950",
                  liked
                    ? "bg-rose-50 text-rose-600 focus-visible:ring-rose-500 dark:bg-rose-500/10 dark:text-rose-400"
                    : "text-slate-500 hover:bg-slate-100 hover:text-slate-800 focus-visible:ring-indigo-500 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100",
                ].join(" ")}
              >
                <motion.span
                  animate={reduced ? undefined : { scale: liked ? [1, 1.35, 1] : 1 }}
                  transition={reduced ? { duration: 0 } : { duration: 0.32, ease: "easeOut" }}
                  className="inline-grid place-items-center"
                >
                  <svg
                    viewBox="0 0 20 20"
                    aria-hidden="true"
                    className="h-4 w-4"
                    fill={liked ? "currentColor" : "none"}
                    stroke="currentColor"
                    strokeWidth="1.6"
                    strokeLinejoin="round"
                  >
                    <path d="M10 16.5S3.5 12.7 3.5 8.2a3.5 3.5 0 016.5-1.9 3.5 3.5 0 016.5 1.9c0 4.5-6.5 8.3-6.5 8.3z" />
                  </svg>
                </motion.span>
                {formatCount(likes)}
              </button>

              <span className="inline-flex items-center gap-1.5 text-xs font-medium tabular-nums text-slate-500 dark:text-slate-400">
                <svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M16.5 9.8a5.9 5.9 0 01-6.4 5.9L5.5 17l.8-3.2A5.7 5.7 0 014.5 9.8C4.5 6.6 7.2 4 10.5 4s6 2.6 6 5.8z" />
                </svg>
                58 replies
              </span>

              <span className="ml-auto text-xs text-slate-400 dark:text-slate-500">4 days ago</span>
            </div>
          </div>
        </article>
      </div>
    </section>
  );
}

Dependencies

motion

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →