fix(provider-badge): unify provider icon spacing

- add a shared provider badge component for icon and status label layout.
- reuse it in channel type and model vendor columns so OpenAI icons align consistently.
This commit is contained in:
QuentinHsu
2026-06-10 22:10:44 +08:00
parent ac694fbc9f
commit b5d13a6fee
3 changed files with 51 additions and 22 deletions
+44
View File
@@ -0,0 +1,44 @@
/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { getLobeIcon } from '@/lib/lobe-icon'
import { cn } from '@/lib/utils'
import { StatusBadge, type StatusBadgeProps } from './status-badge'
type ProviderBadgeProps = Omit<StatusBadgeProps, 'children' | 'label'> & {
iconKey?: string | null
iconSize?: number
label: string
}
export function ProviderBadge({
className,
iconKey,
iconSize = 14,
label,
...badgeProps
}: ProviderBadgeProps) {
const icon = iconKey ? getLobeIcon(iconKey, iconSize) : null
return (
<div className={cn('flex items-center gap-1.5', className)}>
{icon}
<StatusBadge label={label} autoColor={label} size='sm' {...badgeProps} />
</div>
)
}
@@ -35,7 +35,6 @@ import {
formatTimestampToDate,
formatQuota as formatQuotaValue,
} from '@/lib/format'
import { getLobeIcon } from '@/lib/lobe-icon'
import { truncateText } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
@@ -48,6 +47,7 @@ import {
import { ConfirmDialog } from '@/components/confirm-dialog'
import { DataTableColumnHeader } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { ProviderBadge } from '@/components/provider-badge'
import { StatusBadge, StatusBadgeList } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import { TruncatedText } from '@/components/truncated-text'
@@ -623,7 +623,6 @@ export function useChannelsColumns(): ColumnDef<Channel>[] {
const typeNameKey = getChannelTypeLabel(type)
const typeName = t(typeNameKey)
const iconName = getChannelTypeIcon(type)
const icon = getLobeIcon(`${iconName}.Color`, 14)
const channel = row.original as Channel
const isMultiKey = isMultiKeyChannel(channel)
const multiKeyMode = channel.channel_info?.multi_key_mode ?? 'random'
@@ -657,16 +656,12 @@ export function useChannelsColumns(): ColumnDef<Channel>[] {
</Tooltip>
</TooltipProvider>
)}
<StatusBadge
autoColor={typeName}
size='sm'
<ProviderBadge
iconKey={iconName}
label={typeName}
copyable={false}
showDot={false}
className='gap-1 pl-1'
>
{icon}
<span className='truncate'>{typeName}</span>
</StatusBadge>
/>
{isIonet && (
<TooltipProvider delay={100}>
<Tooltip>
@@ -29,6 +29,7 @@ import {
} from '@/components/ui/tooltip'
import { DataTableColumnHeader } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { ProviderBadge } from '@/components/provider-badge'
import { StatusBadge, StatusBadgeList } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import {
@@ -269,18 +270,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef<Model>[] {
return <span className='text-muted-foreground text-xs'>-</span>
}
const icon = vendor.icon ? getLobeIcon(vendor.icon, 14) : null
return (
<div className='flex items-center gap-1.5'>
{icon}
<StatusBadge
label={vendor.name}
autoColor={vendor.name}
size='sm'
/>
</div>
)
return <ProviderBadge iconKey={vendor.icon} label={vendor.name} />
},
filterFn: (row, id, value) => {
if (!value || value.length === 0 || value.includes('all')) return true