Skip to content

Conversation

@lukevella
Copy link
Owner

@lukevella lukevella commented Jan 5, 2026

Summary by CodeRabbit

  • New Features
    • Added a new Branding settings page in the control panel for customizing primary colors, dark mode variants, and logo assets
    • Added Branding navigation in the control panel sidebar and dashboard grid
    • Includes environment variable override support and enterprise licensing checks for custom branding

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

@vercel
Copy link

vercel bot commented Jan 5, 2026

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

Project Deployment Review Updated (UTC)
app Ready Ready Preview, Comment Jan 5, 2026 5:20pm
1 Skipped Deployment
Project Deployment Review Updated (UTC)
landing Skipped Skipped Jan 5, 2026 5:20pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

Walkthrough

This PR introduces a new Branding control panel page allowing admins to view and manage primary colors, dark mode colors, logos, and white-label addon status. The feature includes navigation updates, localization entries, and a supporting query for white-label addon detection.

Changes

Cohort / File(s) Summary
Localization
apps/web/public/locales/en/app.json
Added 12 new translation keys for branding feature (setEnvironmentVariable, branding, brandingDescription, customBrandingAlertDescription, colors, colorsDescription, primaryColor, primaryColorDark, logos, logosDescription, logo, logoIcon).
New Branding Page
apps/web/src/app/[locale]/control-panel/branding/page.tsx
Created async React page component with admin authorization check, loads branding data (colors, logos, white-label status), renders Colors and Logos card sections with environment-variable hints, displays enterprise-only alert if custom branding unavailable, exports generateMetadata for page title.
Navigation Updates
apps/web/src/app/[locale]/control-panel/sidebar.tsx, apps/web/src/app/[locale]/control-panel/page.tsx
Added Branding nav item to sidebar and corresponding Branding tile to control panel grid (with PaletteIcon), both linking to /control-panel/branding; imported PaletteIcon from lucide-react.
Branding Queries
apps/web/src/features/branding/queries.ts
Added new public async function hasWhiteLabelAddon() that loads instance license and returns whiteLabelAddon flag (defaults to false).

Sequence Diagram(s)

sequenceDiagram
    actor Admin
    participant Page as BrandingPage
    participant LoadData as loadData()
    participant Auth as Authorization
    participant Queries as Branding Queries
    participant License as License Service
    participant UI as Render Components

    Admin->>Page: Navigate to /control-panel/branding
    Page->>LoadData: Call loadData()
    LoadData->>Auth: Check admin role
    alt Admin verified
        LoadData->>Queries: Query branding data (colors, logos)
        LoadData->>Queries: hasWhiteLabelAddon()
        Queries->>License: loadInstanceLicense()
        License-->>Queries: License data with whiteLabelAddon flag
        Queries-->>LoadData: Branding data + addon status
        LoadData-->>Page: Return branding data
        Page->>UI: Render SettingsPage with Colors & Logos sections
        UI-->>Admin: Display branding configuration UI
    else Not admin
        Auth-->>Page: Redirect or error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🎨 A palette of change hops into sight,
With colors and logos, the branding shines bright!
The sidebar and grid now guide the way true,
While admins control what their brand will do.
One query to check if white-labels align—
The rabbits rejoice! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add branding page' accurately summarizes the main change—introducing a new branding settings page with associated UI components and localization entries.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch branding-page

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/src/app/[locale]/control-panel/branding/page.tsx (1)

60-67: Variable shadowing: hasWhiteLabelAddon shadows the imported function.

The destructured variable hasWhiteLabelAddon on line 66 shadows the imported function of the same name from line 26. Consider renaming the variable to avoid confusion.

🔎 Proposed fix
 export default async function BrandingPage() {
   const {
     primaryColor,
     primaryColorDark,
     logoUrl,
     logoIconUrl,
-    hasWhiteLabelAddon,
+    hasWhiteLabelAddon: whiteLabelEnabled,
   } = await loadData();
 
   return (
     <SettingsPage>
       ...
       <SettingsPageContent>
-        {!hasWhiteLabelAddon ? (
+        {!whiteLabelEnabled ? (
           <Alert variant="primary">
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4151729 and eb9dce2.

📒 Files selected for processing (5)
  • apps/web/public/locales/en/app.json
  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/features/branding/queries.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Use dayjs for date handling
Use react-query for data fetching
Prefer implicit return values over explicit return values
Use zod for form validation
Create separate import statements for types
Prefer using the React module APIs (e.g. React.useState) instead of standalone hooks (e.g. useState)
Prefer double quotes for strings over single quotes
Only add comments when it is necessary to explain code that isn't self-explanatory

**/*.{ts,tsx}: Only create named interfaces when they're reused or complex
When TypeScript errors occur for missing i18n keys, run pnpm i18n:scan instead of manually adding keys

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/src/features/branding/queries.ts
**/*.{tsx,css,config.ts}

📄 CodeRabbit inference engine (.cursorrules)

Use tailwindcss for styling

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use react-hook-form for form handling
All text in the UI should be translated using either the Trans component or the useTranslation hook
Prefer composable components in the style of shadcn UI over large monolithic components
DropdownMenuItem is a flex container with a preset gap so there is no need to add margins to the children
The size and colour of an icon should be set by wrapping it with the component from @rallly/ui/icon which will give it the correct colour and size
Keep the props of a component as minimal as possible. Pass only the bare minimum amount of information needed to it
All text in the UI should be translatable
Use the component in client components from @/components/trans with the defaults prop to provide the default text
Always use a composable patterns when building components
Use cn() from @rallly/ui to compose classes
Add the "use client" directive to the top of any .tsx file that requires client-side javascript

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,json}: i18n keys are in camelCase
i18nKeys should describe the message in camelCase. Ex. "lastUpdated": "Last Updated"
If the i18nKey is not intended to be reused, prefix it with the component name in camelCase

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/public/locales/en/app.json
  • apps/web/src/features/branding/queries.ts
**/*

📄 CodeRabbit inference engine (.cursorrules)

Always use kebab-case for file names

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/public/locales/en/app.json
  • apps/web/src/features/branding/queries.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Biome for code formatting with indent of 2 spaces and double quotes

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/src/features/branding/queries.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{tsx,ts}: Prefer inline prop types over named interfaces for simple component props (e.g., function Component({ prop }: { prop: string }) instead of defining a separate interface)
Always use the useDialog hook from @rallly/ui/dialog for managing dialog state instead of manual useState for open/close state
Use TanStack Query with tRPC for server state management
Use React Context for client state (auth, preferences, etc.)
Use react-hook-form with Zod validation for form state management
Use TailwindCSS with custom design system for styling

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/src/features/branding/queries.ts
apps/web/src/app/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Next.js App Router conventions for route handlers

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/better-auth.md)

apps/web/**/*.{ts,tsx,js,jsx}: When using the username plugin, require all sign up endpoints to accept a username (used for login, normalized) and an optional displayUsername (raw, for display purposes).
When using the username plugin, all username values must be normalized according to the configuration function before storage or comparison (default: lowercase).
Whenever updating a user's username, always check for uniqueness and apply the normalization procedure.
Login endpoints or forms supporting username authentication must allow signing in with username and password, not just email.

Files:

  • apps/web/src/app/[locale]/control-panel/branding/page.tsx
  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
  • apps/web/src/features/branding/queries.ts
**/*.ts

📄 CodeRabbit inference engine (.cursorrules)

On the server use the getTranslations function from @/i18n/server to get the translations

Files:

  • apps/web/src/features/branding/queries.ts
apps/web/src/features/**

📄 CodeRabbit inference engine (CLAUDE.md)

Organize features in apps/web/src/features/[feature]/ directory structure

Files:

  • apps/web/src/features/branding/queries.ts
🧠 Learnings (2)
📚 Learning: 2025-11-25T11:03:55.173Z
Learnt from: CR
Repo: lukevella/rallly PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T11:03:55.173Z
Learning: Applies to **/*.tsx : The size and colour of an icon should be set by wrapping it with the <Icon> component from rallly/ui/icon which will give it the correct colour and size

Applied to files:

  • apps/web/src/app/[locale]/control-panel/sidebar.tsx
  • apps/web/src/app/[locale]/control-panel/page.tsx
📚 Learning: 2025-11-25T11:04:05.725Z
Learnt from: CR
Repo: lukevella/rallly PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T11:04:05.725Z
Learning: Applies to **/*.{tsx,ts} : Use React Context for client state (auth, preferences, etc.)

Applied to files:

  • apps/web/src/features/branding/queries.ts
🧬 Code graph analysis (4)
apps/web/src/app/[locale]/control-panel/branding/page.tsx (4)
apps/web/src/features/branding/queries.ts (4)
  • getPrimaryColor (16-18)
  • getLogoUrl (44-46)
  • hasWhiteLabelAddon (52-55)
  • getLogoIconUrl (48-50)
apps/web/src/env.ts (1)
  • env (6-210)
packages/ui/src/alert.tsx (2)
  • Alert (71-71)
  • AlertDescription (71-71)
apps/web/src/app/[locale]/control-panel/page.tsx (1)
  • generateMetadata (146-150)
apps/web/src/app/[locale]/control-panel/sidebar.tsx (1)
apps/web/src/app/[locale]/control-panel/nav-item.tsx (1)
  • NavItem (7-24)
apps/web/src/app/[locale]/control-panel/page.tsx (3)
packages/ui/src/tile.tsx (2)
  • Tile (79-79)
  • TileTitle (79-79)
packages/emails/src/components/styled-components.tsx (1)
  • Link (73-80)
apps/web/src/app/components/page-icons.tsx (1)
  • PageIcon (50-62)
apps/web/src/features/branding/queries.ts (1)
apps/web/src/features/licensing/data.ts (1)
  • loadInstanceLicense (24-43)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Integration tests
🔇 Additional comments (6)
apps/web/public/locales/en/app.json (1)

566-578: LGTM!

The new i18n keys follow camelCase convention and provide appropriate translations for the branding feature. The setEnvironmentVariable key correctly uses the <env /> component placeholder for dynamic content rendering.

apps/web/src/features/branding/queries.ts (1)

52-55: LGTM!

The hasWhiteLabelAddon function correctly loads the instance license and safely returns the whiteLabelAddon flag with a false default when the license is absent or the property is undefined.

apps/web/src/app/[locale]/control-panel/page.tsx (1)

113-125: LGTM!

The Branding tile follows the established pattern of other tiles in the grid, using PageIcon to wrap the icon and Trans for internationalization. The structure is appropriately simple, consistent with the Settings tile.

apps/web/src/app/[locale]/control-panel/sidebar.tsx (1)

54-57: LGTM!

The new Branding nav item follows the existing pattern in this sidebar file, using direct className="size-4" on the icon consistent with other menu items.

apps/web/src/app/[locale]/control-panel/branding/page.tsx (2)

41-58: LGTM!

The SetEnvironmentVariableAlert component is well-designed with inline prop types, proper use of the Trans component for interpolation, and appropriate styling for the environment variable code display.


202-207: LGTM!

The generateMetadata function correctly uses getTranslation from @/i18n/server for server-side translation, following the coding guidelines.

@lukevella lukevella merged commit cfd8bdf into main Jan 5, 2026
12 checks passed
@lukevella lukevella deleted the branding-page branch January 5, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants