Skip to content

Improve styling to be more responsive/mobile friendly#63

Open
nooreldeensalah wants to merge 6 commits intomainfrom
mobile-friendly
Open

Improve styling to be more responsive/mobile friendly#63
nooreldeensalah wants to merge 6 commits intomainfrom
mobile-friendly

Conversation

@nooreldeensalah
Copy link
Contributor

@nooreldeensalah nooreldeensalah commented Oct 4, 2025

Overview

All pages and components have been updated to provide an optimal viewing experience across different screen sizes:

  • Mobile phones (< 768px)
  • Tablets (768px - 1024px)
  • Desktops (> 1024px)

Changes by Component

1. Navigation (components/navbar.tsx)

Changes:

  • Added hamburger menu for mobile devices
  • Navigation items hidden on mobile, shown in dropdown menu
  • Mobile menu appears when hamburger icon is clicked
  • Logo and branding adjusted with responsive sizing
  • Reduced header height on mobile (h-16 vs h-20)

2. Hadith Cards (components/hadith-card.tsx)

Changes:

  • Decorative corner elements hidden on very small screens
  • Mobile-friendly ID badge shown only on small screens
  • Responsive padding: p-4 sm:p-6
  • Responsive text sizes: text-lg md:text-xl for titles, text-sm md:text-base for content
  • Source and chapter buttons stack vertically on mobile
  • Adjusted decorative elements sizing

3. Hadith List (components/hadith-list.tsx)

Changes:

  • Responsive padding: px-2 md:px-4
  • Adjusted left padding for virtualized items: pl-1 md:pl-4

4. Search Page (app/search/page.tsx)

Changes:

  • Container padding: px-2 md:px-4
  • Search form margin adjusted: mx-2 md:mx-16
  • Decorative corner hidden on mobile
  • Form padding: p-3 md:p-4
  • Input/select responsive text sizing
  • Reduced padding in all form elements for mobile
  • Loading and no-results states with responsive sizing

5. Narrator Grid (components/narrator-grid.tsx & app/narrator/page.tsx)

Changes:

  • Dynamic grid columns based on screen size:
    • Mobile: 1 column
    • Tablet: 2 columns
    • Desktop: 3-4 columns
  • Added useIsMobile hook for responsive behavior
  • Filter buttons with shortened text on mobile ("الكل" vs "جميع الدرجات")
  • Responsive text sizes throughout
  • Container height: h-[600px] md:h-[800px]
  • Page header with responsive text: text-2xl md:text-4xl

6. Narrator Detail Page (app/narrator/[name]/page.tsx)

Changes:

  • Layout stacks on mobile (1 column), side-by-side on desktop (12-column grid)
  • Responsive heading: text-2xl md:text-4xl
  • Info section grid: 1 col mobile, 2 tablet, 3 desktop
  • Responsive padding and gaps throughout
  • Network graph min-height adjusted: min-h-[400px] md:min-h-screen

7. Hadith Detail Page (app/hadith/[source]/[chapter]/[hadithNo]/page.tsx)

Changes:

  • Layout stacks vertically on mobile, side-by-side on desktop
  • Text and explanation cards responsive
  • Network visualization height: h-[500px] md:h-[600px] lg:h-screen
  • Shadow effects scaled down on mobile
  • Container padding: px-2 md:px-4

8. Hadith Text & Explanation Cards

Changes:

  • Padding: p-4 md:p-6
  • Heading sizes: text-xl md:text-2xl
  • Prose sizes: prose-base md:prose-xl and prose-sm md:prose-lg
  • Shadow effects: shadow-[4px_4px...] md:shadow-[8px_8px...]

9. Chapter Page (components/chapter-page.tsx)

Changes:

  • Responsive container padding
  • Header icon sizes: h-6 w-6 md:h-8 md:w-8
  • Title sizes: text-xl md:text-3xl
  • Stats badges with responsive sizing
  • Border widths: border-2 md:border-4

10. Footer (components/footer.tsx)

Changes:

  • Padding: py-4 md:py-6
  • Icon size: text-base md:text-lg
  • Text size: text-xs md:text-sm

11. About Page (app/about/page.tsx)

Changes:

  • Padding: py-6 md:py-8
  • Heading: text-2xl md:text-3xl

12. Layout Constants (lib/layout-constants.ts)

Changes:

  • Updated CONTAINER_CLASSES with responsive padding
  • Added new responsive utility constants:
    • PADDING_X_RESPONSIVE: "px-2 md:px-4"
    • PADDING_Y_RESPONSIVE: "py-4 md:py-8"
    • GAP_SMALL_RESPONSIVE, GAP_MEDIUM_RESPONSIVE, GAP_LARGE_RESPONSIVE

13. Global Styles (app/globals.css)

Changes:

  • Added mobile-specific improvements:
    • Minimum touch target sizes (44px × 44px)
    • Text size adjustment for better readability
    • Prevented horizontal overflow on mobile

14. Root Layout (app/layout.tsx)

Changes:

  • Added viewport metadata for proper mobile rendering:
    viewport: {
      width: "device-width",
      initialScale: 1,
      maximumScale: 5,
    }

Design Principles Applied

  1. Touch-Friendly Targets: All interactive elements have minimum 44px touch targets
  2. Flexible Layouts: Using CSS Grid and Flexbox with responsive breakpoints
  3. Typography Scale: Text sizes adjust based on screen size
  4. Spacing Scale: Padding and margins reduce proportionally on smaller screens
  5. Content Priority: Less important decorative elements hidden on mobile
  6. Progressive Enhancement: Mobile-first approach with enhancements for larger screens

Breakpoints Used

  • Small (sm): 640px and above
  • Medium (md): 768px and above
  • Large (lg): 1024px and above
  • Extra Large (xl): 1280px and above

Testing Recommendations

  1. Test on actual mobile devices (iOS and Android)
  2. Use Chrome DevTools device emulation
  3. Test with different screen sizes: 320px, 375px, 414px, 768px, 1024px, 1440px
  4. Test in both portrait and landscape orientations
  5. Verify touch interactions work smoothly
  6. Check that all text is readable without zooming
  7. Ensure no horizontal scrolling occurs

Future Improvements

Consider these additional enhancements:

  • Add swipe gestures for navigation
  • Implement pull-to-refresh functionality
  • Optimize images with responsive sizing
  • Add progressive web app (PWA) features
  • Consider dark mode support
  • Add skeleton loaders for better perceived performance

Summary by CodeRabbit

  • New Features

    • Mobile navigation toggle and mobile-friendly panel; responsive narrator grid with adaptive item density and a load-more mechanism; improved viewport scaling for mobile.
  • Style

    • Wide responsive polish: tightened spacing, scaled typography, refined cards/shadows/badges, decorative corner and mobile ID badge behavior, adjusted footer and component layouts.
  • Bug Fixes

    • Prevented horizontal scrolling on mobile; increased touch targets and stabilized mobile text sizing.

@coderabbitai
Copy link

coderabbitai bot commented Oct 4, 2025

Walkthrough

Responsive and mobile-focused UI refinements across pages and components, mobile-specific CSS and viewport metadata added, navbar gains a client-side mobile menu, narrator grid virtualization made responsive by computing itemsPer-row and card height dynamically.

Changes

Cohort / File(s) Summary
Global CSS & metadata
app/globals.css, app/layout.tsx
Adds mobile @media rules (hit-target min sizes, -webkit-text-size-adjust:100%, overflow-x hidden) and exports viewport: Viewport with device-width, initialScale 1, maximumScale 5; layout root gains relative positioning and extra bottom padding on main.
Layout constants
lib/layout-constants.ts
Updates LAYOUT.CONTAINER_CLASSES to responsive padding, changes VIRTUALIZED_CONTAINER_HEIGHT to "calc(100vh - 160px)", and adds exported responsive padding/gap constants (PADDING_X_RESPONSIVE, PADDING_Y_RESPONSIVE, GAP_*_RESPONSIVE).
Top-level page layouts
app/about/page.tsx, app/narrator/page.tsx, app/narrator/[name]/page.tsx, app/search/page.tsx, app/hadith/[source]/[chapter]/[hadithNo]/page.tsx
Presentation-only responsive adjustments: paddings, gaps, typography, grid columns, shadows, min-heights and reflow across breakpoints; no data-fetching or business-logic changes.
Header / Footer / Navigation
components/navbar.tsx, components/footer.tsx, components/chapter-page.tsx
Navbar: adds mobile menu state, toggle button (Menu/X icons) and mobile nav panel with close-on-click; Footer & ChapterPage: responsive spacing/typography tweaks and footer repositioned to bottom with new border/bg.
Hadith cards & lists
components/hadith-card.tsx, components/hadith-text-card.tsx, components/hadith-explanation-card.tsx, components/hadith-list.tsx
Cards and lists made responsive: conditional decorative corner, mobile & desktop ID badges, adjusted paddings, headings, shadows, text sizes; hadith-list uses numeric virtualized container height and adjusted per-item padding.
Narrator grid & cards
components/narrator-grid.tsx, components/narrator-card.tsx, components/narrator-grid.tsx
NarratorGrid: uses useIsMobile, computes itemsPerRow and cardHeight dynamically in useEffect, updates virtualizer size estimates and measurement, reflows grid responsively and adds load-more handling. NarratorCard: replaces direct Link with Button (asChild) wrapping Link for navigation trigger.
Other components / minor
components/hadith-explanation-card.tsx, components/hadith-text-card.tsx, components/footer.tsx, components/chapter-page.tsx
Miscellaneous responsive class and spacing refinements (reduced paddings/shadows, responsive typography) across several components; no API/signature changes.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant Navbar
  participant Router

  User->>Navbar: Tap Menu button
  alt open menu
    Navbar->>Navbar: set isMobileMenuOpen = true
    Navbar-->>User: Render mobile nav panel
  else close menu
    Navbar->>Navbar: set isMobileMenuOpen = false
  end

  User->>Navbar: Tap nav link
  Navbar->>Navbar: set isMobileMenuOpen = false
  Navbar->>Router: Navigate to route
  Router-->>User: New page renders
Loading
sequenceDiagram
  participant Window
  participant useIsMobile
  participant NarratorGrid
  participant Virtualizer

  Window-->>useIsMobile: initial/resize width
  useIsMobile-->>NarratorGrid: isMobile / breakpoint info
  NarratorGrid->>NarratorGrid: compute itemsPerRow & cardHeight (useEffect)
  NarratorGrid->>Virtualizer: update sizeEstimate & rowGenerator
  Virtualizer-->>NarratorGrid: virtual rows
  NarratorGrid-->>Window: render responsive virtualized grid
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

I hop through breakpoints, snug and spry,
Small badges wink as columns fly.
A menu opens, then softly closes,
Grids stretch tall where sunlight poses.
Little rabbit code — responsive and wry. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately conveys that this PR’s main purpose is enhancing styling to improve responsiveness and mobile-friendliness across the app, matching the extensive responsive layout and CSS updates described.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mobile-friendly

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
components/navbar.tsx (1)

62-72: Consider adding keyboard navigation support for the mobile menu.

The mobile menu button works well with mouse/touch, but consider enhancing keyboard accessibility:

  • Handle Escape key to close the menu
  • Trap focus within the mobile menu when open
  • Consider aria-expanded attribute on the button
 <button
   onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
+  onKeyDown={(e) => {
+    if (e.key === 'Escape') setIsMobileMenuOpen(false);
+  }}
   className="p-2 transition-colors hover:bg-parchment md:hidden"
   aria-label="Toggle menu"
+  aria-expanded={isMobileMenuOpen}
 >
components/narrator-grid.tsx (1)

122-138: Consider adding window resize listener for dynamic viewport changes.

The useEffect only runs when isMobile changes, which typically happens once during mount. If a user resizes their browser window (e.g., from mobile to desktop viewport), the grid won't adapt to the new width.

Add a resize listener to handle viewport changes:

  useEffect(() => {
    if (isMobile === undefined) return;

-   if (isMobile) {
+   const updateLayout = () => {
+     if (isMobile) {
-     setItemsPerRow(1);
-     setCardHeight(280);
-   } else if (window.innerWidth < 1024) {
-     setItemsPerRow(2);
-     setCardHeight(300);
-   } else if (window.innerWidth < 1280) {
-     setItemsPerRow(3);
-     setCardHeight(320);
-   } else {
-     setItemsPerRow(4);
-     setCardHeight(320);
-   }
+       setItemsPerRow(1);
+       setCardHeight(280);
+     } else if (window.innerWidth < 1024) {
+       setItemsPerRow(2);
+       setCardHeight(300);
+     } else if (window.innerWidth < 1280) {
+       setItemsPerRow(3);
+       setCardHeight(320);
+     } else {
+       setItemsPerRow(4);
+       setCardHeight(320);
+     }
+   };
+
+   updateLayout();
+   window.addEventListener('resize', updateLayout);
+   return () => window.removeEventListener('resize', updateLayout);
  }, [isMobile]);

Note: Consider debouncing the resize handler to improve performance.

app/hadith/[source]/[chapter]/[hadithNo]/page.tsx (1)

127-127: Fixed height on mobile may truncate visualization.

The network visualization section uses h-[500px] on mobile. Depending on the complexity of the transmission chain, this fixed height might not be sufficient for all hadiths, potentially requiring excessive scrolling within the component.

Consider using min-h-[500px] instead of h-[500px] to allow the visualization to expand if needed:

-        <section className="relative h-[500px] border-4 border-black bg-white p-1 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] md:h-[600px] md:shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] lg:col-span-9 lg:h-screen">
+        <section className="relative min-h-[500px] border-4 border-black bg-white p-1 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] md:min-h-[600px] md:shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] lg:col-span-9 lg:h-screen">

This would provide better flexibility while maintaining the minimum height constraint.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc8ded9 and 2a93b23.

📒 Files selected for processing (16)
  • app/about/page.tsx (1 hunks)
  • app/globals.css (1 hunks)
  • app/hadith/[source]/[chapter]/[hadithNo]/page.tsx (1 hunks)
  • app/layout.tsx (1 hunks)
  • app/narrator/[name]/page.tsx (4 hunks)
  • app/narrator/page.tsx (1 hunks)
  • app/search/page.tsx (4 hunks)
  • components/chapter-page.tsx (1 hunks)
  • components/footer.tsx (1 hunks)
  • components/hadith-card.tsx (3 hunks)
  • components/hadith-explanation-card.tsx (1 hunks)
  • components/hadith-list.tsx (2 hunks)
  • components/hadith-text-card.tsx (1 hunks)
  • components/narrator-grid.tsx (9 hunks)
  • components/navbar.tsx (2 hunks)
  • lib/layout-constants.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
app/search/page.tsx (1)
lib/arabic-utils.ts (1)
  • arabicTexts (2-57)
components/hadith-list.tsx (1)
lib/layout-constants.ts (1)
  • LAYOUT (2-24)
components/hadith-text-card.tsx (1)
components/ui/card.tsx (1)
  • Card (79-79)
app/narrator/[name]/page.tsx (2)
components/brutalist-card.tsx (1)
  • BrutalistCard (6-17)
lib/grade-mapping.ts (2)
  • getBlessings (51-64)
  • getArabicGrade (47-49)
components/chapter-page.tsx (4)
lib/layout-constants.ts (1)
  • LAYOUT (2-24)
lib/arabic-utils.ts (2)
  • arabicTexts (2-57)
  • formatArabicCount (73-82)
lib/utils.ts (1)
  • cleanName (8-17)
lib/book-mapping.ts (1)
  • getArabicSource (10-12)
components/hadith-card.tsx (1)
lib/arabic-utils.ts (2)
  • toArabicNumerals (60-65)
  • arabicTexts (2-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
🔇 Additional comments (24)
components/footer.tsx (1)

6-6: LGTM! Mobile-first padding adjustment.

The responsive vertical padding (py-4 on mobile, md:py-6 on desktop) aligns well with the mobile-first approach and maintains appropriate footer spacing across breakpoints.

app/about/page.tsx (1)

3-4: LGTM! Consistent mobile-first responsive adjustments.

The container padding and heading typography changes follow the mobile-first pattern consistently:

  • Reduced base padding (py-6) scales up on medium screens (md:py-8)
  • Smaller base heading (text-2xl) scales up on medium screens (md:text-3xl)

These changes align well with the broader responsive design strategy.

app/layout.tsx (1)

20-24: LGTM! Essential viewport configuration for responsive design.

The viewport metadata is properly configured:

  • width: "device-width" enables responsive layouts
  • initialScale: 1 prevents unintended zooming
  • maximumScale: 5 permits user zoom for accessibility

This is a foundational change that enables the responsive adjustments throughout the PR.

app/globals.css (1)

50-54: LGTM! Prevents horizontal scroll on mobile.

The overflow-x: hidden rule on html and body prevents horizontal scrolling issues that commonly occur on mobile devices when content or elements exceed viewport width.

components/hadith-explanation-card.tsx (1)

9-13: LGTM! Comprehensive responsive adjustments.

The card, heading, and prose container all follow the mobile-first pattern consistently:

  • Reduced base padding (p-4) and shadow scale up on medium screens
  • Heading typography (text-xl) and spacing (mb-3) scale up appropriately
  • Prose size (prose-sm) scales to prose-lg on medium screens

These changes improve mobile readability while preserving desktop presentation.

components/navbar.tsx (2)

1-9: LGTM! Proper client component setup for mobile menu state.

The component correctly uses "use client" directive and useState to manage mobile menu state. The icon imports from lucide-react are appropriate for the menu toggle functionality.


77-106: Verify mobile menu closes on viewport resize.

The mobile menu state persists across viewport changes. If a user opens the mobile menu, then resizes to desktop width, the menu state remains true (though hidden by CSS). While not critical, consider adding a resize listener to close the menu when crossing the md breakpoint.

Test scenario: Open mobile menu → resize browser to desktop width → resize back to mobile. Verify the menu state is appropriate and doesn't cause unexpected behavior.

lib/layout-constants.ts (2)

13-23: LGTM! Well-structured responsive layout constants.

The new responsive padding and gap utilities provide a consistent, reusable set of spacing values that align with the mobile-first approach. The naming convention is clear and the breakpoint usage (md:) is consistent throughout.


14-14: Verify small-screen padding adjustments across all CONTAINER_CLASSES consumers
CONTAINER_CLASSES changed from py-8 to py-4 md:py-8. Confirm the reduced vertical padding on small viewports is acceptable in:

  • components/hadith-list.tsx:16
  • components/chapter-page.tsx:37
  • components/chapter-list.tsx:24
components/hadith-list.tsx (2)

16-16: LGTM! Proper usage of responsive layout constants.

The component correctly combines LAYOUT.CONTAINER_CLASSES (which provides responsive vertical padding) with additional responsive horizontal padding (px-2 md:px-4), following the established mobile-first pattern.


32-32: Verify that pl-1 (4px) provides sufficient spacing on mobile.

The left padding was reduced from pl-4 (16px) to pl-1 (4px) on mobile devices. This minimal padding might make the layout feel cramped, especially considering the virtualized list already has limited horizontal space on small screens.

Please test the hadith list on mobile devices to ensure:

  • Cards don't appear too close to the container edge
  • Touch interaction with cards is comfortable
  • Visual hierarchy is maintained

Consider using pl-2 (8px) as a middle ground if pl-1 feels too tight.

components/narrator-grid.tsx (4)

75-77: Good progressive enhancement with responsive filter text.

The approach of showing "الكل" on mobile and "جميع الدرجات" on larger screens is appropriate for space-constrained layouts.


185-185: Correct virtualization size calculation.

The estimateSize now uses the dynamic cardHeight instead of a fixed constant, which is essential for accurate virtualization across different viewport sizes.


214-214: Responsive scroll container height is appropriate.

The container height scales from 600px on mobile to 800px on desktop, providing adequate viewing area for both contexts.


7-7: Ignore SSR hydration undefined‐return suggestion for useIsMobile
useIsMobile coerces its initial undefined state to false via !!isMobile, so server and client markup will match—no additional SSR guard or undefined return needed.

Likely an incorrect or invalid review comment.

app/hadith/[source]/[chapter]/[hadithNo]/page.tsx (3)

120-120: Verify adequate horizontal padding on mobile.

The container uses px-2 on mobile, which provides only 8px of padding. For touch-friendly interfaces, consider whether this provides sufficient buffer from screen edges.

Test on actual mobile devices to ensure:

  • Text and interactive elements don't feel cramped
  • Tap targets aren't too close to screen edges
  • Content remains comfortably readable

122-125: Mobile-first stacking is appropriate.

The layout correctly stacks the hadith text and explanation vertically on mobile (grid-cols-1) before transitioning to the side-by-side layout on large screens (lg:col-span-3). This prioritizes content readability on small screens.


127-127: Appropriate shadow scaling for brutalist design.

The shadow scales from 4px on mobile to 8px on medium screens, maintaining the brutalist aesthetic while reducing visual weight on smaller screens. This is a good responsive design choice.

app/narrator/[name]/page.tsx (6)

161-171: Responsive spacing and typography scaling is consistent.

The InfoSection properly scales gaps (gap-4 → md:gap-6), decorative bar thickness (border-t-2 → md:border-t-4), and heading text (text-xl → md:text-2xl), maintaining visual hierarchy across breakpoints.


172-172: Dynamic grid columns provide good content adaptation.

The info cards grid transitions from 1 column (mobile) to 2 columns (medium) to 3 columns (large), ensuring readability at all viewport sizes while maximizing space usage on larger screens.


178-181: Creative use of decorative underline with responsive sizing.

The technique of using an absolutely positioned background element that scales from h-2 to h-3 across breakpoints is a nice touch that maintains the brutalist aesthetic. The translate adjustment keeps it properly positioned.


230-240: Well-structured responsive grid layout.

The main content area effectively uses a 1-column mobile layout that expands to a 12-column grid on large screens, with the sidebar taking 3 columns and the main content taking 9. The explicit lg:order-* classes ensure proper visual ordering.


241-241: Min-height ensures adequate visualization space.

Using min-h-[400px] on mobile and md:min-h-screen on larger screens provides flexibility for the transmission chain visualization while ensuring a minimum usable height. This is more appropriate than a fixed height.


183-183: Verify text overflow behavior in hover state.

The info card content uses max-h-[30vh] overflow-y-auto within the expanded hover state. On mobile devices with limited viewport height, 30vh might be quite small. Ensure scrolling works smoothly on touch devices.

Test the hover/expansion behavior on mobile:

  • Does the expansion work on touch devices (typically requires tap, not hover)?
  • Is 30vh sufficient for readable content on small phones?
  • Does the overflow scrolling feel natural with touch gestures?

Comment on lines +14 to +15
<FaGithub className="text-base md:text-lg" />
<span className="relative z-10 text-xs md:text-sm">الكود</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify text legibility at text-xs on small screens.

The text size is reduced to text-xs (12px) on mobile devices. While this saves space, please confirm that the footer label text remains legible at this size, especially for users with visual impairments.


🌐 Web query:

What is the minimum recommended font size for mobile text according to WCAG and mobile accessibility guidelines?

💡 Result:

Short answer:

  • WCAG does not mandate a single minimum mobile font-size, but defines "large scale (text)" as at least 18pt (or 14pt bold) when delivered and requires text to be resizable (e.g., 200%). [1]
  • Practical mobile guidance: many platform and accessibility guides recommend ~16px (≈12pt) or larger for body text as a minimum for readability on mobile. Also follow platform Dynamic Type / scalable units (iOS Dynamic Type, Android sp). [2][3]

Sources:
[1] WCAG 2.1 (large text / resize text).
[2] Apple — Larger Text / Dynamic Type guidance.
[3] Web accessibility guidance recommending ~16px baseline and use of relative units.


Ensure footer label meets mobile readability guidelines
text-xs (12px) on small screens falls below the ~16px baseline recommended for mobile; either bump it to at least text-sm (14px) or confirm 12px renders legibly and supports 200% resizing per WCAG.

🤖 Prompt for AI Agents
In components/footer.tsx around lines 14 to 15, the span uses "text-xs
md:text-sm" which sets ~12px on small screens; update the class to use at least
"text-sm" for small screens (e.g., "relative z-10 text-sm md:text-sm") so mobile
font meets the recommended baseline and still switches to the md size on larger
viewports.

Comment on lines 119 to 138
const [itemsPerRow, setItemsPerRow] = useState(4);
const [cardHeight, setCardHeight] = useState(320);

useEffect(() => {
if (isMobile === undefined) return;

if (isMobile) {
setItemsPerRow(1);
setCardHeight(280);
} else if (window.innerWidth < 1024) {
setItemsPerRow(2);
setCardHeight(300);
} else if (window.innerWidth < 1280) {
setItemsPerRow(3);
setCardHeight(320);
} else {
setItemsPerRow(4);
setCardHeight(320);
}
}, [isMobile]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential layout shift on initial render.

The component initializes itemsPerRow to 4 and cardHeight to 320 (desktop values), then updates them in a useEffect based on isMobile. This will cause a visible layout shift on mobile devices after the first render, as the grid will initially render with 4 columns before adjusting to 1 column.

Consider initializing with mobile-first values to minimize layout shift:

-  const [itemsPerRow, setItemsPerRow] = useState(4);
-  const [cardHeight, setCardHeight] = useState(320);
+  const [itemsPerRow, setItemsPerRow] = useState(1);
+  const [cardHeight, setCardHeight] = useState(280);

This aligns with the mobile-first approach used elsewhere in the PR.

📝 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
const [itemsPerRow, setItemsPerRow] = useState(4);
const [cardHeight, setCardHeight] = useState(320);
useEffect(() => {
if (isMobile === undefined) return;
if (isMobile) {
setItemsPerRow(1);
setCardHeight(280);
} else if (window.innerWidth < 1024) {
setItemsPerRow(2);
setCardHeight(300);
} else if (window.innerWidth < 1280) {
setItemsPerRow(3);
setCardHeight(320);
} else {
setItemsPerRow(4);
setCardHeight(320);
}
}, [isMobile]);
// Initialize mobile-first to avoid layout shift on initial render
- const [itemsPerRow, setItemsPerRow] = useState(4);
const [itemsPerRow, setItemsPerRow] = useState(1);
const [cardHeight, setCardHeight] = useState(280);
useEffect(() => {
if (isMobile === undefined) return;
if (isMobile) {
setItemsPerRow(1);
setCardHeight(280);
} else if (window.innerWidth < 1024) {
setItemsPerRow(2);
setCardHeight(300);
} else if (window.innerWidth < 1280) {
setItemsPerRow(3);
setCardHeight(320);
} else {
setItemsPerRow(4);
setCardHeight(320);
}
}, [isMobile]);
🤖 Prompt for AI Agents
In components/narrator-grid.tsx around lines 119 to 138, the state defaults are
set to desktop values which cause a layout shift on initial render on mobile;
change the initial state to mobile-first values (e.g., itemsPerRow=1,
cardHeight=280) or compute initial values from isMobile/window in the useState
initializer so the first render matches the device size, keep the existing
useEffect to adjust for other breakpoints.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
components/narrator-grid.tsx (1)

119-138: Layout shift issue previously flagged.

The desktop-first initial state values (itemsPerRow: 4, cardHeight: 320) will cause a visible layout shift on mobile devices during the first render, as noted in the previous review. Consider initializing with mobile-first values or computing initial values based on isMobile to minimize this shift.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a81fe5 and 6fd28a8.

📒 Files selected for processing (8)
  • app/layout.tsx (3 hunks)
  • components/chapter-page.tsx (2 hunks)
  • components/footer.tsx (1 hunks)
  • components/hadith-card.tsx (3 hunks)
  • components/hadith-list.tsx (2 hunks)
  • components/narrator-card.tsx (2 hunks)
  • components/narrator-grid.tsx (11 hunks)
  • lib/layout-constants.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/hadith-list.tsx
  • components/footer.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
components/chapter-page.tsx (4)
lib/layout-constants.ts (1)
  • LAYOUT (2-24)
lib/arabic-utils.ts (2)
  • arabicTexts (2-57)
  • formatArabicCount (73-82)
lib/utils.ts (1)
  • cleanName (8-17)
lib/book-mapping.ts (1)
  • getArabicSource (10-12)
components/hadith-card.tsx (1)
lib/arabic-utils.ts (2)
  • toArabicNumerals (60-65)
  • arabicTexts (2-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
🔇 Additional comments (11)
app/layout.tsx (2)

13-17: LGTM! Proper viewport configuration for mobile rendering.

The viewport export follows Next.js 15.x metadata conventions and includes appropriate settings for mobile devices. The maximumScale: 5 value correctly allows users to zoom, meeting accessibility requirements.


63-65: LGTM! Responsive layout improvements.

The addition of relative positioning enables proper layering of child components, and the responsive bottom padding (pb-20 md:pb-24) follows the mobile-first approach consistently used throughout this PR.

lib/layout-constants.ts (2)

14-23: LGTM! Well-structured responsive utilities.

The new responsive padding and gap utilities follow Tailwind's mobile-first breakpoint pattern and provide consistent spacing scales across the application.


5-5: Type change is safe; no numeric usage detected.

Verified that VIRTUALIZED_CONTAINER_HEIGHT is only used in React style props—which accept string values for CSS—and isn’t involved in any numeric operations.

components/narrator-grid.tsx (2)

48-101: LGTM! Comprehensive responsive refinements.

The filter panel updates implement thorough responsive adjustments including:

  • Scaled input and button text sizes
  • Responsive icon sizing
  • Shortened filter labels on mobile (e.g., "الكل" vs "جميع الدرجات")
  • Appropriate spacing and margins across breakpoints

These changes enhance usability on smaller screens.


214-246: LGTM! Dynamic virtualization with responsive grid.

The virtualization implementation correctly:

  • Uses measureElement and data-index for accurate sizing
  • Applies responsive grid classes (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4)
  • Includes dynamic paddingBottom based on GAP

This enables smooth scrolling with proper measurement across all viewport sizes.

components/chapter-page.tsx (3)

36-38: LGTM! Proper use of layout constants.

The container correctly combines LAYOUT.CONTAINER_CLASSES with LAYOUT.PADDING_X_RESPONSIVE to apply consistent responsive padding across the page.


51-93: LGTM! Thorough responsive header implementation.

The chapter header includes comprehensive responsive adjustments:

  • Scaled padding and spacing (p-4 md:p-8, gap-2 md:gap-4)
  • Typography scaling (text-xl md:text-3xl, text-base md:text-lg)
  • Responsive icon and badge sizing
  • Lighter borders and shadows on mobile (border-2 vs md:border-4)

These changes maintain visual hierarchy while optimizing for touch interaction on smaller screens.


96-99: LGTM! Dynamic container height for virtualization.

The hadith list container correctly uses the updated VIRTUALIZED_CONTAINER_HEIGHT constant (now a CSS calc() expression) to provide viewport-relative sizing that adapts to available screen space.

components/hadith-card.tsx (2)

28-41: LGTM! Excellent mobile-first decorative element handling.

The implementation properly handles decorative elements across breakpoints:

  • Decorative corner hidden on very small screens (hidden sm:block) to reduce clutter
  • Separate mobile ID badge (sm:hidden) ensures the hadith ID remains visible and accessible on small screens without the decorative corner
  • Responsive sizing of decorative elements (h-16 w-16 md:h-24 md:w-24)

This approach prioritizes content readability on mobile while maintaining visual appeal on larger screens.


35-69: LGTM! Comprehensive responsive layout refinements.

The card content applies thorough responsive adjustments:

  • Progressive padding (p-4 sm:p-6 sm:pl-12 sm:pt-8 md:pl-16 md:pt-10)
  • Scaled typography (text-lg md:text-xl, text-xs md:text-sm, text-sm md:text-base)
  • Responsive metadata badges with proper touch targets
  • Flexible wrapping for metadata row

These changes ensure readability and usability across all viewport sizes.

Comment on lines +133 to +143
<div className="absolute bottom-1 left-1">
<Button
asChild
className="flex h-4 items-center gap-0.5 rounded-none border border-isnad-primary bg-isnad-primary px-1 text-[6px] font-bold text-isnad-background shadow-[1px_1px_0px_0px_theme(colors.isnad.primary)] transition-colors hover:bg-isnad-primary-hover focus-visible:ring-isnad-primary focus-visible:ring-offset-0"
>
<Link href={`/narrator/${name}`}>
<span className="leading-none">المزيد</span>
<ArrowUpRightIcon className="h-2 w-2" />
</Link>
</Button>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Touch target size below accessibility guideline.

The button height is set to h-4 (16px), which falls short of the 44×44px minimum touch target mentioned in the PR objectives. This could impact mobile usability, especially since the "المزيد" (More) button appears to be the primary navigation element for this card.

Consider increasing the button size or adding adequate padding to meet the minimum touch target size:

       <Button
         asChild
-        className="flex h-4 items-center gap-0.5 rounded-none border border-isnad-primary bg-isnad-primary px-1 text-[6px] font-bold text-isnad-background shadow-[1px_1px_0px_0px_theme(colors.isnad.primary)] transition-colors hover:bg-isnad-primary-hover focus-visible:ring-isnad-primary focus-visible:ring-offset-0"
+        className="flex min-h-[44px] min-w-[44px] items-center justify-center gap-0.5 rounded-none border border-isnad-primary bg-isnad-primary px-2 text-[6px] font-bold text-isnad-background shadow-[1px_1px_0px_0px_theme(colors.isnad.primary)] transition-colors hover:bg-isnad-primary-hover focus-visible:ring-isnad-primary focus-visible:ring-offset-0"
       >

Alternatively, if the small size is intentional for desktop and you're relying on responsive classes elsewhere, consider adding a responsive variant: h-4 md:min-h-[44px] md:min-w-[44px].

📝 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
<div className="absolute bottom-1 left-1">
<Button
asChild
className="flex h-4 items-center gap-0.5 rounded-none border border-isnad-primary bg-isnad-primary px-1 text-[6px] font-bold text-isnad-background shadow-[1px_1px_0px_0px_theme(colors.isnad.primary)] transition-colors hover:bg-isnad-primary-hover focus-visible:ring-isnad-primary focus-visible:ring-offset-0"
>
<Link href={`/narrator/${name}`}>
<span className="leading-none">المزيد</span>
<ArrowUpRightIcon className="h-2 w-2" />
</Link>
</Button>
</div>
<div className="absolute bottom-1 left-1">
<Button
asChild
className="flex min-h-[44px] min-w-[44px] items-center justify-center gap-0.5 rounded-none border border-isnad-primary bg-isnad-primary px-2 text-[6px] font-bold text-isnad-background shadow-[1px_1px_0px_0px_theme(colors.isnad.primary)] transition-colors hover:bg-isnad-primary-hover focus-visible:ring-isnad-primary focus-visible:ring-offset-0"
>
<Link href={`/narrator/${name}`}>
<span className="leading-none">المزيد</span>
<ArrowUpRightIcon className="h-2 w-2" />
</Link>
</Button>
</div>

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.

1 participant