Skip to content

Consolidated Shade components#27405

Open
peterzimon wants to merge 1 commit intomainfrom
DES-1343/shade-component-consolidation
Open

Consolidated Shade components#27405
peterzimon wants to merge 1 commit intomainfrom
DES-1343/shade-component-consolidation

Conversation

@peterzimon
Copy link
Copy Markdown
Contributor

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

Walkthrough

This pull request renames KPI-related UI components and variant names to more general Metric equivalents across multiple applications. Specifically, component names are updated (e.g., KpiCardHeaderMetricCardHeader, KpiTabTriggerMetricTabTrigger) and variant properties are renamed (e.g., variant='kpis'variant='metrics', variant='cardhead'variant='section'). Deprecated aliases are added to maintain backward compatibility. Changes are applied consistently across component implementations, Storybook stories, and consuming files in the posts, shade, and stats applications.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Consolidated Shade components' is vague and generic, using non-descriptive terms that don't convey meaningful information about the specific changes. Consider a more specific title that describes the main consolidation effort, such as 'Rename KPI components to Metric variants with deprecation aliases' or 'Refactor KPI naming to Metric-based components across Shade and dependent apps'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description provides a reference to a Linear issue tracking the component consolidation work, which is related to the changeset's objective of consolidating Shade components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DES-1343/shade-component-consolidation

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.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
3.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/shade/src/components/ui/card.stories.tsx (1)

120-126: Use the built-in color prop in these stories.

Both stories re-create the color indicator with inline markup even though MetricCardHeaderLabel already exposes color. That makes Storybook document the implementation detail instead of the public API.

As per coding guidelines "In story content, prefer CVA variants/props over ad-hoc class overrides; avoid obvious technical implementation details and prefer one-line guidance per story explaining when to use that variant/size/state".

Also applies to: 170-173

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/shade/src/components/ui/card.stories.tsx` around lines 120 - 126, The
story recreates the color indicator markup instead of using the public API:
replace the manual inline span and style with the MetricCardHeaderLabel's color
prop (e.g., pass color="purple" or the appropriate variant name) in the
MetricCardHeaderLabel component used at lines ~120 and ~170; remove the extra
<span className='inline-block ...' style={{backgroundColor: ...}}/> markup and
update the story text to a one-line note about when to use that color variant.
apps/shade/src/components/ui/tabs.tsx (1)

11-25: Export tabsVariants with deprecated variant support for API consistency.

While the Tabs component correctly resolves deprecated 'navbar''navigation' and 'kpis''metrics' mappings, the exported tabsVariants helper only recognizes the new variant names. This creates an inconsistency in the public API surface: direct callers of the helper will fail if they pass the deprecated names, even though the component itself accepts them. Since tabsVariants is exported as part of the package, maintaining parity between the component and helper is a best practice.

Consider wrapping tabsVariants to apply the same deprecation mapping:

Suggested approach
-const tabsVariants = cva(
+const tabsVariantsBase = cva(
     '',
     {
         variants: {
             variant: {
                 segmented: '',
                 'segmented-sm': '',
                 button: '',
                 'button-sm': '',
                 underline: '',
                 navigation: '',
                 pill: '',
                 metrics: ''
             }
         },
         defaultVariants: {
             variant: 'segmented'
         }
     }
 );
+
+const tabsVariants = (props?: {variant?: TabsVariant; [key: string]: any}) => {
+    if (!props) return tabsVariantsBase();
+    const {variant, ...rest} = props;
+    return tabsVariantsBase({
+        ...rest,
+        variant: variant ? resolveTabsVariant(variant) : undefined
+    });
+};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/shade/src/components/ui/tabs.tsx` around lines 11 - 25, Exported helper
tabsVariants currently only accepts PreferredTabsVariant names, causing callers
using deprecated names ('navbar'/'kpis') to fail; wrap or adapt tabsVariants to
normalize its input using the existing resolveTabsVariant(variant: TabsVariant)
mapping so it accepts TabsVariant (including DeprecatedTabsVariant) and
internally converts deprecated values to PreferredTabsVariant before performing
its logic; update the tabsVariants signature/type to accept TabsVariant and call
resolveTabsVariant at the start of the function so behavior matches the Tabs
component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/shade/src/components/ui/tabs.tsx`:
- Around line 188-199: MetricTabTrigger currently allows incoming
props.className to overwrite the base 'h-auto' class because props are spread
after the literal className; fix by destructuring className from
MetricTabTriggerProps (e.g., const MetricTabTrigger = ({ children, className,
...rest }) => ...) and merge it with the base class using the project's utility
(cn('h-auto', className)), then pass the merged className to TabsTrigger along
with ...rest; keep MetricTabTrigger.displayName unchanged.

---

Nitpick comments:
In `@apps/shade/src/components/ui/card.stories.tsx`:
- Around line 120-126: The story recreates the color indicator markup instead of
using the public API: replace the manual inline span and style with the
MetricCardHeaderLabel's color prop (e.g., pass color="purple" or the appropriate
variant name) in the MetricCardHeaderLabel component used at lines ~120 and
~170; remove the extra <span className='inline-block ...'
style={{backgroundColor: ...}}/> markup and update the story text to a one-line
note about when to use that color variant.

In `@apps/shade/src/components/ui/tabs.tsx`:
- Around line 11-25: Exported helper tabsVariants currently only accepts
PreferredTabsVariant names, causing callers using deprecated names
('navbar'/'kpis') to fail; wrap or adapt tabsVariants to normalize its input
using the existing resolveTabsVariant(variant: TabsVariant) mapping so it
accepts TabsVariant (including DeprecatedTabsVariant) and internally converts
deprecated values to PreferredTabsVariant before performing its logic; update
the tabsVariants signature/type to accept TabsVariant and call
resolveTabsVariant at the start of the function so behavior matches the Tabs
component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae643128-73da-47e3-8ae6-02a146862cdf

📥 Commits

Reviewing files that changed from the base of the PR and between 70a792c and aaf93fb.

📒 Files selected for processing (14)
  • apps/posts/src/views/PostAnalytics/Overview/components/newsletter-overview.tsx
  • apps/posts/src/views/PostAnalytics/Overview/components/web-overview.tsx
  • apps/posts/src/views/PostAnalytics/Web/components/kpis.tsx
  • apps/shade/src/components/ui/card.stories.tsx
  • apps/shade/src/components/ui/card.tsx
  • apps/shade/src/components/ui/table.stories.tsx
  • apps/shade/src/components/ui/table.tsx
  • apps/shade/src/components/ui/tabs.stories.tsx
  • apps/shade/src/components/ui/tabs.tsx
  • apps/stats/src/views/Stats/Growth/components/growth-kpis.tsx
  • apps/stats/src/views/Stats/Newsletters/components/newsletters-kpis.tsx
  • apps/stats/src/views/Stats/Newsletters/newsletters.tsx
  • apps/stats/src/views/Stats/Overview/components/overview-kpis.tsx
  • apps/stats/src/views/Stats/Web/components/web-kpis.tsx

Comment on lines +188 to +199
interface MetricTabTriggerProps extends React.ComponentProps<typeof TabsTrigger> {
children: React.ReactNode;
}

const KpiTabTrigger: React.FC<KpiTabTriggerProps> = ({children, ...props}) => {
const MetricTabTrigger: React.FC<MetricTabTriggerProps> = ({children, ...props}) => {
return (
<TabsTrigger className='h-auto' {...props}>
{children}
</TabsTrigger>
);
};
MetricTabTrigger.displayName = 'MetricTabTrigger';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether any current call sites already pass className to Metric/KPI tab triggers.
rg -nP --type=tsx '<(MetricTabTrigger|KpiTabTrigger)\b[^>]*\bclassName=' -C2

Repository: TryGhost/Ghost

Length of output: 85


🏁 Script executed:

# First, read the file to confirm the current code state and imports
cat -n apps/shade/src/components/ui/tabs.tsx | head -210 | tail -50

Repository: TryGhost/Ghost

Length of output: 1781


🏁 Script executed:

# Check if cn() is imported in the file
rg -n "^import.*cn" apps/shade/src/components/ui/tabs.tsx

Repository: TryGhost/Ghost

Length of output: 91


🏁 Script executed:

# Search for MetricTabTrigger and KpiTabTrigger definitions and usages
rg -n "MetricTabTrigger|KpiTabTrigger" apps/shade/src/components/ui/tabs.tsx

Repository: TryGhost/Ghost

Length of output: 437


🏁 Script executed:

# Search for MetricTabTrigger usage across the codebase
rg -l "MetricTabTrigger" --type=ts --type=js --type=tsx --type=jsx

Repository: TryGhost/Ghost

Length of output: 85


🏁 Script executed:

# Search for MetricTabTrigger usage across the codebase
rg "MetricTabTrigger|KpiTabTrigger" -B2 -A2 | head -100

Repository: TryGhost/Ghost

Length of output: 10577


🏁 Script executed:

# Search specifically for className being passed to these components
rg "<(MetricTabTrigger|KpiTabTrigger)" -B1 -A3 | grep -A3 "className"

Repository: TryGhost/Ghost

Length of output: 2804


Merge className in MetricTabTrigger instead of letting props overwrite it.

Callers in newsletters-kpis.tsx and growth-kpis.tsx are passing className to add conditional styling (e.g., cursor-auto after:hidden). Currently, these custom classes overwrite the base h-auto styling because props spreads after the literal prop. Destructure and merge with cn() to preserve both.

Suggested change
-const MetricTabTrigger: React.FC<MetricTabTriggerProps> = ({children, ...props}) => {
+const MetricTabTrigger: React.FC<MetricTabTriggerProps> = ({children, className, ...props}) => {
     return (
-        <TabsTrigger className='h-auto' {...props}>
+        <TabsTrigger className={cn('h-auto', className)} {...props}>
             {children}
         </TabsTrigger>
     );
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface MetricTabTriggerProps extends React.ComponentProps<typeof TabsTrigger> {
children: React.ReactNode;
}
const KpiTabTrigger: React.FC<KpiTabTriggerProps> = ({children, ...props}) => {
const MetricTabTrigger: React.FC<MetricTabTriggerProps> = ({children, ...props}) => {
return (
<TabsTrigger className='h-auto' {...props}>
{children}
</TabsTrigger>
);
};
MetricTabTrigger.displayName = 'MetricTabTrigger';
interface MetricTabTriggerProps extends React.ComponentProps<typeof TabsTrigger> {
children: React.ReactNode;
}
const MetricTabTrigger: React.FC<MetricTabTriggerProps> = ({children, className, ...props}) => {
return (
<TabsTrigger className={cn('h-auto', className)} {...props}>
{children}
</TabsTrigger>
);
};
MetricTabTrigger.displayName = 'MetricTabTrigger';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/shade/src/components/ui/tabs.tsx` around lines 188 - 199,
MetricTabTrigger currently allows incoming props.className to overwrite the base
'h-auto' class because props are spread after the literal className; fix by
destructuring className from MetricTabTriggerProps (e.g., const MetricTabTrigger
= ({ children, className, ...rest }) => ...) and merge it with the base class
using the project's utility (cn('h-auto', className)), then pass the merged
className to TabsTrigger along with ...rest; keep MetricTabTrigger.displayName
unchanged.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant