Skip to content

refactor:statically generate icon detail pages and remove client-side…#49

Merged
Abhijit-Jha merged 4 commits intomasterfrom
refactor/icon-pages-ssg
Jan 6, 2026
Merged

refactor:statically generate icon detail pages and remove client-side…#49
Abhijit-Jha merged 4 commits intomasterfrom
refactor/icon-pages-ssg

Conversation

@Abhijit-Jha
Copy link
Copy Markdown
Member

@Abhijit-Jha Abhijit-Jha commented Jan 6, 2026

This change reduces unnecessary edge and serverless requests by converting
/icon/[slug] pages from request-time rendering to build-time static generation.

What changed:

  • Added generateStaticParams to pre-render all icon detail pages at build time
  • Read icon slugs directly from icons/index.ts using fs to avoid importing
    client components into the server context
  • Moved icon source fetching to the Server Component (page.tsx)
  • Removed client-side useEffect-based fetching from IconDetailContent
  • Simplified IconDetailContent to accept code via props

Benefits:

  • Zero serverless executions on icon page visits
  • Faster page loads with no extra network requests
  • Cleaner separation between server and client components
  • Architecture aligned with Next.js App Router best practices

Summary by CodeRabbit

  • New Features

    • Static generation added for icon pages to improve load performance.
  • Bug Fixes

    • Fixed CSS class so the accessibility icon shows the pointer cursor correctly.
  • Refactor

    • Icon content now supplied directly to pages, simplifying and speeding icon display.
    • Arrow animations simplified: removed bounce and smoothed opacity behavior for more stable motion.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Jan 6, 2026

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

Project Deployment Review Updated (UTC)
itshover-icons Ready Ready Preview, Comment Jan 6, 2026 0:20am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Icon content fetching moved from the IconDetailContent component to the page layer; pages now generate static params and fetch icon code, passing a required code prop to IconDetailContent. Several icon start animations simplified and a CSS class string was corrected; one file had line-ending normalization.

Changes

Cohort / File(s) Summary
Icon Detail Data Flow
app/icons/[slug]/page.tsx, app/icons/[slug]/icon-detail-content.tsx
generateStaticParams() added to page.tsx; page.tsx now calls getIconsContent(slug) and calls notFound() if missing, then renders IconDetailContent with a new required code: string prop. IconDetailContent signature changed to ({ slug, code }: { slug: string; code: string }) and no longer imports getIconsContent.
Icon Animation Updates
icons/arrow-big-down-dash-icon.tsx, icons/arrow-big-down-icon.tsx, public/r/arrow-big-down-dash-icon.json, public/r/arrow-big-down-icon.json
Start animations simplified to single target values (e.g., y: 4, opacity: 0.5) instead of multi-keyframe sequences; stop animations unchanged.
CSS Class Fix
icons/accessibility-icon.tsx, public/r/accessibility-icon.json
Fixed root SVG className from "cursor - pointer" to "cursor-pointer".
Formatting-only change
icons/coin-bitcoin-icon.tsx, public/r/coin-bitcoin-icon.json
Line ending/formatting normalized (CRLF → LF); no functional change.

Sequence Diagram

sequenceDiagram
    participant Page as Page ([slug])
    participant Service as getIconsContent()
    participant Component as IconDetailContent

    rect rgb(240,248,255)
    note over Page,Service: Static params + server fetch
    Page->>Service: getIconsContent(slug)
    Service-->>Page: code (string) or null
    alt code present
        Page->>Component: render IconDetailContent(slug, code)
        Component->>Component: initialize state from code prop
    else not found
        Page->>Page: notFound()
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Feat: Generate-Registry Script #28 — Changes to registry generation and icons/index.ts that align with this PR's use of icons/index.ts and per-icon JSON artifacts for static generation.

Poem

🐰 Hooray—icons hop from page to prop,
Fetch moved higher, now the render's top.
Animations softer, no extra flop,
Cursor points steady—no hyphen-stop.
A little rabbit cheer and a joyful hop.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
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.
Title check ❓ Inconclusive The title is incomplete and cut off mid-sentence ('remove client-side…'), making it unclear what is being removed. While it clearly references the main change (static generation of icon pages), the truncation makes it vague and prevents full understanding of the scope. Complete the title to clearly state the full objective, e.g., 'refactor: statically generate icon detail pages and remove client-side fetching' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @app/icons/[slug]/page.tsx:
- Around line 40-42: Wrap the getIconsContent(slug) call in a try-catch (or
check for a null/undefined result) inside the page component that returns
<IconDetailContent>; on any error or missing content call notFound() from
next/navigation to render a 404 instead of letting the exception bubble.
Specifically, update the code around getIconsContent and the return of
IconDetailContent so that failed/absent icon content triggers notFound() and
only successful fetches render IconDetailContent.
🧹 Nitpick comments (3)
icons/accessibility-icon.tsx (1)

59-59: CSS class fix looks good.

The className correction from "cursor - pointer" to "cursor-pointer" properly fixes the CSS class name.

Optional: Remove trailing space.

There's a trailing space after ${className} that could be removed for cleaner formatting.

🔎 Suggested cleanup
-        className={`cursor-pointer ${className} `}
+        className={`cursor-pointer ${className}`}
app/icons/[slug]/icon-detail-content.tsx (2)

29-29: Remove unused setIconCode and simplify state management.

Since code is now passed via props and never updated client-side, the iconCode state and its setter are unnecessary. Use the code prop directly.

🔎 Proposed fix
-  const [iconCode, setIconCode] = React.useState<string>(code);

Then replace all occurrences of iconCode with code throughout the component (lines 39, 225, 245, 248).


245-257: Dead code: "Loading code..." fallback is unreachable.

Since code is now provided server-side via props and will always have a value, this loading state branch will never execute. Consider removing it for cleaner code.

🔎 Proposed simplification
                      <div className="max-h-[500px] overflow-auto">
-                        {iconCode ? (
-                          <pre className="p-4 text-sm">
-                            <code className="text-foreground/90">
-                              {iconCode}
-                            </code>
-                          </pre>
-                        ) : (
-                          <div className="flex h-40 items-center justify-center">
-                            <span className="text-muted-foreground text-sm">
-                              Loading code...
-                            </span>
-                          </div>
-                        )}
+                        <pre className="p-4 text-sm">
+                          <code className="text-foreground/90">{code}</code>
+                        </pre>
                      </div>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e25f4d and 8710c05.

📒 Files selected for processing (9)
  • app/icons/[slug]/icon-detail-content.tsx
  • app/icons/[slug]/page.tsx
  • icons/accessibility-icon.tsx
  • icons/arrow-big-down-dash-icon.tsx
  • icons/arrow-big-down-icon.tsx
  • public/r/accessibility-icon.json
  • public/r/arrow-big-down-dash-icon.json
  • public/r/arrow-big-down-icon.json
  • public/r/coin-bitcoin-icon.json
🧰 Additional context used
🧬 Code graph analysis (1)
app/icons/[slug]/page.tsx (2)
actions/get-icons-content.ts (1)
  • getIconsContent (6-10)
app/icons/[slug]/icon-detail-content.tsx (1)
  • IconDetailContent (21-316)
🪛 GitHub Check: build
app/icons/[slug]/icon-detail-content.tsx

[warning] 29-29:
'setIconCode' is assigned a value but never used

🔇 Additional comments (8)
public/r/coin-bitcoin-icon.json (1)

10-10: LGTM! Formatting improvement.

The newline formatting update (CRLF to LF) improves consistency without affecting functionality.

public/r/accessibility-icon.json (1)

10-10: LGTM! Consistent with source component.

The content field correctly reflects the className fix from icons/accessibility-icon.tsx, updating from "cursor - pointer" to "cursor-pointer".

icons/arrow-big-down-icon.tsx (1)

10-10: Animation simplification looks good.

The change from { y: [0, 4, 0] } to { y: [0, 4] } simplifies the animation by removing the automatic return to the origin. The icon now stays at position y: 4 until stop() is called, which is appropriate since the hover handlers correctly trigger stop() on hover end.

icons/arrow-big-down-dash-icon.tsx (1)

10-11: Animation simplifications look good.

Both animations have been simplified from keyframe sequences to fixed target values:

  • Arrow y position: [0, 4, 0]4
  • Dash opacity: [1, 0.5, 1]0.5

This matches the pattern in arrow-big-down-icon.tsx and properly relies on stop() to return elements to their original state. The hover handlers ensure correct animation lifecycle.

public/r/arrow-big-down-icon.json (1)

10-10: LGTM!

The animation simplification from a three-point keyframe sequence (y: [0, 4, 0]) to a single target (y: [0, 4]) is appropriate. The stop() function still handles returning to y: 0, so the hover-in/hover-out behavior remains intact with cleaner separation of concerns.

public/r/arrow-big-down-dash-icon.json (1)

10-10: LGTM!

Consistent animation simplification with arrow-big-down-icon.json. Both the arrow movement and dash opacity now animate to single target values, with stop() handling the restoration. The parallel animation calls for .arrow and .dash are appropriate for synchronized effects.

app/icons/[slug]/page.tsx (1)

11-28: LGTM on the static params generation approach.

The generateStaticParams function correctly extracts icon slugs at build time. Using synchronous fs.readFileSync here is acceptable since this only runs during the build phase.

app/icons/[slug]/icon-detail-content.tsx (1)

21-27: Good refactoring to accept code via props.

The simplification from client-side fetching to server-provided props aligns well with the SSG approach and Next.js App Router best practices for data flow.

Comment thread app/icons/[slug]/page.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI Agents
In @app/icons/[slug]/page.tsx:
- Around line 48-49: The catch block declares an unused error parameter; remove
it by changing the catch clause from `catch (error)` to a parameterless `catch`
so the `notFound()` call remains but the unused `error` variable is eliminated
(update the catch in the code path that calls notFound() in the page component
handling icons/[slug]).
- Around line 12-29: The generateStaticParams function lacks error handling and
incorrectly filters icon names by dash; wrap the file read and regex parsing in
a try/catch around fs.readFileSync(indexPath, "utf-8") and namePattern.exec
usage to throw or log a clear, descriptive error if icons/index.ts is missing or
malformed, and remove the name.includes("-") check so every extracted name (from
namePattern) is pushed into the names array; keep the dedupe and return mapping
as-is.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8710c05 and c0d4189.

📒 Files selected for processing (1)
  • app/icons/[slug]/page.tsx
🧰 Additional context used
🪛 GitHub Check: build
app/icons/[slug]/page.tsx

[warning] 48-48:
'error' is defined but never used

🔇 Additional comments (2)
app/icons/[slug]/page.tsx (2)

1-6: LGTM!

Imports are appropriate for a Next.js App Router server component. Using fs and path in generateStaticParams is valid since it runs at build time.


39-53: Clean implementation of server-side fetching with proper error handling.

The try-catch pattern with notFound() correctly handles both fetch failures and missing icon content. This aligns well with Next.js App Router best practices for static generation.

Comment thread app/icons/[slug]/page.tsx
Comment thread app/icons/[slug]/page.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
app/icons/[slug]/page.tsx (1)

12-34: Good implementation with proper error handling.

The error handling and deduplication logic are solid. The regex-based extraction is a pragmatic approach to avoid importing client components into the server build context.

One consideration: the regex /name:\s*["']([^"']+)["']/g assumes a specific format in icons/index.ts. If the format changes (e.g., multi-line properties or computed names), this could silently miss entries. Consider adding a build-time assertion that compares the extracted count against an expected minimum.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0d4189 and 5fe90e3.

📒 Files selected for processing (1)
  • app/icons/[slug]/page.tsx
🔇 Additional comments (4)
app/icons/[slug]/page.tsx (4)

1-6: LGTM!

The imports are appropriate for static generation with filesystem access at build time, and all are used in the code.


8-10: LGTM!

The Promise<{ slug: string }> type correctly reflects Next.js 15's async params API.


36-42: LGTM!

Metadata generation correctly uses the async params API and produces appropriate SEO-friendly titles and descriptions.


44-58: Solid error handling with clean 404 fallback.

The try-catch with notFound() correctly handles both missing content and fetch failures. The parameterless catch on line 53 properly addresses the previous static analysis warning about unused variables.

Minor note: The let code = "" initialization on line 46 is technically redundant since notFound() throws and the empty string path is never reached. You could use const code = await getIconsContent(slug) directly inside the try block, but the current approach is clear and works correctly.

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