Fix/UI accessibility and navigation - #79
Conversation
…JSDoc to components for doc coverage
…nused Link import
📝 WalkthroughWalkthroughAdds an About section, a client-side ThemeToggle with persistent dark-mode via a DOM class, smooth in-page navigation and an accessible mobile drawer, refactors Button props, moves animated backgrounds into dedicated motion layers with reduced-motion support, expands metadata/SEO, enables Tailwind class-based dark mode, and adds an MIT license file. Changes
Sequence DiagramssequenceDiagram
actor User
participant ThemeToggle as ThemeToggle Component
participant Local as localStorage
participant DOM as document.documentElement
participant Icon as Icon (Sun/Moon)
User->>ThemeToggle: Click toggle
ThemeToggle->>ThemeToggle: setState(newTheme)
ThemeToggle->>Local: localStorage.setItem("theme", newTheme)
ThemeToggle->>DOM: add/remove "dark" class
ThemeToggle->>Icon: animate icon (framer-motion)
DOM->>User: CSS dark: variants apply
sequenceDiagram
actor User
participant Header as Header NavLink/Button
participant Handler as handleSmoothScroll
participant DOM as targetSection (e.g., "#developers")
participant View as Browser viewport
User->>Header: Click nav link
Header->>Handler: preventDefault() + compute id
Handler->>DOM: document.getElementById(id)
Handler->>View: scrollIntoView({ behavior: "smooth" })
View->>User: animated scroll to section
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/sections/LogoTicker.tsx (1)
27-37:⚠️ Potential issue | 🟡 MinorTreat the looping ticker as decorative.
The ticker renders items twice for seamless looping (lines 38–56), so screen readers will announce duplicate partner names. The static heading already communicates this information, so the animated strip should be hidden from assistive tech.
Suggested change
<motion.div + aria-hidden="true" className="flex flex-none gap-8 sm:gap-14 pr-8 sm:pr-14"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/sections/LogoTicker.tsx` around lines 27 - 37, The animated ticker (the motion.div that renders the looping partner strip with className "flex flex-none gap-8..." and animate/transition props) is decorative and duplicates content, so add accessibility attributes to hide it from assistive tech; update the motion.div (or its immediate container) to include aria-hidden="true" and/or role="presentation" so screen readers ignore the animated strip while the static heading remains for users of assistive technologies.src/app/layout.tsx (1)
74-80:⚠️ Potential issue | 🟠 MajorDark-mode users will still get a light-theme flash on first paint.
The initial HTML here is rendered without a
darkclass, andsrc/components/ThemeToggle.tsx:15-32only applies that class in a client effect after mount. Seed the theme on<html>before hydration instead of relying on the toggle component.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/layout.tsx` around lines 74 - 80, The html element in src/app/layout.tsx is rendered without a dark class so users see a light flash before the client-side ThemeToggle applies the class; add a small inline script in layout.tsx (placed before the hydrated body content) that runs immediately to read the saved theme (e.g., from localStorage) or prefers-color-scheme and synchronously add/remove the "dark" class on document.documentElement, mirroring the logic used in ThemeToggle.tsx, so the initial HTML already has the correct theme before hydration.
🤖 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/components/ThemeToggle.tsx`:
- Around line 15-32: The initial theme is only applied inside ThemeToggle's
useEffect after mount causing a flash; fix by applying the theme synchronously
before hydration: extract the logic that reads localStorage.getItem('theme') and
window.matchMedia('(prefers-color-scheme: dark)') into a synchronous initializer
(or inline script in the document head) that computes initialTheme and
immediately mutates document.documentElement.classList (add/remove 'dark') and
sets localStorage if needed, then have ThemeToggle's useEffect (and state
setters setMounted/setTheme) only mirror that already-applied initial value
rather than being the first place that toggles the class. Ensure references to
setTheme, setMounted, the existing useEffect blocks, and
document.documentElement are preserved and consistent with the new pre-hydration
initializer.
- Around line 46-54: The ThemeToggle button in ThemeToggle.tsx currently omits
type and accessible state attributes; update the button element used by
toggleTheme to include type="button" to avoid implicit form submission, add
aria-pressed={isDark} to expose the current toggle state, and make the
aria-label dynamic (e.g., when isDark is true set label to "Switch to light
theme", otherwise "Switch to dark theme") so screen readers convey the action.
In `@src/sections/About.tsx`:
- Around line 8-9: The section with id "about" is missing the anchor offset
class used elsewhere; update the section element (the <section id="about"
className="..."> in About.tsx) to include the same offset utility (e.g., add
"scroll-mt-24" alongside existing classes) so the About heading aligns
consistently with the fixed header during smooth scrolling.
In `@src/sections/CallToAction.tsx`:
- Line 68: The developers section (element with id="developers" and
ref={sectionRef} in the CallToAction component) is missing the same scroll
offset used elsewhere; add the utility class "scroll-mt-24" to its className
(alongside the existing "py-12 sm:py-16 md:py-24") so in-page navigation and
scrollIntoView({ block: 'start' }) won't hide the heading under the sticky
header.
- Around line 35-41: The current throttled handler schedules a new
requestAnimationFrame for every mousemove, allowing multiple RAF callbacks and
no cancellation on unmount; change the implementation around the throttled
function and updateMousePosition usage to store a single pending RAF id and the
latest MouseEvent (e.g., keep let rafId: number | null = null and let
latestEvent: MouseEvent | null = null at component scope), have throttled assign
latestEvent and only call requestAnimationFrame when rafId is null, inside the
RAF callback call updateMousePosition(latestEvent!), clear rafId and
latestEvent, and in the cleanup (the return) both remove the 'mousemove'
listener and cancel any pending frame via cancelAnimationFrame(rafId) to avoid
stale updates after unmount.
In `@src/sections/Features.tsx`:
- Around line 69-70: The prefersReduced constant is computed but unused so
reduced-motion preferences are being ignored; update the motion props (e.g.,
whileHover, whileTap, rotate, and any opacity/scale animate/initial/transition
props) on the motion elements in Features.tsx to check prefersReduced and pass
empty objects or omit the prop when prefersReduced is true (e.g.,
whileHover={prefersReduced ? {} : { scale: 1.05 }} and similarly for whileTap,
rotate and the animated opacity/scale configs) so animations are disabled for
users who prefer reduced motion.
- Around line 72-78: Replace the non-semantic clickable element motion.div with
a semantic motion.button to restore keyboard accessibility and expose selection
state; update the element used at the location where motion.div is rendered (the
element using tabRef, onClick={props.onClick}, and className) to motion.button,
add type="button" and aria-pressed={props.selected}, ensure the existing ref
(tabRef) is forwarded to the button, and keep the same className and motion
props (whileHover/whileTap) so behavior and styling remain unchanged.
In `@src/sections/Footer.tsx`:
- Around line 50-58: In the Footer component update the YouTube anchor (the <a>
wrapping YTSocial) so its href matches the aria-label: either replace the
current "https://www.youtube.com" with the actual Djed Alliance channel URL (or
playlist) or remove the entire YouTube anchor and YTSocial element if no channel
exists; ensure the change is made in the Footer component where the YTSocial JSX
is rendered so aria-label and href remain consistent.
In `@src/sections/Header.tsx`:
- Line 45: Header mounts two ThemeToggle components which each maintain their
own local theme state, causing desynced toggles; fix by using a single shared
theme source or a single toggle instance. Either lift theme state up (create a
theme state + setter in the Header parent or a layout-level context) and pass it
into ThemeToggle (or refactor ThemeToggle to consume a ThemeContext), or render
only one ThemeToggle instance and move it into a common parent so both places
read the same state; update references to ThemeToggle in Header to use the
shared state or the single instance to keep both controls in sync.
- Around line 39-40: The "Integration Docs" anchor currently links to
'#features' incorrectly; update the anchor for the "Integration Docs" element
(the <a> using onClick={(e) => handleSmoothScroll(e, 'features')} and the
duplicate at the second occurrence) to point to the correct target (e.g., 'docs'
or the real section id) or remove the menu item until the section exists; modify
the second argument passed to handleSmoothScroll for the "Integration Docs"
anchors (and the href) to the actual section id (for example 'docs' or
'integration-docs') so both nav variants use the correct target.
- Around line 65-69: The drawer at id="mobile-drawer" is declared as a dialog
but lacks an accessible name, focus management, an Escape handler, and focus
trapping; update the component to (1) provide an accessible name via
aria-labelledby on the drawer pointing to a visible heading or aria-label on the
container (or give the Logo/heading an id and reference it), (2) move focus into
the drawer when opening (capture document.activeElement before open, use a ref
to focus the container or first focusable element in the drawer), (3) trap
keyboard focus inside the drawer while open (implement a simple focus trap by
handling Tab/Shift+Tab or use a small utility), (4) close the drawer on Escape
by adding a keydown handler that calls setOpen(false), and (5) restore focus to
the previously focused element when closing; reference id "mobile-drawer", the
setOpen setter, and the Close button/Logo/heading elements when adding refs/ids.
In `@src/sections/Hero.tsx`:
- Around line 17-18: The detected prefersReduced variable is unused so
animations (starfield and the three ring components rendered as motion.div)
ignore the user's reduced-motion preference; fix this by either using the
prefersReduced boolean to short-circuit or remove animation props when true, or
import and use Framer Motion's useReducedMotion() and conditionally apply/omit
animation props on the motion.div elements that render the starfield and the
three rings (look for the motion.div components that control the starfield and
each ring animation) so that when reduced motion is requested the
animate/transition/variants are disabled and only static markup is rendered.
---
Outside diff comments:
In `@src/app/layout.tsx`:
- Around line 74-80: The html element in src/app/layout.tsx is rendered without
a dark class so users see a light flash before the client-side ThemeToggle
applies the class; add a small inline script in layout.tsx (placed before the
hydrated body content) that runs immediately to read the saved theme (e.g., from
localStorage) or prefers-color-scheme and synchronously add/remove the "dark"
class on document.documentElement, mirroring the logic used in ThemeToggle.tsx,
so the initial HTML already has the correct theme before hydration.
In `@src/sections/LogoTicker.tsx`:
- Around line 27-37: The animated ticker (the motion.div that renders the
looping partner strip with className "flex flex-none gap-8..." and
animate/transition props) is decorative and duplicates content, so add
accessibility attributes to hide it from assistive tech; update the motion.div
(or its immediate container) to include aria-hidden="true" and/or
role="presentation" so screen readers ignore the animated strip while the static
heading remains for users of assistive technologies.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1a335982-5e7c-4eb0-bec1-f6063de29126
⛔ Files ignored due to path filters (5)
src/app/apple-touch-icon.svgis excluded by!**/*.svgsrc/app/favicon.svgis excluded by!**/*.svgsrc/assets/djed-alliance.svgis excluded by!**/*.svgsrc/assets/stability-nexus.svgis excluded by!**/*.svgsrc/assets/svg/logo.svgis excluded by!**/*.svg
📒 Files selected for processing (13)
License.mdsrc/app/layout.tsxsrc/app/page.tsxsrc/components/Button.tsxsrc/components/ThemeToggle.tsxsrc/sections/About.tsxsrc/sections/CallToAction.tsxsrc/sections/Features.tsxsrc/sections/Footer.tsxsrc/sections/Header.tsxsrc/sections/Hero.tsxsrc/sections/LogoTicker.tsxtailwind.config.ts
…anchors, and theme pre-hydration
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/sections/CallToAction.tsx (1)
81-100:⚠️ Potential issue | 🟡 MinorThe stars no longer receive the infinite background animation.
Lines 84-91 still animate
backgroundPositionXon the outer wrapper, but the background image moved to Lines 94-99. That leaves the star layer static and keeps an unnecessary infinite animation running on a plain container.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/sections/CallToAction.tsx` around lines 81 - 100, The outer motion.div currently animates backgroundPositionX while the background image was moved into the inner motion.div, so the star layer is now static and the outer wrapper runs an unnecessary infinite animation; remove the animate and transition props from the outer motion.div (the element using borderedDivRef) and move that animate/transition block to the inner motion.div that sets style.backgroundImage (the element using startBg.src and backgroundPositionY), animating backgroundPositionX with startBg.width and the same repeat/duration/ease so the star/background layer receives the infinite animation.src/sections/Features.tsx (1)
71-111:⚠️ Potential issue | 🔴 Critical
FeatureTabhas two blocking syntax errors.Line 71 redeclares
prefersReducedafter it's already declared at line 45, and the<motion.button>opened at line 74 closes as</motion.div>at line 111. Remove the duplicate declaration and fix the closing tag.Proposed fix
- const prefersReduced = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches - return ( <motion.button type="button" whileHover={prefersReduced ? undefined : { scale: 1.05 }} whileTap={prefersReduced ? undefined : { scale: 0.95 }} @@ - </motion.div> + </motion.button> )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/sections/Features.tsx` around lines 71 - 111, The FeatureTab component has two issues: a duplicate prefersReduced declaration and a mismatched JSX closing tag; remove the second declaration of prefersReduced (the one at the start of the shown diff) so only the initial prefersReduced (declared earlier) remains, and replace the incorrect closing </motion.div> with </motion.button> to properly close the <motion.button> opened in this fragment.
♻️ Duplicate comments (1)
src/sections/Header.tsx (1)
83-85:⚠️ Potential issue | 🟠 Major
Integration Docsstill looks like a dead target.Both nav variants prevent the native anchor behavior and then look up
integration-docs; if no section exposes that id, the click becomes a silent no-op. I couldn't find that target in the sections included here.Run this to confirm whether any section actually defines
id="integration-docs"; if the only matches are the header links, the target is still missing:#!/bin/bash rg -n 'id=["'"'"']integration-docs["'"'"']|href=["'"'"']#integration-docs["'"'"']|getElementById\(["'"'"']integration-docs["'"'"']\)' srcAlso applies to: 129-129
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/sections/Header.tsx` around lines 83 - 85, The "Integration Docs" nav link uses the onClick handler handleSmoothScroll and targets 'integration-docs' but there is no element with id="integration-docs", making the click a no-op; either add id="integration-docs" to the intended section/component (e.g., the IntegrationDocs section component or its container) or update the anchor's href/onClick target to the actual existing id, or remove the custom handler to allow native anchor behavior; locate the anchor in Header.tsx and the candidate target section component and ensure their ids/match strings (the 'integration-docs' literal and handleSmoothScroll) are consistent.
🤖 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/sections/Footer.tsx`:
- Around line 27-29: The "Blog" anchor currently points to '#features' both in
its href and in the onClick handler, so the label doesn't match the destination;
update the anchor so its href and the element lookup in the onClick handler
point to the blog target (for example change href="#blog" and
document.getElementById('blog') or an external path like '/blog'), or remove the
anchor entirely until a real blog target exists; locate the anchor element with
the "Blog" text in Footer.tsx and modify the href and the getElementById string
inside the onClick callback (or delete the <a> node).
In `@src/sections/Header.tsx`:
- Around line 17-22: The handleSmoothScroll function currently forces smooth
scrolling; modify it to respect the user's prefers-reduced-motion setting by
checking window.matchMedia('(prefers-reduced-motion: reduce)').matches and using
behavior: 'auto' (or omitting smooth) when reduced motion is requested,
otherwise use behavior: 'smooth'; update the logic inside handleSmoothScroll to
compute the behavior value before calling el.scrollIntoView and use that
variable so header navigation honors user motion preferences.
- Around line 64-65: The header's className uses "z-0" which places it beneath
later content (e.g., Features.tsx's relative z-10); update the header element in
src/sections/Header.tsx (the <header ... className="... z-0 ...">) to a higher
stacking index such as "z-10" (or remove "z-0" and add "z-10") so the sticky
header and its mobile menu sit above page content; leave the backdrop div's
"-z-10" as-is so the backdrop remains behind the header.
---
Outside diff comments:
In `@src/sections/CallToAction.tsx`:
- Around line 81-100: The outer motion.div currently animates
backgroundPositionX while the background image was moved into the inner
motion.div, so the star layer is now static and the outer wrapper runs an
unnecessary infinite animation; remove the animate and transition props from the
outer motion.div (the element using borderedDivRef) and move that
animate/transition block to the inner motion.div that sets style.backgroundImage
(the element using startBg.src and backgroundPositionY), animating
backgroundPositionX with startBg.width and the same repeat/duration/ease so the
star/background layer receives the infinite animation.
In `@src/sections/Features.tsx`:
- Around line 71-111: The FeatureTab component has two issues: a duplicate
prefersReduced declaration and a mismatched JSX closing tag; remove the second
declaration of prefersReduced (the one at the start of the shown diff) so only
the initial prefersReduced (declared earlier) remains, and replace the incorrect
closing </motion.div> with </motion.button> to properly close the
<motion.button> opened in this fragment.
---
Duplicate comments:
In `@src/sections/Header.tsx`:
- Around line 83-85: The "Integration Docs" nav link uses the onClick handler
handleSmoothScroll and targets 'integration-docs' but there is no element with
id="integration-docs", making the click a no-op; either add
id="integration-docs" to the intended section/component (e.g., the
IntegrationDocs section component or its container) or update the anchor's
href/onClick target to the actual existing id, or remove the custom handler to
allow native anchor behavior; locate the anchor in Header.tsx and the candidate
target section component and ensure their ids/match strings (the
'integration-docs' literal and handleSmoothScroll) are consistent.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 63429989-6611-442f-8271-ebc94e7ae996
📒 Files selected for processing (9)
src/app/layout.tsxsrc/components/ThemeToggle.tsxsrc/sections/About.tsxsrc/sections/CallToAction.tsxsrc/sections/Features.tsxsrc/sections/Footer.tsxsrc/sections/Header.tsxsrc/sections/Hero.tsxsrc/sections/LogoTicker.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/sections/LogoTicker.tsx
- src/components/ThemeToggle.tsx
| <a href="#features" onClick={(e) => { e.preventDefault(); const el = document.getElementById('features'); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }) }} className="text-black/70 hover:text-black dark:text-white/70 dark:hover:text-white text-xs sm:text-sm transition-colors duration-300"> | ||
| Blog | ||
| </a> |
There was a problem hiding this comment.
The Blog footer item still lands on #features.
Both the href and the click handler on Lines 27-29 send users to the Features section, so the label does not match the destination. Point it at a real blog target or remove the item until one exists.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/sections/Footer.tsx` around lines 27 - 29, The "Blog" anchor currently
points to '#features' both in its href and in the onClick handler, so the label
doesn't match the destination; update the anchor so its href and the element
lookup in the onClick handler point to the blog target (for example change
href="#blog" and document.getElementById('blog') or an external path like
'/blog'), or remove the anchor entirely until a real blog target exists; locate
the anchor element with the "Blog" text in Footer.tsx and modify the href and
the getElementById string inside the onClick callback (or delete the <a> node).
| // Smooth scroll helper for same-page navigation | ||
| const handleSmoothScroll = (e: React.MouseEvent, id: string) => { | ||
| e.preventDefault() | ||
| const el = document.getElementById(id) | ||
| if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }) | ||
| } |
There was a problem hiding this comment.
Respect reduced-motion in the nav scroll helper.
handleSmoothScroll always uses behavior: 'smooth', so users who opt out of animation still get forced motion on every header navigation click.
🛠️ Proposed fix
const handleSmoothScroll = (e: React.MouseEvent, id: string) => {
e.preventDefault()
const el = document.getElementById(id)
- if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
+ if (!el) return
+ const behavior = window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth'
+ el.scrollIntoView({ behavior, block: 'start' })
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/sections/Header.tsx` around lines 17 - 22, The handleSmoothScroll
function currently forces smooth scrolling; modify it to respect the user's
prefers-reduced-motion setting by checking
window.matchMedia('(prefers-reduced-motion: reduce)').matches and using
behavior: 'auto' (or omitting smooth) when reduced motion is requested,
otherwise use behavior: 'smooth'; update the logic inside handleSmoothScroll to
compute the behavior value before calling el.scrollIntoView and use that
variable so header navigation honors user motion preferences.
| <header className="py-3 sm:py-4 border-b border-black/10 dark:border-white/15 md:border-none sticky top-0 z-0 transition-colors duration-500 shadow-sm md:shadow-none dark:shadow-none"> | ||
| <div className="absolute inset-0 backdrop-blur-md -z-10 md:hidden bg-white/80 dark:bg-transparent transition-colors duration-500"></div> |
There was a problem hiding this comment.
Raise the header above page content.
z-0 on the sticky header creates the stacking context for the whole drawer/backdrop subtree, so later content can still paint over it. src/sections/Features.tsx, Line 159 already uses relative z-10, which is enough to sit above this header and its mobile menu.
🛠️ Proposed fix
- <header className="py-3 sm:py-4 border-b border-black/10 dark:border-white/15 md:border-none sticky top-0 z-0 transition-colors duration-500 shadow-sm md:shadow-none dark:shadow-none">
+ <header className="py-3 sm:py-4 border-b border-black/10 dark:border-white/15 md:border-none sticky top-0 z-30 transition-colors duration-500 shadow-sm md:shadow-none dark:shadow-none">📝 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.
| <header className="py-3 sm:py-4 border-b border-black/10 dark:border-white/15 md:border-none sticky top-0 z-0 transition-colors duration-500 shadow-sm md:shadow-none dark:shadow-none"> | |
| <div className="absolute inset-0 backdrop-blur-md -z-10 md:hidden bg-white/80 dark:bg-transparent transition-colors duration-500"></div> | |
| <header className="py-3 sm:py-4 border-b border-black/10 dark:border-white/15 md:border-none sticky top-0 z-30 transition-colors duration-500 shadow-sm md:shadow-none dark:shadow-none"> | |
| <div className="absolute inset-0 backdrop-blur-md -z-10 md:hidden bg-white/80 dark:bg-transparent transition-colors duration-500"></div> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/sections/Header.tsx` around lines 64 - 65, The header's className uses
"z-0" which places it beneath later content (e.g., Features.tsx's relative
z-10); update the header element in src/sections/Header.tsx (the <header ...
className="... z-0 ...">) to a higher stacking index such as "z-10" (or remove
"z-0" and add "z-10") so the sticky header and its mobile menu sit above page
content; leave the backdrop div's "-z-10" as-is so the backdrop remains behind
the header.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/app/layout.tsx (1)
2-2: Orphaned font configuration in Tailwind.The
Frauncesfont has been removed from imports, buttailwind.config.ts(lines 28-35) still defines afrauncesfont family referencingvar(--font-fraunces). This CSS variable is no longer provided, so any use offont-fraunceswould silently fall back to the genericserif. Consider removing the orphanedfrauncesentry from the Tailwind config to prevent future confusion.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/layout.tsx` at line 2, Remove the orphaned Tailwind font entry for "fraunces" that references var(--font-fraunces): delete the "fraunces" family definition in your Tailwind config (the object that maps "fraunces" to "var(--font-fraunces)") and any related CSS variable declaration; additionally search the codebase for the utility/class "font-fraunces" and either replace it with an existing font class (e.g., the imported Inter or Caudex) or remove it to avoid silent fallbacks.
🤖 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/app/layout.tsx`:
- Around line 29-44: The OpenGraph/Twitter image fields in the metadata object
(the images array and twitter.images in layout.tsx) currently point to an SVG
('/favicon.svg'), which most social platforms won't render; replace those
references with a raster image (e.g., '/og.png' or '/og.jpg') at the recommended
1200x630 resolution or remove the images entries until a proper PNG/JPG/WebP
asset exists so social previews render correctly. Ensure you update both the
images entry inside the metadata OpenGraph section and the twitter.images value
to the new raster filename.
---
Nitpick comments:
In `@src/app/layout.tsx`:
- Line 2: Remove the orphaned Tailwind font entry for "fraunces" that references
var(--font-fraunces): delete the "fraunces" family definition in your Tailwind
config (the object that maps "fraunces" to "var(--font-fraunces)") and any
related CSS variable declaration; additionally search the codebase for the
utility/class "font-fraunces" and either replace it with an existing font class
(e.g., the imported Inter or Caudex) or remove it to avoid silent fallbacks.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: f15ded24-d502-4717-b0e1-6c56949a9f61
📒 Files selected for processing (2)
src/app/layout.tsxsrc/sections/LogoTicker.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/sections/LogoTicker.tsx
| images: [ | ||
| { | ||
| // public currently does not contain og.png; use repo logo as fallback | ||
| url: '/favicon.svg', | ||
| width: 1200, | ||
| height: 630, | ||
| alt: 'StablePay — Open-source SDK', | ||
| }, | ||
| ], | ||
| type: 'website', | ||
| }, | ||
| twitter: { | ||
| card: 'summary_large_image', | ||
| title: 'StablePay — Open-source SDK for Djed stablecoins', | ||
| description: 'An open-source SDK enabling merchants to accept payments in Djed stablecoins.', | ||
| images: ['/favicon.svg'], |
There was a problem hiding this comment.
SVG is not supported for OpenGraph/Twitter card images.
Most social platforms (Facebook, Twitter/X, LinkedIn, Slack, etc.) require raster formats (PNG, JPG, WebP) for OG images and will not render SVG. Using /favicon.svg will result in missing or broken preview images when the page is shared.
Consider creating a proper OG image at the standard dimensions (1200×630) in PNG/JPG format, or remove the images fields until a proper asset is available to avoid misleading metadata.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/app/layout.tsx` around lines 29 - 44, The OpenGraph/Twitter image fields
in the metadata object (the images array and twitter.images in layout.tsx)
currently point to an SVG ('/favicon.svg'), which most social platforms won't
render; replace those references with a raster image (e.g., '/og.png' or
'/og.jpg') at the recommended 1200x630 resolution or remove the images entries
until a proper PNG/JPG/WebP asset exists so social previews render correctly.
Ensure you update both the images entry inside the metadata OpenGraph section
and the twitter.images value to the new raster filename.
Addressed Issues:
Fixes #78
Additional Notes:
This PR focuses on improving usability, accessibility, and overall navigation.
An About section has been added to the main page to give users a clear understanding of StablePay. The section is responsive and aligned with the existing design.
The navbar has been updated to include an About link for both desktop and mobile. Navigation links have been cleaned up and now scroll smoothly to the correct sections.
Basic accessibility improvements have been made to the mobile menu, including ARIA attributes and better interaction handling.
A small issue in the Button component was fixed where decorative elements could block clicks.
Some performance improvements were made by reducing unnecessary animations and limiting heavy event listeners where possible.
The codebase was also cleaned up by removing unused or confusing parts.
All changes were tested locally and the build completes without errors.
Checklist:
[x] This PR addresses a single improvement
[x] Code follows the project's style and conventions
[x] Changes tested locally
[x] No new warnings or errors
Happy to make further improvements if needed.
Summary by CodeRabbit
New Features
Improvements