From 033fb2f198dba6f0fe5e2af9865dcc16eb1299f6 Mon Sep 17 00:00:00 2001 From: voidash Date: Sun, 27 Sep 2026 17:39:39 +0545 Subject: [PATCH 1/2] fix: show initials instead of guessing a GitHub avatar When a member had no stored avatar, the member card and the members page loaded https://github.com/.png. That is the current owner of the username on GitHub, which is not always the member: a renamed or reclaimed username shows someone else's photo. It also made every visitor's browser request github.com. Members without a stored avatar now show their initials, which the avatar component already falls back to. The profile preview image for shared links is dropped for the same reason: it was built from the username in the URL, whether or not that member exists. Signed-off-by: voidash --- .../(site)/[locale]/members/[username]/layout.tsx | 2 -- apps/api/src/app/(site)/[locale]/members/page.tsx | 10 +++------- .../src/components/modules/members/member-card.tsx | 13 +++++++------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx b/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx index c5e46d3..8df1184 100644 --- a/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx +++ b/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx @@ -14,13 +14,11 @@ export async function generateMetadata({ openGraph: { title: `${title} · Dev Nepal`, description, - images: [`https://github.com/${username}.png`], }, twitter: { card: "summary", title: `${title} · Dev Nepal`, description, - images: [`https://github.com/${username}.png`], }, }; } diff --git a/apps/api/src/app/(site)/[locale]/members/page.tsx b/apps/api/src/app/(site)/[locale]/members/page.tsx index d75e801..f08d3da 100644 --- a/apps/api/src/app/(site)/[locale]/members/page.tsx +++ b/apps/api/src/app/(site)/[locale]/members/page.tsx @@ -214,13 +214,9 @@ export default function MembersPage() {
- + {member.avatarUrl !== null ? ( + + ) : null} {member.displayName.slice(0, 2).toUpperCase()} diff --git a/apps/api/src/components/modules/members/member-card.tsx b/apps/api/src/components/modules/members/member-card.tsx index c43f074..b1d8234 100644 --- a/apps/api/src/components/modules/members/member-card.tsx +++ b/apps/api/src/components/modules/members/member-card.tsx @@ -148,7 +148,6 @@ export function MemberCard({ className?: string; }) { const profileHref = localePath(locale, `/members/${member.githubUsername}`); - const avatarSrc = member.avatarUrl ?? `https://github.com/${member.githubUsername}.png`; const skills = useMemo( () => member.skills.map((skill) => dict.members.skillNames[skill]), [member.skills, dict], @@ -166,11 +165,13 @@ export function MemberCard({
{/* A late image fades in; Base UI skips the fade for one already cached. */} - + {member.avatarUrl !== null ? ( + + ) : null} {initials(member.displayName)} From 59999de473b86648ac01a05e4a132b266a784461 Mon Sep 17 00:00:00 2001 From: voidash Date: Sun, 27 Sep 2026 19:06:17 +0545 Subject: [PATCH 2/2] fix: hide decorative initials and stop claiming an approved profile On the member card and in the members table the name is shown next to the avatar, so screen readers read the initials and then the name. The initials are now hidden from assistive technology there. The account menu is unchanged: its avatar is the button's only content. The profile page description said "approved public profile" for any username in the URL, including pending, hidden and non-existent ones. It is now a neutral description. Signed-off-by: voidash --- .../api/src/app/(site)/[locale]/members/[username]/layout.tsx | 4 +++- apps/api/src/app/(site)/[locale]/members/page.tsx | 2 +- apps/api/src/components/modules/members/member-card.tsx | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx b/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx index 8df1184..d4d7208 100644 --- a/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx +++ b/apps/api/src/app/(site)/[locale]/members/[username]/layout.tsx @@ -7,7 +7,9 @@ export async function generateMetadata({ }): Promise { const { username } = await params; const title = `@${username}`; - const description = `View ${username}'s approved public profile on Dev Nepal, including the details they chose to share.`; + // Metadata is built from the URL alone, so it must not claim the profile + // exists or is approved. + const description = `Dev Nepal member profile for @${username}.`; return { title, description, diff --git a/apps/api/src/app/(site)/[locale]/members/page.tsx b/apps/api/src/app/(site)/[locale]/members/page.tsx index f08d3da..3039f6b 100644 --- a/apps/api/src/app/(site)/[locale]/members/page.tsx +++ b/apps/api/src/app/(site)/[locale]/members/page.tsx @@ -217,7 +217,7 @@ export default function MembersPage() { {member.avatarUrl !== null ? ( ) : null} - + {member.displayName.slice(0, 2).toUpperCase()} diff --git a/apps/api/src/components/modules/members/member-card.tsx b/apps/api/src/components/modules/members/member-card.tsx index b1d8234..fb336b0 100644 --- a/apps/api/src/components/modules/members/member-card.tsx +++ b/apps/api/src/components/modules/members/member-card.tsx @@ -172,7 +172,8 @@ export function MemberCard({ className="transition-opacity duration-200 ease-out data-starting-style:opacity-0" /> ) : null} - {initials(member.displayName)} + {/* The name is shown next to the avatar, so the initials are decorative. */} + {initials(member.displayName)}