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>
This commit is contained in:
Marco
2026-06-30 12:02:48 +00:00
parent f5a2519701
commit d44db8165d
11 changed files with 416 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
export function Footer() {
return (
<footer className="bg-black px-4 md:px-8 pt-12 flex flex-col gap-[120px]">
{/* Top bar: CTA | social (center) | social (right) */}
<div className="flex flex-col md:flex-row items-start md:items-start justify-between gap-8">
{/* CTA */}
<div className="flex flex-col gap-3">
<p className="font-light italic text-white text-2xl tracking-[-0.04em] uppercase leading-[1.1]">
Have a{" "}
<strong className="font-black not-italic">project</strong>{" "}
in mind?
</p>
<button className="self-start border border-white text-white text-sm font-medium tracking-[-0.04em] px-4 py-3 rounded-3xl">
Let&apos;s talk
</button>
</div>
{/* Center social */}
<div className="text-white text-[18px] tracking-[-0.04em] uppercase leading-[1.1] text-center">
<p>Facebook</p>
<p>Instagram</p>
</div>
{/* Right social */}
<div className="text-white text-[18px] tracking-[-0.04em] uppercase leading-[1.1] text-right">
<p>x.com</p>
<p>Linkedin</p>
</div>
</div>
{/* Divider */}
<hr className="border-t border-white/30 -mt-[96px]" />
{/* Bottom: big H.Studio + legal links */}
<div className="flex items-end justify-between pb-8">
{/* H.Studio overflowing text + "[ Coded By Claude ]" */}
<div className="relative overflow-hidden h-[219px] flex-1 max-w-[1093px]">
{/* "[ Coded By Claude ]" rotated vertical */}
<div className="absolute left-0 top-1/2 -translate-y-1/2 flex items-center justify-center w-4 h-[160px]">
<div className="-rotate-90 flex-none">
<span className="font-mono text-white text-sm uppercase whitespace-nowrap">
[ Coded By Claude ]
</span>
</div>
</div>
{/* Giant H.Studio — clipped by overflow-hidden */}
<div className="absolute inset-0 flex items-center justify-center">
<p className="font-semibold text-white capitalize whitespace-nowrap leading-[0.8] tracking-[-0.06em] text-[clamp(120px,20vw,290px)]">
H.Studio
</p>
</div>
</div>
{/* Legal links */}
<div className="flex gap-8 pb-8 shrink-0">
<a href="#" className="text-white text-xs tracking-[-0.04em] uppercase underline">
licences
</a>
<a href="#" className="text-white text-xs tracking-[-0.04em] uppercase underline">
Privacy policy
</a>
</div>
</div>
</footer>
);
}
+130
View File
@@ -0,0 +1,130 @@
import Image from "next/image";
const articles = [
{ id: 1, image: "/news-1.jpg", offset: false },
{ id: 2, image: "/news-2.jpg", offset: true },
{ id: 3, image: "/news-3.jpg", offset: false },
];
function ReadMore() {
return (
<div className="border-b border-black flex items-center gap-2 py-1 w-fit">
<span className="font-medium text-sm text-black tracking-[-0.04em]">
Read more
</span>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/arrow-diagonal.svg"
alt=""
className="size-[18px] -rotate-90 shrink-0"
/>
</div>
);
}
export function News() {
return (
<section className="bg-[#f3f3f3] px-4 md:px-8 py-[120px]">
{/* Mobile */}
<div className="md:hidden flex flex-col gap-10">
<h2 className="font-light text-black text-[clamp(32px,9vw,64px)] tracking-[-0.08em] uppercase leading-[0.86]">
Keep up with my latest
<br />
news &amp; achievements
</h2>
<div className="flex flex-col gap-12">
{articles.map((a) => (
<div key={a.id} className="flex flex-col gap-4">
<div className="relative w-full h-[260px] overflow-hidden">
<Image
src={a.image}
alt=""
fill
className="object-cover"
/>
</div>
<p className="text-[#1f1f1f] text-sm tracking-[-0.04em] leading-[1.3]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<ReadMore />
</div>
))}
</div>
</div>
{/* Desktop */}
<div className="hidden md:flex items-end justify-between gap-8">
{/* Rotated vertical heading */}
<div className="flex items-center justify-center shrink-0 w-[110px] h-[700px]">
<div className="-rotate-90 flex-none">
<div className="font-light text-black text-[64px] tracking-[-0.08em] uppercase whitespace-nowrap leading-[0.86]">
<p>Keep up with my latest</p>
<p>news &amp; achievements</p>
</div>
</div>
</div>
{/* 3 article cards separated by thin vertical lines */}
<div className="flex-1 flex items-start">
{/* Card 1 */}
<div className="flex-1 flex flex-col gap-4 h-[581px]">
<div className="relative flex-1 overflow-hidden">
<Image
src="/news-1.jpg"
alt=""
fill
className="object-cover"
/>
</div>
<p className="text-[#1f1f1f] text-sm tracking-[-0.04em] leading-[1.3]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<ReadMore />
</div>
{/* Divider */}
<div className="w-px self-stretch bg-[#1f1f1f] mx-8 shrink-0" />
{/* Card 2 — offset 120px down */}
<div className="flex-1 flex flex-col gap-4 pt-[120px]">
<div className="relative h-[469px] overflow-hidden">
<Image
src="/news-2.jpg"
alt=""
fill
className="object-cover"
/>
</div>
<p className="text-[#1f1f1f] text-sm tracking-[-0.04em] leading-[1.3]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<ReadMore />
</div>
{/* Divider */}
<div className="w-px self-stretch bg-[#1f1f1f] mx-8 shrink-0" />
{/* Card 3 */}
<div className="flex-1 flex flex-col gap-4 h-[581px]">
<div className="relative flex-1 overflow-hidden">
<Image
src="/news-3.jpg"
alt=""
fill
className="object-cover"
/>
</div>
<p className="text-[#1f1f1f] text-sm tracking-[-0.04em] leading-[1.3]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<ReadMore />
</div>
</div>
</div>
</section>
);
}
+137
View File
@@ -0,0 +1,137 @@
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>
);
}