style(admin): color paid Grok and OpenAI plan badges

Keep free muted gray; SuperGrok cyan, Heavy purple, and distinct colors for
OpenAI Plus/Team/Pro so paid subscriptions stand out in the account list.
This commit is contained in:
IanShaw027
2026-08-08 08:48:38 +08:00
parent e1d6600eb2
commit 6345b048d1
2 changed files with 57 additions and 1 deletions
@@ -139,6 +139,8 @@ const planLabel = computed(() => {
return 'SuperGrok'
case 'supergrokheavy':
return 'SuperGrok Heavy'
case 'heavy':
return 'Heavy'
case 'abnormal':
return t('admin.accounts.subscriptionAbnormal')
default:
@@ -153,9 +155,12 @@ const isGrokFreePlan = computed(() =>
const planIconName = computed<'bolt' | null>(() => {
if (props.platform !== 'grok') return null
// Paid Grok tiers (SuperGrok / Heavy) share the bolt mark; free uses GrokFreeIcon.
if (
normalizedPlanType.value === 'supergrok' ||
normalizedPlanType.value === 'supergrokheavy'
normalizedPlanType.value === 'supergrokheavy' ||
normalizedPlanType.value === 'heavy' ||
normalizedPlanType.value.includes('heavy')
) {
return 'bolt'
}
@@ -198,6 +203,32 @@ const planBadgeClass = computed(() => {
if (normalizedPlanType.value === 'abnormal') {
return 'bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400'
}
// Free stays muted gray; paid Grok tiers get distinct colors (aligned with personal-dev).
if (normalizedPlanType.value === 'free' || normalizedPlanType.value === 'basic') {
return 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300'
}
if (props.platform === 'grok' && normalizedPlanType.value) {
// Heavy / SuperGrok Heavy → purple
if (normalizedPlanType.value.includes('heavy')) {
return 'bg-purple-100 text-purple-600 dark:bg-purple-900/30 dark:text-purple-300'
}
// SuperGrok → cyan
if (normalizedPlanType.value.includes('supergrok')) {
return 'bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-300'
}
// Any other non-free Grok plan (future tiers) → amber so it still stands out
return 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300'
}
// OpenAI / other paid plan labels: keep readable distinction from free gray
if (normalizedPlanType.value === 'plus') {
return 'bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300'
}
if (normalizedPlanType.value === 'team') {
return 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300'
}
if (normalizedPlanType.value === 'pro' || normalizedPlanType.value === 'chatgptpro') {
return 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300'
}
return typeClass.value
})
@@ -46,6 +46,8 @@ describe('PlatformTypeBadge Grok plans', () => {
expect(wrapper.text()).toContain('SuperGrok Heavy')
expect(wrapper.find('[data-testid="grok-plan-icon"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="grok-free-plan-icon"]').exists()).toBe(false)
// Heavy uses purple plan chip (personal-dev parity)
expect(wrapper.html()).toContain('bg-purple-100')
await wrapper.setProps({ platform: 'openai', planType: 'free' })
expect(wrapper.text()).toContain('Free')
@@ -53,6 +55,29 @@ describe('PlatformTypeBadge Grok plans', () => {
expect(wrapper.find('[data-testid="grok-plan-icon"]').exists()).toBe(false)
})
it('colors free gray, SuperGrok cyan, and Heavy purple', async () => {
const free = mount(PlatformTypeBadge, {
props: { platform: 'grok', type: 'oauth', planType: 'free' },
})
expect(free.html()).toContain('bg-gray-100')
expect(free.html()).not.toContain('bg-purple-100')
expect(free.html()).not.toContain('bg-cyan-100')
const superGrok = mount(PlatformTypeBadge, {
props: { platform: 'grok', type: 'oauth', planType: 'supergrok' },
})
expect(superGrok.text()).toContain('SuperGrok')
expect(superGrok.html()).toContain('bg-cyan-100')
expect(superGrok.find('[data-testid="grok-plan-icon"]').exists()).toBe(true)
const heavy = mount(PlatformTypeBadge, {
props: { platform: 'grok', type: 'oauth', planType: 'Heavy' },
})
expect(heavy.text()).toContain('Heavy')
expect(heavy.html()).toContain('bg-purple-100')
expect(heavy.find('[data-testid="grok-plan-icon"]').exists()).toBe(true)
})
it('uses a dedicated 12px currentColor Grok mark with a Free sparkle', () => {
const wrapper = mount(GrokFreeIcon)