Skip to content

Commit f027c1a

Browse files
committed
sponsor fixes + layout fixes
1 parent a659f37 commit f027c1a

5 files changed

Lines changed: 169 additions & 122 deletions

File tree

public/logo_single.svg

Lines changed: 13 additions & 9 deletions
Loading

public/sponsors/uva.png

68.8 KB
Loading

src/app/globals.scss

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ body {
100100
position: relative;
101101
z-index: 0; /* create context so ::before can sit behind */
102102
flex-shrink: 0;
103+
padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
103104
}
104105

105106
/* Remove external fade overlay to avoid covering preceding content */
@@ -794,12 +795,12 @@ body {
794795
0% {
795796
left: -10%;
796797
// Use same vertical position throughout
797-
top: $ypos + %;
798+
top: $ypos + 1%;
798799
}
799800
100% {
800-
left: 100%;
801+
left: 110%;
801802
// Keep vertical position constant
802-
top: $ypos + %;
803+
top: $ypos + 1%;
803804
}
804805
}
805806
}

src/app/sponsors/page.tsx

Lines changed: 50 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,57 @@
11
import type { Metadata } from "next";
2-
import Image from "next/image";
3-
import Link from "next/link";
2+
import SponsorCard, { type Sponsor } from "@/components/SponsorCard";
43

54
export const metadata: Metadata = {
65
title: "Sponsors — Team whIRLwind",
76
description: "Our generous sponsors.",
87
};
98

10-
type Sponsor = {
9+
type SponsorTier = {
1110
name: string;
12-
website?: string;
13-
contribution?: string;
14-
notes?: string;
15-
logo?: string;
16-
logoAlt?: string;
17-
logoWidth?: number;
18-
logoHeight?: number;
11+
sponsors: Sponsor[];
1912
};
2013

21-
// TODO: replace placeholder data with the team's actual sponsors when ready.
22-
const sponsors: Sponsor[] = [
14+
const sponsorTiers: SponsorTier[] = [
2315
{
24-
name: "Rerun",
25-
website: "https://rerun.io",
26-
logo: "/sponsors/rerun.svg",
27-
logoAlt: "Rerun logo",
28-
logoWidth: 94,
29-
logoHeight: 28,
16+
name: "Premier Partner",
17+
sponsors: [
18+
{
19+
name: "Rerun",
20+
website: "https://rerun.io",
21+
logo: "/sponsors/rerun.svg",
22+
logoAlt: "Rerun logo",
23+
logoWidth: 94,
24+
logoHeight: 28,
25+
logoMaxWidth: "420px",
26+
logoDisplayHeight: "96px",
27+
captionGapClass: "gap-2",
28+
logoWrapperClassName: "px-4 pt-2 pb-1",
29+
},
30+
],
3031
},
3132
{
32-
name: "StartUp Village",
33-
website: "https://startupvillage.nl",
34-
logo: "/sponsors/startup_village.webp",
35-
logoAlt: "StartUp Village logo",
36-
logoWidth: 1500,
37-
logoHeight: 756,
33+
name: "Supporting Partners",
34+
sponsors: [
35+
{
36+
name: "StartUp Village",
37+
website: "https://startupvillage.nl",
38+
logo: "/sponsors/startup_village.webp",
39+
logoAlt: "StartUp Village logo",
40+
logoWidth: 480,
41+
logoHeight: 242,
42+
},
43+
{
44+
name: "University of Amsterdam",
45+
website: "https://uva.nl",
46+
logo: "/sponsors/uva.png",
47+
logoAlt: "University of Amsterdam logo",
48+
logoWidth: 480,
49+
logoHeight: 242,
50+
},
51+
],
3852
},
3953
];
4054

41-
function formatWebsite(url?: string): string | null {
42-
if (!url) return null;
43-
return url.replace(/^https?:\/\//, "").replace(/\/$/, "");
44-
}
45-
4655
export default function SponsorsPage() {
4756
return (
4857
<section className="page">
@@ -54,90 +63,21 @@ export default function SponsorsPage() {
5463
</p>
5564

5665
<div className="space-y-12">
57-
{sponsors.map((sponsor) => {
58-
const isRerun = sponsor.name === "Rerun";
59-
const imageStyle = {
60-
width: "auto" as const,
61-
maxWidth: isRerun ? "420px" : "240px",
62-
height: isRerun ? "96px" : "80px",
63-
};
64-
const hasDetails = Boolean(
65-
sponsor.contribution || sponsor.notes,
66-
);
67-
const captionClass = [
68-
"flex flex-col items-center text-center",
69-
isRerun ? "gap-2" : "gap-3",
70-
].join(" ");
71-
const logoWrapperClass = [
72-
"flex shrink-0 items-center justify-center rounded-xl",
73-
isRerun
74-
? "px-4 pt-2 pb-1"
75-
: "px-4 py-4 bg-white shadow-sm border border-[rgba(255,255,255,0.12)]",
66+
{sponsorTiers.map((tier) => {
67+
const tierClasses = "sponsor-entry space-y-8";
68+
const rowClasses = [
69+
"flex flex-col gap-4",
70+
tier.sponsors.length > 1
71+
? "sm:flex-row sm:flex-wrap sm:gap-6"
72+
: "",
7673
].join(" ");
7774

7875
return (
79-
<div
80-
key={sponsor.name}
81-
className="sponsor-entry space-y-6"
82-
>
83-
<div
84-
className={[
85-
"flex flex-col gap-6 sm:gap-10",
86-
hasDetails ? "sm:flex-row sm:items-start" : "items-start",
87-
].join(" ")}
88-
>
89-
<div className={captionClass}>
90-
{sponsor.logo &&
91-
sponsor.logoWidth &&
92-
sponsor.logoHeight && (
93-
<div className={logoWrapperClass}>
94-
<Image
95-
src={sponsor.logo}
96-
alt={sponsor.logoAlt ?? `${sponsor.name} logo`}
97-
width={sponsor.logoWidth ?? 200}
98-
height={sponsor.logoHeight ?? 80}
99-
sizes="(min-width: 640px) 280px, 60vw"
100-
className="object-contain"
101-
style={imageStyle}
102-
/>
103-
</div>
104-
)}
105-
106-
{formatWebsite(sponsor.website) && sponsor.website && (
107-
<Link
108-
href={sponsor.website}
109-
target={
110-
sponsor.website.startsWith("http")
111-
? "_blank"
112-
: undefined
113-
}
114-
rel={
115-
sponsor.website.startsWith("http")
116-
? "noopener noreferrer"
117-
: undefined
118-
}
119-
className="text-[0.85rem] uppercase tracking-wide text-(--ink-muted) transition-colors duration-200 hover:text-(--orange-400)"
120-
>
121-
{formatWebsite(sponsor.website)}
122-
</Link>
123-
)}
124-
</div>
125-
126-
{hasDetails && (
127-
<div className="space-y-3 sm:flex-1">
128-
{sponsor.contribution && (
129-
<p className="max-w-3xl text-[0.95rem] text-(--ink-dim)">
130-
{sponsor.contribution}
131-
</p>
132-
)}
133-
134-
{sponsor.notes && (
135-
<p className="text-[0.9rem] text-(--ink-muted)">
136-
{sponsor.notes}
137-
</p>
138-
)}
139-
</div>
140-
)}
76+
<div key={tier.name} className={tierClasses}>
77+
<div className={rowClasses}>
78+
{tier.sponsors.map((sponsor) => (
79+
<SponsorCard key={sponsor.name} sponsor={sponsor} />
80+
))}
14181
</div>
14282
</div>
14383
);

src/components/SponsorCard.tsx

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import Image from "next/image";
2+
import Link from "next/link";
3+
4+
export type Sponsor = {
5+
name: string;
6+
website?: string;
7+
contribution?: string;
8+
notes?: string;
9+
logo?: string;
10+
logoAlt?: string;
11+
logoWidth?: number;
12+
logoHeight?: number;
13+
logoMaxWidth?: string;
14+
logoDisplayHeight?: string;
15+
captionGapClass?: string;
16+
logoWrapperClassName?: string;
17+
};
18+
19+
function formatWebsite(url?: string): string | null {
20+
if (!url) return null;
21+
return url.replace(/^https?:\/\//, "").replace(/\/$/, "");
22+
}
23+
24+
type SponsorCardProps = {
25+
sponsor: Sponsor;
26+
};
27+
28+
export default function SponsorCard({ sponsor }: SponsorCardProps) {
29+
const logoMaxWidth = sponsor.logoMaxWidth ?? "240px";
30+
const logoDisplayHeight = sponsor.logoDisplayHeight ?? "80px";
31+
const captionGapClass = sponsor.captionGapClass ?? "gap-3";
32+
const logoWrapperRestClass =
33+
sponsor.logoWrapperClassName ??
34+
"justify-start px-4 py-4 bg-white shadow-sm border border-[rgba(255,255,255,0.12)]";
35+
const imageStyle = {
36+
width: "auto" as const,
37+
maxWidth: logoMaxWidth,
38+
height: logoDisplayHeight,
39+
};
40+
const hasDetails = Boolean(sponsor.contribution || sponsor.notes);
41+
const captionClass = [
42+
"flex flex-col items-start text-center",
43+
captionGapClass,
44+
].join(" ");
45+
const logoWrapperClass = [
46+
"flex shrink-0 items-center rounded-xl",
47+
logoWrapperRestClass,
48+
].join(" ");
49+
const cardClasses = [
50+
"flex flex-col items-start gap-4",
51+
hasDetails ? "sm:flex-row sm:items-start sm:gap-8 sm:flex-1" : "",
52+
].join(" ");
53+
54+
return (
55+
<div className={cardClasses}>
56+
<div className={captionClass}>
57+
{sponsor.logo && sponsor.logoWidth && sponsor.logoHeight && (
58+
<div className={logoWrapperClass}>
59+
<Image
60+
src={sponsor.logo}
61+
alt={sponsor.logoAlt ?? `${sponsor.name} logo`}
62+
width={sponsor.logoWidth ?? 200}
63+
height={sponsor.logoHeight ?? 80}
64+
sizes="(min-width: 640px) 280px, 60vw"
65+
className="object-contain"
66+
style={imageStyle}
67+
/>
68+
</div>
69+
)}
70+
71+
{formatWebsite(sponsor.website) && sponsor.website && (
72+
<Link
73+
href={sponsor.website}
74+
target={sponsor.website.startsWith("http") ? "_blank" : undefined}
75+
rel={
76+
sponsor.website.startsWith("http")
77+
? "noopener noreferrer"
78+
: undefined
79+
}
80+
className="self-center text-[0.85rem] uppercase tracking-wide text-(--ink-muted) transition-colors duration-200 hover:text-(--orange-400)"
81+
>
82+
{formatWebsite(sponsor.website)}
83+
</Link>
84+
)}
85+
</div>
86+
87+
{hasDetails && (
88+
<div className="space-y-3 sm:flex-1">
89+
{sponsor.contribution && (
90+
<p className="max-w-3xl text-[0.95rem] text-(--ink-dim)">
91+
{sponsor.contribution}
92+
</p>
93+
)}
94+
95+
{sponsor.notes && (
96+
<p className="text-[0.9rem] text-(--ink-muted)">{sponsor.notes}</p>
97+
)}
98+
</div>
99+
)}
100+
</div>
101+
);
102+
}

0 commit comments

Comments
 (0)