Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Aug 13, 2025

created a @workspace/ui package - shared by dashboard and playground. for now it only has button component for testing


PR-Codex overview

This PR focuses on restructuring the codebase by introducing a new @workspace/ui package, which centralizes UI components and styles. It replaces direct imports and configurations across various applications, enhancing maintainability and consistency.

Detailed summary

  • Introduced @workspace/ui package for shared components and styles.
  • Replaced CSS imports with @workspace/ui/global.css in multiple apps.
  • Updated postcss.config files to use @workspace/ui/postcss.config.
  • Refactored button components to use centralized Button from @workspace/ui.
  • Adjusted Tailwind CSS configurations to extend from @workspace/ui/tailwind.config.
  • Removed redundant global styles and configurations from individual apps.
  • Updated TypeScript configurations to align with the new structure.
  • Added type exports for improved type safety in components.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added a shared UI package and centralized Button component used across apps.
  • Style

    • Apps now load shared global styles from the UI package; many local global CSS files were simplified or removed.
  • Bug Fixes

    • AI chat header now safely falls back when the client ID is missing.
  • Refactor

    • Replaced local UI implementations with shared re-exports and composed Tailwind configs.
  • Chores

    • Added workspace UI dependency, delegated PostCSS to the UI package, enabled Next.js transpilation for the UI package, and updated lint/scan ignore lists.

@vercel vercel bot temporarily deployed to Preview – wallet-ui August 13, 2025 18:06 Inactive
@vercel
Copy link

vercel bot commented Aug 13, 2025

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

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Aug 16, 2025 1:06pm
nebula Ready Ready Preview Comment Aug 16, 2025 1:06pm
thirdweb_playground Ready Ready Preview Comment Aug 16, 2025 1:06pm
thirdweb-www Ready Ready Preview Comment Aug 16, 2025 1:06pm
wallet-ui Ready Ready Preview Comment Aug 16, 2025 1:06pm

@vercel vercel bot temporarily deployed to Preview – docs-v2 August 13, 2025 18:06 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 13, 2025 18:06 Inactive
@changeset-bot
Copy link

changeset-bot bot commented Aug 13, 2025

⚠️ No Changeset found

Latest commit: 92896dd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added Dashboard Involves changes to the Dashboard. Playground Changes involving the Playground codebase. packages labels Aug 13, 2025
@MananTank MananTank marked this pull request as ready for review August 13, 2025 18:06
@MananTank MananTank requested review from a team as code owners August 13, 2025 18:06
Copy link
Member Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new shared UI workspace package (@workspace/ui) with components, styles, and build configs; apps adopt it via workspace deps and Next.js transpilePackages. Local Button implementations, Tailwind/PostCSS and many global CSS files are replaced by re-exports or wrappers; some thirdweb type imports/re-exports updated.

Changes

Cohort / File(s) Summary of changes
New shared UI package
packages/ui/package.json, packages/ui/tsconfig.json, packages/ui/tailwind.config.ts, packages/ui/postcss.config.mjs, packages/ui/src/global.css, packages/ui/src/lib/utils.ts, packages/ui/src/components/button.tsx
Adds @workspace/ui package: exports map, TS config, typed Tailwind/PostCSS configs, global.css, cn utility, and a polymorphic Button component with variants.
App manifests — add dependency
apps/dashboard/package.json, apps/playground-web/package.json, apps/portal/package.json
Adds @workspace/ui as a workspace dependency to the listed apps.
Button component re-exports in apps
apps/dashboard/src/@/components/ui/button.tsx, apps/playground-web/src/components/ui/button.tsx, apps/portal/src/components/ui/button.tsx
Remove local Button implementations; add "use client" and re-export Button, buttonVariants, and ButtonProps from @workspace/ui/components/button.
Tailwind / PostCSS delegation and wrappers
apps/dashboard/tailwind.config.ts, apps/portal/tailwind.config.ts, apps/playground-web/tailwind.config.ts, apps/dashboard/postcss.config.js (removed), apps/dashboard/postcss.config.mjs, apps/playground-web/postcss.config.js (removed), apps/playground-web/postcss.config.mjs, packages/ui/postcss.config.mjs
Replace or wrap app Tailwind/PostCSS configs to reuse UI package config; convert to typed ES module configs and add .mjs re-exports; remove old CommonJS postcss.config.js files.
Global CSS switched / removed / trimmed
apps/dashboard/src/app/(app)/layout.tsx, apps/dashboard/src/app/bridge/layout.tsx, apps/dashboard/src/app/login/layout.tsx, apps/dashboard/src/app/pay/layout.tsx, apps/playground-web/src/app/layout.tsx, apps/playground-web/src/app/globals.css (removed), apps/portal/src/app/globals.css (trimmed), apps/portal/src/app/layout.tsx, packages/ui/src/global.css
Apps now import @workspace/ui/global.css (dashboard/portal/playground); playground globals removed; portal globals trimmed; UI package provides central global.css.
Next.js transpilePackages & webpack cleanup
apps/dashboard/next.config.ts, apps/playground-web/next.config.mjs, apps/portal/next.config.mjs, apps/wallet-ui/next.config.mjs
Add transpilePackages: ["@workspace/ui"] to Next configs where applicable; remove custom webpack externals hooks in several apps.
Thirdweb type re-exports & import path updates
packages/thirdweb/src/exports/utils.ts, packages/thirdweb/src/exports/extensions/marketplace.ts, multiple app files (various paths)
Add type-only re-exports (ClaimConditionInput, ClaimConditionsInput, OverrideEntry, ListingStatus) and update several type-only import paths to consolidated thirdweb entry points; small type simplifications.
Playground AI types and chat changes
apps/playground-web/src/app/ai/api/chat.ts, apps/playground-web/src/app/ai/api/types.ts, apps/playground-web/src/app/ai/components/ChatPageContent.tsx
x-client-id header uses safe fallback; removed NebulaSessionHistoryMessage type and related parse helper; minor prop cleanup in chat components.
Tooling / TS / knip edits
apps/dashboard/tsconfig.json, apps/dashboard/knip.json, apps/playground-web/knip.json, packages/ui/tsconfig.json
Adjust TS compiler options (module/target/moduleResolution/moduleDetection); update knip ignoreDependencies to include @workspace/ui and related packages; add UI package tsconfig.
Misc config cleanup
apps/dashboard/postcss.config.mjs, apps/playground-web/postcss.config.mjs, apps/wallet-ui/next.config.mjs, apps/portal/next.config.mjs
Add .mjs PostCSS re-exports delegating to @workspace/ui/postcss.config; remove webpack externals functions from Next configs where present.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant App as App (dashboard/playground/portal)
participant Next as Next.js build
participant UI as @workspace/ui
participant Types as thirdweb (types)

App->>UI: import Button, buttonVariants, ButtonProps, global.css, tailwind/postcss configs
Next->>UI: transpile @workspace/ui during build
App->>Types: consume re-exported or updated thirdweb types
UI-->>App: provide shared components, styles, and configs

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 08-13-create_shared_ui_library

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@MananTank MananTank changed the title Create shared UI library [test] Create shared UI library Aug 13, 2025
@codecov
Copy link

codecov bot commented Aug 13, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.54%. Comparing base (a08b62b) to head (92896dd).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7855   +/-   ##
=======================================
  Coverage   56.54%   56.54%           
=======================================
  Files         904      904           
  Lines       58586    58586           
  Branches     4140     4140           
=======================================
  Hits        33126    33126           
  Misses      25354    25354           
  Partials      106      106           
Flag Coverage Δ *Carryforward flag
packages 56.54% <ø> (ø) Carriedforward from a08b62b

*This pull request uses carry forward flags. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 13, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.06 KB (0%) 1.3 s (0%) 246 ms (+88.86% 🔺) 1.6 s
thirdweb (cjs) 357.05 KB (0%) 7.2 s (0%) 897 ms (+1.33% 🔺) 8.1 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 73 ms (+1098.52% 🔺) 188 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 46 ms (+1435.6% 🔺) 56 ms
thirdweb/react (minimal + tree-shaking) 19.15 KB (0%) 383 ms (0%) 84 ms (+297.49% 🔺) 467 ms

Copy link
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: 4

🔭 Outside diff range comments (2)
apps/dashboard/package.json (1)

28-32: Fix dependency order to unblock CI (alphabetical ordering).

CI is failing with "dependencies should be ordered alphabetically." Move "@workspace/ui" after the "@vercel/*" entries.

Apply this diff:

-    "@workspace/ui": "workspace:*",
     "@thirdweb-dev/vault-sdk": "workspace:*",
     "@vercel/functions": "2.2.2",
     "@vercel/og": "^0.6.8",
+    "@workspace/ui": "workspace:*",
     "abitype": "1.0.8",
apps/playground-web/package.json (1)

17-21: Fix dependency order to satisfy CI (alphabetical ordering).

Move "@workspace/ui" into the block of scoped packages, right after "@tanstack/react-query".

Apply this diff:

     "@tanstack/react-query": "5.81.5",
+    "@workspace/ui": "workspace:*",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
     "date-fns": "4.1.0",
@@
-    "@workspace/ui": "workspace:*",
     "use-debounce": "^10.0.5",

Also applies to: 40-43

♻️ Duplicate comments (1)
packages/ui/src/components/button.tsx (1)

21-33: Variant parity: font weight and “upsell” styling diverge from playground-web (confirm intent or restore)

If this design change is intentional across apps, document it. If parity is desired, restore the previous classes (including font-semibold on several variants and the gradient for upsell).

Example diff:

       variant: {
         default: "bg-foreground text-background hover:bg-foreground/90",
         destructive:
-          "bg-destructive hover:bg-destructive/90 text-destructive-foreground ",
+          "bg-destructive hover:bg-destructive/90 text-destructive-foreground font-semibold",
         ghost: "hover:bg-accent hover:text-accent-foreground",
-        link: "underline-offset-4 hover:underline",
+        link: "underline-offset-4 hover:underline font-semibold",
         outline:
-          "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
+          "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground font-semibold",
-        primary: "bg-primary hover:bg-primary/90 text-primary-foreground ",
+        primary: "bg-primary hover:bg-primary/90 text-primary-foreground font-semibold",
-        secondary:
-          "bg-secondary hover:bg-secondary/80 text-secondary-foreground ",
+        secondary:
+          "bg-secondary hover:bg-secondary/80 text-secondary-foreground font-semibold",
         upsell:
-          "bg-green-600 text-white hover:bg-green-700 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
+          "bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:from-purple-600 hover:to-pink-600 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
       },
🧹 Nitpick comments (7)
packages/ui/tsconfig.json (1)

3-26: Tighten tsconfig for a library: fix lib target, drop Next plugin, and disallow JS.

  • Use a lib that matches your target (ES2020 or ESNext) instead of "es6".
  • This package isn’t a Next app; remove the "next" TS plugin to avoid unnecessary coupling.
  • Prefer "allowJs": false to keep the UI package source strictly typed.

Apply:

   "compilerOptions": {
     "target": "ES2020",
-    "lib": ["dom", "dom.iterable", "es6"],
-    "allowJs": true,
+    "lib": ["dom", "dom.iterable", "ES2020"],
+    "allowJs": false,
     "skipLibCheck": true,
     "strict": true,
     "forceConsistentCasingInFileNames": true,
     "noEmit": true,
     "esModuleInterop": true,
     "module": "esnext",
     "moduleResolution": "bundler",
     "resolveJsonModule": true,
     "isolatedModules": true,
     "jsx": "preserve",
     "incremental": true,
-    "plugins": [
-      {
-        "name": "next"
-      }
-    ],
     "baseUrl": ".",
     "paths": {
       "@/*": ["./src/*"]
     }
   },

Optionally, add a dedicated build config to emit type declarations without changing this tsconfig:

// packages/ui/tsconfig.build.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noEmit": false,
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "dist/types"
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}

Then wire it into your build tooling as needed.

packages/ui/src/lib/utils.ts (1)

4-6: Add an explicit return type and spread inputs into clsx.

Keeps with explicit typing guidelines and aligns with common clsx usage.

-export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs));
+export function cn(...inputs: ClassValue[]): string {
+  return twMerge(clsx(...inputs));
 }
packages/ui/package.json (1)

4-6: Mark package as side-effect free for better tree-shaking.

The UI package should be tree-shakeable. Declare sideEffects: false.

Apply this diff:

   "private": true,
+  "sideEffects": false,
   "main": "./src/index.ts",
packages/ui/src/components/button.tsx (4)

38-42: Prefer a type alias for ButtonProps (per repo guidelines)

Switching to a type alias aligns with the project’s TypeScript conventions.

-export interface ButtonProps
-  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
-    VariantProps<typeof buttonVariants> {
-  asChild?: boolean;
-}
+export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
+  VariantProps<typeof buttonVariants> & {
+    asChild?: boolean;
+  };

15-19: Minor: remove redundant rounded-md from size variants

rounded-md is already in the base classes (Line 7). Avoid duplication in lg and sm.

         lg: "h-11 rounded-md px-8",
-        sm: "h-9 rounded-md px-3",
+        sm: "h-9 px-3",

Optionally drop rounded-md from lg too if relying solely on the base class:

-        lg: "h-11 rounded-md px-8",
+        lg: "h-11 px-8",

25-25: Link variant lacks explicit color; consider text-primary for consistency

Without a color token, links rely on inherited text color and can blend in.

-        link: "underline-offset-4 hover:underline",
+        link: "text-primary underline-offset-4 hover:underline",

66-77: Accessibility: consider making non-button disabled elements unfocusable/inert

For asChild cases (e.g., ), adding tabIndex={-1} and preventing default onClick when disabled improves a11y and UX.

Example (apply alongside the earlier disabled-prop change):

-      <Comp
-        aria-disabled={disabled ? true : undefined}
+      <Comp
+        aria-disabled={disabled ? true : undefined}
+        {...(!("type" in (btnOnlyProps ?? {})) && disabled
+          ? { tabIndex: -1, onClick: (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); } }
+          : undefined)}
         className={cn(
           buttonVariants({ size, variant }),
           disabledClass,
           className,
         )}
-        disabled={disabled}
         ref={ref}
         {...props}
         {...btnOnlyProps}
       />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3b2f8f and 5cc22af.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/tailwind.config.js (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/index.ts (1 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • apps/dashboard/package.json
  • packages/ui/src/index.ts
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/package.json
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/**/index.ts : Group related components in their own folder and expose a single barrel `index.ts` where necessary.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`

Applied to files:

  • packages/ui/src/index.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • packages/ui/src/index.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
🪛 GitHub Actions: CI
apps/dashboard/package.json

[error] 1-1: dependencies should be ordered alphabetically. unordered-dependencies

apps/playground-web/package.json

[error] 1-1: dependencies should be ordered alphabetically. unordered-dependencies

🔇 Additional comments (8)
apps/playground-web/tailwind.config.ts (1)

5-5: Including the UI package in Tailwind content is correct.

This ensures classes used inside the shared UI components are picked up during compilation for playground-web.

apps/dashboard/tailwind.config.js (1)

5-5: Good add: scanning the shared UI package for Tailwind classes.

This ensures dashboard picks up classes used by the shared components.

packages/ui/src/index.ts (1)

1-6: Public API surface looks clean and minimal.

Type-only export for ButtonProps, named exports for Button, buttonVariants, and cn are appropriate for tree-shaking and DX.

apps/playground-web/src/components/ui/button.tsx (2)

1-2: Re-export façade looks good.

Pass-through to the shared UI package keeps app imports stable and centralizes the implementation.


1-2: No changes needed: direct imports in UI wrapper modules are intentional

The only occurrences of from "@workspace/ui" are in each app’s local UI wrapper files, which are meant to re-export the shared primitives:

  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx

All other app code correctly imports UI components via @/components/ui/*. You can ignore the earlier suggestion.

Likely an incorrect or invalid review comment.

apps/dashboard/src/@/components/ui/button.tsx (2)

1-2: Re-export façade looks good.

Keeps dashboard imports stable while delegating implementation to the shared UI lib.


1-2: No direct @workspace/ui imports outside the UI wrapper

The only occurrences of direct imports from @workspace/ui are in your dashboard’s central UI façade (apps/dashboard/src/@/components/ui/button.tsx), which is the intended pattern for re-exporting shared primitives. No other files import @workspace/ui directly—all other components should continue to import from @/components/ui/*.

• apps/dashboard/src/@/components/ui/button.tsx: intentional re-exports of Button and ButtonProps from @workspace/ui

packages/ui/src/components/button.tsx (1)

68-71: Critical: className is being dropped by passing it into cva (buttonVariants); consumer styles won’t apply

cva only accepts defined variant keys; className is ignored and never merged. External className props from consumers currently don’t make it into the DOM.

Apply this diff to merge className outside of buttonVariants:

-        className={cn(
-          buttonVariants({ className, size, variant }),
-          disabledClass,
-        )}
+        className={cn(
+          buttonVariants({ size, variant }),
+          disabledClass,
+          className,
+        )}
⛔ Skipped due to learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{tsx} : Expose `className` prop on root element of components for overrides
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Add `className` to the root element of every component for external overrides.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Copy link
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: 5

🔭 Outside diff range comments (1)
apps/playground-web/package.json (1)

1-77: Add Next.js transpilePackages for the UI workspace package

The Next.js config for playground-web is missing the transpilePackages setting, so the TypeScript sources in @workspace/ui won’t be compiled. Update apps/playground-web/next.config.mjs to include it:

// apps/playground-web/next.config.mjs
-import { withContentlayer } from 'next-contentlayer'
-
-export default withContentlayer({
+import { withContentlayer } from 'next-contentlayer'
+
+export default withContentlayer({
   // existing config…
+  // Ensure TS sources from @workspace/ui are transpiled
+  transpilePackages: ['@workspace/ui'],
 })

Tailwind’s content scan already includes ../../packages/ui/src/**/*.{ts,tsx}, so no changes are needed there.

♻️ Duplicate comments (1)
packages/ui/src/components/button.tsx (1)

20-33: Consider preserving original styling for consistency.

The shared UI library's button variants differ from the original playground-web implementation in styling choices that may cause visual inconsistencies when apps adopt the shared implementation. Consider either preserving the original styling or documenting these intentional design changes.

🧹 Nitpick comments (2)
packages/ui/src/lib/utils.ts (1)

4-6: Add explicit return type to align with TS guidelines.

Explicit return type improves clarity and adheres to the repo’s TS rules.

-export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs));
-}
+export function cn(...inputs: ClassValue[]): string {
+  return twMerge(clsx(inputs));
+}
packages/ui/package.json (1)

1-29: Consider future-proofing package entry and build for potential publication.

Current setup points main/types/exports to TS sources. That’s fine for private workspaces if apps transpile the package (ensure transpilePackages). If you plan to publish or consume outside Next, consider:

  • Emitting JS and d.ts (tsup/rollup), and pointing exports to dist.
  • Adding "sideEffects": false for better tree-shaking.
  • Keeping only "exports" and removing "main"/"types" if you rely solely on exports map.

Example minimal adjustments (optional, if/when you add a build step):

   "name": "@workspace/ui",
   "version": "0.0.1",
   "private": true,
-  "main": "./src/index.ts",
-  "types": "./src/index.ts",
+  "main": "./dist/index.js",
+  "types": "./dist/index.d.ts",
+  "sideEffects": false,
   "exports": {
     ".": {
-      "types": "./src/index.ts",
-      "import": "./src/index.ts"
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.js"
     }
   },

If you’d like, I can sketch a tsup config and scripts for a tiny build pipeline.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3b2f8f and 5cc22af.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/tailwind.config.js (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/index.ts (1 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/tailwind.config.js
  • packages/ui/src/lib/utils.ts
  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • packages/ui/src/lib/utils.ts
  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/dashboard/tailwind.config.js
  • apps/playground-web/tailwind.config.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.

Applied to files:

  • apps/dashboard/tailwind.config.js
  • apps/playground-web/tailwind.config.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/tailwind.config.js
  • apps/playground-web/package.json
  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/package.json
  • apps/playground-web/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • packages/ui/src/lib/utils.ts
  • packages/ui/src/index.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.

Applied to files:

  • packages/ui/src/lib/utils.ts
  • packages/ui/src/index.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/lib/utils.ts
  • packages/ui/src/index.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`

Applied to files:

  • packages/ui/src/index.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
🧬 Code Graph Analysis (2)
packages/ui/src/lib/utils.ts (1)
packages/ui/src/index.ts (1)
  • cn (6-6)
packages/ui/src/components/button.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
🪛 GitHub Actions: CI
apps/playground-web/package.json

[error] 1-1: pnpm lint: dependencies should be ordered alphabetically. (unordered-dependencies)

apps/dashboard/package.json

[error] 1-1: pnpm lint: dependencies should be ordered alphabetically. (unordered-dependencies)

🔇 Additional comments (13)
apps/dashboard/tailwind.config.js (1)

5-5: LGTM: Tailwind content now scans shared UI package.

The added glob will ensure classes used in the shared UI are included in the dashboard build.

apps/playground-web/tailwind.config.ts (1)

5-5: LGTM: Tailwind content extended to include UI package.

This aligns the playground app with the shared UI consumption.

packages/ui/src/lib/utils.ts (1)

1-6: Import usage of cn in apps is correct
A search for import { cn } from "@workspace/ui" under apps returned no matches. All apps continue to import cn from @/lib/utils as intended.

packages/ui/src/index.ts (1)

1-6: LGTM: clean public surface for UI primitives.

Type-only re-export and minimal surface are solid. This aligns with centralizing UI primitives.

apps/dashboard/src/@/components/ui/button.tsx (1)

1-2: LGTM: dashboard now sources Button from the shared UI package.

This aligns with the consolidation goal and our UI primitive reuse guidance.

apps/playground-web/src/components/ui/button.tsx (1)

1-2: LGTM: playground button now proxies the shared UI component.

Consistent with the central UI package adoption.

packages/ui/src/components/button.tsx (7)

1-4: LGTM! Clean imports and proper dependency setup.

The imports are well-structured with external libraries first, React second, and internal utilities last. The import path @/lib/utils correctly uses the path alias configured in the TypeScript config.


6-36: Well-structured button variants with comprehensive styling.

The cva implementation provides a solid foundation with appropriate base styles and comprehensive variant coverage. The focus management, accessibility features, and transition effects are well-implemented.


38-42: Excellent interface design with proper type composition.

The ButtonProps interface correctly extends both React's native button attributes and the variant props, with the optional asChild prop for Radix Slot integration. This follows TypeScript best practices for component prop types.


44-79: Robust component implementation with excellent accessibility handling.

The Button component implementation is exemplary:

  • Properly handles both native button and Slot rendering via asChild
  • Comprehensive disabled state management for both native and custom elements
  • Correct accessibility attributes with aria-disabled
  • Proper ref forwarding
  • Default button type handling for native elements
  • Clean class name composition using the cn utility

The component follows React best practices and provides excellent developer experience.


48-54: Excellent disabled state handling for accessibility.

The detailed comment and implementation for handling disabled state across different element types demonstrates thorough consideration of accessibility requirements. The approach of using pointer-events-none opacity-50 with aria-disabled for non-button elements is exactly right.


56-63: Smart conditional prop handling for type safety.

The btnOnlyProps logic correctly ensures that button-specific properties (like type) are only applied to actual button elements, with a sensible default of "button" to prevent form submission issues.


80-82: Proper component naming and exports.

Setting the displayName aids in debugging, and the clean export structure makes the component and its variants easily consumable by other parts of the application.

@MananTank MananTank marked this pull request as draft August 13, 2025 18:34
Copy link
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

🔭 Outside diff range comments (1)
apps/dashboard/package.json (1)

27-32: Fix dependency order to satisfy CI (unordered-dependencies).

The newly added dependency "@workspace/ui" is out of alphabetical order, which is causing the CI failure. Place it after "@vercel/og".

Apply this diff to re-order the entry:

@@
-    "@thirdweb-dev/service-utils": "workspace:*",
-    "@workspace/ui": "workspace:*",
-    "@thirdweb-dev/vault-sdk": "workspace:*",
+    "@thirdweb-dev/service-utils": "workspace:*",
+    "@thirdweb-dev/vault-sdk": "workspace:*",
     "@vercel/functions": "2.2.2",
     "@vercel/og": "^0.6.8",
+    "@workspace/ui": "workspace:*",
♻️ Duplicate comments (1)
packages/ui/src/components/button.tsx (1)

6-36: Button variant styling looks good overall, but be aware of intentional design changes.

The buttonVariants implementation is well-structured using cva with comprehensive size and variant options. The base classes provide good accessibility features with focus-visible states and proper disabled handling.

Note: This implementation intentionally differs from the original playground-web button in two ways:

  1. Removes font-semibold from several variants
  2. Changes the upsell variant from a purple-to-pink gradient to solid green

These changes will affect visual consistency when apps migrate to this shared library, so ensure this is intentional.

🧹 Nitpick comments (7)
packages/ui/src/lib/utils.ts (1)

4-6: Add explicit return type to cn for API clarity and consistency

Our TS guidelines call for explicit return types. twMerge returns a string, so we can lock this down for better DX and to prevent accidental regressions.

-export function cn(...inputs: ClassValue[]) {
+export function cn(...inputs: ClassValue[]): string {
   return twMerge(clsx(inputs));
 }
apps/playground-web/tailwind.config.ts (1)

5-5: Tailwind content path updated correctly; consider making it path-resilient

The additional glob ensures UI package classes are scanned. To avoid brittle relative paths (repo reorgs, symlink variance), consider resolving the path via Node’s path API.

-  content: ["./src/**/*.{ts,tsx}", "../../packages/ui/src/**/*.{ts,tsx}"],
+  // Optionally make the UI path resolution robust to directory moves
+  // at the top: import { join } from "node:path";
+  content: ["./src/**/*.{ts,tsx}", join(__dirname, "../../packages/ui/src/**/*.{ts,tsx}")],

If you prefer CommonJS in config files, you can instead:

-const { fontFamily } = require("tailwindcss/defaultTheme");
+const { fontFamily } = require("tailwindcss/defaultTheme");
+const { join } = require("node:path");

 module.exports = {
-  content: ["./src/**/*.{ts,tsx}", "../../packages/ui/src/**/*.{ts,tsx}"],
+  content: ["./src/**/*.{ts,tsx}", join(__dirname, "../../packages/ui/src/**/*.{ts,tsx}")],
packages/ui/tsconfig.json (2)

17-21: Remove Next.js TS plugin from a library tsconfig

This package isn’t a Next.js app. Keeping the config minimal avoids unintended type plugin side-effects for consumers.

-    "plugins": [
-      {
-        "name": "next"
-      }
-    ],

5-5: Tighten TS config: allowJs is unnecessary for a TS-only library

If this package only ships TS/TSX, disabling JS keeps the surface stricter and catches accidental JS files.

-    "allowJs": true,
+    "allowJs": false,
packages/ui/package.json (2)

1-29: Mark package as side-effect free to improve tree-shaking

UI components/utilities here shouldn’t have side-effects. Adding this helps bundlers drop unused exports reliably.

 {
   "name": "@workspace/ui",
   "version": "0.0.1",
   "private": true,
+  "sideEffects": false,
   "main": "./src/index.ts",
   "types": "./src/index.ts",
   "exports": {
     ".": {
       "types": "./src/index.ts",
       "import": "./src/index.ts"
     }
   },

5-12: TS source entry: ensure consumer apps transpile this

Pointing main/types to TS is fine for private workspaces, but requires consumers to transpile. Confirm your Next apps are configured (transpilePackages or equivalent) or consider adding a build step with dist outputs later if you plan to publish.

I can generate a minimal build config (tsup/rollup) and update fields to dist if you want to future-proof this package. Want me to open a follow-up PR?

packages/ui/src/index.ts (1)

1-6: Condense exports for clarity.

Minor cleanup: combine type and value exports from the same module into a single line.

-// button
-export type { ButtonProps } from "./components/button";
-export { Button, buttonVariants } from "./components/button";
-
-// utils
-export { cn } from "./lib/utils";
+// button
+export { type ButtonProps, Button, buttonVariants } from "./components/button";
+
+// utils
+export { cn } from "./lib/utils";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3b2f8f and 5cc22af.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/tailwind.config.js (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/index.ts (1 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • packages/ui/src/lib/utils.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • packages/ui/src/lib/utils.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • apps/dashboard/package.json
  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/package.json
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • packages/ui/src/index.ts
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/**/index.ts : Group related components in their own folder and expose a single barrel `index.ts` where necessary.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.{tsx,jsx} : Place the file close to its feature: `feature/components/MyComponent.tsx`.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
🪛 GitHub Actions: CI
apps/playground-web/package.json

[error] 1-1: Unordered dependencies in './apps/playground-web/package.json' (unordered-dependencies).

apps/dashboard/package.json

[error] 1-1: Unordered dependencies in './apps/dashboard/package.json' (unordered-dependencies).

🔇 Additional comments (11)
packages/ui/src/lib/utils.ts (1)

1-2: LGTM: idiomatic clsx + tailwind-merge combo

Imports and usage are standard and correct for a Tailwind-aware className utility.

apps/dashboard/tailwind.config.js (1)

5-5: Include UI package in Tailwind content globs – LGTM.

This ensures classes used in the shared UI package are picked up by JIT. Path looks correct from apps/dashboard to packages/ui/src.

packages/ui/src/index.ts (1)

1-6: Add ’use client’ directive to Button component

The packages/ui/src/components/button.tsx file is missing the required Client Component directive. Since Button attaches event handlers, prepend the file with:

+ 'use client';
  import React from "react";
  // rest of imports…

This ensures Button is treated as a React Client Component.

⛔ Skipped due to learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.{tsx,jsx} : Name files after the component in PascalCase; append `.client.tsx` when interactive.
apps/dashboard/src/@/components/ui/button.tsx (1)

1-2: Pass-through re-exports to shared UI – LGTM.

Keeps app imports stable (@/components/ui/button) while centralizing implementation in the UI package.

apps/playground-web/src/components/ui/button.tsx (1)

1-2: Pass-through re-exports to shared UI – LGTM.

Matches the dashboard approach for consistency across apps.

packages/ui/src/components/button.tsx (6)

1-4: LGTM! Clean imports with appropriate dependencies.

The imports are well-structured and align with the modern UI library pattern using Radix UI, class-variance-authority for variants, and a utility function for class merging.


38-42: Well-designed interface with proper type composition.

The ButtonProps interface correctly extends both native button attributes and variant props, with the optional asChild prop for Radix Slot compatibility. This follows modern React component patterns effectively.


44-54: Excellent handling of the asChild pattern with proper disabled state management.

The component correctly implements the Radix Slot pattern and handles the complex case where disabled state needs to work for both native buttons and non-button elements rendered via asChild. The comment clearly explains the reasoning behind the disabledClass approach.


56-63: Smart type-specific prop handling.

The btnOnlyProps logic correctly applies the type attribute only to actual button elements, with a sensible default of "button". The conditional typing and spreading approach is clean and type-safe.


65-79: Robust component rendering with comprehensive prop handling.

The render logic properly handles:

  • Accessibility with aria-disabled
  • Class merging with variant styles and disabled state
  • Conditional prop spreading for button-specific attributes
  • Proper ref forwarding

The implementation is thorough and follows React best practices.


80-82: Proper component setup and exports.

The display name is set correctly for debugging, and the exports include both the component and variants function, providing a complete API surface for consumers.

Copy link
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: 7

♻️ Duplicate comments (1)
packages/ui/src/components/button.tsx (1)

21-33: Align button variant styles with prior implementation (font weight and upsell gradient)

This has been flagged previously: variants dropped the bold weight and the upsell style changed from a purple-pink gradient to solid green. Unless this is an intentional design update, keep parity to avoid regressions in playground-web.

Apply this diff if parity is desired:

       variant: {
         default: "bg-foreground text-background hover:bg-foreground/90",
         destructive:
-          "bg-destructive hover:bg-destructive/90 text-destructive-foreground ",
+          "bg-destructive hover:bg-destructive/90 text-destructive-foreground font-semibold",
         ghost: "hover:bg-accent hover:text-accent-foreground",
-        link: "underline-offset-4 hover:underline",
+        link: "underline-offset-4 hover:underline font-semibold",
         outline:
-          "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
-        primary: "bg-primary hover:bg-primary/90 text-primary-foreground ",
+          "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground font-semibold",
+        primary: "bg-primary hover:bg-primary/90 text-primary-foreground font-semibold",
         secondary:
-          "bg-secondary hover:bg-secondary/80 text-secondary-foreground ",
+          "bg-secondary hover:bg-secondary/80 text-secondary-foreground font-semibold",
         upsell:
-          "bg-green-600 text-white hover:bg-green-700 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
+          "bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:from-purple-600 hover:to-pink-600 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
       },

If the change is intentional, consider documenting it in the UI package README and a migration note for consuming apps.

🧹 Nitpick comments (5)
packages/ui/package.json (1)

20-23: Consider more flexible React version constraints.

The peer dependencies specify React 19.0.0, but using more flexible version ranges like "^18.0.0 || ^19.0.0" would improve compatibility across different projects that might not have upgraded to React 19 yet.

  "peerDependencies": {
-    "react": "^19.0.0",
-    "react-dom": "^19.0.0"
+    "react": "^18.0.0 || ^19.0.0",
+    "react-dom": "^18.0.0 || ^19.0.0"
  },
packages/ui/src/components/button.tsx (4)

38-42: Prefer a type alias over interface for props to match guidelines

Per the repo’s TS guidelines, use a type alias for structural props.

Apply this diff:

-export interface ButtonProps
-  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
-    VariantProps<typeof buttonVariants> {
-  asChild?: boolean;
-}
+export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
+  VariantProps<typeof buttonVariants> & {
+    asChild?: boolean;
+  };

23-30: Remove trailing whitespace in class strings

Minor cleanup for consistency.

Apply this diff:

-          "bg-destructive hover:bg-destructive/90 text-destructive-foreground ",
+          "bg-destructive hover:bg-destructive/90 text-destructive-foreground",
-        primary: "bg-primary hover:bg-primary/90 text-primary-foreground ",
+        primary: "bg-primary hover:bg-primary/90 text-primary-foreground",
-        secondary:
-          "bg-secondary hover:bg-secondary/80 text-secondary-foreground ",
+        secondary:
+          "bg-secondary hover:bg-secondary/80 text-secondary-foreground",

66-71: Optional: pass className outside CVA for clarity

Both patterns work, but it’s more explicit to keep variant selection inside CVA and merge external classes with cn separately. Current code is fine; sharing an alternative for readability:

Apply this diff:

-        className={cn(
-          buttonVariants({ className, size, variant }),
-          disabledClass,
-        )}
+        className={cn(buttonVariants({ size, variant }), className, disabledClass)}

44-52: Optional: polymorphic typing for asChild

When asChild is true, the ref and props may not match HTMLButtonElement. Consider a polymorphic prop pattern (e.g., as?: ElementType) or overloads to improve type-safety. Not blocking.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3b2f8f and 5cc22af.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/tailwind.config.js (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/index.ts (1 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/lib/utils.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • packages/ui/src/components/button.tsx
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/lib/utils.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/tailwind.config.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • packages/ui/src/index.ts
  • apps/dashboard/package.json
  • packages/ui/package.json
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.

Applied to files:

  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/tailwind.config.js
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/tailwind.config.js
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • packages/ui/src/index.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Combine class names via `cn`, expose `className` prop if useful.

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/index.ts
  • packages/ui/src/lib/utils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • packages/ui/src/index.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • packages/ui/src/components/button.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.{tsx,jsx} : Place the file close to its feature: `feature/components/MyComponent.tsx`.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/**/index.ts : Group related components in their own folder and expose a single barrel `index.ts` where necessary.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
🧬 Code Graph Analysis (1)
packages/ui/src/lib/utils.ts (1)
packages/ui/src/index.ts (1)
  • cn (6-6)
🪛 GitHub Actions: CI
apps/dashboard/package.json

[error] 1-1: Command: pnpm lint. ESLint: dependencies should be ordered alphabetically (unordered-dependencies).

apps/playground-web/package.json

[error] 1-1: Command: pnpm lint. ESLint: dependencies should be ordered alphabetically (unordered-dependencies).

🔇 Additional comments (5)
apps/playground-web/tailwind.config.ts (1)

5-5: LGTM! Proper UI package integration.

The content array is correctly updated to include TypeScript/TSX files from the shared UI package, ensuring Tailwind CSS can process classes used by the UI components.

packages/ui/src/lib/utils.ts (1)

4-6: LGTM! Standard class composition utility.

The cn function correctly implements the standard pattern for combining and merging Tailwind classes using clsx and tailwind-merge. This aligns with the coding guidelines for using cn() for conditional class logic.

apps/dashboard/tailwind.config.js (1)

5-5: Including the shared UI package in Tailwind content globs looks correct

This ensures classes used inside packages/ui are picked up in the Dashboard build.

packages/ui/src/index.ts (2)

2-6: Good, minimal public surface re-exports

Cleanly re-exporting Button, buttonVariants, ButtonProps, and cn from the root keeps the consumer API simple and tree-shakeable.


1-6: Add Next.js transpilePackages for @workspace/ui to all apps

The UI package ships TypeScript sources, so each Next.js app must transpile it. None of your next.config.* files currently include transpilePackages or reference @workspace/ui. Without this, builds may fail or behave inconsistently.

Files needing an update:

  • apps/dashboard/next.config.ts
  • apps/nebula/next.config.ts
  • apps/playground-web/next.config.mjs
  • apps/portal/next.config.mjs
  • apps/wallet-ui/next.config.mjs

Suggested change (add inside your existing nextConfig object):

/** @type {import('next').NextConfig} */
const nextConfig = {
+  transpilePackages: ["@workspace/ui"],
  // …other config
};
export default nextConfig;
⛔ Skipped due to learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Wrap client-side data fetching calls in React Query (`tanstack/react-query`)

@MananTank MananTank force-pushed the 08-13-create_shared_ui_library branch from dc72a4a to e44b2a0 Compare August 16, 2025 12:31
@github-actions github-actions bot added Portal Involves changes to the Portal (docs) codebase. Ecosystem Portal Involves changes to the Ecosystem Portal labels Aug 16, 2025
Copy link
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: 4

♻️ Duplicate comments (1)
apps/dashboard/package.json (1)

31-31: Dependency ordering fix looks correct

Placing "@workspace/ui" after "@vercel/og" aligns with the linter’s alphabetical ordering requirement noted earlier. This should unblock the unordered-dependencies error.

If convenient, re-run the dashboard lint locally to confirm the fix:

  • From repo root: pnpm -w --filter ./apps/dashboard lint
🧹 Nitpick comments (9)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx (1)

5-8: Nits: add explicit return type and props alias; prefer nullish coalescing over logical OR

  • Add a props type alias and explicit JSX.Element return type per repo guidelines.
  • Use ?? instead of || so empty strings aren’t unintentionally overridden.
 import { ChainIconClient } from "@/icons/ChainIcon";
 
+type ChainOverviewProps = {
+  chainId: string;
+  client: ThirdwebClient;
+};
+
-export function ChainOverview(props: {
-  chainId: string;
-  client: ThirdwebClient;
-}) {
+export function ChainOverview(props: ChainOverviewProps): JSX.Element {
   const { idToChain } = useAllChainsData();
   const chainMetadata = idToChain.get(Number(props.chainId));
 
   return (
     <div className="flex items-center gap-2">
       <ChainIconClient
         className="size-3.5"
         client={props.client}
-        src={chainMetadata?.icon?.url || ""}
+        src={chainMetadata?.icon?.url ?? ""}
       />
       <p className="text-foreground text-sm">
-        {chainMetadata?.name || `Chain ${props.chainId}`}
+        {chainMetadata?.name ?? `Chain ${props.chainId}`}
       </p>
     </div>
   );
 }

Also applies to: 17-20

apps/dashboard/src/app/pay/layout.tsx (1)

1-1: (Nit) Mark server components explicitly

Add the server-only directive to ensure this layout is never bundled for the client.

Apply this diff:

+import "server-only";
+// global styles are imported at the root layout
apps/portal/package.json (1)

2-44: Classify @workspace/ui as a runtime dependency, not a devDependency

The app imports components and CSS from @workspace/ui; that’s part of the build/runtime graph, so it should live under dependencies (to avoid surprises in prod installs that omit devDependencies).

Apply this diff:

@@
   "dependencies": {
@@
-    "typedoc-better-json": "0.9.4"
+    "typedoc-better-json": "0.9.4",
+    "@workspace/ui": "workspace:*"
   },
@@
   "devDependencies": {
@@
-    "@workspace/ui": "workspace:*",

Also applies to: 45-71

packages/ui/tsconfig.json (1)

6-6: Tighten compiler settings: disable JS, set JSX runtime, and drop unused declaration flags

Given this package is TS-only and doesn’t emit artifacts, these settings reduce noise and make intent explicit.

Apply this diff:

-    "allowJs": true,
+    "allowJs": false,
@@
-    "declaration": true,
-    "declarationMap": true,
+    // noEmit is true; declarations won't be written anyway
+    "declaration": false,
+    "declarationMap": false,
@@
-    "jsx": "preserve",
+    "jsx": "react-jsx",

Also applies to: 10-11, 21-21

packages/ui/tailwind.config.ts (1)

5-10: Centralize and export UI content globs for reuse in apps

To avoid brittle relative paths in consumers (e.g., ../../packages/ui/src/**) and keep purge content in sync across apps, consider exporting a reusable content helper from the UI package.

Apply this change in the UI package to export a content helper:

 import type { Config } from "tailwindcss";
 import { fontFamily } from "tailwindcss/defaultTheme";
 import tailwindcssAnimate from "tailwindcss-animate";

+// Optional: export helper paths for consumers to include UI sources in their Tailwind content
+export const uiContentGlobs = ["./src/**/*.{ts,tsx}"] as const;
+
 const config: Config = {
-  content: [
-    "./src/**/*.{ts,tsx}",
-    // Note: when importing this config in website project,
-    // add a relative path to the ui package here
-  ],
+  content: [...uiContentGlobs],
   darkMode: ["class"],
   plugins: [tailwindcssAnimate],

Then in app configs (example), replace ad-hoc relative paths:

// apps/portal/tailwind.config.ts
import tailwindConfig, { uiContentGlobs } from "@workspace/ui/tailwind.config";

const config: Config = {
  ...tailwindConfig,
  content: [
    "./components/**/*.{ts,tsx}",
    "./app/**/*.{ts,tsx,mdx}",
    "./src/**/*.{ts,tsx,mdx}",
    // include UI content by resolving from the package root
    // when needed, resolve absolute path(s) here based on monorepo layout
    "../../packages/ui/src/**/*.{ts,tsx}",
  ],
  // ...
};
export default config;
apps/portal/tailwind.config.ts (2)

10-12: Resolve UI content path programmatically to avoid brittle relative paths

Hard-coding "../../packages/ui/src/**" works in this monorepo, but using a resolved path tied to the package is more robust to refactors.

Example using ESM createRequire:

// at top of file
import { createRequire } from "node:module";
import path from "node:path";
const require = createRequire(import.meta.url);
const uiPkgRoot = path.dirname(require.resolve("@workspace/ui/package.json"));
const uiContent = path.join(uiPkgRoot, "src/**/*.{ts,tsx}");

// then in content:
content: [
  "./components/**/*.{ts,tsx}",
  "./app/**/*.{ts,tsx,mdx}",
  "./src/**/*.{ts,tsx,mdx}",
  uiContent,
],

23-39: Nit: use numeric values for zIndex

Tailwind accepts both strings and numbers, but numeric values are a bit cleaner and consistent with Tailwind defaults.

-      zIndex: {
-        // base
-        base: "0",
-        //
-        codeToken: "5",
-        codeTokenHighlight: "1",
-        //
-        copyCodeButton: "20",
-        dropdownMenu: "1200",
-        floatingButton: "1000",
-        menu: "1100",
-        modal: "1400",
-        modalOverlay: "1300",
-        stickyMobileSidebar: "500",
-        //
-        stickyTop: "1000",
-      },
+      zIndex: {
+        // base
+        base: 0,
+        //
+        codeToken: 5,
+        codeTokenHighlight: 1,
+        //
+        copyCodeButton: 20,
+        dropdownMenu: 1200,
+        floatingButton: 1000,
+        menu: 1100,
+        modal: 1400,
+        modalOverlay: 1300,
+        stickyMobileSidebar: 500,
+        //
+        stickyTop: 1000,
+      },
packages/ui/package.json (1)

5-15: Mark CSS as side-effectful to prevent tree-shaking from dropping styles

Since consumers import "@workspace/ui/global.css", add a sideEffects entry so bundlers don’t remove CSS-only imports.

 {
   "name": "@workspace/ui",
   "version": "0.0.1",
   "private": true,
+  "sideEffects": [
+    "./src/global.css",
+    "*.css"
+  ],
   "exports": {
     "./global.css": "./src/global.css",
     "./postcss.config": "./postcss.config.mjs",
     "./tailwind.config": "./tailwind.config.ts",
     "./lib/*": "./src/lib/*.ts",
     "./hooks/*": [
       "./src/hooks/*.ts",
       "./src/hooks/*.tsx"
     ],
     "./components/*": "./src/components/*.tsx"
   },
apps/portal/src/components/ui/button.tsx (1)

2-3: Re-export pattern is clean; consider avoiding deep-import coupling if root exports exist

If @workspace/ui exposes Button, buttonVariants, and ButtonProps at its package root, prefer importing from the root to avoid coupling to internal paths and to simplify future refactors. If not, this is fine to keep as-is.

Example (only if root exports exist):

-export type { ButtonProps } from "@workspace/ui/components/button";
-export { Button, buttonVariants } from "@workspace/ui/components/button";
+export type { ButtonProps } from "@workspace/ui";
+export { Button, buttonVariants } from "@workspace/ui";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dc72a4a and e44b2a0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (45)
  • apps/dashboard/knip.json (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/postcss.config.js (0 hunks)
  • apps/dashboard/postcss.config.mjs (1 hunks)
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (2 hunks)
  • apps/dashboard/src/app/(app)/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/layout.tsx (1 hunks)
  • apps/dashboard/src/app/login/layout.tsx (1 hunks)
  • apps/dashboard/src/app/pay/layout.tsx (1 hunks)
  • apps/dashboard/tailwind.config.ts (1 hunks)
  • apps/dashboard/tsconfig.json (2 hunks)
  • apps/playground-web/knip.json (1 hunks)
  • apps/playground-web/next.config.mjs (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/postcss.config.js (0 hunks)
  • apps/playground-web/postcss.config.mjs (1 hunks)
  • apps/playground-web/src/app/ai/api/chat.ts (1 hunks)
  • apps/playground-web/src/app/ai/api/types.ts (0 hunks)
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx (2 hunks)
  • apps/playground-web/src/app/globals.css (0 hunks)
  • apps/playground-web/src/app/layout.tsx (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • apps/portal/next.config.mjs (1 hunks)
  • apps/portal/package.json (1 hunks)
  • apps/portal/src/app/globals.css (0 hunks)
  • apps/portal/src/app/layout.tsx (1 hunks)
  • apps/portal/src/components/ui/button.tsx (1 hunks)
  • apps/portal/tailwind.config.ts (1 hunks)
  • apps/wallet-ui/next.config.mjs (0 hunks)
  • packages/thirdweb/src/exports/extensions/marketplace.ts (1 hunks)
  • packages/thirdweb/src/exports/utils.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/postcss.config.mjs (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/global.css (2 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tailwind.config.ts (2 hunks)
  • packages/ui/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (6)
  • apps/wallet-ui/next.config.mjs
  • apps/dashboard/postcss.config.js
  • apps/playground-web/postcss.config.js
  • apps/playground-web/src/app/globals.css
  • apps/playground-web/src/app/ai/api/types.ts
  • apps/portal/src/app/globals.css
✅ Files skipped from review due to trivial changes (1)
  • apps/portal/src/app/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (26)
  • apps/playground-web/knip.json
  • apps/playground-web/postcss.config.mjs
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx
  • apps/dashboard/src/app/(app)/layout.tsx
  • apps/playground-web/package.json
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
  • packages/ui/postcss.config.mjs
  • apps/dashboard/src/app/bridge/layout.tsx
  • packages/thirdweb/src/exports/extensions/marketplace.ts
  • packages/thirdweb/src/exports/utils.ts
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts
  • apps/playground-web/src/app/layout.tsx
  • apps/dashboard/postcss.config.mjs
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/dashboard/next.config.ts
  • apps/playground-web/tailwind.config.ts
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/src/lib/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts
  • apps/dashboard/src/app/login/layout.tsx
  • packages/ui/src/global.css
  • apps/playground-web/src/app/ai/api/chat.ts
  • apps/dashboard/tailwind.config.ts
  • apps/dashboard/knip.json
  • packages/ui/src/components/button.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/pay/layout.tsx
  • packages/ui/tailwind.config.ts
  • apps/portal/src/components/ui/button.tsx
  • apps/portal/tailwind.config.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/pay/layout.tsx
  • packages/ui/tailwind.config.ts
  • apps/portal/src/components/ui/button.tsx
  • apps/portal/tailwind.config.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/pay/layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/package.json
  • apps/dashboard/src/app/pay/layout.tsx
  • apps/portal/src/components/ui/button.tsx
  • packages/ui/package.json
  • apps/portal/tailwind.config.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
  • apps/dashboard/tsconfig.json
  • packages/ui/tailwind.config.ts
  • packages/ui/package.json
  • apps/portal/tailwind.config.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Tailwind CSS is the styling system – avoid inline styles or CSS modules.

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
  • apps/portal/src/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • apps/dashboard/src/app/pay/layout.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`

Applied to files:

  • apps/dashboard/tsconfig.json
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.

Applied to files:

  • apps/dashboard/tsconfig.json
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{ts,tsx} : Export default async functions without `'use client';` – they run on the Node edge.

Applied to files:

  • apps/dashboard/tsconfig.json
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/portal/src/components/ui/button.tsx
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
PR: thirdweb-dev/js#7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
PR: thirdweb-dev/js#7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types

Applied to files:

  • packages/ui/tsconfig.json
🧬 Code Graph Analysis (1)
apps/portal/tailwind.config.ts (1)
packages/ui/postcss.config.mjs (1)
  • config (2-7)
⏰ 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). (9)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (10)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx (1)

1-1: Type-only import from "thirdweb" is correct and preferred

Good move to import the ThirdwebClient type from the package root using import type — keeps bundles clean and aligns with the migration away from deep imports.

apps/dashboard/tsconfig.json (2)

12-14: ESNext + Bundler resolution + ES2022 target look correct for Next 15

These align with Next 15/SWC and modern ESM. No issues spotted.

Also applies to: 25-25


12-14: ✅ TypeScript version meets requirement

The dashboard app declares TypeScript 5.8.3, which is above the 5.2 minimum needed for moduleResolution: "Bundler". No further changes required.

apps/portal/next.config.mjs (2)

50-50: Transpiling @workspace/ui is the right call

Ensures TS/ESM inside the workspace package compiles correctly under Next. Looks good.


48-86: Confirm webpack externals removal safety

A search across the codebase didn’t turn up any direct imports or requires of pino-pretty, lokijs, or encoding.

  • No occurrences of from 'pino-pretty', require('pino-pretty'), lokijs, or encoding were found outside node_modules.

Please verify that none of your transitive dependencies still expect these modules at runtime, ensuring the removal of the old externals config won’t introduce missing-module errors.

packages/ui/tailwind.config.ts (1)

1-3: Typed Tailwind config and ESM export are solid

Using Config typing and default ESM export improves DX and aligns with modern Tailwind setups. Plugin import via tailwindcss-animate is also correct.

apps/portal/tailwind.config.ts (1)

1-5: Nice composition with the shared UI Tailwind config

Spreading the base UI config keeps plugins/darkMode/theme aligned across apps and reduces duplication.

packages/ui/package.json (1)

24-27: Peer deps aligned with React 19

Peer versions match the apps’ React 19 usage; no concerns from me.

apps/portal/src/components/ui/button.tsx (2)

1-1: LGTM: "use client" is correctly applied for this re-export

Since you re-export runtime values from a Client Component module, marking this file as a client module avoids the “Server Component importing Client Component” constraint in Next.js. Looks good.


1-3: All sanity-check configurations for @workspace/ui are correctly set up in Portal
Verified:

  • apps/portal/next.config.mjs: transpilePackages: ["@workspace/ui"] (line 50)
  • apps/portal/src/app/layout.tsx: import "@workspace/ui/global.css"; present
  • apps/portal/tailwind.config.ts: imports/extending from @workspace/ui/tailwind.config

No further changes needed—this re-export will work end-to-end.

Copy link
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

♻️ Duplicate comments (3)
packages/ui/src/components/button.tsx (3)

54-76: Do not pass disabled to non-button elements; apply manual disabled styles only with asChild

Right now disabled is applied to all render targets, including when using asChild (e.g., ), where disabled is invalid and won’t trigger Tailwind’s :disabled styles. Also, native buttons already get disabled: utilities from the base class, so the manual disabledClass duplicates styling. Move disabled into btnOnlyProps when the rendered element is a native , and only apply the manual disabled visuals for asChild.

Apply this diff:

-    const disabledClass = disabled ? "pointer-events-none opacity-50" : "";
+    // Apply manual disabled visuals only when not rendering a native <button>
+    const disabledClass =
+      asChild && disabled ? "pointer-events-none opacity-50" : "";

     const btnOnlyProps =
       Comp === "button"
         ? {
-            type:
-              (props as React.ButtonHTMLAttributes<HTMLButtonElement>).type ||
-              ("button" as const),
+            disabled,
+            type:
+              (props as React.ButtonHTMLAttributes<HTMLButtonElement>).type ??
+              ("button" as const),
           }
-        : undefined;
+        : disabled
+        ? { tabIndex: -1 }
+        : undefined;

     return (
       <Comp
-        aria-disabled={disabled ? true : undefined}
+        aria-disabled={asChild && disabled ? true : undefined}
         className={cn(
           buttonVariants({ className, size, variant }),
           disabledClass,
         )}
-        disabled={disabled}
         ref={ref}
         {...props}
         {...btnOnlyProps}
       />
     );

Optional follow-up: for non-button elements in the disabled state, also prevent interaction with an onClick guard that no-ops when disabled.


21-33: Confirm intended design changes vs. app parity (font weight and upsell variant restyle)

Compared to prior app-specific buttons, this central version uses base font-medium and removes font-semibold from several variants, and restyles upsell from a purple-pink gradient to solid green. If unintentional, this will cause visual drift when apps adopt the shared component. Either restore parity or document the new design as intentional.

If parity is desired, apply:

         variant: {
           default: "bg-foreground text-background hover:bg-foreground/90",
-          destructive:
-            "bg-destructive hover:bg-destructive/90 text-destructive-foreground ",
-          ghost: "hover:bg-accent hover:text-accent-foreground",
-          link: "underline-offset-4 hover:underline",
-          outline:
-            "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
-          primary: "bg-primary hover:bg-primary/90 text-primary-foreground ",
-          secondary:
-            "bg-secondary hover:bg-secondary/80 text-secondary-foreground ",
-          upsell:
-            "bg-green-600 text-white hover:bg-green-700 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
+          destructive:
+            "bg-destructive hover:bg-destructive/90 text-destructive-foreground font-semibold",
+          ghost: "hover:bg-accent hover:text-accent-foreground font-semibold",
+          link: "underline-offset-4 hover:underline font-semibold",
+          outline:
+            "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground font-semibold",
+          primary:
+            "bg-primary hover:bg-primary/90 text-primary-foreground font-semibold",
+          secondary:
+            "bg-secondary hover:bg-secondary/80 text-secondary-foreground font-semibold",
+          upsell:
+            "bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:from-purple-600 hover:to-pink-600 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200",
         },

If the new green upsell is intentional, consider a new variant name (e.g., upsellGreen) to keep both styles available during migration.


4-4: Replace workspace alias with relative import to avoid unresolved paths in the published package

Using "@/lib/utils" inside a published package relies on consumers’ alias configuration. Without a bundler/plugin to rewrite TS path aliases at build time, this will break for consumers. Switch to a relative import within the package.

Apply this diff:

-import { cn } from "@/lib/utils";
+import { cn } from "../lib/utils";

🧹 Nitpick comments (8)
packages/ui/src/components/button.tsx (1)

44-46: Optional: improve polymorphic typing for asChild

The ref is typed as HTMLButtonElement even when rendering via Slot (e.g., ). This is common and workable, but if you want stricter types, consider a polymorphic typing approach so the ref/props match the rendered element.

For example, you can type the component with a generic ElementType and map props accordingly, or use React.ElementRef for the ref when asChild is true. This is optional and can be deferred.

apps/portal/knip.json (1)

10-14: It looks like the import-scan step is still failing to run properly in CI. Could you please manually verify that, in apps/portal/src:

  • No files import from either @/components/ui/ or src/components/ui/
  • No files import from either @/icons/ or src/icons/
  • No files import the standalone Banner.tsx under src/components/others/
  • There are no stray Next.js auto-injected files matching instrumentation.* or global-error.* that should be added to your Knip “entry” patterns

If all of those checks confirm there’s truly no usage, the ignored folders/files can be safely deleted (or moved) and removed from knip.json. Otherwise, keep the ignores for any persistent false positives.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx (3)

181-186: BigInt on possibly fractional quantities can throw; confirm units for airdrop amounts

If recipient.quantity can be fractional (e.g., "1.5"), BigInt(recipient.quantity) will throw. Also, unit expectations for distributeToken.amount may be in token units or base units depending on API; current code assumes integer token units → base unit bigint.

Two safe options depending on API expectations:

  • If distributeToken expects base units (recommended when decimals are known): convert with toUnits and the token’s decimals.
  • If it expects whole tokens only: validate and disallow fractional quantities before converting to BigInt.

Option A (convert to base units – assumes 18 decimals; adjust if different):

-      contents: values.airdropAddresses.map((recipient) => ({
-        amount: BigInt(recipient.quantity),
-        recipient: recipient.address,
-      })),
+      contents: values.airdropAddresses.map((recipient) => ({
+        amount: toUnits(String(recipient.quantity), 18),
+        recipient: recipient.address,
+      })),

Option B (enforce whole tokens only and surface a clear error):

-      contents: values.airdropAddresses.map((recipient) => ({
-        amount: BigInt(recipient.quantity),
-        recipient: recipient.address,
-      })),
+      contents: values.airdropAddresses.map((recipient) => {
+        const q = String(recipient.quantity);
+        if (q.includes("."))
+          throw new Error("Airdrop quantity must be a whole number of tokens");
+        return {
+          amount: BigInt(q),
+          recipient: recipient.address,
+        };
+      }),

306-309: Redundant null check on account

getAccount() throws if no activeAccount, so account is never falsy here. The check is unreachable and can be removed.

-    if (!account) {
-      throw new Error("No connected account");
-    }

90-94: Align function naming: use consistent “ERC20Asset” casing

Other helpers use “ERC20Asset_*”. Rename Erc20Asset_deployContract for consistency and easier grepability.

-  async function Erc20Asset_deployContract(params: {
+  async function ERC20Asset_deployContract(params: {

And update the usage:

-          deployContract: Erc20Asset_deployContract,
+          deployContract: ERC20Asset_deployContract,

Also applies to: 431-435

apps/portal/tailwind.config.ts (3)

4-5: Prefer Tailwind’s presets over object spread to compose configs

Using presets avoids subtle overrides (e.g., future plugin changes, flags, or experimental toggles) and communicates intent more clearly than spreading the entire base config.

Apply this diff:

-const config: Config = {
-  ...tailwindConfig,
+const config: Config = {
+  presets: [tailwindConfig as Config],
   content: [
@@
-  theme: {
-    ...tailwindConfig.theme,
-    extend: {
-      ...tailwindConfig.theme?.extend,
+  theme: {
+    extend: {

Also applies to: 14-17


6-12: Merge base content globs and add a fallback for the published UI package

Overriding content drops any globs the UI config might define. Also, when the app consumes the published UI package instead of a workspace path, adding a node_modules fallback prevents missing classes in production builds. Note: scanning node_modules can increase build time; weigh this tradeoff.

Apply this diff:

   content: [
+    // include any content globs defined by the shared UI config
+    ...(tailwindConfig.content ?? []),
     "./components/**/*.{ts,tsx}",
     "./app/**/*.{ts,tsx,mdx}",
     "./src/**/*.{ts,tsx,mdx}",
     // add contents of ui package
     "../../packages/ui/src/**/*.{ts,tsx}",
+    // fallback when consuming published @workspace/ui
+    "../../node_modules/@workspace/ui/**/*.{js,jsx,ts,tsx}",
   ],

23-39: Use numeric z-index values (nit)

Tailwind accepts either strings or numbers here, but numbers are conventional and slightly clearer when scanning configs.

Apply this diff:

   zIndex: {
-        // base
-        base: "0",
-        //
-        codeToken: "5",
-        codeTokenHighlight: "1",
-        //
-        copyCodeButton: "20",
-        dropdownMenu: "1200",
-        floatingButton: "1000",
-        menu: "1100",
-        modal: "1400",
-        modalOverlay: "1300",
-        stickyMobileSidebar: "500",
-        //
-        stickyTop: "1000",
+        // base
+        base: 0,
+        //
+        codeToken: 5,
+        codeTokenHighlight: 1,
+        //
+        copyCodeButton: 20,
+        dropdownMenu: 1200,
+        floatingButton: 1000,
+        menu: 1100,
+        modal: 1400,
+        modalOverlay: 1300,
+        stickyMobileSidebar: 500,
+        //
+        stickyTop: 1000,
       },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e44b2a0 and 171eb7e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (46)
  • apps/dashboard/knip.json (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/postcss.config.js (0 hunks)
  • apps/dashboard/postcss.config.mjs (1 hunks)
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (2 hunks)
  • apps/dashboard/src/app/(app)/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/layout.tsx (1 hunks)
  • apps/dashboard/src/app/login/layout.tsx (1 hunks)
  • apps/dashboard/src/app/pay/layout.tsx (1 hunks)
  • apps/dashboard/tailwind.config.ts (1 hunks)
  • apps/dashboard/tsconfig.json (2 hunks)
  • apps/playground-web/knip.json (1 hunks)
  • apps/playground-web/next.config.mjs (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/postcss.config.js (0 hunks)
  • apps/playground-web/postcss.config.mjs (1 hunks)
  • apps/playground-web/src/app/ai/api/chat.ts (1 hunks)
  • apps/playground-web/src/app/ai/api/types.ts (0 hunks)
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx (2 hunks)
  • apps/playground-web/src/app/globals.css (0 hunks)
  • apps/playground-web/src/app/layout.tsx (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • apps/portal/knip.json (1 hunks)
  • apps/portal/next.config.mjs (1 hunks)
  • apps/portal/package.json (1 hunks)
  • apps/portal/src/app/globals.css (0 hunks)
  • apps/portal/src/app/layout.tsx (1 hunks)
  • apps/portal/src/components/ui/button.tsx (1 hunks)
  • apps/portal/tailwind.config.ts (1 hunks)
  • apps/wallet-ui/next.config.mjs (0 hunks)
  • packages/thirdweb/src/exports/extensions/marketplace.ts (1 hunks)
  • packages/thirdweb/src/exports/utils.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/postcss.config.mjs (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/global.css (2 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tailwind.config.ts (2 hunks)
  • packages/ui/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (6)
  • apps/dashboard/postcss.config.js
  • apps/wallet-ui/next.config.mjs
  • apps/playground-web/src/app/globals.css
  • apps/playground-web/postcss.config.js
  • apps/playground-web/src/app/ai/api/types.ts
  • apps/portal/src/app/globals.css
✅ Files skipped from review due to trivial changes (2)
  • apps/portal/src/app/layout.tsx
  • apps/dashboard/src/app/(app)/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (34)
  • apps/dashboard/postcss.config.mjs
  • apps/playground-web/package.json
  • packages/thirdweb/src/exports/utils.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx
  • apps/playground-web/src/app/ai/api/chat.ts
  • apps/dashboard/tsconfig.json
  • apps/playground-web/knip.json
  • apps/dashboard/src/app/pay/layout.tsx
  • packages/ui/package.json
  • apps/playground-web/postcss.config.mjs
  • apps/playground-web/next.config.mjs
  • apps/portal/next.config.mjs
  • apps/dashboard/tailwind.config.ts
  • packages/thirdweb/src/exports/extensions/marketplace.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts
  • apps/dashboard/package.json
  • apps/portal/package.json
  • apps/playground-web/src/app/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts
  • packages/ui/src/lib/utils.ts
  • packages/ui/tsconfig.json
  • apps/playground-web/tailwind.config.ts
  • packages/ui/src/global.css
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
  • packages/ui/postcss.config.mjs
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/tailwind.config.ts
  • apps/playground-web/src/components/ui/button.tsx
  • apps/dashboard/knip.json
  • apps/dashboard/src/app/bridge/layout.tsx
  • apps/dashboard/src/app/login/layout.tsx
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx
  • apps/portal/src/components/ui/button.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
  • packages/ui/src/components/button.tsx
  • apps/portal/tailwind.config.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
  • packages/ui/src/components/button.tsx
  • apps/portal/tailwind.config.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
📚 Learning: 2025-05-20T19:03:35.954Z
Learnt from: MananTank
PR: thirdweb-dev/js#7081
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/assets/create/create-token-page-impl.tsx:160-165
Timestamp: 2025-05-20T19:03:35.954Z
Learning: The `claimTo` function in Thirdweb's ERC20 extension does not require converting the quantity to the smallest units (using toUnits) as it handles unit conversion internally or works with the units as provided.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
📚 Learning: 2025-06-18T02:01:06.006Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7363
File: apps/dashboard/src/app/(app)/layout.tsx:63-74
Timestamp: 2025-06-18T02:01:06.006Z
Learning: In Next.js applications, instrumentation files (instrumentation.ts or instrumentation-client.ts) placed in the src/ directory are automatically handled by the framework and included in the client/server bundles without requiring manual imports. The framework injects these files as part of the build process.

Applied to files:

  • apps/portal/knip.json
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/portal/tailwind.config.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/portal/tailwind.config.ts
🧬 Code Graph Analysis (2)
packages/ui/src/components/button.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/portal/tailwind.config.ts (1)
packages/ui/postcss.config.mjs (1)
  • config (2-7)
⏰ 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). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx (4)

27-27: Type import moved to public module looks correct

Switching ClaimConditionsInput to thirdweb/utils is cleaner and avoids deep-imports. Using import type keeps it out of the bundle. Good change.


382-394: Hard-coded 18 decimals for maxClaimableSupply; confirm token decimals

toUnits(totalSupply.toString(), 18) assumes 18 decimals for DropERC20. If this contract ever uses non-18 decimals, claim supply math will be off. Validate that DropERC20 is always 18 decimals or derive decimals from the contract before converting.


355-359: claimTo quantity usage is correct per prior guidance

Passing quantity as a token-denominated string (not pre-converted to base units) matches our prior learning that claimTo handles units internally.


1-2: All deep imports for ClaimConditionsInput have been removed
I searched the entire repo for any imports from thirdweb/dist/types/utils/extensions/drops/types and for import type { ClaimConditionsInput } from 'thirdweb/utils'. No matches were found.

apps/portal/tailwind.config.ts (2)

10-12: LGTM on including the UI source in content globs

Pointing to the shared UI package’s src ensures utility classes used inside the library’s components make it into the app build. This aligns with the PR objective to centralize UI.


1-1: No issues: tailwind.config is correctly exported by @workspace/ui

  • packages/ui/tailwind.config.ts exists.
  • package.json exports include "./tailwind.config": "./tailwind.config.ts", so the import will resolve as expected.

@graphite-app
Copy link
Contributor

graphite-app bot commented Aug 16, 2025

Merge activity

created a @workspace/ui package - shared by dashboard and playground. for now it only has button component for testing

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `postcss` and `tailwind` configurations across multiple applications to centralize styles in the `@workspace/ui` package, along with various updates to components and layouts.

### Detailed summary
- Deleted `postcss.config.js` files and replaced them with `postcss.config.mjs` referencing `@workspace/ui`.
- Updated CSS imports to use `@workspace/ui/global.css`.
- Added `tailwindcss` configuration in `@workspace/ui` and updated references.
- Introduced new utility functions in `packages/ui/src/lib/utils.ts`.
- Modified component imports to utilize centralized components from `@workspace/ui`.
- Updated `package.json` files to include `@workspace/ui` as a dependency.
- Refactored button components to use a centralized button definition in `@workspace/ui`.
- Adjusted TypeScript configurations to align with the new structure.
- Enhanced global styles and configurations across multiple applications to ensure consistency.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - Added a shared UI package and unified Button component used across apps.

- Style
  - Apps now load shared global styles and animations from the UI package; global CSS and theme tokens consolidated.

- Bug Fixes
  - AI chat header uses a safe fallback when the client ID is missing.

- Refactor
  - Replaced local UI implementations with shared re-exports and composed Tailwind configs.

- Chores
  - Added UI package dependencies, PostCSS delegation, and enabled Next.js transpilation for the UI package; lint/scan ignore lists updated.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Copy link
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

🔭 Outside diff range comments (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (2)

284-296: SnapshotEntry type mismatch: mapping returns bigint where strings are expected

SnapshotEntry defines maxClaimable: string and price?: string, but the mapper returns bigint for both. This will either fail type-checking or leak non-JSON-serializable bigints at runtime.

Apply this diff to normalize to strings:

-        return raw.claims.map(
-          (claim: {
-            address: string;
-            maxClaimable: bigint;
-            price: bigint;
-            currencyAddress: string;
-          }) => ({
-            address: claim.address,
-            currencyAddress: claim.currencyAddress,
-            maxClaimable: claim.maxClaimable,
-            price: claim.price,
-          }),
-        );
+        return raw.claims.map(
+          (claim: {
+            address: string;
+            maxClaimable: string | number | bigint;
+            price?: string | number | bigint;
+            currencyAddress?: string;
+          }) => ({
+            address: claim.address,
+            currencyAddress: claim.currencyAddress,
+            maxClaimable: claim.maxClaimable.toString(),
+            price: claim.price !== undefined ? claim.price.toString() : undefined,
+          }),
+        );

275-282: Normalize sharded snapshot payload to SnapshotEntry[] instead of returning raw JSON

For sharded trees you currently return the raw JSON for originalEntriesUri. Normalize it to SnapshotEntry[] so downstream consumers get a consistent shape.

Apply this diff:

-        return download({
-          client: client,
-          uri: raw.originalEntriesUri,
-        })
-          .then((r) => r.json())
-          .catch(() => null);
+        return download({
+          client: client,
+          uri: raw.originalEntriesUri,
+        })
+          .then((r) => r.json())
+          .then(
+            (
+              entries: Array<
+                string | { address: string; maxClaimable: string | number | bigint; price?: string | number | bigint; currencyAddress?: string }
+              >,
+            ) =>
+              entries.map((entry) =>
+                typeof entry === "string"
+                  ? { address: entry }
+                  : {
+                      address: entry.address,
+                      currencyAddress: entry.currencyAddress,
+                      maxClaimable: entry.maxClaimable.toString(),
+                      price: entry.price !== undefined ? entry.price.toString() : undefined,
+                    },
+              ),
+          )
+          .catch(() => null);
♻️ Duplicate comments (3)
packages/ui/src/components/button.tsx (2)

4-4: Replace repo-local alias import in shared UI package

Consumers won’t resolve @/lib/utils, so update the import in packages/ui/src/components/button.tsx:

  • File: packages/ui/src/components/button.tsx, Line 4
-import { cn } from "@/lib/utils";
+import { cn } from "../lib/utils";

I ran:

rg -nP "from\s+['\"]@/" packages/ui/src

and confirmed this is the only alias usage in the UI package.


48-76: Fix disabled semantics for non-button renders (asChild) and avoid invalid DOM attributes

Currently, disabled is forwarded to non-button elements (e.g., ), which is invalid, and disabled styles are duplicated on native buttons. Pass disabled only to real buttons, use aria-disabled and inert behavior for non-buttons, and only apply manual disabled classes when not rendering a native button.

Apply this diff:

@@
-    // "button" elements automatically handle the `disabled` attribute.
-    // For non-button elements rendered via `asChild` (e.g. <a>), we still want
-    // to visually convey the disabled state and prevent user interaction.
-    // We do that by conditionally adding the same utility classes that the
-    // `disabled:` pseudo-variant would normally apply and by setting
-    // `aria-disabled` for accessibility.
-    const disabledClass = disabled ? "pointer-events-none opacity-50" : "";
+    // "button" elements automatically handle the `disabled` attribute.
+    // For non-button elements rendered via `asChild` (e.g. <a>), we still want
+    // to visually convey the disabled state and prevent user interaction.
+    // Apply manual disabled styling only when not rendering a native <button>.
+    const disabledClass =
+      asChild && disabled ? "pointer-events-none opacity-50" : "";
@@
-    const btnOnlyProps =
-      Comp === "button"
-        ? {
-            type:
-              (props as React.ButtonHTMLAttributes<HTMLButtonElement>).type ||
-              ("button" as const),
-          }
-        : undefined;
+    const btnOnlyProps =
+      Comp === "button"
+        ? {
+            disabled,
+            type:
+              (props as React.ButtonHTMLAttributes<HTMLButtonElement>).type ??
+              ("button" as const),
+          }
+        : disabled
+        ? { tabIndex: -1 }
+        : undefined;
@@
-      <Comp
-        aria-disabled={disabled ? true : undefined}
+      <Comp
+        aria-disabled={asChild && disabled ? true : undefined}
         className={cn(
           buttonVariants({ className, size, variant }),
           disabledClass,
         )}
-        disabled={disabled}
         ref={ref}
         {...props}
         {...btnOnlyProps}
       />
apps/portal/knip.json (1)

20-23: Don’t ignore @workspace/ui and UI impl details in dependencies (carry-forward)

Keeping "@workspace/ui", "@radix-ui/react-slot", and "tailwindcss-animate" in ignoreDependencies masks true unused-dep signals. Let @workspace/ui own its implementation details and only keep type-only ignores if needed.

Proposed minimal change:

   "ignoreDependencies": [
     "@thirdweb-dev/chains",
     "@thirdweb-dev/wallets",
     "thirdweb",
-    "@workspace/ui",
     "@types/flexsearch",
-    "@radix-ui/react-slot",
-    "tailwindcss-animate"
   ],

If radix-slot or tailwindcss-animate are required by UI components, declare them in packages/ui (dependency or peerDependency) rather than in apps/portal, and remove them from apps/portal/package.json accordingly.

🧹 Nitpick comments (11)
apps/dashboard/tsconfig.json (1)

12-14: Bundler-friendly TS settings look good; consider adding verbatimModuleSyntax for cleaner ESM/CJS interop

Nice move to ESNext modules, Bundler resolution, and ES2022 target. Add "verbatimModuleSyntax": true to align with TS 5 bundler flows and improve tree-shaking by avoiding synthetic default interop.

Apply this minimal change:

   "lib": ["dom", "dom.iterable", "esnext"],
   "module": "ESNext",
   "moduleResolution": "Bundler",
   "moduleDetection": "force",
+  "verbatimModuleSyntax": true,
   "noEmit": true,

Also applies to: 25-25

packages/ui/src/components/button.tsx (1)

21-33: Remove stray trailing spaces in variant class strings

There are extra spaces at the end of some variant class strings (destructive, primary, secondary). Small cleanup to keep diffs tidy.

-        destructive:
-          "bg-destructive hover:bg-destructive/90 text-destructive-foreground ",
+        destructive:
+          "bg-destructive hover:bg-destructive/90 text-destructive-foreground",
@@
-        primary: "bg-primary hover:bg-primary/90 text-primary-foreground ",
+        primary: "bg-primary hover:bg-primary/90 text-primary-foreground",
@@
-        secondary:
-          "bg-secondary hover:bg-secondary/80 text-secondary-foreground ",
+        secondary:
+          "bg-secondary hover:bg-secondary/80 text-secondary-foreground",
apps/playground-web/src/app/ai/components/ChatPageContent.tsx (3)

600-601: Avoid "undefined" token in className; use cn() for safe composition.

Interpolating props.className can yield a literal "undefined" class. Use cn() per app guidelines.

Apply this diff:

-      <div className={`flex flex-col gap-5 py-6 pb-8 ${props.className}`}>
+      <div className={cn("flex flex-col gap-5 py-6 pb-8", props.className)}>

And add the import at the top of the file:

import { cn } from "@/lib/utils";

144-147: Add explicit return type to exported component for consistency with TS guidelines.

Explicit return types help with refactors and align with the repo’s TS conventions.

For example:

export function ChatPageContent(props: {
  client: ThirdwebClient;
  type: "landing" | "new-chat";
}): JSX.Element {
  // ...
}

585-585: Remove unused setEnableAutoScroll prop from SimpleChats

The SimpleChats component no longer uses props.setEnableAutoScroll, so it should be removed from both its signature and its callsite in ChatPageContent.tsx.

• In apps/playground-web/src/app/ai/components/ChatPageContent.tsx, update the SimpleChats declaration (around line 580) to drop setEnableAutoScroll:

-function SimpleChats(props: {
-  messages: Array<ChatMessage>;
-  isChatStreaming: boolean;
-  className?: string;
-  client: ThirdwebClient;
-  setEnableAutoScroll: (enable: boolean) => void;
-  enableAutoScroll: boolean;
-  sendMessage: (message: NebulaUserMessage) => void;
-}) {
+function SimpleChats(props: {
+  messages: Array<ChatMessage>;
+  isChatStreaming: boolean;
+  className?: string;
+  client: ThirdwebClient;
+  enableAutoScroll: boolean;
+  sendMessage: (message: NebulaUserMessage) => void;
+}) {

• In the JSX where SimpleChats is rendered (around lines 372–376), remove the prop:

<SimpleChats
  className="min-w-0"
  client={props.client}
  enableAutoScroll={enableAutoScroll}
  isChatStreaming={isChatStreaming}
  messages={messages}
- setEnableAutoScroll={setEnableAutoScroll}
  sendMessage={handleSendMessage}
/>

[optional_refactors_recommended]

apps/portal/src/app/layout.tsx (1)

9-9: Consider migrating cn to the shared util from @workspace/ui

Given the new centralized utility (cn in @workspace/ui), consider importing it from the UI package to avoid divergence of implementations.

Apply this minimal diff if the UI package re-exports cn:

-import { cn } from "../lib/utils";
+import { cn } from "@workspace/ui/lib/utils";
apps/portal/knip.json (1)

10-14: Narrow the ignore globs to avoid masking unused export detection

Ignoring entire trees like src/components/ui/** and src/icons/** can hide real issues. Prefer targeted ignores (per-file comments or narrower patterns), and plan to remove these once the UI migration stabilizes.

For example, consider dropping the broad UI folder ignore and keeping only specific dynamic cases:

   "ignore": [
-    "src/components/ui/**",
     "src/icons/**",
     "src/components/others/Banner.tsx"
   ],
apps/portal/tailwind.config.ts (1)

4-5: Prefer Tailwind “presets” over object spread for composition

Using presets ensures Tailwind merges themes/plugins correctly and avoids accidental overrides or duplicate plugin execution.

Apply this diff:

 const config: Config = {
-  ...tailwindConfig,
+  presets: [tailwindConfig as Config],
   content: [
@@
   theme: {
-    ...tailwindConfig.theme,
     extend: {
-      ...tailwindConfig.theme?.extend,
       spacing: {
         "offset-top": "calc(var(--sticky-top-height) + 18px)",
         "offset-top-mobile": "calc(var(--sticky-top-height) + 100px)",
         "sidebar-height": "calc(100vh - var(--sticky-top-height))",
         "sticky-top-height": "var(--sticky-top-height)",
       },
       zIndex: {
         // base
         base: "0",
         //
         codeToken: "5",
         codeTokenHighlight: "1",
         //
         copyCodeButton: "20",
         dropdownMenu: "1200",
         floatingButton: "1000",
         menu: "1100",
         modal: "1400",
         modalOverlay: "1300",
         stickyMobileSidebar: "500",
         //
         stickyTop: "1000",
       },
     },
   },
 };

Also applies to: 14-17

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (3)

70-86: Don’t await inside Promise.all — you’re serializing the first request

The leading await inside Promise.all forces getCurrencyMetadata to complete before the other two start, defeating concurrency.

Apply this diff:

   const [currencyMetadata, metadata, contractMetadata] = await Promise.all([
-        await ERC20Ext.getCurrencyMetadata({
+        ERC20Ext.getCurrencyMetadata({
           contract: getContract({
             ...options.contract,
             address: condition.currency,
           }),
         }).then((m) => ({
           ...m,
           displayValue: toTokens(condition.pricePerToken, m.decimals),
           value: condition.pricePerToken,
         })),
         download({
           client: options.contract.client,
           uri: condition.metadata,
         }).then((r) => r.json()),
         getContractMetadata(options),
       ]);

230-233: Handle decimals=0 correctly; use strict undefined check

Using if (decimals) treats 0 as falsy. Tokens can have 0 decimals. Prefer decimals !== undefined in both conversions.

Apply this diff:

-  if (decimals) {
+  if (decimals !== undefined) {
     return toUnits(value.toString(), decimals);
   }
-  if (decimals) {
+  if (decimals !== undefined) {
     return toTokens(value, decimals);
   }

Also applies to: 246-248


125-128: Consider annotating an explicit return type for setClaimPhasesTx

Consistency with the TypeScript guidelines: make return types explicit. If all three setClaimConditions overloads return the same type (e.g., PreparedTransaction), you can reuse that.

Potential change:

-export function setClaimPhasesTx(
+export function setClaimPhasesTx(
   baseOptions: BaseTransactionOptions<Options> & { isSinglePhase?: boolean },
   rawPhases: PhaseInput[],
-) {
+): ReturnType<typeof ERC20Ext.setClaimConditions> {

Please verify ERC721Ext.setClaimConditions and ERC1155Ext.setClaimConditions return the same type; if not, a shared exported type (e.g., PreparedTransaction) from thirdweb/extensions would be preferable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 171eb7e and 92896dd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (46)
  • apps/dashboard/knip.json (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/package.json (1 hunks)
  • apps/dashboard/postcss.config.js (0 hunks)
  • apps/dashboard/postcss.config.mjs (1 hunks)
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx (1 hunks)
  • apps/dashboard/src/@/components/ui/button.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (2 hunks)
  • apps/dashboard/src/app/(app)/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/layout.tsx (1 hunks)
  • apps/dashboard/src/app/login/layout.tsx (1 hunks)
  • apps/dashboard/src/app/pay/layout.tsx (1 hunks)
  • apps/dashboard/tailwind.config.ts (1 hunks)
  • apps/dashboard/tsconfig.json (2 hunks)
  • apps/playground-web/knip.json (1 hunks)
  • apps/playground-web/next.config.mjs (1 hunks)
  • apps/playground-web/package.json (1 hunks)
  • apps/playground-web/postcss.config.js (0 hunks)
  • apps/playground-web/postcss.config.mjs (1 hunks)
  • apps/playground-web/src/app/ai/api/chat.ts (1 hunks)
  • apps/playground-web/src/app/ai/api/types.ts (0 hunks)
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx (2 hunks)
  • apps/playground-web/src/app/globals.css (0 hunks)
  • apps/playground-web/src/app/layout.tsx (1 hunks)
  • apps/playground-web/src/components/ui/button.tsx (1 hunks)
  • apps/playground-web/tailwind.config.ts (1 hunks)
  • apps/portal/knip.json (1 hunks)
  • apps/portal/next.config.mjs (1 hunks)
  • apps/portal/package.json (1 hunks)
  • apps/portal/src/app/globals.css (0 hunks)
  • apps/portal/src/app/layout.tsx (1 hunks)
  • apps/portal/src/components/ui/button.tsx (1 hunks)
  • apps/portal/tailwind.config.ts (1 hunks)
  • apps/wallet-ui/next.config.mjs (0 hunks)
  • packages/thirdweb/src/exports/extensions/marketplace.ts (1 hunks)
  • packages/thirdweb/src/exports/utils.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/postcss.config.mjs (1 hunks)
  • packages/ui/src/components/button.tsx (1 hunks)
  • packages/ui/src/global.css (2 hunks)
  • packages/ui/src/lib/utils.ts (1 hunks)
  • packages/ui/tailwind.config.ts (2 hunks)
  • packages/ui/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (6)
  • apps/dashboard/postcss.config.js
  • apps/playground-web/src/app/globals.css
  • apps/wallet-ui/next.config.mjs
  • apps/playground-web/postcss.config.js
  • apps/playground-web/src/app/ai/api/types.ts
  • apps/portal/src/app/globals.css
🚧 Files skipped from review as they are similar to previous changes (31)
  • apps/playground-web/postcss.config.mjs
  • apps/dashboard/tailwind.config.ts
  • apps/portal/package.json
  • apps/playground-web/package.json
  • apps/dashboard/src/@/components/sponsored-transactions-table/SponsoredTransactionsTable.tsx
  • packages/ui/postcss.config.mjs
  • apps/dashboard/package.json
  • packages/thirdweb/src/exports/utils.ts
  • apps/dashboard/src/app/pay/layout.tsx
  • apps/playground-web/src/app/layout.tsx
  • apps/dashboard/src/app/login/layout.tsx
  • apps/dashboard/postcss.config.mjs
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/types.ts
  • apps/portal/next.config.mjs
  • apps/playground-web/src/components/ui/button.tsx
  • packages/ui/package.json
  • apps/dashboard/src/app/(app)/layout.tsx
  • apps/playground-web/next.config.mjs
  • apps/playground-web/src/app/ai/api/chat.ts
  • packages/ui/src/global.css
  • packages/ui/src/lib/utils.ts
  • apps/dashboard/src/app/bridge/layout.tsx
  • packages/thirdweb/src/exports/extensions/marketplace.ts
  • apps/playground-web/knip.json
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/chain-overview.tsx
  • apps/portal/src/components/ui/button.tsx
  • packages/ui/tsconfig.json
  • packages/ui/tailwind.config.ts
  • apps/playground-web/tailwind.config.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx
  • apps/dashboard/knip.json
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/portal/src/app/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
  • apps/portal/tailwind.config.ts
  • apps/dashboard/next.config.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/portal/src/app/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
  • apps/portal/tailwind.config.ts
  • apps/dashboard/next.config.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts
  • apps/playground-web/src/app/ai/components/ChatPageContent.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/dashboard/next.config.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/portal/src/app/layout.tsx
  • apps/dashboard/src/@/components/ui/button.tsx
  • apps/portal/tailwind.config.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use Tailwind CSS only – no inline styles or CSS modules

Applied to files:

  • apps/portal/src/app/layout.tsx
  • apps/dashboard/tsconfig.json
  • apps/portal/tailwind.config.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`

Applied to files:

  • apps/dashboard/tsconfig.json
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.

Applied to files:

  • apps/dashboard/tsconfig.json
  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{ts,tsx} : Export default async functions without `'use client';` – they run on the Node edge.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Pages requiring fast transitions where data is prefetched on the client.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/@/components/ui/button.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `cn()` from `@/lib/utils` for conditional class logic

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • packages/ui/src/components/button.tsx
📚 Learning: 2025-06-18T02:01:06.006Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7363
File: apps/dashboard/src/app/(app)/layout.tsx:63-74
Timestamp: 2025-06-18T02:01:06.006Z
Learning: In Next.js applications, instrumentation files (instrumentation.ts or instrumentation-client.ts) placed in the src/ directory are automatically handled by the framework and included in the client/server bundles without requiring manual imports. The framework injects these files as part of the build process.

Applied to files:

  • apps/portal/knip.json
🧬 Code Graph Analysis (1)
apps/portal/tailwind.config.ts (1)
packages/ui/postcss.config.mjs (1)
  • config (2-7)
⏰ 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). (8)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/next.config.ts (1)

118-118: Adding transpilePackages for @workspace/ui is correct

This ensures TS/modern syntax in the shared UI compiles under Next and allows CSS imports (global.css) from the package to work properly.

apps/dashboard/src/@/components/ui/button.tsx (1)

1-3: Client boundary + re-export pattern LGTM

Explicit 'use client' on this proxy prevents server/client boundary pitfalls. Re-exporting from the shared UI package is clean and centralizes the API.

apps/playground-web/src/app/ai/components/ChatPageContent.tsx (1)

35-35: No leftover history types/helpers in playground-web
Ran a project-wide search for NebulaSessionHistoryMessage and parseHistoryToMessages and confirmed there are no occurrences under apps/playground-web.

apps/portal/src/app/layout.tsx (1)

1-2: No duplicate Tailwind preflight rules detected

Verified that only packages/ui/src/global.css contains the @tailwind base/components/utilities directives and that the local apps/portal/src/globals.css has no Tailwind layer directives. Your import order is correct—there will be only one preflight reset.

apps/portal/tailwind.config.ts (1)

10-12: Including UI sources in content is correct for JIT class extraction

Scanning "../../packages/ui/src/**/*.{ts,tsx}" ensures classes used in shared UI components are not purged in the app bundle.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/hooks.ts (2)

28-36: Prettify removal is fine; type remains clear and accurate

Dropping Prettify<> is harmless here and keeps the shape readable without altering the effective surface.


13-15: Consolidate thirdweb/utils imports

No occurrences of the old thirdweb/dist/... path were found—feel free to merge these into a single import:

-import type { OverrideEntry } from "thirdweb/utils";
-import { maxUint256 } from "thirdweb/utils";
+import { maxUint256, type OverrideEntry } from "thirdweb/utils";

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard. Ecosystem Portal Involves changes to the Ecosystem Portal packages Playground Changes involving the Playground codebase. Portal Involves changes to the Portal (docs) codebase. SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants