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:
@@ -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'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>
|
||||
);
|
||||
}
|
||||
@@ -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 & 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 & 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user