Skip to content

Commit 28859cf

Browse files
feat(seo): enhance team avatar handling, update contact page content, and improve image source resolution across components
1 parent 616089d commit 28859cf

17 files changed

Lines changed: 153 additions & 20 deletions

File tree

‎.env‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ CONTACT_EMAIL=cipherunit.dev@gmail.com
55
NEXT_PUBLIC_BRAND_IMAGE_MAIN=https://res.cloudinary.com/djc6gxgjc/image/upload/q_auto/f_auto/v1781272726/SharpCipherUnit_krk0zv.png
66
NEXT_PUBLIC_BRAND_IMAGE_LOGO=https://res.cloudinary.com/djc6gxgjc/image/upload/q_auto/f_auto/v1781272725/CipherUnit_gkjt2m.jpg
77
NEXT_PUBLIC_BRAND_IMAGE_ALT=https://res.cloudinary.com/djc6gxgjc/image/upload/q_auto/f_auto/v1781272726/CipherUnitWithoutBG_zbbq4w.png
8-
GOOGLE_PUBLIC_KEY=JAqVoZOf1UANedsrHM9nVT00TPrWuA8na9tIGSticg4
8+
GOOGLE_PUBLIC_KEY=LvFG04WguElw5_gD50zQhyMH1xEQUJua1Xj1Mh9nQ80
99
INSTAGRAM_PAGE=https://instagram.com/cipherunits

‎public/llms.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
- Public GitHub organization members: https://cipherunit.xyz/team
3232
- Organization: https://github.com/cipherunits
33-
- Team photos/avatars are listed on https://cipherunit.xyz/team and in https://cipherunit.xyz/image-sitemap.xml
33+
- Team photos/avatars are served from https://cipherunit.xyz/avatars/<github-login> and listed in https://cipherunit.xyz/image-sitemap.xml
3434

3535
## Focus
3636

‎src/app/avatars/[login]/route.ts‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { getTeamMembers } from "@/lib/team";
2+
import { seoAvatarUrl } from "@/lib/seo-images";
3+
4+
export const revalidate = 3600;
5+
6+
type RouteContext = {
7+
params: Promise<{ login: string }>;
8+
};
9+
10+
/**
11+
* Same-origin avatar URLs so Google Image Search attributes photos to
12+
* cipherunit.xyz instead of avatars.githubusercontent.com.
13+
*/
14+
export async function GET(_request: Request, context: RouteContext) {
15+
const { login } = await context.params;
16+
const members = await getTeamMembers();
17+
const member = members.find(
18+
(entry) => entry.login.toLowerCase() === login.toLowerCase(),
19+
);
20+
21+
if (!member) {
22+
return new Response("Avatar not found", { status: 404 });
23+
}
24+
25+
const upstream = await fetch(seoAvatarUrl(member.avatarUrl), {
26+
next: { revalidate: 3600 },
27+
headers: {
28+
Accept: "image/*",
29+
"User-Agent": "CipherPortfolio-AvatarProxy",
30+
},
31+
});
32+
33+
if (!upstream.ok || !upstream.body) {
34+
return new Response("Upstream avatar unavailable", { status: 502 });
35+
}
36+
37+
const contentType = upstream.headers.get("content-type") || "image/jpeg";
38+
39+
return new Response(upstream.body, {
40+
status: 200,
41+
headers: {
42+
"Content-Type": contentType,
43+
"Cache-Control": "public, max-age=86400, s-maxage=86400, stale-while-revalidate=604800",
44+
},
45+
});
46+
}

‎src/app/contact/page.tsx‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Image from "next/image";
12
import ContactBox from "@/components/contacts/ContactBox";
23
import ContactMedia from "@/components/contacts/ContactMedia";
34
import ContactText from "@/components/contacts/ContactText";
@@ -80,11 +81,44 @@ export default function ContactPage() {
8081

8182
<header className="space-y-3">
8283
<NamePage title="Contact CipherUnit" />
83-
<SubNamePage text="Contact CipherUnit" />
84+
<SubNamePage text="Open-source collaborations, contributions, and technical inquiries." />
85+
<p className="max-w-3xl text-sm leading-7 text-(--color-stroke)">
86+
Reach the Cipher Unit engineering collective for open-source project
87+
partnerships, GitHub contributions, consulting, and developer support.
88+
Prefer email at{" "}
89+
<a
90+
href={`mailto:${siteConfig.email}`}
91+
className="text-white underline-offset-2 hover:underline"
92+
>
93+
{siteConfig.email}
94+
</a>{" "}
95+
or message the team through{" "}
96+
<a
97+
href={siteConfig.github}
98+
target="_blank"
99+
rel="noopener noreferrer"
100+
className="text-white underline-offset-2 hover:underline"
101+
>
102+
GitHub @{siteConfig.githubOrg}
103+
</a>
104+
.
105+
</p>
84106
</header>
85107

86108
<section className="mt-10 flex flex-col items-center justify-between gap-10 md:flex-row">
87-
<ContactText />
109+
<div className="space-y-6">
110+
<ContactText />
111+
<Image
112+
src={siteConfig.brand.main}
113+
overrideSrc={absoluteUrl(siteConfig.brand.main)}
114+
alt="Contact Cipher Unit (CipherUnit) — open-source engineering collective"
115+
title="Contact Cipher Unit"
116+
width={420}
117+
height={240}
118+
sizes="(max-width: 768px) 90vw, 420px"
119+
className="h-auto w-full max-w-[420px] rounded-lg border border-(--color-stroke)/40"
120+
/>
121+
</div>
88122
<ContactBox />
89123
</section>
90124

‎src/app/image-sitemap.xml/route.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export async function GET() {
4949
pageUrl: absoluteUrl("/team"),
5050
images: teamSitemapImages(members),
5151
},
52+
{
53+
pageUrl: absoluteUrl("/contact"),
54+
images: brandImages,
55+
},
5256
]);
5357

5458
return new Response(xml, {

‎src/app/projects/[slug]/page.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
151151
<meta itemProp="caption" content={imageCaption} />
152152
<Image
153153
src={project.imageUrl}
154+
overrideSrc={absoluteUrl(project.imageUrl)}
154155
alt={`${project.title} open source software developed by Cipher Unit (CipherUnit). ${project.description}`}
155156
title={imageTitle}
156157
fill

‎src/app/robots.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { MetadataRoute } from "next";
22
import { absoluteUrl, siteConfig } from "@/lib/site";
33

4-
const allowAssets = ["/", "/_next/static/", "/_next/image/"];
5-
const allowAi = ["/", "/llms.txt", "/_next/static/", "/_next/image/"];
4+
const allowAssets = ["/", "/avatars/", "/_next/static/", "/_next/image/"];
5+
const allowAi = ["/", "/llms.txt", "/avatars/", "/_next/static/", "/_next/image/"];
66
const disallow = [
77
"/api/",
88
"/_next/data/",

‎src/app/sitemap.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import {
55
brandImageUrls,
66
projectImageUrls,
77
projectPagePath,
8-
seoAvatarUrl,
8+
teamAvatarUrl,
99
} from "@/lib/seo-images";
1010
import { absoluteUrl, siteConfig } from "@/lib/site";
1111
import { getTeamMembers } from "@/lib/team";
1212

1313
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
1414
const members = await getTeamMembers();
15-
const teamAvatars = members.map((member) => seoAvatarUrl(member.avatarUrl));
15+
const teamAvatars = members.map((member) => teamAvatarUrl(member));
1616
const projectImages = projectImageUrls();
1717
const brandImages = brandImageUrls();
1818
const lastModified = new Date();

‎src/app/team/page.tsx‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
buildTeamGraphJsonLd,
88
JsonLd,
99
} from "@/components/shared/JsonLd";
10-
import { seoAvatarUrl, teamImageTitle } from "@/lib/seo-images";
10+
import { teamAvatarUrl, teamImageTitle } from "@/lib/seo-images";
1111
import { absoluteUrl, brandOgImages, siteConfig } from "@/lib/site";
1212
import { getTeamMembers } from "@/lib/team";
1313

@@ -18,7 +18,7 @@ export const revalidate = 3600;
1818
export async function generateMetadata(): Promise<Metadata> {
1919
const members = await getTeamMembers();
2020
const memberOgImages = members.slice(0, 8).map((member) => ({
21-
url: seoAvatarUrl(member.avatarUrl),
21+
url: teamAvatarUrl(member),
2222
alt: teamImageTitle(member),
2323
}));
2424

@@ -97,9 +97,23 @@ export default async function TeamPage() {
9797
<main id="main-content" className="mx-auto my-8 max-w-6xl px-4 sm:px-6 md:my-22">
9898
<JsonLd id="jsonld-team-graph" data={buildTeamGraphJsonLd(members)} />
9999

100-
<header className="mb-10 space-y-2">
100+
<header className="mb-10 space-y-3">
101101
<NamePage title="GitHub Team & Contributors" />
102102
<SubNamePage text="Public GitHub members of the Cipher Units organization." />
103+
<p className="max-w-3xl text-sm leading-7 text-(--color-stroke)">
104+
Cipher Unit ({siteConfig.shortName}) is built by public members of the{" "}
105+
<a
106+
href={siteConfig.github}
107+
target="_blank"
108+
rel="noopener noreferrer"
109+
className="text-white underline-offset-2 hover:underline"
110+
>
111+
@{siteConfig.githubOrg}
112+
</a>{" "}
113+
GitHub organization. Browse profiles, avatars, and open-source
114+
contributions from engineers shipping developer tools, Rust/Python
115+
libraries, and infrastructure projects.
116+
</p>
103117
</header>
104118

105119
<Team preview={false} />

‎src/components/landing/about-me/AboutMe.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Image from "next/image";
22
import Fields from "@/components/shared/Fields";
33
import Button from "@/components/shared/Button";
44
import Link from "next/link";
5-
import { siteConfig } from "@/lib/site";
5+
import { absoluteUrl, siteConfig } from "@/lib/site";
66

77
export default function AboutMe() {
88
return (
@@ -30,6 +30,7 @@ export default function AboutMe() {
3030
</div>
3131
<Image
3232
src="/images/AboutMe.png"
33+
overrideSrc={absoluteUrl("/images/AboutMe.png")}
3334
alt="CipherUnit Cipher Unit Open Source Engineering Collective — about us"
3435
width={300}
3536
height={300}

0 commit comments

Comments
 (0)