Skip to content

Conversation

@afsar-dev
Copy link
Owner

@afsar-dev afsar-dev commented Oct 10, 2025

  • Implemented CounterLoading component with CSS grid and keyframe animations.
  • Created CounterLoadingDemo for showcasing the loading animation.
  • Added installation instructions and usage documentation in counter-loader.mdx.
  • Defined common types in common.type.ts for better type safety.
  • Updated registry.type.ts to include component entry structure.
  • Enhanced createEntry utility to dynamically import components and their demos.

Summary by CodeRabbit

  • New Features

    • Added bundle analysis option (build with ANALYZE flag).
    • Introduced Spinner component.
    • Component previews and code examples now load dynamically with a loading state.
  • Refactor

    • Overhauled component registry to a dynamic entry system.
    • Simplified preview imports; updated Preview/ComponentPreview props.
    • Removed Copy Button component, demo, and navigation entry.
    • Renamed “counter-loading” to “counter-loader” across app and docs.
  • Documentation

    • Major Contributing guide update reflecting new registry workflow and live preview.
    • Fixed multiple docs and paths (e.g., drawCursor, playButton, sparkles, animated-list items).
  • Chores

    • Updated .env example.

- Implemented CounterLoading component with CSS grid and keyframe animations.
- Created CounterLoadingDemo for showcasing the loading animation.
- Added installation instructions and usage documentation in counter-loader.mdx.
- Defined common types in common.type.ts for better type safety.
- Updated registry.type.ts to include component entry structure.
- Enhanced createEntry utility to dynamically import components and their demos.
@vercel
Copy link

vercel bot commented Oct 10, 2025

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

Project Deployment Preview Comments Updated (UTC)
nurui Ready Ready Preview Comment Oct 12, 2025 0:54am

@coderabbitai
Copy link

coderabbitai bot commented Oct 10, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds bundle analysis support and ANALYZE flag, introduces a dynamic component registry via createEntry with asynchronous preview/code loading, removes CopyButton component and its registry/navigation entries, standardizes component export styles (default), updates Preview/CodeBlock to dynamic patterns with loading UI, renames several docs/paths, and adjusts imports.

Changes

Cohort / File(s) Summary of changes
Build & Env (Analyzer)
/.env.example, /next.config.ts, /package.json, /tsconfig.json
Added ANALYZE flag and bundle analyzer wrapper; new analyze script using cross-env; added dev deps; included src/scripts/generateMetadata.ts in TS project.
Dynamic Registry System
/src/registry/components-registry.tsx, /src/types/registry.type.ts, /src/utils/createEntry.ts, /src/app/preview/[component]/components-preview-registry.tsx
Switched to createEntry-based registry with new ComponentEntry type and as-const Index; added createEntry utility for dynamic preview/code loading; simplified dynamic imports in preview registry; renamed key counter-loading → counter-loader.
Registry Data & Navigation Cleanup
/registry.json, /registry-cli.json, /src/registry/component-navigation.tsx
Removed copy-button entries from registries and navigation; updated Counter Loader route from /counter-loading to /counter-loader.
Common Components (Preview/Code)
/src/components/common/ComponentPreview.tsx, /src/components/common/Preview.tsx, /src/components/common/FullScreenPreview.tsx, /src/components/common/CLICommandButton.tsx, /src/components/ui/code-block/CodeBlock.tsx, /src/components/nurui/spinner.tsx
ComponentPreview made client, dynamically loads code and tabs; Preview prop changed to Component and instantiates; type import path tweaks; CodeBlock now async-loads code with loading Spinner; added Spinner component.
Copy Button Removal
/src/components/nurui/copy-button.tsx, /src/components/nurui/copy-button-demo.tsx
Deleted CopyButton component and its demo.
Export Style Normalization (Default exports)
/src/components/nurui/animated-list-demo.tsx, .../animated-pricing-demo.tsx, .../creative-pricing-demo.tsx, .../following-eye-demo.tsx
Converted named exports to default exports without logic changes.
Component Renames/Path Fixes
/src/components/nurui/counter-loader-demo.tsx, .../animated-input.tsx, .../news-letter.tsx, .../marquee-testimonial-demo.tsx, /src/components/pages/Home/..., /src/components/ui/marquee/MarqueeDemo.tsx
Renamed counter-loading → counter-loader import; AnimateInput → AnimatedInput and usage; fixed Marquee import path typo marquemarquee; updated Home sections; renamed AllComponentSection → AllTechnologySection and usage.
Docs Updates
/src/content/docs/counter-loader.mdx, .../draw-cursor.mdx, .../ripple-loader.mdx, .../animated-list.mdx, .../play-button.mdx, .../video-modal.mdx, .../canvas-cursor.mdx, .../research-hero.mdx
Synced docs with new names/paths and dynamic preview/code usage; adjusted props tables and fileName references.
Layouts & App Wiring
/src/app/(docs)/docs/layout.tsx, /src/app/layout.tsx, /src/app/page.tsx, /src/context/AppContext.tsx
Type import path changes; removed commented SplashCursorDemo refs; swapped AllComponentSection for AllTechnologySection on Home; no runtime logic changes otherwise.
Misc UI Adjustment
/src/components/ui/CopyButton.tsx
Increased overlay z-index to z-[999]; whitespace edits.
Repo Docs
/README.md, /CONTRIBUTING.md
Renamed brand to Nur/ui; expanded contribution flow to dynamic registry with CLI and entry JSON details.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Registry as components-registry (Index)
  participant Factory as createEntry()
  participant Next as Next.js Runtime

  Dev->>Registry: Import { Index }
  Registry->>Factory: createEntry("name", ["otherA","otherB"], ssr?)
  Factory->>Next: dynamic(() => tryImport("name"), { ssr })
  Note over Factory,Next: preview is dynamically resolved (-demo fallback to base)
  Factory->>Factory: code(): import raw name-demo.tsx || name.tsx
  Factory->>Factory: othersCode[]: raw imports for "otherA","otherB"
  Factory-->>Registry: ComponentEntry { preview, code, othersCode, ssr }
  Registry-->>Dev: Index[name] entry
Loading
sequenceDiagram
  participant UI as ComponentPreview
  participant Reg as Index[componentName]
  participant Code as CodeBlock (lazy)
  participant Loader as Spinner

  UI->>Reg: const Demo = Reg.preview
  UI->>Reg: Reg.code() to load TSX source
  Reg-->>UI: Promise<{ default: string }>
  UI->>Code: render with sourceCode when resolved
  alt loading
    UI->>Loader: show Spinner
  else ready
    Code-->>UI: render tabs: Preview | Code
  end
Loading
sequenceDiagram
  participant Dev as CLI/Script
  participant Env as ENV ANALYZE
  participant Next as next.config.ts
  participant Analyzer as @next/bundle-analyzer

  Dev->>Env: cross-env ANALYZE=true next build
  Env-->>Next: ANALYZE=true
  Next->>Analyzer: analyzer(withMDX(config))
  Analyzer-->>Dev: Build with bundle analysis
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

I nibbled wires, flipped a switch—ANALYZE, away!
Hopped through entries, dynamic burrows all the way.
CopyButton’s gone; I tidied every lane,
Spun a Spinner, loading calm like rain.
Docs now hum the new registry tune—
Thump-thump! Ship it soon. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title only highlights adding the CounterLoading component but omits other significant changes like registry and createEntry enhancements, documentation overhauls, bundle analyzer integration, and type updates, so it does not fully summarize the main scope of this changeset. Please update the pull request title to reflect the broader scope of this changeset, including registry improvements, dynamic entry utility enhancements, documentation updates, and the bundle analyzer integration.
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 (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02bac1c and cecd592.

📒 Files selected for processing (6)
  • src/components/nurui/animated-input.tsx (2 hunks)
  • src/components/nurui/news-letter.tsx (2 hunks)
  • src/content/docs/animated-list.mdx (1 hunks)
  • src/content/docs/canvas-cursor.mdx (1 hunks)
  • src/content/docs/research-hero.mdx (1 hunks)
  • src/registry/components-registry.tsx (1 hunks)

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: 6

Caution

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

⚠️ Outside diff range comments (1)
src/content/docs/counter-loader.mdx (1)

2-2: Fix title to match filename convention.

The title remains "counter-loading" but the component has been renamed to "counter-loader" throughout the codebase (as evidenced by the fileName prop on Line 40 and the navigation update in src/registry/component-navigation.tsx).

Apply this diff:

-title: "counter-loading"
+title: "counter-loader"
🧹 Nitpick comments (17)
src/components/ui/CopyButton.tsx (1)

100-100: Verify the necessity of such a high z-index value.

The z-index was increased from z-50 (50) to z-[999] (999), which is a very high stacking value. While this ensures the menu appears above most content, it may indicate a layering strategy issue or a "z-index arms race" pattern.

Consider:

  • Whether a more moderate value (e.g., z-[100] or z-[200]) would suffice for this dropdown menu
  • Establishing a systematic z-index scale across the application to avoid arbitrary high values
  • Documenting the reason for this specific value if it's intentionally needed to override other high-z-index elements

Also note: there's a trailing space after dark:text-white which is minor cosmetic noise.

tsconfig.json (1)

37-37: LGTM: Added generateMetadata.ts to TypeScript compilation.

The inclusion of src/scripts/generateMetadata.ts ensures the script participates in TypeScript's type checking and project compilation.

Consider formatting the array entry on its own line for consistency:

-    "src/content/docs/animated-form.mdx"
-, "src/scripts/generateMetadata.ts"  ],
+    "src/content/docs/animated-form.mdx",
+    "src/scripts/generateMetadata.ts"
+  ],
registry-cli.json (1)

473-473: LGTM: Registry updated as part of copy-button removal.

The changes align with the broader PR refactor that removes the copy-button component and migrates to a dynamic registry system.

Minor: Line 473 contains trailing whitespace. Consider removing it for cleaner formatting.

src/components/nurui/following-eye-demo.tsx (1)

7-7: LGTM: Export style updated to default export.

The change to a default export aligns with the project-wide migration to support the new dynamic registry system via createEntry.

Minor: Remove the extra space between default and FollowingEyeDemo:

-export default  FollowingEyeDemo ;
+export default FollowingEyeDemo;
next.config.ts (1)

60-61: Remove commented-out code.

The commented export on line 60 should be removed as it's no longer needed and adds clutter.

Apply this diff:

-// export default withMDX(nextConfig);
 export default analyzer(withMDX(nextConfig));
src/types/registry.type.ts (2)

1-4: Consider exporting CodeEntry for external use.

The CodeEntry interface is currently internal, but consumers of the registry may need to reference it when working with ComponentEntry.othersCode. Consider exporting it unless there's a specific reason to keep it private.

If it should remain internal, this is acceptable. If external access is needed:

-interface CodeEntry  {
+export interface CodeEntry  {
   fileName: string;
   code: () => Promise<{ default: string }>;
 };

1-11: Add newline at end of file.

Missing newline at end of file. While minor, this is a common formatting convention.

 export interface ComponentEntry {
   preview: React.ComponentType;
   code: () => Promise<{ default: string }>;
   othersCode?: CodeEntry[];
   ssr?: boolean;
-};
+};
+
src/components/ui/code-block/CodeBlock.tsx (3)

38-51: Add error handling for async code loading.

The async code loading lacks error handling. If the loader fails (network issue, missing file, etc.), users will see an empty code block with no indication of what went wrong.

 const loadCode = async () => {
   if (!code && componentName && fileName) {
     const matched = Index[componentName]?.othersCode?.find(
       (otherCode) => otherCode.fileName === fileName,
     );
     const loader = matched?.code || Index[componentName]?.code;
     if (loader) {
-      const result = await loader();
-      setSourceCode(result.default);
+      try {
+        const result = await loader();
+        setSourceCode(result.default);
+      } catch (error) {
+        console.error(`Failed to load code for ${componentName}/${fileName}:`, error);
+        setSourceCode(`// Error loading component code: ${error instanceof Error ? error.message : 'Unknown error'}`);
+      }
     }
   }
 };

62-84: Consider loading state during language switch.

When switching from TypeScript to JavaScript or vice versa, the async code loading could introduce a brief delay where the old code is displayed. Consider adding a loading state to improve UX during transitions.

Example approach:

const [isLoading, setIsLoading] = useState(false);

const handleSelect = async (languageName: string) => {
  setSelectedLanguage(languageName);
  setIsOpen(false);
  setIsLoading(true);

  try {
    // ... existing logic ...
  } finally {
    setIsLoading(false);
  }
};

// In JSX:
{isLoading && <div className="loading-spinner">Loading...</div>}

77-81: Add error handling for language switch code loading.

Similar to the initial load, the language switch path lacks error handling for failed async loads.

 const loader = matched?.code || Index[componentName]?.code;
 if (loader) {
-  const result = await loader();
-  setSourceCode(result.default);
+  try {
+    const result = await loader();
+    setSourceCode(result.default);
+  } catch (error) {
+    console.error(`Failed to reload code for ${componentName}/${fileName}:`, error);
+    setSourceCode(`// Error loading component code: ${error instanceof Error ? error.message : 'Unknown error'}`);
+  }
 }
src/utils/createEntry.ts (2)

4-12: Avoid brittle fallback to the first export; fail fast if no component found

Using Object.values(mod)[0] can select the wrong thing. Prefer default (or an explicit named export), otherwise throw to surface errors early.

 const tryImport = async (name: string) => {
   try {
     const mod = await import(`@/components/nurui/${name}-demo`);
-    return mod.default || mod[name] || Object.values(mod)[0];
+    const component = mod.default || (mod as Record<string, unknown>)[name as never];
+    if (!component) throw new Error(`[createEntry] No component export found for "${name}-demo"`);
+    return component as React.ComponentType;
   } catch {
     const mod = await import(`@/components/nurui/${name}`);
-    return mod.default || mod[name] || Object.values(mod)[0];
+    const component = mod.default || (mod as Record<string, unknown>)[name as never];
+    if (!component) throw new Error(`[createEntry] No component export found for "${name}"`);
+    return component as React.ComponentType;
   }
 };

19-20: Add a lightweight loading fallback for previews

Improves UX while the preview chunk loads.

-  preview: dynamic(() => tryImport(name), { ssr }),
+  preview: dynamic(() => tryImport(name), { ssr, loading: () => null }),
CONTRIBUTING.md (2)

170-185: Fix typos and correct registry file path

Small doc fixes to reduce confusion.

- Nur/ui now uses a dynamic registry system useing the function createEntry().
+ Nur/ui now uses a dynamic registry system using the function createEntry().
 
- Open `src/registry/componentRegistry.ts` and add your entry:
+ Open `src/registry/components-registry.tsx` and add your entry:

333-335: Typo in note and example

- ## If this component is not default export then use likt this:
+ ## If this component is not a default export then use like this:
 import("@/components/nurui/shiny-button-demo").then((mod) => mod.TextButtonDemo)
src/components/common/ComponentPreview.tsx (3)

8-9: Use exported ComponentName for strong typing

After tightening Index typing, prefer the exported alias for clarity and safety.

-import { Index } from "@/registry/components-registry";
+import { Index } from "@/registry/components-registry";
+import type { ComponentName } from "@/registry/components-registry";
 
 interface ComponentPreviewProps {
-  componentName: keyof typeof Index;
+  componentName: ComponentName;
   introName?: boolean;
   exampleName?: string;
   v0ComponentName?: string;
   previewComponentName?: string;
 }

Also applies to: 15-21


10-13: Optional: add a loading fallback for the code tab

 const LazyCodeBlock = dynamic<{ code: string }>(
   () => import("../ui/code-block/CodeBlock").then((mod) => mod.CodeBlock),
-  { ssr: false },
+  { ssr: false, loading: () => <div className="text-sm text-muted-foreground">Loading code…</div> },
 );

34-44: Handle importer errors to avoid unhandled rejections

Wrap in try/catch and guard against stale updates.

   useEffect(() => {
-    const loadCode = async () => {
-      const importer = Index[componentName]?.code;
-      if (typeof importer === "function") {
-        const mod = await importer();
-        setSourceCode(mod.default || ""); // ?raw exports default string
-      }
-    };
-    loadCode();
+    let cancelled = false;
+    const loadCode = async () => {
+      try {
+        const importer = Index[componentName]?.code;
+        if (typeof importer === "function") {
+          const mod = await importer();
+          if (!cancelled) setSourceCode(mod.default || "");
+        }
+      } catch {
+        if (!cancelled) setSourceCode("");
+      }
+    };
+    loadCode();
+    return () => {
+      cancelled = true;
+    };
   }, [componentName]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ecfcb6 and b8603bc.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (35)
  • .env.example (1 hunks)
  • CONTRIBUTING.md (5 hunks)
  • next.config.ts (2 hunks)
  • package.json (4 hunks)
  • registry-cli.json (1 hunks)
  • registry.json (0 hunks)
  • src/app/(docs)/docs/layout.tsx (2 hunks)
  • src/app/layout.tsx (0 hunks)
  • src/app/preview/[component]/components-preview-registry.tsx (3 hunks)
  • src/components/common/CLICommandButton.tsx (1 hunks)
  • src/components/common/ComponentPreview.tsx (2 hunks)
  • src/components/common/FullScreenPreview.tsx (1 hunks)
  • src/components/common/Preview.tsx (2 hunks)
  • src/components/layout/components-layout/ComponentsLayout.tsx (1 hunks)
  • src/components/nurui/animated-list-demo.tsx (2 hunks)
  • src/components/nurui/animated-pricing-demo.tsx (1 hunks)
  • src/components/nurui/copy-button-demo.tsx (0 hunks)
  • src/components/nurui/copy-button.tsx (0 hunks)
  • src/components/nurui/counter-loader-demo.tsx (1 hunks)
  • src/components/nurui/creative-pricing-demo.tsx (1 hunks)
  • src/components/nurui/following-eye-demo.tsx (1 hunks)
  • src/components/nurui/ripple-loader-demo.tsx (0 hunks)
  • src/components/pages/Home/ComponentDemosSection.tsx (1 hunks)
  • src/components/pages/components/ComponentsPage.tsx (1 hunks)
  • src/components/ui/CopyButton.tsx (1 hunks)
  • src/components/ui/code-block/CodeBlock.tsx (2 hunks)
  • src/content/docs/counter-loader.mdx (3 hunks)
  • src/content/docs/draw-cursor.mdx (2 hunks)
  • src/content/docs/ripple-loader.mdx (3 hunks)
  • src/context/AppContext.tsx (1 hunks)
  • src/registry/component-navigation.tsx (1 hunks)
  • src/registry/components-registry.tsx (1 hunks)
  • src/types/registry.type.ts (1 hunks)
  • src/utils/createEntry.ts (1 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (5)
  • src/app/layout.tsx
  • registry.json
  • src/components/nurui/copy-button.tsx
  • src/components/nurui/ripple-loader-demo.tsx
  • src/components/nurui/copy-button-demo.tsx
🧰 Additional context used
🧬 Code graph analysis (4)
src/components/ui/code-block/CodeBlock.tsx (1)
src/registry/components-registry.tsx (1)
  • Index (4-127)
src/utils/createEntry.ts (1)
src/types/registry.type.ts (1)
  • ComponentEntry (6-11)
src/registry/components-registry.tsx (2)
src/types/registry.type.ts (1)
  • ComponentEntry (6-11)
src/utils/createEntry.ts (1)
  • createEntry (14-31)
src/components/common/ComponentPreview.tsx (1)
src/registry/components-registry.tsx (1)
  • Index (4-127)
🪛 dotenv-linter (3.3.0)
.env.example

[warning] 2-2: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 2-2: [UnorderedKey] The ANALYZE key should go before the NODE_ENV key

(UnorderedKey)

⏰ 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: 🛠️ Build Project
🔇 Additional comments (25)
src/components/common/CLICommandButton.tsx (1)

6-6: LGTM: Type import path updated consistently.

The import path update aligns with the project-wide refactor to consolidate common types under @/types/common.type.

src/context/AppContext.tsx (1)

2-2: LGTM: Type import path updated consistently.

The IChildren import path update aligns with the project-wide migration to @/types/common.type.

.env.example (1)

2-2: LGTM: ANALYZE flag added for bundle analysis.

The new ANALYZE environment variable supports the Next.js bundle analyzer integration introduced in this PR.

Note: Static analysis tools suggest adding a blank line at the end of the file and ordering keys alphabetically (ANALYZE before NODE_ENV). While these are minor formatting suggestions, consider addressing them for consistency.

src/components/common/FullScreenPreview.tsx (1)

7-7: LGTM: Type import path updated consistently.

The import path update is part of the project-wide consolidation of common types under @/types/common.type.

src/components/nurui/animated-pricing-demo.tsx (1)

59-59: LGTM: Export style updated to default export.

The migration to a default export is consistent with other demo components and supports the new dynamic registry system introduced in this PR.

src/components/nurui/creative-pricing-demo.tsx (1)

56-56: LGTM! Export change aligns with registry refactor.

The switch from named export to default export is consistent with the broader PR objective to support dynamic, entry-based component loading.

next.config.ts (1)

3-9: LGTM! Bundle analyzer integration is correct.

The integration of @next/bundle-analyzer with environment-based enablement is properly implemented. The isAnalyzerEnabled flag provides good control over when analysis runs.

package.json (3)

10-10: LGTM! Analyze script properly integrates with bundle analyzer.

The new "analyze" script correctly sets the ANALYZE environment variable to enable bundle analysis during builds, aligning with the configuration in next.config.ts.


66-66: LGTM! DevDependencies align with new features.

  • @next/bundle-analyzer@^15.5.4 matches the Next.js version and enables bundle analysis.
  • ts-node@^10.9.2 is appropriate for executing TypeScript scripts during the build process.

Also applies to: 82-82


29-29: Ignore outdated version check
[email protected] exists in the npm registry; no change required.

Likely an incorrect or invalid review comment.

src/components/pages/Home/ComponentDemosSection.tsx (1)

15-15: LGTM! Import change aligns with component export update.

The switch to a default import is consistent with the component's new default export pattern and the broader registry refactor.

src/components/layout/components-layout/ComponentsLayout.tsx (1)

4-4: LGTM! Type import consolidation.

The import path change to @/types/common.type is part of the type consolidation refactor across the codebase. The behavior remains unchanged.

src/components/nurui/counter-loader-demo.tsx (1)

2-2: LGTM! Import path updated to match component rename.

The import path change from "./counter-loading" to "./counter-loader" aligns with the component renaming mentioned in the PR objectives.

However, note that the imported component is still named CounterLoading (line 2) while the file is now counter-loader. Consider whether the component should be renamed to CounterLoader for consistency:

-import CounterLoading from "./counter-loader";
+import CounterLoader from "./counter-loader";
 
 const CounterLoadingDemo = () => {
   return (
     <div className="flex items-center justify-center min-h-[30rem]">
-      <CounterLoading />
+      <CounterLoader />
     </div>
   );
 };
src/components/pages/components/ComponentsPage.tsx (1)

18-18: LGTM! Import change aligns with component export update.

The switch to a default import is consistent with the broader registry refactor and matches the component's new export pattern.

src/app/(docs)/docs/layout.tsx (2)

3-3: LGTM! Type import consolidation.

The import path change to @/types/common.type is consistent with the type consolidation refactor across the codebase.


25-25: LGTM! Formatting change preserves behavior.

The JSX formatting change from multiline to single-line is cosmetic and preserves the component's functionality.

src/content/docs/draw-cursor.mdx (1)

6-6: LGTM! Naming convention update is consistent.

The componentName updates from kebab-case to camelCase align with the new dynamic registry pattern observed across the PR. The separation between componentName (camelCase) and fileName (kebab-case) is appropriate for the registry lookup system.

Also applies to: 52-52

src/content/docs/counter-loader.mdx (1)

6-6: Component reference updates look correct.

The componentName and fileName props correctly reflect the new camelCase/kebab-case naming conventions used by the dynamic registry system.

Also applies to: 40-40

src/content/docs/ripple-loader.mdx (1)

6-6: LGTM! Consistent naming convention.

The componentName updates follow the same camelCase pattern used across other loader components in this PR.

Also applies to: 29-29

src/registry/component-navigation.tsx (1)

112-112: LGTM! Navigation path updated correctly.

The href change from /counter-loading to /counter-loader correctly aligns with the component rename observed throughout the PR.

src/components/common/Preview.tsx (1)

6-6: LGTM! Type safety improvement with component instantiation.

The change from React.ReactNode to React.ComponentType improves type safety by ensuring only component constructors are passed, not pre-rendered elements. This aligns with the dynamic component loading pattern introduced across the PR.

The capitalized prop name Component correctly follows React conventions for component references.

Also applies to: 10-10, 24-24

src/types/registry.type.ts (1)

6-11: Well-structured type definitions.

The ComponentEntry interface provides a clean contract for the dynamic registry system with clear separation of concerns:

  • preview: Component constructor for rendering
  • code: Async loader for main component source
  • othersCode: Optional additional code variants
  • ssr: Optional SSR flag
src/components/nurui/animated-list-demo.tsx (1)

65-65: LGTM! Export pattern aligns with dynamic imports.

The change from named to default export aligns with the dynamic component loading pattern used throughout the registry system. According to the AI summary, consuming files have been updated to use the default import.

Also applies to: 84-84

src/components/ui/code-block/CodeBlock.tsx (1)

32-32: Async code loading implementation is solid.

The transition to async code loading via loader functions correctly integrates with the new dynamic registry system. The fallback to empty string and the dependency array in useEffect are appropriate.

Also applies to: 38-51

src/app/preview/[component]/components-preview-registry.tsx (1)

28-30: Dynamic imports verified: all referenced demo modules export default components, no changes required.

@@ -1 +1,2 @@
NODE_ENV=developmnet
NODE_ENV=developmnet
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the typo in NODE_ENV value.

The value "developmnet" contains a typo and should be "development". This error will propagate to developers who copy this example file.

Apply this diff:

-NODE_ENV=developmnet
+NODE_ENV=development
📝 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
NODE_ENV=developmnet
NODE_ENV=development
🤖 Prompt for AI Agents
In .env.example around lines 1 to 1, the NODE_ENV value has a typo
("developmnet"); update the value to the correct string "development" so example
consumers get the correct environment name.

Comment on lines +140 to 146
// loaders
"ripple-loader": {
component: dynamic(() => import("@/components/nurui/ripple-loader-demo")),
},
"counter-loading": {
component: dynamic(() => import("@/components/nurui/counter-loading-demo")),
"counter-loader": {
component: dynamic(() => import("@/components/nurui/counter-loader-demo")),
},
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

New loader entries look good; confirm slug consistency

The new "counter-loader" preview entry aligns with the rename. LGTM. Please also ensure no stale "counter-loading" references remain in routes/docs.


🏁 Script executed:

#!/bin/bash
# Find any lingering "counter-loading" references
rg -nP 'counter-loading'

Length of output: 1359


Update stale “counter-loading” references in registry and docs

  • Change all occurrences of "counter-loading" to "counter-loader" (names, slugs, titles)
  • Update file paths in registry.json, registry-cli.json, public/r/*.json, and src/content/docs/counter-loader.mdx to use counter-loader-demo.tsx and counter-loader.tsx
🤖 Prompt for AI Agents
In src/app/preview/[component]/components-preview-registry.tsx around lines 140
to 146, the registry still references the old "counter-loading" naming and
possibly stale file paths; update the key/name/slug/title occurrences from
"counter-loading" to "counter-loader" and ensure the dynamic import paths point
to the new files (use "@/components/nurui/counter-loader-demo" for the demo
component and "@/components/nurui/counter-loader" where appropriate). Also apply
the same rename across registry.json and registry-cli.json, every
public/r/*.json entry, and update src/content/docs/counter-loader.mdx to
reference counter-loader-demo.tsx and counter-loader.tsx filenames and use the
new slug/title "counter-loader".


<Step>Copy and paste the following code into your project.</Step>

`components/nurui/counter-loading.tsx`
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

Update file path to match renamed component.

The path comment shows counter-loading.tsx but should reflect the new naming convention counter-loader.tsx to match the fileName prop on Line 40.

Apply this diff:

-`components/nurui/counter-loading.tsx`
+`components/nurui/counter-loader.tsx`
📝 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
`components/nurui/counter-loading.tsx`
`components/nurui/counter-loader.tsx`
🤖 Prompt for AI Agents
In src/content/docs/counter-loader.mdx around line 38, update the inline path
comment which currently reads `components/nurui/counter-loading.tsx` to the
renamed component path `components/nurui/counter-loader.tsx` so it matches the
fileName prop on line 40; simply replace the old filename in that comment with
the new one.

import { ComponentEntry } from "@/types/registry.type";
import { createEntry } from "@/utils/createEntry";

export const Index: Record<string, ComponentEntry> = {
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

Preserve key literal union for strong typing (use satisfies instead of Record annotation)

The explicit Record<string, ComponentEntry> annotation widens keys to string, so keyof typeof Index becomes string. Switch to satisfies to keep the key union while validating value shape.

-export const Index: Record<string, ComponentEntry> = {
+export const Index = {
   // ...entries...
-} as const;
+} as const satisfies Record<string, ComponentEntry>;
 
-export type ComponentName = keyof typeof Index;
+export type ComponentName = keyof typeof Index;

Also applies to: 127-129

🤖 Prompt for AI Agents
In src/registry/components-registry.tsx around line 4 (and also at lines
127-129), remove the explicit Record<string, ComponentEntry> type annotation
which widens the key type, and instead let the object keep its literal key types
and validate its shape using TypeScript's satisfies operator; i.e. declare the
object without the Record annotation (optionally add as const for literal
preservation) and append "satisfies Record<string, ComponentEntry>" to the
object expression so keyof typeof Index retains the union of keys while values
are type-checked.

{ fileName: "frame", code: FrameCode },
],
},
futureNavbar: createEntry("futrue-navbar", ["future-button", "frame"]),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Typo breaks import: "futrue-navbar" → "future-navbar"
This will fail dynamic import at runtime.

-  futureNavbar: createEntry("futrue-navbar", ["future-button", "frame"]),
+  futureNavbar: createEntry("future-navbar", ["future-button", "frame"]),
📝 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
futureNavbar: createEntry("futrue-navbar", ["future-button", "frame"]),
futureNavbar: createEntry("future-navbar", ["future-button", "frame"]),
🤖 Prompt for AI Agents
In src/registry/components-registry.tsx around line 28, the component entry key
has a typo "futrue-navbar" which will break dynamic imports; change it to
"future-navbar" (update the string passed to createEntry) so the registry key
matches the expected import name and dependent dynamic imports resolve
correctly.

Comment on lines +109 to +110
neuralBackground: createEntry("nural-background", ["neural-background"]),

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Typo breaks import: "nural-background" → "neural-background"
Name and others mismatch; current value won’t resolve.

-  neuralBackground: createEntry("nural-background", ["neural-background"]),
+  neuralBackground: createEntry("neural-background", ["neural-background"]),
📝 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
neuralBackground: createEntry("nural-background", ["neural-background"]),
neuralBackground: createEntry("neural-background", ["neural-background"]),
🤖 Prompt for AI Agents
In src/registry/components-registry.tsx around lines 109 to 110, the entry
key/value has a typo "nural-background" which prevents imports from resolving;
change the string to "neural-background" and ensure the slug array element(s)
also use "neural-background" so the component name and aliases match the actual
import path.

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

Caution

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

⚠️ Outside diff range comments (1)
src/components/ui/code-block/CodeBlock.tsx (1)

76-89: Set loading state when reloading TypeScript code.

When the user switches back to TypeScript, code is reloaded asynchronously (lines 83-87) but loading is not set to true, unlike the initial load. This creates an inconsistent UX where the spinner appears on mount but not on language toggle.

Apply this diff to show the spinner during reload:

     } else {
       // Reload original TS code
       if (code) {
         setSourceCode(code);
       } else if (componentName && fileName) {
+        setLoading(true);
+        try {
           const matched = Index[componentName]?.othersCode?.find(
             (otherCode) => otherCode.fileName === fileName,
           );
           const loader = matched?.code || Index[componentName]?.code;
           if (loader) {
             const result = await loader();
             setSourceCode(result.default);
           }
+        } catch (error) {
+          console.error("Failed to reload code:", error);
+          setSourceCode(`// Error reloading code for ${componentName}/${fileName}`);
+        } finally {
+          setLoading(false);
+        }
       }
     }
♻️ Duplicate comments (3)
src/registry/components-registry.tsx (3)

4-130: Keep literal key union by switching to satisfies.
Annotating Index as Record<string, ComponentEntry> widens keyof typeof Index to string, so ComponentName loses the intended literal union. Drop the explicit Record annotation and use satisfies instead to retain strong typing while still validating the entry shape.

-export const Index: Record<string, ComponentEntry> = {
+export const Index = {
   // …
-} as const;
+} as const satisfies Record<string, ComponentEntry>;
 
 export type ComponentName = keyof typeof Index;

28-28: Fix typo in dynamic import slug.
createEntry("futrue-navbar", …) will try to import @/components/nurui/futrue-navbar, which does not exist, so the preview/code loaders throw at runtime. Please correct the slug to future-navbar.

-  futureNavbar: createEntry("futrue-navbar", ["future-button", "frame"]),
+  futureNavbar: createEntry("future-navbar", ["future-button", "frame"]),

112-113: Correct “nural” → “neural” slug.
The registry currently points at @/components/nurui/nural-background, which misses the “e” and fails to load. Align both occurrences with the actual neural-background filename so dynamic imports resolve.

-  neuralBackground: createEntry("nural-background", ["neural-background"]),
+  neuralBackground: createEntry("neural-background", ["neural-background"]),
🧹 Nitpick comments (1)
src/components/nurui/animated-Input.tsx (1)

61-61: Consider aligning filename with component name convention.

The export correctly reflects the renamed component. However, the filename animated-Input.tsx uses an inconsistent mixed-case convention. Consider renaming the file to either:

  • AnimatedInput.tsx (PascalCase, matching the component name)
  • animated-input.tsx (kebab-case, fully lowercase)

This would improve consistency and make the file easier to locate.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9142fc1 and 02bac1c.

⛔ Files ignored due to path filters (1)
  • nurui-logo.png is excluded by !**/*.png
📒 Files selected for processing (17)
  • README.md (1 hunks)
  • src/app/page.tsx (2 hunks)
  • src/components/nurui/animated-Input.tsx (2 hunks)
  • src/components/nurui/marquee-testimonial-demo.tsx (1 hunks)
  • src/components/nurui/news-letter.tsx (2 hunks)
  • src/components/nurui/spinner.tsx (1 hunks)
  • src/components/pages/Home/AllTechnologySection.tsx (1 hunks)
  • src/components/pages/Home/ButtonsMarquee.tsx (1 hunks)
  • src/components/pages/Home/ComponentDemosSection.tsx (1 hunks)
  • src/components/pages/Home/HeroSection.tsx (1 hunks)
  • src/components/pages/Home/MarqueeTestimonialSection.tsx (2 hunks)
  • src/components/pages/components/ComponentsPage.tsx (3 hunks)
  • src/components/ui/code-block/CodeBlock.tsx (3 hunks)
  • src/components/ui/marquee/MarqueeDemo.tsx (1 hunks)
  • src/content/docs/animated-list.mdx (1 hunks)
  • src/registry/components-registry.tsx (1 hunks)
  • src/utils/createEntry.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/content/docs/animated-list.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/pages/Home/ComponentDemosSection.tsx
  • src/utils/createEntry.ts
🧰 Additional context used
🧬 Code graph analysis (5)
src/components/nurui/spinner.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
src/components/pages/Home/MarqueeTestimonialSection.tsx (1)
src/data/testimonial.ts (1)
  • testimonialData (1-248)
src/registry/components-registry.tsx (2)
src/types/registry.type.ts (1)
  • ComponentEntry (6-11)
src/utils/createEntry.ts (1)
  • createEntry (14-37)
src/app/page.tsx (1)
src/components/pages/Home/AllTechnologySection.tsx (1)
  • AllTechnologySection (18-183)
src/components/ui/code-block/CodeBlock.tsx (2)
src/registry/components-registry.tsx (1)
  • Index (4-130)
src/components/nurui/spinner.tsx (1)
  • Spinner (15-15)
⏰ 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: 🛠️ Build Project
🔇 Additional comments (12)
src/components/nurui/news-letter.tsx (2)

1-1: LGTM! Import updated to match renamed component.

The import correctly references the renamed AnimatedInput component. The change from an alias import to a relative path is consistent with the component rename.


12-12: LGTM! JSX usage updated correctly.

The component usage is properly updated to AnimatedInput, maintaining consistency with the import and the renamed component.

src/components/nurui/animated-Input.tsx (1)

12-17: LGTM! Component rename is an improvement.

The rename from AnimateInput to AnimatedInput is more grammatically correct (using the adjective form). The component definition and props remain unchanged, making this a safe refactor.

src/components/pages/Home/AllTechnologySection.tsx (1)

18-18: LGTM! Clear improvement in component naming.

The rename from AllComponentSection to AllTechnologySection better reflects the component's purpose—displaying technology stack icons rather than component demos.

src/app/page.tsx (2)

2-2: LGTM! Import correctly updated.

The import statement properly reflects the component rename.


11-11: All references to AllComponentSection have been removed
No matches found in any files.

src/components/pages/Home/MarqueeTestimonialSection.tsx (2)

1-1: LGTM! Import path corrected.

The import path has been fixed from the incorrect "marque" to "marquee", aligning with similar corrections throughout the codebase.


32-38: LGTM! Formatting improved.

The multiline formatting improves readability while maintaining the same slice operation behavior.

src/components/nurui/spinner.tsx (1)

1-15: LGTM! Well-structured loading indicator.

The Spinner component is properly implemented with:

  • Appropriate accessibility attributes (role="status", aria-label="Loading")
  • Type-safe SVG props spreading
  • Clean composition with lucide-react's LoaderIcon
src/components/pages/components/ComponentsPage.tsx (2)

9-9: LGTM! Import path corrected.

The Marquee import path has been fixed to use the correct "marquee" module path.


18-18: LGTM! Import updated to match export change.

The import has been correctly updated to use a default import, aligning with the AnimatedListDemo component now being exported as default.

src/components/ui/code-block/CodeBlock.tsx (1)

92-98: LGTM! Loading UI implemented correctly.

The loading state with Spinner provides clear feedback during async code loading, improving the user experience.

Comment on lines 39 to 58
useEffect(() => {
if (!code && componentName && fileName) {
const matched = Index[componentName]?.othersCode?.find(
(otherCode) => otherCode.fileName === fileName,
);
const content = matched?.code || Index[componentName]?.code || "";
setSourceCode(content);
}
const loadCode = async () => {
if (!code && componentName && fileName) {
setLoading(true);
try {
const matched = Index[componentName]?.othersCode?.find(
(otherCode) => otherCode.fileName === fileName,
);
const loader = matched?.code || Index[componentName]?.code;
if (loader) {
const result = await loader();
setSourceCode(result.default);
}
} finally {
setLoading(false);
}
}
};
loadCode();
}, [code, componentName, fileName]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add cleanup and error handling to prevent stale updates and improve UX.

The async code loading lacks two important safeguards:

  1. Race condition risk: If componentName or fileName changes while loading is in progress, stale state updates may occur.
  2. Missing error handling: If the loader fails, the user sees neither the code nor an error message.

Apply this diff to add cleanup and error handling:

 useEffect(() => {
+  let cancelled = false;
   const loadCode = async () => {
     if (!code && componentName && fileName) {
       setLoading(true);
       try {
         const matched = Index[componentName]?.othersCode?.find(
           (otherCode) => otherCode.fileName === fileName,
         );
         const loader = matched?.code || Index[componentName]?.code;
         if (loader) {
           const result = await loader();
+          if (!cancelled) {
             setSourceCode(result.default);
+          }
         }
+      } catch (error) {
+        if (!cancelled) {
+          console.error("Failed to load code:", error);
+          setSourceCode(`// Error loading code for ${componentName}/${fileName}`);
+        }
       } finally {
-        setLoading(false);
+        if (!cancelled) {
+          setLoading(false);
+        }
       }
     }
   };
   loadCode();
+  return () => {
+    cancelled = true;
+  };
 }, [code, componentName, fileName]);
📝 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
useEffect(() => {
if (!code && componentName && fileName) {
const matched = Index[componentName]?.othersCode?.find(
(otherCode) => otherCode.fileName === fileName,
);
const content = matched?.code || Index[componentName]?.code || "";
setSourceCode(content);
}
const loadCode = async () => {
if (!code && componentName && fileName) {
setLoading(true);
try {
const matched = Index[componentName]?.othersCode?.find(
(otherCode) => otherCode.fileName === fileName,
);
const loader = matched?.code || Index[componentName]?.code;
if (loader) {
const result = await loader();
setSourceCode(result.default);
}
} finally {
setLoading(false);
}
}
};
loadCode();
}, [code, componentName, fileName]);
useEffect(() => {
let cancelled = false;
const loadCode = async () => {
if (!code && componentName && fileName) {
setLoading(true);
try {
const matched = Index[componentName]?.othersCode?.find(
(otherCode) => otherCode.fileName === fileName,
);
const loader = matched?.code || Index[componentName]?.code;
if (loader) {
const result = await loader();
if (!cancelled) {
setSourceCode(result.default);
}
}
} catch (error) {
if (!cancelled) {
console.error("Failed to load code:", error);
setSourceCode(`// Error loading code for ${componentName}/${fileName}`);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
};
loadCode();
return () => {
cancelled = true;
};
}, [code, componentName, fileName]);
🤖 Prompt for AI Agents
In src/components/ui/code-block/CodeBlock.tsx around lines 39 to 58, the async
loader lacks cancellation and error handling which can cause stale state updates
and silent failures; wrap the async work with a mounted/aborted flag (or
AbortController) captured by the effect to ignore results if
componentName/fileName changes or the component unmounts, add a try/catch around
the await to capture loader errors and set an error state (or setSourceCode to
an error message) so the UI can show feedback, and ensure loading is always
cleared in finally only if the effect is still current (check the
mounted/aborted flag before calling setLoading/setSourceCode/setError).

@afsar-dev afsar-dev merged commit 4fc0250 into main Oct 12, 2025
3 of 5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Nov 25, 2025
Merged
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.

2 participants