Wall of Love
Twitter/X-style social proof cards with handles, checkmarks, heart counts, and star ratings.
Preview
Source
tsx
"use client";
import { Star } from "lucide-react";
import { testimonials } from "@/lib/placeholders";
const likeCounts: Record<number, number> = {};
testimonials.forEach((t) => {
likeCounts[t.id] = 10 + ((t.id * 17 + 3) % 90);
});
function HeartIcon({ filled }: { filled?: boolean }) {
return (
<svg viewBox="0 0 24 24" className="w-4 h-4" fill={filled ? "currentColor" : "none"} stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
);
}
function CheckBadge() {
return (
<svg viewBox="0 0 24 24" className="w-4 h-4 text-sky-500" fill="currentColor">
<path fillRule="evenodd" d="M8.603 3.799A4.49 4.49 0 0112 2.25c1.357 0 2.573.6 3.397 1.549a4.49 4.49 0 013.498 1.307 4.491 4.491 0 011.307 3.497A4.49 4.49 0 0121.75 12a4.49 4.49 0 01-1.549 3.397 4.491 4.491 0 01-1.307 3.497 4.491 4.491 0 01-3.497 1.307A4.49 4.49 0 0112 21.75a4.49 4.49 0 01-3.397-1.549 4.49 4.49 0 01-3.498-1.307 4.491 4.491 0 01-1.307-3.497A4.49 4.49 0 012.25 12c0-1.357.6-2.573 1.549-3.397a4.49 4.49 0 011.307-3.497 4.49 4.49 0 013.497-1.307zm7.007 6.387a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z" clipRule="evenodd" />
</svg>
);
}
export default function WallOfLove() {
return (
<section className="py-20 px-4 sm:px-6 bg-background">
<div className="max-w-6xl mx-auto">
{/* Header */}
<div className="text-center mb-14">
<span className="inline-block text-xs font-semibold uppercase tracking-widest text-primary bg-primary/10 border border-primary/20 rounded-full px-4 py-1.5 mb-4">
Wall of Love
</span>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-extrabold tracking-tight text-foreground mb-4">
People are talking
</h2>
<p className="text-lg text-muted-foreground max-w-xl mx-auto">
Join thousands of happy clients who've shared their experiences.
</p>
</div>
{/* Social post grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
{testimonials.map((t) => {
const handle = "@" + t.name.split(" ")[0].toLowerCase();
const likes = likeCounts[t.id];
return (
<div
key={t.id}
className="bg-card border border-border rounded-2xl p-5 hover:shadow-md transition-shadow duration-300 flex flex-col gap-3"
>
{/* Top row */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<img
src={t.avatar}
alt={t.name}
className="w-10 h-10 rounded-full object-cover"
/>
<div>
<div className="flex items-center gap-1">
<span className="font-bold text-sm text-foreground">{t.name}</span>
<CheckBadge />
</div>
<span className="text-xs text-muted-foreground">{handle}</span>
</div>
</div>
{/* X/Twitter logo */}
<svg viewBox="0 0 24 24" className="w-5 h-5 text-foreground" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.747l7.73-8.835L2.011 2.25h6.938l4.26 5.632 5.035-5.632zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77z" />
</svg>
</div>
{/* Quote */}
<p className="text-sm text-foreground leading-relaxed flex-1">
{t.text}
</p>
{/* Stars + like */}
<div className="flex items-center justify-between pt-1 border-t border-border">
<div className="flex gap-0.5">
{Array.from({ length: 5 }).map((_, i) => (
<Star key={i} className="w-3.5 h-3.5 fill-amber-400 text-amber-400" />
))}
</div>
<button className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-rose-500 transition-colors group">
<span className="group-hover:text-rose-500 transition-colors">
<HeartIcon />
</span>
{likes}
</button>
</div>
</div>
);
})}
</div>
</div>
</section>
);
} Claude Code Instructions
CLI Install
npx innovations add wall-of-loveWhere to use it
Great for social proof sections on homepages or sales pages. The X/Twitter aesthetic makes it feel modern and credible.
In Astro:
import WallOfLove from '../components/innovations/testimonials/wall-of-love';
<WallOfLove client:load />
In Next.js:
import WallOfLove from '@/components/innovations/testimonials/wall-of-love';
// Place after your features section or before the CTA
Edit testimonials in src/lib/placeholders.ts to use real social proof. The heart counts and handles are auto-generated from the data.