Files
my-app/app/components/Testimonials.tsx
T
Marco d44db8165d Add Testimonials, News, and Footer sections
- Testimonials: scattered absolute-positioned cards with rotations over a giant background "Testimonials" text (desktop), stacked on mobile
- News: bg-[#f3f3f3], rotated vertical heading, 3 article cards with vertical dividers, middle card offset 120px down
- Footer: black bg, CTA + socials, hr, giant clipped H.Studio wordmark, "[ Coded By Claude ]" rotated label, legal links

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 12:02:48 +00:00

138 lines
4.3 KiB
TypeScript

const testimonials = [
{
id: "marko",
name: "Marko Stojković",
logo: "/logo-marko.svg",
logoW: 143,
logoH: 19,
text: "A brilliant creative partner who transformed our vision into a unique, high-impact brand identity. Their ability to craft everything from custom mascots to polished logos is truly impressive.",
rotation: "-6.85deg",
left: 102,
top: 142,
},
{
id: "lukas",
name: "Lukas Weber",
logo: "/logo-lukas.svg",
logoW: 138,
logoH: 19,
text: "Professional, precise, and incredibly fast at handling complex product visualizations and templates.",
rotation: "2.9deg",
left: 676,
top: 272,
},
{
id: "sarah",
name: "Sarah Jenkins",
logo: "/logo-sarah.svg",
logoW: 109,
logoH: 31,
text: "A strategic partner who balances stunning aesthetics with high-performance UX for complex platforms. They don't just make things look good; they solve business problems through visual clarity.",
rotation: "2.23deg",
left: 305,
top: 553,
},
{
id: "sofia",
name: "Sofia Martínez",
logo: "/logo-sofia.svg",
logoW: 81,
logoH: 36,
text: "An incredibly versatile designer who delivers consistent quality across a wide range of styles and formats.",
rotation: "-4.15deg",
left: 987,
top: 546,
},
];
function Card({
logo,
logoW,
logoH,
name,
text,
}: (typeof testimonials)[number]) {
return (
<div className="bg-[#f1f1f1] border border-[#ddd] rounded-[4px] p-6 w-[353px] flex flex-col gap-4">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={logo}
alt={name}
style={{ width: logoW, height: logoH }}
className="object-contain object-left shrink-0"
/>
<p className="text-[#1f1f1f] text-[18px] tracking-[-0.04em] leading-[1.3]">
{text}
</p>
<p className="font-black text-black text-[16px] tracking-[-0.04em] uppercase">
{name}
</p>
</div>
);
}
export function Testimonials() {
return (
<section className="bg-white overflow-hidden">
{/* ── Mobile: simple stacked column ── */}
<div className="md:hidden px-4 py-16 flex flex-col gap-5">
<h2 className="font-medium text-black text-[clamp(40px,13vw,80px)] tracking-[-0.07em] leading-[1.1] capitalize">
Testimonials
</h2>
{testimonials.map((t) => (
<div key={t.id} className="w-full">
{/* on mobile, reset width to full */}
<div
className="bg-[#f1f1f1] border border-[#ddd] rounded-[4px] p-6 flex flex-col gap-4"
style={{ transform: `rotate(${t.rotation})` }}
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={t.logo}
alt={t.name}
style={{ width: t.logoW * 0.7, height: t.logoH * 0.7 }}
className="object-contain object-left shrink-0"
/>
<p className="text-[#1f1f1f] text-base tracking-[-0.04em] leading-[1.3]">
{t.text}
</p>
<p className="font-black text-black text-sm tracking-[-0.04em] uppercase">
{t.name}
</p>
</div>
</div>
))}
</div>
{/* ── Desktop: scattered absolute cards over massive background text ── */}
<div className="hidden md:block relative min-h-[987px]">
{/* Background "Testimonials" — in flow so it drives section height,
centered vertically with absolute inset trick */}
<div
aria-hidden
className="absolute inset-0 flex items-center justify-center pointer-events-none select-none"
>
<p className="font-medium text-black text-[198px] tracking-[-13.86px] leading-[1.1] capitalize whitespace-nowrap">
Testimonials
</p>
</div>
{/* Cards — z-10 so they sit above the background text */}
{testimonials.map((t) => (
<div
key={t.id}
className="absolute z-10"
style={{
left: t.left,
top: t.top,
transform: `rotate(${t.rotation})`,
}}
>
<Card {...t} />
</div>
))}
</div>
</section>
);
}