Skip to content

fix: improve internal linking for SEO authority distribution#1350

Draft
devanshk404 wants to merge 5 commits into
SuperteamDAO:mainfrom
devanshk404:fix/seo-internal-links
Draft

fix: improve internal linking for SEO authority distribution#1350
devanshk404 wants to merge 5 commits into
SuperteamDAO:mainfrom
devanshk404:fix/seo-internal-links

Conversation

@devanshk404
Copy link
Copy Markdown
Contributor

@devanshk404 devanshk404 commented Mar 20, 2026

Summary

  • Add hidden breadcrumb nav (sr-only) to every listing page — links back to the type hub (/earn/bounties, /earn/projects), sponsor page, and listing title. Invisible to users, crawlable by Google
  • Make the region badge in the listing header a clickable <Link> to the region hub page (e.g. /earn/regions/india) — every regional listing now links back to its hub
  • Convert mobile "Skills Needed" section on listing pages from plain <div> tags to <Link> tags pointing to skill pages
  • Fix footer internal links incorrectly using target="_blank" (Bounties, Projects, Grants, Categories were opening in a new tab)
  • Fix Date serialization error in grants/[slug] getServerSideProps — Prisma returns Date objects which Next.js can't serialize; fixed with JSON.parse(JSON.stringify(...)) to match the existing string type expectation

Context

Part of an internal linking SEO audit. The goal is to distribute ranking authority from strong pages into key Earn hubs (bounties, projects, grants, region pages, skill pages). Without consistent internal links pointing to these hubs, Google treats them as weakly connected and crawls them less frequently.

Footer regions column was explored but deferred — the Footer has ssr: false in Default.tsx so any links added there won't be in the initial HTML.

Test plan

  • Visit any listing page — breadcrumb should be invisible but present in page source (aria-label="Breadcrumb" with sr-only class)
  • Open a regional listing (one with a country flag/badge in the header) — click the region badge and confirm it navigates to the correct /earn/regions/ hub
  • On mobile, visit a listing page — "Skills Needed" pills should be clickable links
  • Visit any grant page (e.g. /earn/grants/[slug]) — should load without the Date serialization error

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Region labels are now clickable to view region pages.
    • Mobile "Skills needed" chips are interactive links.
    • Accessible breadcrumb navigation and breadcrumb structured data added across several pages.
    • Visually-hidden site links included in the main layout for screen-reader navigation.
  • Bug Fixes

    • Footer links open in a new tab only for external URLs; internal links remain same-window.

- Add hidden breadcrumb nav (sr-only) to listing pages linking back to
  type hub (/earn/bounties, /earn/projects), sponsor page, and listing title
- Make region badge in listing header a clickable link to the region hub page
- Fix footer internal links incorrectly opening in new tab (target="_blank")
- Convert mobile skills section on listing pages from plain divs to <Link> tags
- Fix Date serialization error in grants/[slug] getServerSideProps (Prisma
  returns Date objects; serialize via JSON.parse/stringify to match string type)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 20, 2026

@devanshk404 is attempting to deploy a commit to the Superteam Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 20, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b40dc931-39eb-42b4-9901-77f61d5b4c64

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds accessible, screen-reader breadcrumb/nav and JSON-LD to multiple earn pages, makes region labels link to region pages when resolvable, converts mobile skill chips into clickable links, conditions external-link attributes in the footer, and JSON-serializes grant objects returned from getServerSideProps.

Changes

Cohort / File(s) Summary
Region Navigation
src/features/listings/components/ListingPage/RegionLabel.tsx
Compute regionSlug from region + chapters and conditionally wrap region UI in next/link to /earn/regions/${regionSlug}; refactor inner JSX and Tooltip rendering.
Footer Link Handling
src/features/navbar/components/Footer.tsx
Only apply target="_blank" and rel="noopener noreferrer" when link.href starts with http (external URLs).
Listing UI & Skills
src/layouts/Listing.tsx
Add an sr-only breadcrumb nav for listing details (type, optional sponsor, truncated title); turn mobile "SKILLS NEEDED" chips into next/link items with slugified hrefs and updated styling.
Default Layout Nav (SSR)
src/layouts/Default.tsx
Insert an sr-only static site links <nav> (internal earn and Superteam region links) into the layout so links appear in SSR HTML.
Grant Serialization
src/pages/earn/grants/[slug]/index.tsx, src/pages/earn/grants/[slug]/references.tsx
Return grant via JSON.parse(JSON.stringify(grantData)) in getServerSideProps, ensuring props are JSON-serializable.
Breadcrumbs & JsonLd — Earn pages
src/pages/earn/all/index.tsx, src/pages/earn/bounties/index.tsx, src/pages/earn/grants/index.tsx, src/pages/earn/projects/index.tsx
Add visually-hidden breadcrumb <nav> with next/link items and generate/emit breadcrumb JSON-LD (generateBreadcrumbListSchema + JsonLd) alongside page Meta.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Staging #1145: Modifies src/features/listings/components/ListingPage/RegionLabel.tsx (region slug/display/linking), overlapping with this PR's region label changes.

Poem

🐰 I hopped through links and breadcrumbs bright,
Regions now point to pages just right,
Skill chips turned clicky, paths laid clear,
Footer whispers when the web winds steer,
Grants come tidy, serialized with delight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: improve internal linking for SEO authority distribution' accurately reflects the primary change: adding internal links throughout the earn section pages for SEO purposes, including breadcrumbs, region links, and skill links.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/layouts/Listing.tsx`:
- Around line 186-194: The breadcrumb renders a sponsor Link using
initialListing.sponsor.slug but only checks initialListing.sponsor, causing a
bad href if slug is missing; update the conditional around the fragment to
require a valid slug (e.g., initialListing.sponsor &&
initialListing.sponsor.slug) or otherwise render the sponsor name without the
Link, targeting the fragment around the Link/slug usage (initialListing.sponsor,
initialListing.sponsor.slug, and the Link component) so no `/earn/s/undefined`
is produced.
- Around line 234-240: Replace the ad-hoc slugification inside the Link href
(the .toLowerCase().replace(/\s+/g, '-') on the skill variable) with the
project's shared skill slug utility so special names like C++, C#, .NET, Node.js
produce correct routes; import the canonical slug function (e.g., skillSlug or
toSkillSlug) at the top of Listing.tsx and call it in the href:
href={`/earn/skill/${skillSlug(skill)}`} (or the actual utility name), keeping
the Link and key={skill} intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5fe94f7d-4607-4975-93f1-4e336c6b38e2

📥 Commits

Reviewing files that changed from the base of the PR and between 490b36d and cbd7484.

📒 Files selected for processing (5)
  • src/features/listings/components/ListingPage/RegionLabel.tsx
  • src/features/navbar/components/Footer.tsx
  • src/layouts/Listing.tsx
  • src/pages/earn/grants/[slug]/index.tsx
  • src/pages/earn/grants/[slug]/references.tsx

Comment thread src/layouts/Listing.tsx
Comment on lines +186 to +194
{initialListing.sponsor && (
<>
<span>/</span>
<Link
href={`/earn/s/${initialListing.sponsor.slug}`}
className="hover:text-slate-600"
>
{initialListing.sponsor.name}
</Link>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard sponsor breadcrumb link with a slug check.

The current condition only checks initialListing.sponsor, but href depends on initialListing.sponsor.slug. If slug is missing, this renders /earn/s/undefined.

Suggested fix
-                {initialListing.sponsor && (
+                {initialListing.sponsor?.slug && initialListing.sponsor?.name && (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{initialListing.sponsor && (
<>
<span>/</span>
<Link
href={`/earn/s/${initialListing.sponsor.slug}`}
className="hover:text-slate-600"
>
{initialListing.sponsor.name}
</Link>
{initialListing.sponsor?.slug && initialListing.sponsor?.name && (
<>
<span>/</span>
<Link
href={`/earn/s/${initialListing.sponsor.slug}`}
className="hover:text-slate-600"
>
{initialListing.sponsor.name}
</Link>
</>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/layouts/Listing.tsx` around lines 186 - 194, The breadcrumb renders a
sponsor Link using initialListing.sponsor.slug but only checks
initialListing.sponsor, causing a bad href if slug is missing; update the
conditional around the fragment to require a valid slug (e.g.,
initialListing.sponsor && initialListing.sponsor.slug) or otherwise render the
sponsor name without the Link, targeting the fragment around the Link/slug usage
(initialListing.sponsor, initialListing.sponsor.slug, and the Link component) so
no `/earn/s/undefined` is produced.

Comment thread src/layouts/Listing.tsx
Comment on lines +234 to +240
<Link
key={skill}
href={`/earn/skill/${skill.toLowerCase().replace(/\s+/g, '-')}`}
className="m-0 rounded-sm bg-slate-100 px-4 py-1 text-xs font-medium text-slate-600 hover:bg-slate-200"
>
<p className="text-xs">{skill}</p>
</div>
{skill}
</Link>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the shared skill slug utility to avoid broken skill routes.

Line 236 uses simplified slugification, which won’t match existing skill route expectations for cases like C++, C#, .NET, or Node.js. This can generate non-resolvable /earn/skill/* links.

Suggested fix
+import { generateSkillSlug } from '@/features/listings/utils/skill';
...
-                          href={`/earn/skill/${skill.toLowerCase().replace(/\s+/g, '-')}`}
+                          href={`/earn/skill/${generateSkillSlug(skill)}`}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Link
key={skill}
href={`/earn/skill/${skill.toLowerCase().replace(/\s+/g, '-')}`}
className="m-0 rounded-sm bg-slate-100 px-4 py-1 text-xs font-medium text-slate-600 hover:bg-slate-200"
>
<p className="text-xs">{skill}</p>
</div>
{skill}
</Link>
<Link
key={skill}
href={`/earn/skill/${generateSkillSlug(skill)}`}
className="m-0 rounded-sm bg-slate-100 px-4 py-1 text-xs font-medium text-slate-600 hover:bg-slate-200"
>
{skill}
</Link>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/layouts/Listing.tsx` around lines 234 - 240, Replace the ad-hoc
slugification inside the Link href (the .toLowerCase().replace(/\s+/g, '-') on
the skill variable) with the project's shared skill slug utility so special
names like C++, C#, .NET, Node.js produce correct routes; import the canonical
slug function (e.g., skillSlug or toSkillSlug) at the top of Listing.tsx and
call it in the href: href={`/earn/skill/${skillSlug(skill)}`} (or the actual
utility name), keeping the Link and key={skill} intact.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
earn Ready Ready Preview Apr 15, 2026 4:22am

Request Review

- Fix /bounties BreadcrumbList position 2 missing item URL
- Add BreadcrumbList JSON-LD to /all and /grants (were missing entirely)
- Add sr-only breadcrumb nav to /bounties, /all, /grants, /projects
- Add sr-only static links block in Default layout for all 21 region
  hub pages + main listing hubs (footer is ssr:false so Googlebot
  couldn't see footer links — this block is always in SSR HTML)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/layouts/Default.tsx (1)

57-82: Refactor the static link block into a typed constant + map.

The current hardcoded list is easy to desync when regions change. Move these entries into a single source-of-truth constant and render with .map().

Refactor sketch
+const SEO_SITE_LINKS = [
+  { href: '/earn/bounties', label: 'Crypto Bounties' },
+  { href: '/earn/projects', label: 'Crypto Projects' },
+  // ...
+  { href: '/earn/regions/balkan', label: 'Superteam Balkan' },
+] as const;

-      <nav aria-label="Site links" className="sr-only" aria-hidden="true">
-        <Link href="/earn/bounties" tabIndex={-1}>Crypto Bounties</Link>
-        ...
-      </nav>
+      <nav aria-label="Site links" className="sr-only" aria-hidden="true">
+        {SEO_SITE_LINKS.map((link) => (
+          <Link key={link.href} href={link.href} tabIndex={-1}>
+            {link.label}
+          </Link>
+        ))}
+      </nav>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/layouts/Default.tsx` around lines 57 - 82, Replace the hardcoded <Link>
list in Default.tsx with a typed constant array (e.g., export const EARN_LINKS:
{ href: string; label: string; key?: string }[]) that contains each href/label
pair (regions and top-level items) as the single source of truth, then render
the nav by mapping EARN_LINKS.map(link => <Link key={link.href || link.key}
href={link.href}>{link.label}</Link>) so updates are centralized and strongly
typed; ensure you import or define the constant in the same module (or a nearby
config file) and preserve existing hrefs/labels exactly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/layouts/Default.tsx`:
- Around line 56-82: The hidden nav with className="sr-only" is still exposing
many focusable <Link> elements to keyboard users (nav and Link elements in
Default.tsx), so update the block to remove it from the accessibility tree and
tab order: add aria-hidden="true" to the <nav> (or role="presentation" +
aria-hidden) and ensure each <Link> inside is non-focusable (tabIndex={-1} or
render as inert) or set aria-hidden on the links themselves so they cannot be
tabbed into; keep the links only for SEO/crawlers while preventing keyboard
focus and screen-reader exposure.

In `@src/pages/earn/bounties/index.tsx`:
- Around line 38-42: The breadcrumb nav currently exposes the "/" separator to
screen readers and leaves the current page as a link; update the markup so the
separator span has aria-hidden="true" (or role="presentation") and replace the
final Link for the current page with non-link text that has aria-current="page"
(e.g., <span aria-current="page">Crypto Bounties</span>), applying the same
changes to the corresponding breadcrumb blocks in the other pages that repeat
this pattern.

---

Nitpick comments:
In `@src/layouts/Default.tsx`:
- Around line 57-82: Replace the hardcoded <Link> list in Default.tsx with a
typed constant array (e.g., export const EARN_LINKS: { href: string; label:
string; key?: string }[]) that contains each href/label pair (regions and
top-level items) as the single source of truth, then render the nav by mapping
EARN_LINKS.map(link => <Link key={link.href || link.key}
href={link.href}>{link.label}</Link>) so updates are centralized and strongly
typed; ensure you import or define the constant in the same module (or a nearby
config file) and preserve existing hrefs/labels exactly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7e60a2eb-1fae-425b-8eac-c99ee1c72ee3

📥 Commits

Reviewing files that changed from the base of the PR and between cbd7484 and f48f3f8.

📒 Files selected for processing (5)
  • src/layouts/Default.tsx
  • src/pages/earn/all/index.tsx
  • src/pages/earn/bounties/index.tsx
  • src/pages/earn/grants/index.tsx
  • src/pages/earn/projects/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/pages/earn/projects/index.tsx

Comment thread src/layouts/Default.tsx
Comment on lines +56 to +82
<nav aria-label="Site links" className="sr-only">
<Link href="/earn/bounties">Crypto Bounties</Link>
<Link href="/earn/projects">Crypto Projects</Link>
<Link href="/earn/grants">Crypto Grants</Link>
<Link href="/earn/all">All Opportunities</Link>
<Link href="/earn/regions/india">Superteam India</Link>
<Link href="/earn/regions/nigeria">Superteam Nigeria</Link>
<Link href="/earn/regions/brazil">Superteam Brazil</Link>
<Link href="/earn/regions/germany">Superteam Germany</Link>
<Link href="/earn/regions/united-states">Superteam United States</Link>
<Link href="/earn/regions/uk">Superteam UK</Link>
<Link href="/earn/regions/ukraine">Superteam Ukraine</Link>
<Link href="/earn/regions/singapore">Superteam Singapore</Link>
<Link href="/earn/regions/malaysia">Superteam Malaysia</Link>
<Link href="/earn/regions/indonesia">Superteam Indonesia</Link>
<Link href="/earn/regions/uae">Superteam UAE</Link>
<Link href="/earn/regions/spain">Superteam Spain</Link>
<Link href="/earn/regions/netherlands">Superteam Netherlands</Link>
<Link href="/earn/regions/canada">Superteam Canada</Link>
<Link href="/earn/regions/japan">Superteam Japan</Link>
<Link href="/earn/regions/poland">Superteam Poland</Link>
<Link href="/earn/regions/korea">Superteam Korea</Link>
<Link href="/earn/regions/ireland">Superteam Ireland</Link>
<Link href="/earn/regions/kazakhstan">Superteam Kazakhstan</Link>
<Link href="/earn/regions/georgia">Superteam Georgia</Link>
<Link href="/earn/regions/balkan">Superteam Balkan</Link>
</nav>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid invisible keyboard focus targets in the sr-only SEO links block.

At Line 56, this nav is visually hidden but all links remain focusable, which can trap keyboard users on non-visible elements. If this block is SEO-only, remove it from the accessibility tree and tab order.

Safe SEO-only variant
-      <nav aria-label="Site links" className="sr-only">
+      <nav aria-label="Site links" className="sr-only" aria-hidden="true">
-        <Link href="/earn/bounties">Crypto Bounties</Link>
+        <Link href="/earn/bounties" tabIndex={-1}>Crypto Bounties</Link>
-        <Link href="/earn/projects">Crypto Projects</Link>
+        <Link href="/earn/projects" tabIndex={-1}>Crypto Projects</Link>
         ...
-        <Link href="/earn/regions/balkan">Superteam Balkan</Link>
+        <Link href="/earn/regions/balkan" tabIndex={-1}>Superteam Balkan</Link>
       </nav>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<nav aria-label="Site links" className="sr-only">
<Link href="/earn/bounties">Crypto Bounties</Link>
<Link href="/earn/projects">Crypto Projects</Link>
<Link href="/earn/grants">Crypto Grants</Link>
<Link href="/earn/all">All Opportunities</Link>
<Link href="/earn/regions/india">Superteam India</Link>
<Link href="/earn/regions/nigeria">Superteam Nigeria</Link>
<Link href="/earn/regions/brazil">Superteam Brazil</Link>
<Link href="/earn/regions/germany">Superteam Germany</Link>
<Link href="/earn/regions/united-states">Superteam United States</Link>
<Link href="/earn/regions/uk">Superteam UK</Link>
<Link href="/earn/regions/ukraine">Superteam Ukraine</Link>
<Link href="/earn/regions/singapore">Superteam Singapore</Link>
<Link href="/earn/regions/malaysia">Superteam Malaysia</Link>
<Link href="/earn/regions/indonesia">Superteam Indonesia</Link>
<Link href="/earn/regions/uae">Superteam UAE</Link>
<Link href="/earn/regions/spain">Superteam Spain</Link>
<Link href="/earn/regions/netherlands">Superteam Netherlands</Link>
<Link href="/earn/regions/canada">Superteam Canada</Link>
<Link href="/earn/regions/japan">Superteam Japan</Link>
<Link href="/earn/regions/poland">Superteam Poland</Link>
<Link href="/earn/regions/korea">Superteam Korea</Link>
<Link href="/earn/regions/ireland">Superteam Ireland</Link>
<Link href="/earn/regions/kazakhstan">Superteam Kazakhstan</Link>
<Link href="/earn/regions/georgia">Superteam Georgia</Link>
<Link href="/earn/regions/balkan">Superteam Balkan</Link>
</nav>
<nav aria-label="Site links" className="sr-only" aria-hidden="true">
<Link href="/earn/bounties" tabIndex={-1}>Crypto Bounties</Link>
<Link href="/earn/projects" tabIndex={-1}>Crypto Projects</Link>
<Link href="/earn/grants" tabIndex={-1}>Crypto Grants</Link>
<Link href="/earn/all" tabIndex={-1}>All Opportunities</Link>
<Link href="/earn/regions/india" tabIndex={-1}>Superteam India</Link>
<Link href="/earn/regions/nigeria" tabIndex={-1}>Superteam Nigeria</Link>
<Link href="/earn/regions/brazil" tabIndex={-1}>Superteam Brazil</Link>
<Link href="/earn/regions/germany" tabIndex={-1}>Superteam Germany</Link>
<Link href="/earn/regions/united-states" tabIndex={-1}>Superteam United States</Link>
<Link href="/earn/regions/uk" tabIndex={-1}>Superteam UK</Link>
<Link href="/earn/regions/ukraine" tabIndex={-1}>Superteam Ukraine</Link>
<Link href="/earn/regions/singapore" tabIndex={-1}>Superteam Singapore</Link>
<Link href="/earn/regions/malaysia" tabIndex={-1}>Superteam Malaysia</Link>
<Link href="/earn/regions/indonesia" tabIndex={-1}>Superteam Indonesia</Link>
<Link href="/earn/regions/uae" tabIndex={-1}>Superteam UAE</Link>
<Link href="/earn/regions/spain" tabIndex={-1}>Superteam Spain</Link>
<Link href="/earn/regions/netherlands" tabIndex={-1}>Superteam Netherlands</Link>
<Link href="/earn/regions/canada" tabIndex={-1}>Superteam Canada</Link>
<Link href="/earn/regions/japan" tabIndex={-1}>Superteam Japan</Link>
<Link href="/earn/regions/poland" tabIndex={-1}>Superteam Poland</Link>
<Link href="/earn/regions/korea" tabIndex={-1}>Superteam Korea</Link>
<Link href="/earn/regions/ireland" tabIndex={-1}>Superteam Ireland</Link>
<Link href="/earn/regions/kazakhstan" tabIndex={-1}>Superteam Kazakhstan</Link>
<Link href="/earn/regions/georgia" tabIndex={-1}>Superteam Georgia</Link>
<Link href="/earn/regions/balkan" tabIndex={-1}>Superteam Balkan</Link>
</nav>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/layouts/Default.tsx` around lines 56 - 82, The hidden nav with
className="sr-only" is still exposing many focusable <Link> elements to keyboard
users (nav and Link elements in Default.tsx), so update the block to remove it
from the accessibility tree and tab order: add aria-hidden="true" to the <nav>
(or role="presentation" + aria-hidden) and ensure each <Link> inside is
non-focusable (tabIndex={-1} or render as inert) or set aria-hidden on the links
themselves so they cannot be tabbed into; keep the links only for SEO/crawlers
while preventing keyboard focus and screen-reader exposure.

Comment on lines +38 to +42
<nav aria-label="Breadcrumb" className="sr-only">
<Link href="/earn">Home</Link>
<span>/</span>
<Link href="/earn/bounties">Crypto Bounties</Link>
</nav>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten breadcrumb semantics for assistive tech.

At Line 40, the / separator should be hidden from screen readers, and at Line 41 the current page item should be marked as current (typically non-link text). This same pattern repeats in src/pages/earn/all/index.tsx (Lines 39-43) and src/pages/earn/grants/index.tsx (Lines 46-50).

Suggested markup adjustment
-      <nav aria-label="Breadcrumb" className="sr-only">
-        <Link href="/earn">Home</Link>
-        <span>/</span>
-        <Link href="/earn/bounties">Crypto Bounties</Link>
-      </nav>
+      <nav aria-label="Breadcrumb" className="sr-only">
+        <ol>
+          <li><Link href="/earn">Home</Link></li>
+          <li aria-hidden="true">/</li>
+          <li aria-current="page">Crypto Bounties</li>
+        </ol>
+      </nav>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<nav aria-label="Breadcrumb" className="sr-only">
<Link href="/earn">Home</Link>
<span>/</span>
<Link href="/earn/bounties">Crypto Bounties</Link>
</nav>
<nav aria-label="Breadcrumb" className="sr-only">
<ol>
<li><Link href="/earn">Home</Link></li>
<li aria-hidden="true">/</li>
<li aria-current="page">Crypto Bounties</li>
</ol>
</nav>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/earn/bounties/index.tsx` around lines 38 - 42, The breadcrumb nav
currently exposes the "/" separator to screen readers and leaves the current
page as a link; update the markup so the separator span has aria-hidden="true"
(or role="presentation") and replace the final Link for the current page with
non-link text that has aria-current="page" (e.g., <span
aria-current="page">Crypto Bounties</span>), applying the same changes to the
corresponding breadcrumb blocks in the other pages that repeat this pattern.

…atch

Placing the nav after Footer (ssr:false) caused React to see it as an
unexpected element during client hydration due to dynamic import tree
shifting. Moving it before the footer keeps its position stable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/layouts/Default.tsx Outdated
Comment on lines +60 to +72
<Link href="/earn/regions/india">Superteam India</Link>
<Link href="/earn/regions/nigeria">Superteam Nigeria</Link>
<Link href="/earn/regions/brazil">Superteam Brazil</Link>
<Link href="/earn/regions/germany">Superteam Germany</Link>
<Link href="/earn/regions/united-states">Superteam United States</Link>
<Link href="/earn/regions/uk">Superteam UK</Link>
<Link href="/earn/regions/ukraine">Superteam Ukraine</Link>
<Link href="/earn/regions/singapore">Superteam Singapore</Link>
<Link href="/earn/regions/malaysia">Superteam Malaysia</Link>
<Link href="/earn/regions/indonesia">Superteam Indonesia</Link>
<Link href="/earn/regions/uae">Superteam UAE</Link>
<Link href="/earn/regions/spain">Superteam Spain</Link>
<Link href="/earn/regions/netherlands">Superteam Netherlands</Link>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetch these regions from prisma.chapters and dynamically create this map instead of having to manually update this everytime a new chapter is added

Comment thread src/pages/earn/grants/[slug]/index.tsx Outdated
return {
props: {
grant: grantData,
grant: JSON.parse(JSON.stringify(grantData)),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to .map and change date fields in there instead of doing this hacky way

return {
props: {
grant: grantData,
grant: JSON.parse(JSON.stringify(grantData)),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here

@devanshk404 devanshk404 marked this pull request as draft May 8, 2026 06:09
devanshk404 and others added 2 commits May 8, 2026 12:13
- Replace hardcoded chapter links in Default.tsx with dynamic useQuery fetch
- Replace JSON.parse/stringify in grants slug pages with explicit date mapping
- Fix nested <a> in ListingCard by converting sponsor link to span with router.push
- Fix undefined serialization error for icons/link fields in homepage chapters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Resolve ListingCard conflict: keep useRouter, drop useTokenLookup (replaced by TokenIcon on main)
- Update grants slug pages: remove redundant toISOString calls since getGrantBySlug now serializes dates
- Fix next.config.ts type assertion for browserToTerminal (not yet in Next.js 16.1.6 types)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants