🎨 fix(theme): align UI controls with global radius tokens
Remove hard-coded and capped border radius overrides so shared controls and feature actions consistently follow the active theme radius. - Replace fixed radius utilities with semantic theme-aware radius tokens - Remove redundant `rounded-full` and pixel-based overrides from header, toolbar, Playground, and utility actions - Drop unused `StatusBadge` rounded prop usage - Keep existing component behavior intact while improving global theme consistency
This commit is contained in:
@@ -75,7 +75,7 @@ export function OAuthCallbackScreen({
|
||||
<AuthLayout>
|
||||
<div className='w-full space-y-8'>
|
||||
<div className='flex flex-col items-center space-y-4 text-center'>
|
||||
<div className='bg-muted flex h-16 w-16 items-center justify-center rounded-full'>
|
||||
<div className='bg-muted flex h-16 w-16 items-center justify-center rounded-2xl'>
|
||||
<Icon className='h-8 w-8' />
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
|
||||
Vendored
+1
-1
@@ -92,7 +92,7 @@ export function SecureVerificationDialog({
|
||||
<div className='flex-1 overflow-y-auto px-6 py-5'>
|
||||
{availableTabs.length === 0 ? (
|
||||
<div className='grid place-items-center gap-4 text-center'>
|
||||
<div className='bg-muted flex h-16 w-16 items-center justify-center rounded-full'>
|
||||
<div className='bg-muted flex h-16 w-16 items-center justify-center rounded-2xl'>
|
||||
<ShieldCheck className='text-muted-foreground h-8 w-8' />
|
||||
</div>
|
||||
<p className='text-muted-foreground text-sm'>
|
||||
|
||||
@@ -637,7 +637,7 @@ export function useChannelsColumns(): ColumnDef<Channel>[] {
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={
|
||||
<span className='border-border bg-muted text-primary inline-flex h-6 w-6 items-center justify-center rounded-full border' />
|
||||
<span className='border-border bg-muted text-primary inline-flex h-6 w-6 items-center justify-center rounded-md border' />
|
||||
}
|
||||
>
|
||||
<MultiKeyModeIcon className='h-3.5 w-3.5' />
|
||||
|
||||
+1
-1
@@ -264,7 +264,7 @@ function RateLimitGroupSection(props: RateLimitGroupSectionProps) {
|
||||
<div className='text-muted-foreground flex flex-wrap items-center gap-2 text-xs'>
|
||||
{props.description && <span>{props.description}</span>}
|
||||
{props.meteredFeature && (
|
||||
<span className='bg-muted/60 inline-flex max-w-full items-center gap-2 rounded-full px-2 py-0.5'>
|
||||
<span className='bg-muted/60 inline-flex max-w-full items-center gap-2 rounded-md px-2 py-0.5'>
|
||||
<span className='text-[11px]'>metered_feature</span>
|
||||
<span className='min-w-0 font-mono text-xs break-all'>
|
||||
{props.meteredFeature}
|
||||
|
||||
+15
-2
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { VChart } from '@visactor/react-vchart'
|
||||
import { AreaChart, BarChart3, WalletCards } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThemeRadiusPx } from '@/lib/theme-radius'
|
||||
import type { TimeGranularity } from '@/lib/time'
|
||||
import { VCHART_OPTION } from '@/lib/vchart'
|
||||
import { useThemeCustomization } from '@/context/theme-customization-provider'
|
||||
@@ -41,6 +42,10 @@ export function ConsumptionDistributionChart(
|
||||
const { t } = useTranslation()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const { customization } = useThemeCustomization()
|
||||
const chartRadius = useThemeRadiusPx(
|
||||
'--radius-md',
|
||||
`${customization.preset}:${customization.radius}`
|
||||
)
|
||||
const [chartType, setChartType] = useState<ConsumptionDistributionChartType>(
|
||||
props.defaultChartType ?? 'bar'
|
||||
)
|
||||
@@ -79,9 +84,17 @@ export function ConsumptionDistributionChart(
|
||||
props.loading ? [] : props.data,
|
||||
timeGranularity,
|
||||
t,
|
||||
customization.preset
|
||||
customization.preset,
|
||||
chartRadius
|
||||
),
|
||||
[props.data, props.loading, timeGranularity, t, customization.preset]
|
||||
[
|
||||
props.data,
|
||||
props.loading,
|
||||
timeGranularity,
|
||||
t,
|
||||
customization.preset,
|
||||
chartRadius,
|
||||
]
|
||||
)
|
||||
const spec = chartType === 'bar' ? chartData.spec_line : chartData.spec_area
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState, useRef } from 'react'
|
||||
import { VChart } from '@visactor/react-vchart'
|
||||
import { PieChart as PieChartIcon } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThemeRadiusPx } from '@/lib/theme-radius'
|
||||
import type { TimeGranularity } from '@/lib/time'
|
||||
import { VCHART_OPTION } from '@/lib/vchart'
|
||||
import { useThemeCustomization } from '@/context/theme-customization-provider'
|
||||
@@ -39,6 +40,10 @@ export function ModelCharts(props: ModelChartsProps) {
|
||||
const { t } = useTranslation()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const { customization } = useThemeCustomization()
|
||||
const chartRadius = useThemeRadiusPx(
|
||||
'--radius-md',
|
||||
`${customization.preset}:${customization.radius}`
|
||||
)
|
||||
const [activeTab, setActiveTab] = useState<ModelAnalyticsChartTab>(
|
||||
props.defaultChartTab ?? 'trend'
|
||||
)
|
||||
@@ -77,9 +82,17 @@ export function ModelCharts(props: ModelChartsProps) {
|
||||
props.loading ? [] : props.data,
|
||||
timeGranularity,
|
||||
t,
|
||||
customization.preset
|
||||
customization.preset,
|
||||
chartRadius
|
||||
),
|
||||
[props.data, props.loading, timeGranularity, t, customization.preset]
|
||||
[
|
||||
props.data,
|
||||
props.loading,
|
||||
timeGranularity,
|
||||
t,
|
||||
customization.preset,
|
||||
chartRadius,
|
||||
]
|
||||
)
|
||||
|
||||
const spec = chartData[CHART_SPEC_KEYS[activeTab]]
|
||||
|
||||
+2
-2
@@ -209,7 +209,7 @@ function StartStepItem(props: {
|
||||
)}
|
||||
<span
|
||||
className={cn(
|
||||
'bg-background relative z-10 flex size-8 shrink-0 items-center justify-center rounded-full border shadow-xs',
|
||||
'bg-background relative z-10 flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs',
|
||||
props.step.completed && 'border-success/30 bg-success/10'
|
||||
)}
|
||||
>
|
||||
@@ -657,7 +657,7 @@ export function OverviewDashboard() {
|
||||
? t('Setup guide complete')
|
||||
: t('Setup guide')}
|
||||
</h3>
|
||||
<span className='text-muted-foreground bg-background/60 rounded-full border px-2 py-0.5 text-xs'>
|
||||
<span className='text-muted-foreground bg-background/60 rounded-md border px-2 py-0.5 text-xs'>
|
||||
{t('Setup progress: {{completed}}/{{total}}', {
|
||||
completed: completedStepCount,
|
||||
total: startSteps.length,
|
||||
|
||||
@@ -129,6 +129,7 @@ export function UserCharts() {
|
||||
t,
|
||||
topUserLimit,
|
||||
customization.preset,
|
||||
customization.radius,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
+4
-2
@@ -80,7 +80,8 @@ export function processChartData(
|
||||
data: QuotaDataItem[],
|
||||
timeGranularity: TimeGranularity = 'day',
|
||||
t?: TFunction,
|
||||
themeKey?: string
|
||||
themeKey?: string,
|
||||
chartCornerRadius?: number
|
||||
): ProcessedChartData {
|
||||
const tt: TFunction = t ?? ((x) => x)
|
||||
const otherLabel = tt('Other')
|
||||
@@ -472,7 +473,8 @@ export function processChartData(
|
||||
valueField: 'value',
|
||||
categoryField: 'type',
|
||||
pie: {
|
||||
style: { cornerRadius: 10 },
|
||||
style:
|
||||
chartCornerRadius == null ? {} : { cornerRadius: chartCornerRadius },
|
||||
state: {
|
||||
hover: { outerRadius: 0.85, stroke: '#000', lineWidth: 1 },
|
||||
selected: { outerRadius: 0.85, stroke: '#000', lineWidth: 1 },
|
||||
|
||||
@@ -15,7 +15,7 @@ export function GatewayCard({ logo, systemName }: GatewayCardProps) {
|
||||
const features = getGatewayFeatures(t)
|
||||
|
||||
return (
|
||||
<div className='glass-3 group border-border/50 dark:border-border/20 relative overflow-hidden rounded-[32px] border p-10 shadow-2xl transition-all duration-500 sm:p-12 dark:shadow-[0_25px_80px_-15px_rgba(0,0,0,0.4)]'>
|
||||
<div className='glass-3 group border-border/50 dark:border-border/20 relative overflow-hidden rounded-4xl border p-10 shadow-2xl transition-all duration-500 sm:p-12 dark:shadow-[0_25px_80px_-15px_rgba(0,0,0,0.4)]'>
|
||||
{/* Top gradient border effect */}
|
||||
<Separator className='absolute top-0 left-[10%] h-[2px] w-[80%] bg-gradient-to-r from-transparent via-amber-500/80 to-transparent' />
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ function ApiKeysMobileSkeleton() {
|
||||
>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Skeleton className='h-4 w-32' />
|
||||
<Skeleton className='h-5 w-16 rounded-full' />
|
||||
<Skeleton className='h-5 w-16 rounded-md' />
|
||||
</div>
|
||||
<div className='flex items-center justify-between gap-3'>
|
||||
<Skeleton className='h-7 w-44' />
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ export function LegalDocument({
|
||||
<div className='mx-auto max-w-2xl py-12'>
|
||||
<Card className='border-dashed'>
|
||||
<CardHeader className='flex flex-row items-center gap-4'>
|
||||
<div className='bg-muted rounded-full p-2'>
|
||||
<div className='bg-muted rounded-lg p-2'>
|
||||
<FileWarning className='text-muted-foreground h-5 w-5' />
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
|
||||
@@ -122,7 +122,7 @@ export function DeploymentAccessGuard({
|
||||
return (
|
||||
<div className='mx-auto mt-8 max-w-md'>
|
||||
<div className='text-center'>
|
||||
<div className='mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-amber-100 dark:bg-amber-900/20'>
|
||||
<div className='mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-amber-100 dark:bg-amber-900/20'>
|
||||
<Server className='h-8 w-8 text-amber-600 dark:text-amber-400' />
|
||||
</div>
|
||||
<h3 className='mb-6 text-xl font-semibold'>
|
||||
@@ -153,7 +153,7 @@ export function DeploymentAccessGuard({
|
||||
return (
|
||||
<div className='mx-auto mt-8 max-w-md'>
|
||||
<div className='text-center'>
|
||||
<div className='mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/20'>
|
||||
<div className='mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-red-100 dark:bg-red-900/20'>
|
||||
<WifiOff className='h-8 w-8 text-red-600 dark:text-red-400' />
|
||||
</div>
|
||||
<h3 className='mb-6 text-xl font-semibold'>
|
||||
|
||||
@@ -85,7 +85,6 @@ export function useDeploymentsColumns(opts: {
|
||||
showDot={config.showDot}
|
||||
size='sm'
|
||||
copyable={false}
|
||||
rounded='full'
|
||||
/>
|
||||
)
|
||||
},
|
||||
@@ -117,7 +116,6 @@ export function useDeploymentsColumns(opts: {
|
||||
autoColor={String(provider)}
|
||||
size='sm'
|
||||
copyable={false}
|
||||
rounded='full'
|
||||
/>
|
||||
)
|
||||
},
|
||||
@@ -161,7 +159,6 @@ export function useDeploymentsColumns(opts: {
|
||||
variant='info'
|
||||
size='sm'
|
||||
copyable={false}
|
||||
rounded='full'
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ export function PrefillGroupManagementDialog({
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='icon'
|
||||
className='text-muted-foreground hover:text-foreground absolute top-4 right-4 rounded-full border border-transparent sm:top-5 sm:right-6'
|
||||
className='text-muted-foreground hover:text-foreground absolute top-4 right-4 border border-transparent sm:top-5 sm:right-6'
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -95,10 +95,7 @@ export function PlaygroundInput({
|
||||
|
||||
return (
|
||||
<div className='grid shrink-0 gap-4 px-1 md:pb-4'>
|
||||
<PromptInput
|
||||
groupClassName='rounded-[20px] [--radius:20px]'
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<PromptInput groupClassName='rounded-xl' onSubmit={handleSubmit}>
|
||||
<PromptInputTextarea
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
@@ -117,7 +114,7 @@ export function PlaygroundInput({
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<PromptInputButton
|
||||
className='!rounded-full border font-medium'
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
variant='outline'
|
||||
/>
|
||||
@@ -156,7 +153,7 @@ export function PlaygroundInput({
|
||||
</DropdownMenu>
|
||||
|
||||
<PromptInputButton
|
||||
className='rounded-full border font-medium'
|
||||
className='border font-medium'
|
||||
disabled={disabled}
|
||||
onClick={() => toast.info(t('Search feature in development'))}
|
||||
variant='outline'
|
||||
@@ -180,7 +177,7 @@ export function PlaygroundInput({
|
||||
|
||||
{isGenerating && onStop ? (
|
||||
<PromptInputButton
|
||||
className='text-foreground rounded-full font-medium'
|
||||
className='text-foreground font-medium'
|
||||
onClick={onStop}
|
||||
variant='secondary'
|
||||
>
|
||||
@@ -190,7 +187,7 @@ export function PlaygroundInput({
|
||||
</PromptInputButton>
|
||||
) : (
|
||||
<PromptInputButton
|
||||
className='text-foreground rounded-full font-medium'
|
||||
className='text-foreground font-medium'
|
||||
disabled={disabled || !text.trim()}
|
||||
type='submit'
|
||||
variant='secondary'
|
||||
|
||||
@@ -12,7 +12,7 @@ export function getMessageContentStyles() {
|
||||
'group-[.is-user]:text-foreground',
|
||||
'group-[.is-user]:bg-secondary',
|
||||
'dark:group-[.is-user]:bg-muted',
|
||||
'group-[.is-user]:rounded-[24px]',
|
||||
'group-[.is-user]:rounded-3xl',
|
||||
// Assistant bubble: flat serif style (one-sided style)
|
||||
'group-[.is-assistant]:text-foreground',
|
||||
'group-[.is-assistant]:bg-transparent',
|
||||
|
||||
@@ -179,7 +179,7 @@ export function DynamicPricingBreakdown({
|
||||
return (
|
||||
<section className='min-w-0 py-4'>
|
||||
<div className='mb-3 flex items-center gap-2'>
|
||||
<span className='inline-flex size-6 items-center justify-center rounded-full bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||
<span className='inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||
<TagIcon className='size-3.5' />
|
||||
</span>
|
||||
<div>
|
||||
@@ -212,7 +212,7 @@ export function DynamicPricingBreakdown({
|
||||
return (
|
||||
<section className='min-w-0 py-3 sm:py-4'>
|
||||
<div className='mb-3 flex items-start gap-2 sm:mb-4'>
|
||||
<span className='mt-0.5 inline-flex size-6 items-center justify-center rounded-full bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||
<span className='mt-0.5 inline-flex size-6 items-center justify-center rounded-lg bg-amber-100 text-amber-700 shadow-sm dark:bg-amber-500/20 dark:text-amber-300'>
|
||||
<TagIcon className='size-3.5' />
|
||||
</span>
|
||||
<div>
|
||||
|
||||
@@ -67,7 +67,7 @@ function FilterBarSkeleton() {
|
||||
{[80, 90, 75, 85, 70].map((width, i) => (
|
||||
<Skeleton
|
||||
key={i}
|
||||
className='h-8 rounded-full'
|
||||
className='h-8 rounded-lg'
|
||||
style={{ width: `${width}px` }}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -41,7 +41,7 @@ function RankBadge(props: { rank: number }) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'inline-flex size-7 shrink-0 items-center justify-center rounded-full font-mono text-xs font-bold tabular-nums',
|
||||
'inline-flex size-7 shrink-0 items-center justify-center rounded-md font-mono text-xs font-bold tabular-nums',
|
||||
palette
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useMemo } from 'react'
|
||||
import { VChart } from '@visactor/react-vchart'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThemeRadiusPx } from '@/lib/theme-radius'
|
||||
import { useChartTheme } from '@/lib/use-chart-theme'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { VCHART_OPTION } from '@/lib/vchart'
|
||||
import { useThemeCustomization } from '@/context/theme-customization-provider'
|
||||
import type { LatencyTimePoint, UptimeDayPoint } from '../lib/mock-stats'
|
||||
|
||||
function formatHourLabel(iso: string): string {
|
||||
@@ -246,6 +248,11 @@ export function ThroughputBarChart(props: {
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const { resolvedTheme, themeReady } = useChartTheme()
|
||||
const { customization } = useThemeCustomization()
|
||||
const barRadius = useThemeRadiusPx(
|
||||
'--radius-sm',
|
||||
`${customization.preset}:${customization.radius}`
|
||||
)
|
||||
|
||||
const filtered = useMemo(
|
||||
() => props.rows.filter((r) => r.throughput_tps > 0),
|
||||
@@ -261,7 +268,10 @@ export function ThroughputBarChart(props: {
|
||||
xField: 'throughput_tps',
|
||||
yField: 'group',
|
||||
bar: {
|
||||
style: { fill: '#6366f1', cornerRadius: 2 },
|
||||
style: {
|
||||
fill: '#6366f1',
|
||||
...(barRadius == null ? {} : { cornerRadius: barRadius }),
|
||||
},
|
||||
},
|
||||
label: {
|
||||
visible: true,
|
||||
@@ -294,7 +304,7 @@ export function ThroughputBarChart(props: {
|
||||
},
|
||||
},
|
||||
}
|
||||
}, [filtered, t])
|
||||
}, [barRadius, filtered, t])
|
||||
|
||||
if (filtered.length === 0) {
|
||||
return null
|
||||
|
||||
+2
-2
@@ -87,7 +87,7 @@ export function UptimeSparkline(props: UptimeSparklineProps) {
|
||||
render={
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-[1px] transition-opacity hover:opacity-80',
|
||||
'rounded-sm transition-opacity hover:opacity-80',
|
||||
barWidth,
|
||||
containerHeight,
|
||||
'flex items-end'
|
||||
@@ -97,7 +97,7 @@ export function UptimeSparkline(props: UptimeSparklineProps) {
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'w-full rounded-[1px]',
|
||||
'w-full rounded-sm',
|
||||
colourFor(day.uptime_pct),
|
||||
heightFor(day.uptime_pct)
|
||||
)}
|
||||
|
||||
@@ -95,7 +95,7 @@ function FilterChip(props: {
|
||||
{(props.option.suffix || props.option.count != null) && (
|
||||
<span
|
||||
className={cn(
|
||||
'rounded-full px-1.5 py-0.5 text-[10px]',
|
||||
'rounded-md px-1.5 py-0.5 text-[10px]',
|
||||
props.active
|
||||
? 'bg-background text-foreground'
|
||||
: 'bg-muted text-muted-foreground'
|
||||
|
||||
@@ -154,7 +154,7 @@ export function PricingToolbar(props: PricingToolbarProps) {
|
||||
<Filter className='size-4' />
|
||||
{t('Filter')}
|
||||
{props.activeFilterCount > 0 && (
|
||||
<Badge className='ml-0.5 size-5 justify-center rounded-full p-0 text-[10px]'>
|
||||
<Badge className='ml-0.5 size-5 justify-center p-0 text-[10px]'>
|
||||
{props.activeFilterCount}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -212,13 +212,13 @@ export function CheckinCalendarCard({
|
||||
<div className='p-6'>
|
||||
<div className='flex items-start justify-between gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<Skeleton className='h-10 w-10 rounded-full' />
|
||||
<Skeleton className='h-10 w-10 rounded-xl' />
|
||||
<div className='space-y-2'>
|
||||
<Skeleton className='h-5 w-32' />
|
||||
<Skeleton className='h-3 w-56' />
|
||||
</div>
|
||||
</div>
|
||||
<Skeleton className='h-9 w-28 rounded-full' />
|
||||
<Skeleton className='h-9 w-28 rounded-md' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -280,7 +280,7 @@ export function CheckinCalendarCard({
|
||||
{t('Daily Check-in')}
|
||||
</h3>
|
||||
{checkedToday && (
|
||||
<div className='inline-flex items-center gap-1 rounded-full bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-600 sm:gap-1.5 sm:px-2.5 sm:text-xs dark:text-emerald-400'>
|
||||
<div className='inline-flex items-center gap-1 rounded-md bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-600 sm:gap-1.5 sm:px-2.5 sm:text-xs dark:text-emerald-400'>
|
||||
<Sparkles className='h-2.5 w-2.5 sm:h-3 sm:w-3' />
|
||||
{t('Checked in')}
|
||||
</div>
|
||||
@@ -304,7 +304,7 @@ export function CheckinCalendarCard({
|
||||
onClick={() => doCheckin()}
|
||||
disabled={checkinLoading || checkedToday}
|
||||
size='sm'
|
||||
className='w-full shrink-0 rounded-full sm:w-auto'
|
||||
className='w-full shrink-0 sm:w-auto'
|
||||
>
|
||||
{checkinLoading
|
||||
? t('Loading...')
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ export function TelegramBindDialog({
|
||||
</Alert>
|
||||
|
||||
<div className='flex flex-col items-center justify-center gap-4 rounded-lg border p-6'>
|
||||
<div className='flex h-12 w-12 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900'>
|
||||
<div className='flex h-12 w-12 items-center justify-center rounded-xl bg-blue-100 dark:bg-blue-900'>
|
||||
<Send className='h-6 w-6 text-blue-600 dark:text-blue-400' />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ import { useMemo } from 'react'
|
||||
import { VChart } from '@visactor/react-vchart'
|
||||
import { PieChart } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThemeRadiusPx } from '@/lib/theme-radius'
|
||||
import { useChartTheme } from '@/lib/use-chart-theme'
|
||||
import { VCHART_OPTION } from '@/lib/vchart'
|
||||
import { useThemeCustomization } from '@/context/theme-customization-provider'
|
||||
import { formatShare, formatTokens } from '../lib/format'
|
||||
import type { RankingPeriod, VendorRanking, VendorShareSeries } from '../types'
|
||||
import { VendorLink } from './entity-links'
|
||||
@@ -84,6 +86,11 @@ type MarketShareSectionProps = {
|
||||
export function MarketShareSection(props: MarketShareSectionProps) {
|
||||
const { t } = useTranslation()
|
||||
const { resolvedTheme, themeReady } = useChartTheme()
|
||||
const { customization } = useThemeCustomization()
|
||||
const barRadius = useThemeRadiusPx(
|
||||
'--radius-sm',
|
||||
`${customization.preset}:${customization.radius}`
|
||||
)
|
||||
|
||||
const colourMap = useMemo(
|
||||
() => buildVendorColourMap(props.history.vendors.map((v) => v.name)),
|
||||
@@ -112,7 +119,9 @@ export function MarketShareSection(props: MarketShareSectionProps) {
|
||||
stack: true,
|
||||
paddingInner: 0.12,
|
||||
legends: { visible: false },
|
||||
bar: { style: { cornerRadius: 1 } },
|
||||
bar: {
|
||||
style: barRadius == null ? {} : { cornerRadius: barRadius },
|
||||
},
|
||||
color: { specified: colourMap },
|
||||
axes: [
|
||||
{
|
||||
@@ -175,7 +184,7 @@ export function MarketShareSection(props: MarketShareSectionProps) {
|
||||
},
|
||||
animationAppear: { duration: 500 },
|
||||
}
|
||||
}, [colourMap, orderedPoints])
|
||||
}, [barRadius, colourMap, orderedPoints])
|
||||
|
||||
const visible = props.rows.slice(0, MAX_VENDORS_IN_LIST)
|
||||
const half = Math.ceil(visible.length / 2)
|
||||
|
||||
@@ -2,8 +2,10 @@ import { useMemo } from 'react'
|
||||
import { VChart } from '@visactor/react-vchart'
|
||||
import { BarChart3, Trophy } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThemeRadiusPx } from '@/lib/theme-radius'
|
||||
import { useChartTheme } from '@/lib/use-chart-theme'
|
||||
import { VCHART_OPTION } from '@/lib/vchart'
|
||||
import { useThemeCustomization } from '@/context/theme-customization-provider'
|
||||
import { formatTokens } from '../lib/format'
|
||||
import type { ModelHistorySeries, ModelRanking, RankingPeriod } from '../types'
|
||||
import { ModelLeaderboard } from './model-leaderboard'
|
||||
@@ -32,6 +34,11 @@ type ModelsSectionProps = {
|
||||
export function ModelsSection(props: ModelsSectionProps) {
|
||||
const { t } = useTranslation()
|
||||
const { resolvedTheme, themeReady } = useChartTheme()
|
||||
const { customization } = useThemeCustomization()
|
||||
const barRadius = useThemeRadiusPx(
|
||||
'--radius-sm',
|
||||
`${customization.preset}:${customization.radius}`
|
||||
)
|
||||
|
||||
// Order points so the largest model appears at the bottom of every stack.
|
||||
const orderedPoints = useMemo(() => {
|
||||
@@ -59,7 +66,9 @@ export function ModelsSection(props: ModelsSectionProps) {
|
||||
yField: 'tokens',
|
||||
seriesField: 'model',
|
||||
stack: true,
|
||||
bar: { style: { cornerRadius: 1 } },
|
||||
bar: {
|
||||
style: barRadius == null ? {} : { cornerRadius: barRadius },
|
||||
},
|
||||
legends: { visible: false },
|
||||
axes: [
|
||||
{
|
||||
@@ -132,7 +141,7 @@ export function ModelsSection(props: ModelsSectionProps) {
|
||||
},
|
||||
animationAppear: { duration: 500 },
|
||||
}
|
||||
}, [orderedPoints, t])
|
||||
}, [barRadius, orderedPoints, t])
|
||||
|
||||
return (
|
||||
<section className='bg-card overflow-hidden rounded-lg border'>
|
||||
|
||||
@@ -32,7 +32,7 @@ export function CompleteStep({ status, values }: CompleteStepProps) {
|
||||
|
||||
return (
|
||||
<div className='flex flex-col items-center gap-6 text-center'>
|
||||
<div className='rounded-full bg-emerald-500/10 p-4 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-300'>
|
||||
<div className='rounded-2xl bg-emerald-500/10 p-4 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-300'>
|
||||
<CheckCircle2 className='size-8' />
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
|
||||
+1
-1
@@ -320,7 +320,7 @@ export function SetupWizard() {
|
||||
<div className='flex items-start gap-3'>
|
||||
<span
|
||||
className={cn(
|
||||
'flex size-6 items-center justify-center rounded-full border text-xs font-semibold',
|
||||
'flex size-6 items-center justify-center rounded-md border text-xs font-semibold',
|
||||
isActive
|
||||
? 'border-primary bg-primary text-primary-foreground'
|
||||
: isCompleted
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ export function AmountOptionsVisualEditor({
|
||||
e.stopPropagation()
|
||||
handleRemove(amount)
|
||||
}}
|
||||
className='hover:bg-muted-foreground/20 size-auto rounded-full p-0.5'
|
||||
className='hover:bg-muted-foreground/20 size-auto p-0.5'
|
||||
aria-label={t('Remove ${{amount}}', { amount })}
|
||||
>
|
||||
<X className='h-3.5 w-3.5' />
|
||||
|
||||
Reference in New Issue
Block a user