SEO improvements: add semantic headings, FAQ section, and updated copy#1318
SEO improvements: add semantic headings, FAQ section, and updated copy#1318devanshk404 wants to merge 3 commits into
Conversation
|
@devanshk404 is attempting to deploy a commit to the Superteam Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThe PR introduces SEO-focused components (SeoSection, SeoFaq), updates copy and marketing language across banners and sections, improves semantic HTML by replacing Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@src/features/home/components/SeoFaq.tsx`:
- Line 1: Remove the stray `'use client'` directive at the top of the SeoFaq.tsx
file because this project uses the Pages Router (next/router) and the directive
is an App Router artifact; open the SeoFaq component (the SeoFaq function /
default export) and delete the `'use client'` line so imports/exports and
component logic remain unchanged.
In `@src/features/listings/components/ListingsSection.tsx`:
- Line 317: Prettier flags the JSX heading line in ListingsSection (the h2
rendering getTitle()) for formatting; open the ListingsSection component and
reformat the <h2> element that calls getTitle() (the line containing <h2
className="text-lg font-semibold text-slate-800">{getTitle()}</h2>) to satisfy
project's Prettier rules—typically by ensuring proper spacing, wrapping JSX
attributes and children per Prettier (or running the project's formatter) so the
line is reformatted consistently with other JSX elements in this file.
In `@src/pages/earn/grants/index.tsx`:
- Around line 12-15: The page renders an empty grid when grants is undefined
because loading and error states were removed; update the grants consumer in
this file to check the useGrants hook's loading and error outputs (or infer
loading when grants === undefined) and render a loading skeleton/spinner while
fetching and an error message/UI when the hook reports an error; specifically
modify the component that uses const { data: grants } = useGrants(...) and the
grid render block (the current grants mapping/render around lines 50-61) to
short-circuit to a Skeleton/Spinner component during loading and an
ErrorFallback when there is an error.
- Around line 50-61: The grant prop access is inconsistent inside the
grants?.map — some fields use optional chaining (grant?.title, grant?.minReward,
grant?.maxReward, grant?.token, grant?.logo) while slug uses grant.slug; make
them consistent by assuming each map item is defined and remove the unnecessary
optional chaining so all props use grant.title, grant.slug, grant.minReward,
grant.maxReward, grant.token, grant.logo when rendering GrantEntry;
alternatively, if map items can be nullish, change grant.slug to grant?.slug and
keep the other grant?.* accesses — update the GrantEntry prop usage accordingly
in the grants?.map block.
🧹 Nitpick comments (5)
src/features/listings/components/ListingsSection.tsx (1)
313-317: Inconsistent heading semantics: bookmarks path still uses<p>.Line 314 renders the "Bookmarks" title in a
<p>tag while the non-bookmarks path now uses<h2>. If the goal of this PR is to improve semantic headings across sections, consider updating the bookmarks branch to<h2>as well for consistency.src/components/SeoSection.tsx (2)
1-4: AddreadonlytoSeoSectionItemproperties.Per coding guidelines, object type properties should be
readonlyby default.Proposed fix
interface SeoSectionItem { - heading: string; - content: string; + readonly heading: string; + readonly content: string; }As per coding guidelines, "Use
readonlyproperties for object types by default in TypeScript to prevent accidental mutation at runtime."
14-15: Usingsection.headingaskeyis fragile if headings aren't unique.Consider using the array index or a composite key to avoid potential key collisions.
src/features/home/components/SeoFaq.tsx (2)
9-12: AddreadonlytoFaqItemproperties.Proposed fix
interface FaqItem { - question: string; - answer: string; + readonly question: string; + readonly answer: string; }As per coding guidelines, "Use
readonlyproperties for object types by default in TypeScript to prevent accidental mutation at runtime."
78-107: Missing accessibility attributes on the accordion.The toggle button should communicate expanded state to assistive technologies. Consider adding
aria-expandedand anid/aria-controlspairing.Proposed fix (key lines)
<button type="button" className="flex w-full items-center justify-between py-2.5 text-left" onClick={() => setIsOpen(!isOpen)} + aria-expanded={isOpen} >
| @@ -0,0 +1,128 @@ | |||
| 'use client'; | |||
There was a problem hiding this comment.
'use client' directive is unnecessary in Pages Router.
This project uses next/router (Pages Router). The 'use client' directive is an App Router concept and has no effect here — it's misleading and should be removed.
Proposed fix
-'use client';
-
import { ChevronDown } from 'lucide-react';📝 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.
| 'use client'; | |
| import { ChevronDown } from 'lucide-react'; |
🤖 Prompt for AI Agents
In `@src/features/home/components/SeoFaq.tsx` at line 1, Remove the stray `'use
client'` directive at the top of the SeoFaq.tsx file because this project uses
the Pages Router (next/router) and the directive is an App Router artifact; open
the SeoFaq component (the SeoFaq function / default export) and delete the `'use
client'` line so imports/exports and component logic remain unchanged.
| const { data: grants } = useGrants({ | ||
| context: 'all', | ||
| category: 'All', | ||
| }); |
There was a problem hiding this comment.
Removal of loading and error states is a UX regression.
The previous implementation had loading skeletons and error handling. Now, when grants is undefined (during fetch), the page renders an empty grid with no feedback. Consider at minimum restoring a loading skeleton or spinner.
Also applies to: 50-61
🤖 Prompt for AI Agents
In `@src/pages/earn/grants/index.tsx` around lines 12 - 15, The page renders an
empty grid when grants is undefined because loading and error states were
removed; update the grants consumer in this file to check the useGrants hook's
loading and error outputs (or infer loading when grants === undefined) and
render a loading skeleton/spinner while fetching and an error message/UI when
the hook reports an error; specifically modify the component that uses const {
data: grants } = useGrants(...) and the grid render block (the current grants
mapping/render around lines 50-61) to short-circuit to a Skeleton/Spinner
component during loading and an ErrorFallback when there is an error.
| {grants?.map((grant) => ( | ||
| <div key={grant?.id} className="w-full max-w-[20rem]"> | ||
| <GrantEntry | ||
| title={grant?.title} | ||
| slug={grant.slug} | ||
| minReward={grant?.minReward} | ||
| maxReward={grant?.maxReward} | ||
| token={grant?.token} | ||
| logo={grant?.logo} | ||
| /> | ||
| </div> | ||
| ))} |
There was a problem hiding this comment.
Inconsistent optional chaining on grant properties.
grant?.title, grant?.minReward, etc. use optional chaining, but grant.slug on line 54 does not. If grant can be nullish, this will throw. If it can't, the other ?. operators are unnecessary noise — pick one approach consistently.
Proposed fix (assuming grant is always defined in the array)
- <GrantEntry
- title={grant?.title}
- slug={grant.slug}
- minReward={grant?.minReward}
- maxReward={grant?.maxReward}
- token={grant?.token}
- logo={grant?.logo}
- />
+ <GrantEntry
+ title={grant.title}
+ slug={grant.slug}
+ minReward={grant.minReward}
+ maxReward={grant.maxReward}
+ token={grant.token}
+ logo={grant.logo}
+ />📝 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.
| {grants?.map((grant) => ( | |
| <div key={grant?.id} className="w-full max-w-[20rem]"> | |
| <GrantEntry | |
| title={grant?.title} | |
| slug={grant.slug} | |
| minReward={grant?.minReward} | |
| maxReward={grant?.maxReward} | |
| token={grant?.token} | |
| logo={grant?.logo} | |
| /> | |
| </div> | |
| ))} | |
| {grants?.map((grant) => ( | |
| <div key={grant?.id} className="w-full max-w-[20rem]"> | |
| <GrantEntry | |
| title={grant.title} | |
| slug={grant.slug} | |
| minReward={grant.minReward} | |
| maxReward={grant.maxReward} | |
| token={grant.token} | |
| logo={grant.logo} | |
| /> | |
| </div> | |
| ))} |
🤖 Prompt for AI Agents
In `@src/pages/earn/grants/index.tsx` around lines 50 - 61, The grant prop access
is inconsistent inside the grants?.map — some fields use optional chaining
(grant?.title, grant?.minReward, grant?.maxReward, grant?.token, grant?.logo)
while slug uses grant.slug; make them consistent by assuming each map item is
defined and remove the unnecessary optional chaining so all props use
grant.title, grant.slug, grant.minReward, grant.maxReward, grant.token,
grant.logo when rendering GrantEntry; alternatively, if map items can be
nullish, change grant.slug to grant?.slug and keep the other grant?.* accesses —
update the GrantEntry prop usage accordingly in the grants?.map block.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/features/home/components/SeoFaq.tsx (4)
131-147: Consider using<h2>for the "FAQ" heading instead of<p>.Given this PR's focus on semantic headings for SEO, the "FAQ" label on line 140 should arguably be a heading element (e.g.,
<h2>) rather than a<p>to maintain consistent semantic structure and improve accessibility.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/components/SeoFaq.tsx` around lines 131 - 147, The "FAQ" label in the SeoFaq component is rendered as a <p> which is non-semantic for a section heading; change that element to an appropriate heading element (e.g., <h2>) while preserving the existing classes and styling so the DOM semantics improve for SEO/accessibility; update the element inside the SeoFaq function (near where FaqAccordionItem is rendered) from the <p className="mb-2 text-sm font-medium text-gray-400">FAQ</p> to an <h2> with the same classes.
95-128: Accordion items lack accessibility attributes.The toggle button should communicate expanded/collapsed state to assistive technology. Consider adding
aria-expandedand anid/aria-controlspairing so screen readers can associate the button with its content panel.Proposed fix (minimal)
+ const answerId = `faq-answer-${item.question.replace(/\s+/g, '-').toLowerCase()}`; + return ( <div className="border-b border-slate-100 last:border-b-0"> <button type="button" className="flex w-full items-center justify-between py-2.5 text-left" onClick={() => setIsOpen(!isOpen)} + aria-expanded={isOpen} + aria-controls={answerId} > <span className="text-sm font-medium text-slate-600"> {item.question} </span> ... </button> <div + id={answerId} + role="region" className={cn( 'grid transition-all duration-200 ease-in-out', isOpen ? 'grid-rows-[1fr] pb-3' : 'grid-rows-[0fr]', )} >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/components/SeoFaq.tsx` around lines 95 - 128, In FaqAccordionItem, add accessible attributes so the button exposes expanded state and references the panel: set aria-expanded on the button using the isOpen state and give the panel a stable id (e.g., derived from item.id or item.question) and set aria-controls on the button to that id; also add role="region" and aria-labelledby on the content panel pointing back to the button id to create the button↔panel pairing and ensure assistive tech can associate them (update the button element, the panel div that wraps the answer, and use the existing isOpen state to drive aria-expanded).
9-12: AddreadonlytoFaqItemproperties.Per coding guidelines, use
readonlyproperties for object types by default.Proposed fix
interface FaqItem { - question: string; - answer: string; + readonly question: string; + readonly answer: string; }As per coding guidelines, "Use
readonlyproperties for object types by default in TypeScript to prevent accidental mutation at runtime."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/components/SeoFaq.tsx` around lines 9 - 12, The FaqItem interface exposes mutable properties; update the interface declaration for FaqItem in SeoFaq.tsx so both properties are readonly (e.g., make question and answer readonly) to follow the coding guideline and prevent accidental mutation; check usages of FaqItem (e.g., where FaqItem is referenced or constructed) and ensure they remain compatible with readonly properties.
133-133: Path normalization may not match routes with hash fragments.
router.asPath.split('?')[0]strips query params but preserves hash fragments (e.g.,/earn/bounties#section), which won't match any key inFAQ_BY_PAGE. Consider also stripping the hash:- const path = router.asPath.split('?')[0]?.replace(/\/$/, '') || '/earn'; + const path = router.asPath.split(/[?#]/)[0]?.replace(/\/$/, '') || '/earn';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/components/SeoFaq.tsx` at line 133, The path normalization currently uses router.asPath.split('?')[0] which leaves hash fragments (e.g., /earn#section) and can fail to match keys in FAQ_BY_PAGE; update the logic that sets the path constant (the router.asPath -> path assignment) to also strip any hash fragment (for example by splitting on both '?' and '#' or using a regex like /[?#]/) before trimming a trailing slash, and keep the existing fallback to '/earn' so path matches FAQ_BY_PAGE keys.
🤖 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/features/home/components/SeoFaq.tsx`:
- Line 29: In the SeoFaq component, replace single-quoted strings that currently
escape apostrophes with double-quoted string literals (remove the backslash
escapes) so Prettier/ESLint stops flagging them; locate the FAQ text entries
(the array of FAQ items used in SeoFaq) and change those two strings to use
double quotes instead of single quotes.
---
Duplicate comments:
In `@src/features/home/components/SeoFaq.tsx`:
- Line 1: Remove the unnecessary 'use client' directive at the top of the SeoFaq
component file: this project uses the Pages Router (next/router) so the client
directive is ineffective and misleading—open the SeoFaq.tsx file, delete the
`'use client'` string (at the top of the module) so the module remains a
server-side module and keep the rest of the component (export/default function
or named component) unchanged.
In `@src/pages/earn/grants/index.tsx`:
- Around line 48-59: The grant items use inconsistent optional chaining: remove
unnecessary `?.` on properties accessed inside the map callback so all uses are
consistent (e.g., use `grant.id`, `grant.title`, `grant.slug`,
`grant.minReward`, `grant.maxReward`, `grant.token`, `grant.logo`) while keeping
the outer `grants?.map(...)` guard; update the JSX where `GrantEntry` is
rendered and the surrounding div key to reference the plain `grant` properties
instead of mixed optional-chained ones.
- Around line 11-14: The page currently destructures only "data: grants" from
useGrants which yields undefined during fetch and results in an empty grid;
change the hook destructure to include isLoading and isError (e.g., const {
data: grants, isLoading, isError, error } = useGrants(...)) and update the
component render logic in src/pages/earn/grants/index.tsx to return a loading
skeleton or spinner when isLoading is true and an error message (using error)
when isError is true before rendering the grants grid; ensure you reference the
useGrants hook and the grants variable when wiring these conditions so the UI
shows feedback during fetch.
- Around line 48-59: The GrantEntry props title and slug are required strings
but the JSX uses optional chaining (grant?.title, grant?.slug) producing string
| undefined; inside the grants.map callback treat each item as defined and pass
grant.title and grant.slug (and similarly grant.id for key) without optional
chaining so the types match GrantEntry's required props; update the map callback
to remove the "?" on grant properties (e.g., use grant.title, grant.slug,
grant.id) or add a non-null assertion only if you're certain items are present.
---
Nitpick comments:
In `@src/features/home/components/SeoFaq.tsx`:
- Around line 131-147: The "FAQ" label in the SeoFaq component is rendered as a
<p> which is non-semantic for a section heading; change that element to an
appropriate heading element (e.g., <h2>) while preserving the existing classes
and styling so the DOM semantics improve for SEO/accessibility; update the
element inside the SeoFaq function (near where FaqAccordionItem is rendered)
from the <p className="mb-2 text-sm font-medium text-gray-400">FAQ</p> to an
<h2> with the same classes.
- Around line 95-128: In FaqAccordionItem, add accessible attributes so the
button exposes expanded state and references the panel: set aria-expanded on the
button using the isOpen state and give the panel a stable id (e.g., derived from
item.id or item.question) and set aria-controls on the button to that id; also
add role="region" and aria-labelledby on the content panel pointing back to the
button id to create the button↔panel pairing and ensure assistive tech can
associate them (update the button element, the panel div that wraps the answer,
and use the existing isOpen state to drive aria-expanded).
- Around line 9-12: The FaqItem interface exposes mutable properties; update the
interface declaration for FaqItem in SeoFaq.tsx so both properties are readonly
(e.g., make question and answer readonly) to follow the coding guideline and
prevent accidental mutation; check usages of FaqItem (e.g., where FaqItem is
referenced or constructed) and ensure they remain compatible with readonly
properties.
- Line 133: The path normalization currently uses router.asPath.split('?')[0]
which leaves hash fragments (e.g., /earn#section) and can fail to match keys in
FAQ_BY_PAGE; update the logic that sets the path constant (the router.asPath ->
path assignment) to also strip any hash fragment (for example by splitting on
both '?' and '#' or using a regex like /[?#]/) before trimming a trailing slash,
and keep the existing fallback to '/earn' so path matches FAQ_BY_PAGE keys.
| { | ||
| question: 'Who is it for?', | ||
| answer: | ||
| 'Anyone building in web3 — developers, designers, writers, researchers, community contributors, and operators — can participate. Whether you\'re new to crypto or already experienced, you can start contributing and earning.', |
There was a problem hiding this comment.
Fix Prettier violations: use double quotes for strings containing apostrophes.
ESLint/Prettier flags lines 29 and 32 for using escaped single quotes instead of double quotes. Switch to double-quoted strings to satisfy the formatter and improve readability.
Proposed fix
- 'Anyone building in web3 — developers, designers, writers, researchers, community contributors, and operators — can participate. Whether you\'re new to crypto or already experienced, you can start contributing and earning.',
+ "Anyone building in web3 — developers, designers, writers, researchers, community contributors, and operators — can participate. Whether you're new to crypto or already experienced, you can start contributing and earning.",- question: 'What\'s the difference between bounties, projects, and grants?',
+ question: "What's the difference between bounties, projects, and grants?",Also applies to: 32-32
🧰 Tools
🪛 ESLint
[error] 29-29: Replace 'Anyone·building·in·web3·—·developers,·designers,·writers,·researchers,·community·contributors,·and·operators·—·can·participate.·Whether·you\'re·new·to·crypto·or·already·experienced,·you·can·start·contributing·and·earning.' with "Anyone·building·in·web3·—·developers,·designers,·writers,·researchers,·community·contributors,·and·operators·—·can·participate.·Whether·you're·new·to·crypto·or·already·experienced,·you·can·start·contributing·and·earning."
(prettier/prettier)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/home/components/SeoFaq.tsx` at line 29, In the SeoFaq component,
replace single-quoted strings that currently escape apostrophes with
double-quoted string literals (remove the backslash escapes) so Prettier/ESLint
stops flagging them; locate the FAQ text entries (the array of FAQ items used in
SeoFaq) and change those two strings to use double quotes instead of single
quotes.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/features/listings/components/ListingPage/DescriptionUI.tsx (1)
50-52: Heading hierarchy is not fully preserved — onlyh1is downgraded.If sponsor content uses sub-headings beneath their
h1(e.g.,h2for sections,h3for sub-sections), those levels are left unchanged after theh1→h2transform, collapsing distinct levels into peers:
Sponsor HTML After transform h1→ Main titleh2h2→ Sectionh2← same level as main title nowh3→ Sub-sectionh3A full cascade (shift all heading levels down by one) preserves the original hierarchy:
♻️ Proposed refactor — cascade all heading levels down by one
- if (name === 'h1') { - return <h2>{domToReact(children, memoizedOptions)}</h2>; - } + const HEADING_DOWNGRADE: Record<string, string> = { + h1: 'h2', + h2: 'h3', + h3: 'h4', + h4: 'h5', + h5: 'h6', + h6: 'h6', + }; + if (name in HEADING_DOWNGRADE) { + const Tag = HEADING_DOWNGRADE[name] as keyof JSX.IntrinsicElements; + return <Tag>{domToReact(children, memoizedOptions)}</Tag>; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/listings/components/ListingPage/DescriptionUI.tsx` around lines 50 - 52, The current renderer only downgrades 'h1' to 'h2', which flattens the rest of the heading hierarchy; change the logic in DescriptionUI where name and children are handled (the block that checks name === 'h1' and calls domToReact with memoizedOptions) to detect any heading tag /^h([1-6])$/ and compute newLevel = Math.min(6, parseInt(capturedGroup) + 1); then render the heading dynamically (e.g., via React.createElement or a dynamic JSX tag) using `domToReact(children, memoizedOptions)` as the content so that h1→h2, h2→h3, ..., and h6 remains at h6 (or converted to an appropriate fallback) preserving relative hierarchy.
🤖 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/features/listings/components/ListingPage/ListingHeader.tsx`:
- Around line 305-307: Add a screen-reader-only h1 for mobile so mobile users
and crawlers see a heading: in ListingHeader (where title is rendered inside the
<p> with {title}), add an h1 that uses the same title but is sr-only on small
screens and hidden on desktop (so it does not duplicate the existing
ListingTitle h1 in the hidden md:flex block) — e.g., render an <h1> with the
project's sr-only utility class and md:hidden behavior around the same title
variable to ensure one accessible h1 on mobile and keep the visible desktop
ListingTitle as the single visible h1.
---
Nitpick comments:
In `@src/features/listings/components/ListingPage/DescriptionUI.tsx`:
- Around line 50-52: The current renderer only downgrades 'h1' to 'h2', which
flattens the rest of the heading hierarchy; change the logic in DescriptionUI
where name and children are handled (the block that checks name === 'h1' and
calls domToReact with memoizedOptions) to detect any heading tag /^h([1-6])$/
and compute newLevel = Math.min(6, parseInt(capturedGroup) + 1); then render the
heading dynamically (e.g., via React.createElement or a dynamic JSX tag) using
`domToReact(children, memoizedOptions)` as the content so that h1→h2, h2→h3,
..., and h6 remains at h6 (or converted to an appropriate fallback) preserving
relative hierarchy.
| <p className="text-lg font-semibold tracking-tight text-slate-700 sm:text-xl"> | ||
| {title} | ||
| </p> |
There was a problem hiding this comment.
Missing h1 on mobile — accessibility regression for screen readers and mobile SEO.
The desktop <ListingTitle> (h1) lives inside <div className="hidden md:flex">, which is display: none on mobile. display: none removes an element from the accessibility tree, so on a mobile viewport the page has no accessible h1. The new <p> is visually correct but provides no heading landmark.
Impact:
- Screen readers on mobile cannot navigate to the page heading via heading shortcuts — WCAG 1.3.1 violation.
- Google's mobile-first crawler sees no visible H1 on the mobile view, which partially defeats the SEO goal of this PR.
Minimal fix: keep the visual <p> but add a screen-reader-only h1:
♿ Proposed fix — sr-only h1 for mobile screen readers
<div className="mb-5 flex w-full flex-col gap-1 md:hidden">
+ <h1 className="sr-only">{title}</h1>
- <p className="text-lg font-semibold tracking-tight text-slate-700 sm:text-xl">
+ <p className="text-lg font-semibold tracking-tight text-slate-700 sm:text-xl" aria-hidden="true">
{title}
</p>This ensures:
- Mobile screen readers find an
h1landmark. - Visual presentation stays as
<p>(no layout change). - Desktop
<ListingTitle>(h1) remains the single visible heading on desktop.
📝 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.
| <p className="text-lg font-semibold tracking-tight text-slate-700 sm:text-xl"> | |
| {title} | |
| </p> | |
| <div className="mb-5 flex w-full flex-col gap-1 md:hidden"> | |
| <h1 className="sr-only">{title}</h1> | |
| <p className="text-lg font-semibold tracking-tight text-slate-700 sm:text-xl" aria-hidden="true"> | |
| {title} | |
| </p> | |
| </div> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/listings/components/ListingPage/ListingHeader.tsx` around lines
305 - 307, Add a screen-reader-only h1 for mobile so mobile users and crawlers
see a heading: in ListingHeader (where title is rendered inside the <p> with
{title}), add an h1 that uses the same title but is sr-only on small screens and
hidden on desktop (so it does not duplicate the existing ListingTitle h1 in the
hidden md:flex block) — e.g., render an <h1> with the project's sr-only utility
class and md:hidden behavior around the same title variable to ensure one
accessible h1 on mobile and keep the visible desktop ListingTitle as the single
visible h1.
- Change section titles from <p> to <h2> in ListingsSection and GrantsSection - Change homepage banner <p> to <h1> with updated SEO-friendly copy - Update TypeBanner H1 text and descriptions for bounties and projects pages - Change grants page hero <p> to <h1> with updated copy - Add SeoFaq sidebar component with collapsible FAQ dropdowns per page - Add SeoFaq to sidebar between HowItWorks and RecentEarners - Add SeoFaq to grants page (which uses Default layout without sidebar) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update home banner subtext with new Solana-focused copy - Update bounties FAQ answers (crypto bounties, beginner friendly) - Update projects FAQ answer to include other tokens - Update projects banner subtext - Simplify grants page heading and subtext - Remove FAQ section from grants page Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace paragraph tag with h1 for the main banner headline on the Pro page, making it consistent with other pages (Bounties, Projects, Grants, Homepage). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
da90c6b to
7821d36
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/features/home/components/SeoFaq.tsx (1)
95-129: Consider adding keyboard accessibility.The accordion button lacks explicit keyboard accessibility attributes. While native
<button>elements handle Enter/Space, adding ARIA attributes improves screen reader support.♿ Suggested accessibility enhancement
<button type="button" className="flex w-full items-center justify-between py-2.5 text-left" onClick={() => setIsOpen(!isOpen)} + aria-expanded={isOpen} >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/components/SeoFaq.tsx` around lines 95 - 129, The accordion lacks ARIA attributes for screen readers—update FaqAccordionItem to add an id for the answer panel (e.g., generate panelId from item or index), set aria-controls on the button to that id, and set aria-expanded={isOpen} on the button; also add aria-hidden={!isOpen} (or role="region" with aria-labelledby pointing back to the button) on the answer container so assistive tech knows when the panel is visible; ensure the existing button and panel elements (button, ChevronDown, and the answer div) are the targets of these attributes.
🤖 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/features/pro/components/ProBanner.tsx`:
- Line 51: In ProBanner.tsx update the className on the h1 element to satisfy
Prettier's class ordering by moving "whitespace-nowrap" after the text size and
weight classes; specifically reorder the h1's className string so "text-2xl
font-medium" come before "whitespace-nowrap" to resolve the lint warning on that
element.
- Line 88: Reorder the Tailwind classes on the h1 in ProBanner.tsx to match the
project's Prettier/Tailwind ordering: group base utility types together, put
color utilities (text-white) before size utilities, and place responsive
variants after their base counterparts; update the className on the h1
(currently "whitespace-nowrap text-2xl font-medium text-white md:text-3xl
md:font-semibold") to the properly ordered form (e.g., "whitespace-nowrap
text-white text-2xl font-medium md:text-3xl md:font-semibold").
---
Nitpick comments:
In `@src/features/home/components/SeoFaq.tsx`:
- Around line 95-129: The accordion lacks ARIA attributes for screen
readers—update FaqAccordionItem to add an id for the answer panel (e.g.,
generate panelId from item or index), set aria-controls on the button to that
id, and set aria-expanded={isOpen} on the button; also add aria-hidden={!isOpen}
(or role="region" with aria-labelledby pointing back to the button) on the
answer container so assistive tech knows when the panel is visible; ensure the
existing button and panel elements (button, ChevronDown, and the answer div) are
the targets of these attributes.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/components/SeoSection.tsxsrc/features/grants/components/GrantsSection.tsxsrc/features/home/components/Banner/TalentBanner.tsxsrc/features/home/components/SeoFaq.tsxsrc/features/home/components/SideBar.tsxsrc/features/home/components/TypeBanner.tsxsrc/features/listings/components/ListingsSection.tsxsrc/features/pro/components/ProBanner.tsxsrc/pages/earn/grants/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- src/features/home/components/TypeBanner.tsx
- src/features/home/components/Banner/TalentBanner.tsx
- src/pages/earn/grants/index.tsx
- src/components/SeoSection.tsx
| <p className="text-2xl font-medium text-white md:text-3xl md:font-semibold"> | ||
| You’re very close to being eligible | ||
| </p> | ||
| <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold"> |
There was a problem hiding this comment.
Fix Prettier class ordering.
Static analysis flags the class order. Reorder whitespace-nowrap to follow text-2xl font-medium.
🔧 Proposed fix
- <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold">
+ <h1 className="text-2xl font-medium whitespace-nowrap text-white md:text-3xl md:font-semibold">📝 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.
| <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold"> | |
| <h1 className="text-2xl font-medium whitespace-nowrap text-white md:text-3xl md:font-semibold"> |
🧰 Tools
🪛 ESLint
[error] 51-51: Replace whitespace-nowrap·text-2xl·font-medium with text-2xl·font-medium·whitespace-nowrap
(prettier/prettier)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/pro/components/ProBanner.tsx` at line 51, In ProBanner.tsx
update the className on the h1 element to satisfy Prettier's class ordering by
moving "whitespace-nowrap" after the text size and weight classes; specifically
reorder the h1's className string so "text-2xl font-medium" come before
"whitespace-nowrap" to resolve the lint warning on that element.
| <p className="text-2xl font-medium text-white md:text-3xl md:font-semibold"> | ||
| You’re very close to being eligible | ||
| </p> | ||
| <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold"> |
There was a problem hiding this comment.
Fix Prettier class ordering.
Same formatting fix needed here.
🔧 Proposed fix
- <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold">
+ <h1 className="text-2xl font-medium whitespace-nowrap text-white md:text-3xl md:font-semibold">📝 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.
| <h1 className="whitespace-nowrap text-2xl font-medium text-white md:text-3xl md:font-semibold"> | |
| <h1 className="text-2xl font-medium whitespace-nowrap text-white md:text-3xl md:font-semibold"> |
🧰 Tools
🪛 ESLint
[error] 88-88: Replace whitespace-nowrap·text-2xl·font-medium with text-2xl·font-medium·whitespace-nowrap
(prettier/prettier)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/pro/components/ProBanner.tsx` at line 88, Reorder the Tailwind
classes on the h1 in ProBanner.tsx to match the project's Prettier/Tailwind
ordering: group base utility types together, put color utilities (text-white)
before size utilities, and place responsive variants after their base
counterparts; update the className on the h1 (currently "whitespace-nowrap
text-2xl font-medium text-white md:text-3xl md:font-semibold") to the properly
ordered form (e.g., "whitespace-nowrap text-white text-2xl font-medium
md:text-3xl md:font-semibold").
to
in ListingsSection and GrantsSection
to
with updated SEO-friendly copy
to
with updated copy
What does this PR do?
Where should the reviewer start?
How should this be manually tested?
Any background context you want to provide?
What are the relevant issues?
Screenshots (if appropriate)
Summary by CodeRabbit
New Features
Updates