Skip to content

Fix/button props and type - #71

Open
raj-aryan-official wants to merge 14 commits into
DjedAlliance:mainfrom
raj-aryan-official:fix/button-props-and-type
Open

Fix/button props and type#71
raj-aryan-official wants to merge 14 commits into
DjedAlliance:mainfrom
raj-aryan-official:fix/button-props-and-type

Conversation

@raj-aryan-official

@raj-aryan-official raj-aryan-official commented Mar 30, 2026

Copy link
Copy Markdown

Addressed Issues:
Fixes #43

Additional Notes:
The Button component was missing the type="button" attribute and did not support standard HTML button props like onClick.

I updated the component to include a default type="button" and extended it to accept common button props. This improves accessibility and makes the component more reusable across the application.

The changes were tested locally to ensure existing functionality is not affected.

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

Summary by CodeRabbit

  • New Features

    • Added light/dark theme toggle with persistent user settings
    • Introduced mobile navigation drawer
    • Added cursor-responsive visual effects to hero section
  • Enhancements

    • Implemented dark mode styling across the entire application
    • Updated navigation with real internal routes
    • Enhanced social links with external URLs
    • Improved Button component with enhanced attribute support
    • Updated partner logo assets and styling
  • Documentation

    • Added MIT License file

@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces comprehensive light/dark theme support across the landing page while enhancing component accessibility. Changes include adding a new MIT License file, implementing a ThemeToggle component with localStorage persistence, configuring Tailwind for class-based dark mode, updating the layout viewport, refactoring the Button component to forward HTML attributes, and applying theme-aware styling across multiple sections and the header.

Changes

Cohort / File(s) Summary
Licensing & Configuration
License.md, tailwind.config.ts
Added MIT License file; enabled class-based dark mode in Tailwind configuration.
Layout & Root Setup
src/app/layout.tsx, src/app/page.tsx
Added viewport theme color configuration; switched default body classes from fixed dark theme to light with dark overrides; added JSDoc comment to Home component.
Core Components
src/components/Button.tsx, src/components/ThemeToggle.tsx
Expanded Button props to accept standard HTML button attributes with style merging; added new ThemeToggle client component managing theme state with localStorage persistence and animated icon transitions.
Themed Sections
src/sections/CallToAction.tsx, src/sections/Features.tsx, src/sections/LogoTicker.tsx, src/sections/Hero.tsx
Applied dark mode variants and transition utilities to text/border/background colors; restructured animated backgrounds into separate motion div layers; added mouse position tracking and radial masking in CallToAction; replaced colored placeholders with SVG logos in LogoTicker.
Header & Footer
src/sections/Header.tsx, src/sections/Footer.tsx
Converted Header to client component with mobile menu drawer state; added ThemeToggle integration and updated navigation to use Next.js Link; updated Footer with real social URLs (GitHub, X, YouTube), added LinkedIn share link, and applied dark mode styling throughout.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🌙 ✨ A toggle springs to life, dark and bright,
Where rabbits dance between the night and light,
With localStorage whispering secrets true,
Each click reveals a fresh and themed view! 🐰

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is narrowly focused on the Button component changes but the PR includes significant theme system additions (dark mode, ThemeToggle, viewport config) unrelated to button props and type. Revise the title to reflect the full scope, such as 'Add dark mode support and improve Button component props handling' or split into multiple focused PRs.
Out of Scope Changes check ⚠️ Warning The PR includes substantial out-of-scope changes: dark mode implementation (tailwind.config.ts, ThemeToggle.tsx, Header.tsx), viewport configuration, and theme updates across multiple components unrelated to issue #43. Remove theme-related changes or document corresponding issues; focus this PR on Button component accessibility improvements only, or create separate PRs for theme work.
Linked Issues check ❓ Inconclusive Issue #43 requirements (type='button' attribute and HTML button props) are met in Button.tsx, but the PR includes extensive unrelated changes to theme system, layout, and multiple components. Clarify whether theme-related changes (dark mode support, ThemeToggle, viewport) address separate linked issues or should be separated into a distinct PR.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/layout.tsx (1)

47-58: ⚠️ Potential issue | 🟠 Major

Dark mode will still flash on first paint.

<body> defaults to light styles, but ThemeToggle only adds the dark class after hydration. Users with a saved or system dark preference will see a light-theme flash before the page becomes interactive. Add an inline script in the root layout that runs before React hydrates to seed the theme class on <html> based on localStorage or prefers-color-scheme.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/layout.tsx` around lines 47 - 58, Add a small synchronous inline
script in the root layout (in src/app/layout.tsx near the <html> element, before
the <body>) that seeds the theme class on the documentElement so dark-mode
doesn't flash: implement logic to read localStorage.getItem('theme') (e.g.
'dark'|'light') and, if absent, use window.matchMedia('(prefers-color-scheme:
dark)').matches; then immediately add or remove the 'dark' class on
document.documentElement accordingly. Insert it as a raw script node (using
dangerouslySetInnerHTML) so it runs before React hydration and keep your
existing twMerge usage (inter.variable, fraunces.variable, caudex.variable)
intact; this ensures ThemeToggle can hydrate without causing a flash of the
wrong theme.
🧹 Nitpick comments (1)
src/sections/LogoTicker.tsx (1)

37-55: Deduplicate the ticker item markup.

The two map blocks render the same element tree. Building the loop from a single items.concat(items) array or extracting a tiny render helper will keep future logo/text class changes from drifting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sections/LogoTicker.tsx` around lines 37 - 55, The markup for each ticker
entry is duplicated in two map blocks; consolidate by mapping over a doubled
array (e.g., items.concat(items)) or extracting a small render helper (e.g.,
renderTickerItem(item, index, repeatFlag)) and use that single mapper to produce
the same <div> structure with LogoComp and label; update the key logic to remain
unique (like `${index}` for first pass and `${index}-repeat` for the second)
while keeping the same class names and props on LogoComp so future style changes
only need one edit.
🤖 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 12-36: The ThemeToggle component currently keeps theme in local
state causing desync when multiple instances mount; lift the single source of
truth into shared state (e.g., a ThemeContext or a top-level provider) and have
ThemeToggle read theme and call setTheme from that context instead of using its
own useState. Initialize the shared provider once (on app/root mount) to read
localStorage ('theme'), apply/remove the 'dark' class on
document.documentElement, and persist changes to localStorage; update
ThemeToggle to use the provider's theme and the existing toggleTheme/setTheme
function (replace local setTheme, mounted logic and the effect that writes to
document.documentElement/localStorage). Ensure both Header-mounted ThemeToggle
instances consume the same context so icons/knobs stay in sync.
- Around line 46-54: The <ThemeToggle> button currently lacks explicit type and
ARIA state; update the <button> element used with onClick={toggleTheme} to
include type="button" and aria-pressed={isDark} (or aria-pressed={!!isDark}) so
it won't implicitly submit forms and assistive tech can read the current
dark-mode state; keep the existing aria-label and other props unchanged.

In `@src/sections/Footer.tsx`:
- Around line 50-58: The YouTube anchor in the Footer component uses a
placeholder href ("https://www.youtube.com"); locate the anchor element that
contains aria-label="Djed Alliance on YouTube" (the one rendering <YTSocial
.../>) and replace the href value with the actual Djed Alliance YouTube channel
URL (ensuring target="_blank" and rel="noreferrer" are preserved) before
release.

In `@src/sections/Header.tsx`:
- Around line 40-46: The mobile menu trigger/button (onClick={() =>
setOpen(true)} with MenuIcon) and corresponding drawer must be treated as a
modal dialog: add aria-expanded and aria-controls to the trigger (toggle with
setOpen), give the drawer dialog semantics (role="dialog" and aria-modal="true"
and an id referenced by aria-controls), trap keyboard focus inside the drawer
and set initial focus to the first focusable element when it opens, restore
focus to the trigger when it closes, handle Escape to close (listen for Escape
and call setOpen(false)), and hide/inert background content (or set aria-hidden
on background regions) while open so screen readers and keyboard users cannot
reach behind the modal. Ensure these behaviors are applied to the same mobile
drawer used in the later block (lines around 52-73).
- Around line 29-33: Desktop nav anchors use placeholder href="#" while the
drawer uses real routes; update the desktop anchor hrefs to the correct paths
(e.g., "/docs" and "/integration") and refactor both desktop and drawer
navigation to consume a single shared links array (e.g., navItems or NAV_LINKS)
so targets remain consistent; locate the anchors in Header.tsx (the desktop
links around "Developers Guide" and "Integration Docs" and the drawer link
rendering) and replace static hrefs with link.href from the shared data, mapping
that array in both places.

---

Outside diff comments:
In `@src/app/layout.tsx`:
- Around line 47-58: Add a small synchronous inline script in the root layout
(in src/app/layout.tsx near the <html> element, before the <body>) that seeds
the theme class on the documentElement so dark-mode doesn't flash: implement
logic to read localStorage.getItem('theme') (e.g. 'dark'|'light') and, if
absent, use window.matchMedia('(prefers-color-scheme: dark)').matches; then
immediately add or remove the 'dark' class on document.documentElement
accordingly. Insert it as a raw script node (using dangerouslySetInnerHTML) so
it runs before React hydration and keep your existing twMerge usage
(inter.variable, fraunces.variable, caudex.variable) intact; this ensures
ThemeToggle can hydrate without causing a flash of the wrong theme.

---

Nitpick comments:
In `@src/sections/LogoTicker.tsx`:
- Around line 37-55: The markup for each ticker entry is duplicated in two map
blocks; consolidate by mapping over a doubled array (e.g., items.concat(items))
or extracting a small render helper (e.g., renderTickerItem(item, index,
repeatFlag)) and use that single mapper to produce the same <div> structure with
LogoComp and label; update the key logic to remain unique (like `${index}` for
first pass and `${index}-repeat` for the second) while keeping the same class
names and props on LogoComp so future style changes only need one edit.
🪄 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: 00c002aa-ec97-4a93-ab5c-88b60a7f0a65

📥 Commits

Reviewing files that changed from the base of the PR and between 072747f and 6224a29.

⛔ Files ignored due to path filters (5)
  • src/app/apple-touch-icon.svg is excluded by !**/*.svg
  • src/app/favicon.svg is excluded by !**/*.svg
  • src/assets/djed-alliance.svg is excluded by !**/*.svg
  • src/assets/stability-nexus.svg is excluded by !**/*.svg
  • src/assets/svg/logo.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • License.md
  • src/app/layout.tsx
  • src/app/page.tsx
  • src/components/Button.tsx
  • src/components/ThemeToggle.tsx
  • src/sections/CallToAction.tsx
  • src/sections/Features.tsx
  • src/sections/Footer.tsx
  • src/sections/Header.tsx
  • src/sections/Hero.tsx
  • src/sections/LogoTicker.tsx
  • tailwind.config.ts

Comment on lines +12 to +36
const [theme, setTheme] = useState<'light' | 'dark'>('dark');
const [mounted, setMounted] = useState(false);

// Read initial theme and apply classes
useEffect(() => {
setMounted(true);
const storedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null;
const initialTheme = storedTheme || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
setTheme(initialTheme);
}, []);

useEffect(() => {
if (!mounted) return;
const root = document.documentElement;
if (theme === 'dark') {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
localStorage.setItem('theme', theme);
}, [theme, mounted]);

const toggleTheme = () => {
setTheme(prev => (prev === 'dark' ? 'light' : 'dark'));
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid storing the active theme in each toggle instance.

theme is component-local state and is only mirrored to document.documentElement/localStorage. src/sections/Header.tsx now mounts two ThemeToggles, so toggling the drawer copy leaves the header copy with stale icon/knob state. Move the theme source of truth into shared state and let each toggle render from that single value.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ThemeToggle.tsx` around lines 12 - 36, The ThemeToggle
component currently keeps theme in local state causing desync when multiple
instances mount; lift the single source of truth into shared state (e.g., a
ThemeContext or a top-level provider) and have ThemeToggle read theme and call
setTheme from that context instead of using its own useState. Initialize the
shared provider once (on app/root mount) to read localStorage ('theme'),
apply/remove the 'dark' class on document.documentElement, and persist changes
to localStorage; update ThemeToggle to use the provider's theme and the existing
toggleTheme/setTheme function (replace local setTheme, mounted logic and the
effect that writes to document.documentElement/localStorage). Ensure both
Header-mounted ThemeToggle instances consume the same context so icons/knobs
stay in sync.

Comment on lines +46 to +54
<button
onClick={toggleTheme}
className={`relative flex items-center w-[60px] h-[32px] rounded-full p-1 transition-colors duration-500 ease-in-out border border-white/10
${isDark ? 'bg-white/10 shadow-[inset_0px_0px_10px_rgba(255,255,255,0.1)]' : 'bg-black/5 shadow-[inset_0px_0px_10px_rgba(0,0,0,0.05)]'}`}
aria-label="Toggle Theme"
style={{
WebkitTapHighlightColor: 'transparent',
}}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Expose this as a real toggle button.

The control is missing type="button" and aria-pressed, so it will submit if reused inside a form and assistive tech cannot tell whether dark mode is currently active.

🔧 Minimal fix
     <button
+      type="button"
       onClick={toggleTheme}
+      aria-pressed={isDark}
       className={`relative flex items-center w-[60px] h-[32px] rounded-full p-1 transition-colors duration-500 ease-in-out border border-white/10
         ${isDark ? 'bg-white/10 shadow-[inset_0px_0px_10px_rgba(255,255,255,0.1)]' : 'bg-black/5 shadow-[inset_0px_0px_10px_rgba(0,0,0,0.05)]'}`}
-      aria-label="Toggle Theme"
+      aria-label={isDark ? 'Switch to light theme' : 'Switch to dark theme'}
       style={{
         WebkitTapHighlightColor: 'transparent',
       }}
📝 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
<button
onClick={toggleTheme}
className={`relative flex items-center w-[60px] h-[32px] rounded-full p-1 transition-colors duration-500 ease-in-out border border-white/10
${isDark ? 'bg-white/10 shadow-[inset_0px_0px_10px_rgba(255,255,255,0.1)]' : 'bg-black/5 shadow-[inset_0px_0px_10px_rgba(0,0,0,0.05)]'}`}
aria-label="Toggle Theme"
style={{
WebkitTapHighlightColor: 'transparent',
}}
>
<button
type="button"
onClick={toggleTheme}
aria-pressed={isDark}
className={`relative flex items-center w-[60px] h-[32px] rounded-full p-1 transition-colors duration-500 ease-in-out border border-white/10
${isDark ? 'bg-white/10 shadow-[inset_0px_0px_10px_rgba(255,255,255,0.1)]' : 'bg-black/5 shadow-[inset_0px_0px_10px_rgba(0,0,0,0.05)]'}`}
aria-label={isDark ? 'Switch to light theme' : 'Switch to dark theme'}
style={{
WebkitTapHighlightColor: 'transparent',
}}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ThemeToggle.tsx` around lines 46 - 54, The <ThemeToggle>
button currently lacks explicit type and ARIA state; update the <button> element
used with onClick={toggleTheme} to include type="button" and
aria-pressed={isDark} (or aria-pressed={!!isDark}) so it won't implicitly submit
forms and assistive tech can read the current dark-mode state; keep the existing
aria-label and other props unchanged.

Comment thread src/sections/Footer.tsx
Comment on lines +50 to +58
<a
href="https://www.youtube.com"
target="_blank"
rel="noreferrer"
aria-label="Djed Alliance on YouTube"
className="text-black/40 hover:text-black dark:text-white/40 dark:hover:text-white transition-colors duration-300"
>
<YTSocial className="w-5 h-5 sm:w-6 sm:h-6" />
</a>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

YouTube URL appears to be a placeholder.

The YouTube link points to https://www.youtube.com instead of the actual Djed Alliance YouTube channel. This should be updated to the correct channel URL before release.

Suggested fix
              <a
-               href="https://www.youtube.com"
+               href="https://www.youtube.com/@DjedAlliance"
                target="_blank"
                rel="noreferrer"
                aria-label="Djed Alliance on YouTube"

Replace with the actual YouTube channel URL.

📝 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
<a
href="https://www.youtube.com"
target="_blank"
rel="noreferrer"
aria-label="Djed Alliance on YouTube"
className="text-black/40 hover:text-black dark:text-white/40 dark:hover:text-white transition-colors duration-300"
>
<YTSocial className="w-5 h-5 sm:w-6 sm:h-6" />
</a>
<a
href="https://www.youtube.com/@DjedAlliance"
target="_blank"
rel="noreferrer"
aria-label="Djed Alliance on YouTube"
className="text-black/40 hover:text-black dark:text-white/40 dark:hover:text-white transition-colors duration-300"
>
<YTSocial className="w-5 h-5 sm:w-6 sm:h-6" />
</a>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sections/Footer.tsx` around lines 50 - 58, The YouTube anchor in the
Footer component uses a placeholder href ("https://www.youtube.com"); locate the
anchor element that contains aria-label="Djed Alliance on YouTube" (the one
rendering <YTSocial .../>) and replace the href value with the actual Djed
Alliance YouTube channel URL (ensuring target="_blank" and rel="noreferrer" are
preserved) before release.

Comment thread src/sections/Header.tsx
Comment on lines +29 to 33
<a href="#" className="text-black/70 hover:text-black dark:text-white/70 dark:hover:text-white transition-colors duration-300">
Developers Guide
</a>
<a href="#" className="text-white/70 hover:text-white transition">
<a href="#" className="text-black/70 hover:text-black dark:text-white/70 dark:hover:text-white transition-colors duration-300">
Integration Docs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Desktop navigation still points to placeholders.

Lines 29 and 32 still use href="#", while the drawer links go to /docs and /integration. Desktop users cannot reach those pages. Drive both navs from the same link data so the targets stay consistent.

Also applies to: 62-64

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sections/Header.tsx` around lines 29 - 33, Desktop nav anchors use
placeholder href="#" while the drawer uses real routes; update the desktop
anchor hrefs to the correct paths (e.g., "/docs" and "/integration") and
refactor both desktop and drawer navigation to consume a single shared links
array (e.g., navItems or NAV_LINKS) so targets remain consistent; locate the
anchors in Header.tsx (the desktop links around "Developers Guide" and
"Integration Docs" and the drawer link rendering) and replace static hrefs with
link.href from the shared data, mapping that array in both places.

Comment thread src/sections/Header.tsx
Comment on lines +40 to +46
<button
onClick={() => setOpen(true)}
aria-label="Open menu"
className="md:hidden w-5 h-5 sm:w-6 sm:h-6 text-black dark:text-white transition-colors duration-500"
>
<MenuIcon />
</button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Treat the mobile drawer as a modal dialog.

The trigger does not expose aria-expanded/aria-controls, and the drawer has no dialog semantics, focus management, or Escape handling. Keyboard and screen-reader users can still end up in background content while the drawer is open.

Also applies to: 52-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sections/Header.tsx` around lines 40 - 46, The mobile menu trigger/button
(onClick={() => setOpen(true)} with MenuIcon) and corresponding drawer must be
treated as a modal dialog: add aria-expanded and aria-controls to the trigger
(toggle with setOpen), give the drawer dialog semantics (role="dialog" and
aria-modal="true" and an id referenced by aria-controls), trap keyboard focus
inside the drawer and set initial focus to the first focusable element when it
opens, restore focus to the trigger when it closes, handle Escape to close
(listen for Escape and call setOpen(false)), and hide/inert background content
(or set aria-hidden on background regions) while open so screen readers and
keyboard users cannot reach behind the modal. Ensure these behaviors are applied
to the same mobile drawer used in the later block (lines around 52-73).

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.

Button Component Missing Accessibility Attributes

1 participant