Skip to content

Commit 50cb879

Browse files
committed
Add sponsors section to About page
- Introduced a new Sponsors section in the About component to display sponsor logos. - Created a SponsorLogo component for rendering individual sponsor logos with optional links. - Updated the About component to include the Sponsors section and ensure proper accessibility attributes. - Modified Nginx configuration to prevent internal port leakage in redirects and handle deep link landing page without trailing-slash redirect.
1 parent ad5258d commit 50cb879

5 files changed

Lines changed: 108 additions & 0 deletions

File tree

nginx/pecha.conf.template

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,19 @@ server {
33
server_name localhost;
44
proxy_http_version 1.1;
55

6+
# Avoid leaking internal port 4173 in redirects when behind a reverse proxy
7+
absolute_redirect off;
8+
port_in_redirect off;
9+
610
root /usr/share/nginx/html;
711
index index.html;
812

13+
# App deep link landing page — serve without trailing-slash redirect
14+
location = /open {
15+
try_files /open/index.html =404;
16+
include /etc/nginx/security-headers.conf;
17+
}
18+
919
location / {
1020
try_files $uri $uri/ /index.html;
1121
include /etc/nginx/security-headers.conf;

public/img/sponsors/dharmaduta.svg

Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

src/routes/about/About.test.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,20 @@ describe("About", () => {
143143
screen.getByText(/Six teams carry on our mission/),
144144
).toBeInTheDocument();
145145
});
146+
147+
test("renders the sponsors section with logos", () => {
148+
setup();
149+
150+
expect(
151+
screen.getByRole("heading", { level: 2, name: "Sponsors" }),
152+
).toBeInTheDocument();
153+
154+
expect(screen.getByAltText("OpenPecha Trust")).toBeInTheDocument();
155+
expect(screen.getByAltText("Dharmaduta")).toBeInTheDocument();
156+
157+
const sponsorsSection = screen
158+
.getByRole("heading", { name: "Sponsors" })
159+
.closest("section");
160+
expect(sponsorsSection).toHaveAttribute("aria-labelledby", "sponsors");
161+
});
146162
});

src/routes/about/About.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,25 @@ const sectionSlug = (heading: string) =>
308308
.replace(/[^a-z0-9]+/g, "-")
309309
.replace(/(^-|-$)/g, "");
310310

311+
type Sponsor = {
312+
name: string;
313+
logo: string;
314+
href?: string;
315+
};
316+
317+
const SPONSORS: Sponsor[] = [
318+
{
319+
name: "OpenPecha",
320+
logo: "https://openpecha.org/lovable-uploads/d40b99df-a81c-4b68-8c6c-84301d427a2b.png",
321+
href: "https://openpecha.org",
322+
},
323+
{
324+
name: "Dharmaduta",
325+
logo: "https://dharmaduta.in/logo.png",
326+
href: "https://dharmaduta.in",
327+
},
328+
];
329+
311330
const { title, tagline, mission, vision, sections } =
312331
parseAboutContent(aboutContent);
313332

@@ -449,6 +468,61 @@ const TeamCard = ({ text }: { text: string }) => {
449468
);
450469
};
451470

471+
const SponsorLogo = ({ sponsor }: { sponsor: Sponsor }) => {
472+
const image = (
473+
<img
474+
src={sponsor.logo}
475+
alt={sponsor.name}
476+
className="max-h-10 w-auto max-w-[160px] object-contain opacity-80 transition-opacity hover:opacity-100 sm:max-h-12 sm:max-w-[180px]"
477+
/>
478+
);
479+
480+
if (!sponsor.href) {
481+
return (
482+
<div className="flex h-16 items-center justify-center px-4 sm:h-20">
483+
{image}
484+
</div>
485+
);
486+
}
487+
488+
return (
489+
<a
490+
href={sponsor.href}
491+
target="_blank"
492+
rel="noopener noreferrer"
493+
aria-label={`Visit ${sponsor.name}`}
494+
className="flex h-16 items-center justify-center px-4 sm:h-20 gap-2"
495+
>
496+
{image}{" "}
497+
<span className="text-xl text-gray-700 font-bold ">{sponsor.name}</span>
498+
</a>
499+
);
500+
};
501+
502+
const SponsorsSection = () => {
503+
if (SPONSORS.length === 0) return null;
504+
505+
return (
506+
<section
507+
aria-labelledby="sponsors"
508+
className="border-t border-custom-border py-12 sm:py-14"
509+
>
510+
<h2
511+
id="sponsors"
512+
className="en-serif-text text-2xl sm:text-3xl font-medium text-foreground"
513+
>
514+
Sponsors
515+
</h2>
516+
517+
<div className="mt-8 flex flex-wrap items-center justify-center gap-x-10 gap-y-6 sm:gap-x-14">
518+
{SPONSORS.map((sponsor) => (
519+
<SponsorLogo key={sponsor.name} sponsor={sponsor} />
520+
))}
521+
</div>
522+
</section>
523+
);
524+
};
525+
452526
const About = () => {
453527
return (
454528
<>
@@ -582,6 +656,8 @@ const About = () => {
582656
</section>
583657
);
584658
})}
659+
660+
<SponsorsSection />
585661
</div>
586662
</div>
587663
</>

0 commit comments

Comments
 (0)