Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/fixes/ui-badge-brand-contrast.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(dashboard):** Log, proxy and conversation badges (provider, protocol, proxy type, level, HTTP status) use the kit chart and status tones instead of a parallel hex palette, so their text reaches 4.5:1 in Classic and Editions, light and dark (white on `#10B981` was 2.54:1). Provider and CLI tool brand colours are no longer text or a fill under white text: the provider header links use the primary ink, the rankings and CLI step avatars use a brand tint with body text, the onboarding provider tiles and the batch wizard's done steps use the kit tint + ink ([#19066](https://github.com/cheaper-inference/OmniRoute/issues/19066))
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function StepIndicator({
<div
aria-current={isCurrent ? "step" : undefined}
className={`flex items-center justify-center w-6 h-6 rounded-full text-xs font-medium transition-colors
${isDone ? "bg-success text-white" : isCurrent ? "bg-accent text-accent-foreground" : "bg-border text-text-muted"}`}
${isDone ? "bg-success-bg text-success" : isCurrent ? "bg-accent text-accent-foreground" : "bg-border text-text-muted"}`}
>
{isDone ? <Icon name="check" size={14} /> : s}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useTranslations } from "next-intl";
import { CheckboxGroup } from "@omniroute/ui-kit/checkbox";
import { matchesSearch } from "@/shared/utils/turkishText";
import { cn } from "@/shared/utils/cn";
import { brandTintStyle } from "@/shared/utils/brandTint";
import Checkbox from "@/shared/components/Checkbox";
import { CARD_TOGGLE_CLASS, cardToggleProps } from "./cardToggle";

Expand Down Expand Up @@ -248,8 +249,8 @@ export default function CopilotToolCard({
<div>
<div className="flex items-center gap-2 mb-2">
<div
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-white"
style={{ backgroundColor: tool.color }}
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-text-main"
style={brandTintStyle(tool.color)}
>
1
</div>
Expand All @@ -274,8 +275,8 @@ export default function CopilotToolCard({
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-2">
<div
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-white"
style={{ backgroundColor: tool.color }}
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-text-main"
style={brandTintStyle(tool.color)}
>
{cloudEnabled && apiKeys?.length > 0 ? "2" : "1"}
</div>
Expand Down Expand Up @@ -380,8 +381,8 @@ export default function CopilotToolCard({
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-2">
<div
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-white"
style={{ backgroundColor: tool.color }}
className="size-6 rounded-full flex items-center justify-center text-xs font-semibold text-text-main"
style={brandTintStyle(tool.color)}
>
{cloudEnabled && apiKeys?.length > 0 ? "3" : "2"}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useTheme } from "@/shared/hooks/useTheme";
import { DEFAULT_DISPLAY_BASE_URL } from "@/shared/hooks";
import ProviderIcon from "@/shared/components/ProviderIcon";
import { cn } from "@/shared/utils/cn";
import { brandTintStyle } from "@/shared/utils/brandTint";
import { CARD_TOGGLE_CLASS, cardToggleProps } from "./cardToggle";

export default function DefaultToolCard({
Expand Down Expand Up @@ -539,8 +540,8 @@ export default function DefaultToolCard({
tool.guideSteps.map((item) => (
<div key={item.step} className="flex items-start gap-4">
<div
className="size-8 rounded-full flex items-center justify-center shrink-0 text-sm font-semibold text-white"
style={{ backgroundColor: tool.color }}
className="size-8 rounded-full flex items-center justify-center shrink-0 text-sm font-semibold text-text-main"
style={brandTintStyle(tool.color)}
>
{item.step}
</div>
Expand Down
6 changes: 2 additions & 4 deletions src/app/(dashboard)/dashboard/conversations/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ const LIVE_TEXT_POLL_INTERVAL_MS = 1200;

function ProviderBadge({ provider }: { provider: string | null }) {
if (!provider) return <span className="text-text-muted text-[10px]">—</span>;
const style = (PROVIDER_COLORS as Record<string, { bg: string; text: string; label: string }>)[
provider
];
const style = PROVIDER_COLORS[provider];
if (!style) {
return (
<span className="inline-block px-2 py-0.5 rounded-full text-[9px] font-bold bg-bg-subtle text-text-muted border border-border">
Expand All @@ -110,7 +108,7 @@ function StatusBadge({ status }: { status: number | null }) {
return (
<span
className="inline-block px-2 py-0.5 rounded-full text-[9px] font-bold"
style={{ backgroundColor: style.bg, color: style.text ?? "#fff" }}
style={{ backgroundColor: style.bg, color: style.text }}
>
{status}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
// client component must never take a runtime value from it. The page used to
// keep its own copy of this shape, which had already drifted past the API.
import type { FreeProviderRanking } from "@/lib/freeProviderRankings";
import { brandTintStyle } from "@/shared/utils/brandTint";

/**
* Convert a normalized task-fit score (0.4–0.98) to a human-readable label.
Expand Down Expand Up @@ -221,8 +222,8 @@ export default function FreeProviderRankingsPage() {
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<div
className="w-6 h-6 rounded flex items-center justify-center text-[10px] font-bold text-white"
style={{ backgroundColor: provider.color }}
className="w-6 h-6 rounded flex items-center justify-center text-[10px] font-bold text-text-main"
style={brandTintStyle(provider.color)}
>
{provider.textIcon || provider.name.charAt(0)}
</div>
Expand Down Expand Up @@ -277,8 +278,8 @@ export default function FreeProviderRankingsPage() {
<TableCell>
<div className="flex items-center gap-2">
<div
className="w-6 h-6 rounded flex items-center justify-center text-[10px] font-bold text-white"
style={{ backgroundColor: provider.color }}
className="w-6 h-6 rounded flex items-center justify-center text-[10px] font-bold text-text-main"
style={brandTintStyle(provider.color)}
>
{provider.textIcon || provider.name.charAt(0)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ export default function ProviderPageHeader({
href={noticeUrl}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-medium underline underline-offset-2 opacity-70 hover:opacity-100 transition-opacity inline-flex items-center gap-1"
style={{ color: providerInfo.color }}
className="text-sm font-medium text-primary underline underline-offset-2 hover:text-text-main transition-colors inline-flex items-center gap-1"
>
<Icon name="open_in_new" size={16} />
{t("getApiKey")}
Expand All @@ -100,6 +99,7 @@ export default function ProviderPageHeader({
}
title={
<span className="inline-flex items-center gap-4">
{/* The brand colour is only a tint behind the icon; text uses neutral/primary tokens. */}
<span
className="inline-flex items-center justify-center rounded-lg"
style={{ backgroundColor: `${providerInfo.color}15` }}
Expand All @@ -124,8 +124,7 @@ export default function ProviderPageHeader({
href={providerInfo.website}
target="_blank"
rel="noopener noreferrer"
className="hover:underline inline-flex items-center gap-2"
style={{ color: providerInfo.color }}
className="hover:underline hover:text-primary inline-flex items-center gap-2"
title={showPartnerNote ? kimiPartnerLinkNote : undefined}
aria-label={
showPartnerNote ? `${providerInfo.name} — ${kimiPartnerLinkNote}` : undefined
Expand Down Expand Up @@ -153,8 +152,7 @@ export default function ProviderPageHeader({
variant="ghost"
size="sm"
onClick={onOpenTutorial}
className="h-auto min-h-0 px-0 text-sm font-medium underline underline-offset-2 opacity-70 hover:bg-transparent hover:opacity-100"
style={{ color: providerInfo.color }}
className="h-auto min-h-0 px-0 text-sm font-medium text-primary underline underline-offset-2 hover:bg-transparent hover:text-text-main"
>
Tutorial
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,14 @@ function StepPill({ active, done, label }: { active: boolean; done: boolean; lab
);
}

// Kit chart tint + its AA ink (never white on the solid chart hue: 2.4–3.5:1 in dark).
function getProviderIconClass(providerId: string): string {
const classes = ["bg-chart-2", "bg-chart-3", "bg-chart-4", "bg-chart-5"];
const classes = [
"bg-[var(--ci-chart-2-subtle)] text-[var(--ci-chart-2-ink)]",
"bg-[var(--ci-chart-3-subtle)] text-[var(--ci-chart-3-ink)]",
"bg-[var(--ci-chart-4-subtle)] text-[var(--ci-chart-4-ink)]",
"bg-[var(--ci-chart-5-subtle)] text-[var(--ci-chart-5-ink)]",
];
const index = [...providerId].reduce((sum, char) => sum + char.charCodeAt(0), 0) % classes.length;
return classes[index];
}
Expand Down Expand Up @@ -167,7 +173,7 @@ function ProviderOptionCard({
<div className="flex items-start justify-between gap-3">
<div className="flex items-center gap-3">
<div
className={`flex size-10 items-center justify-center rounded-lg text-white ${getProviderIconClass(
className={`flex size-10 items-center justify-center rounded-lg ${getProviderIconClass(
option.id
)}`}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,7 @@ export default function SecurityTab() {
<ProviderIcon
providerId={provider.id}
size={14}
className="shrink-0"
style={{ color: provider.color }}
className="shrink-0 text-text-muted"
/>
)}
<span className="truncate">{provider.name}</span>
Expand Down
20 changes: 9 additions & 11 deletions src/shared/components/ProxyLogDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"use client";

import { useTranslations } from "next-intl";
import { TYPE_COLORS, LEVEL_COLORS, PROVIDER_COLORS } from "@/shared/constants/colors";
import {
TYPE_COLORS,
LEVEL_COLORS,
PROVIDER_COLORS,
neutralBadge,
} from "@/shared/constants/colors";
import {
formatDuration as formatLatency,
maskAccount,
Expand Down Expand Up @@ -93,17 +98,10 @@ function ObservedLinkField({ label, href, title, short }) {
}

function StatusBadges({ log, t }) {
const typeColor = TYPE_COLORS[log.proxy?.type] || {
bg: "#6B7280",
text: "#fff",
label: log.proxy?.type || "-",
};
const typeColor = TYPE_COLORS[log.proxy?.type] || neutralBadge(log.proxy?.type || "-");
const levelColor = LEVEL_COLORS[log.level] || LEVEL_COLORS.direct;
const providerColor = PROVIDER_COLORS[log.provider] || {
bg: "#374151",
text: "#fff",
label: (log.provider || "-").toUpperCase(),
};
const providerColor =
PROVIDER_COLORS[log.provider] || neutralBadge((log.provider || "-").toUpperCase());
return (
<>
<div>
Expand Down
39 changes: 18 additions & 21 deletions src/shared/components/ProxyLogger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ import EmptyState from "./EmptyState";
import Input from "./Input";
import Select from "./Select";
import ProxyLogDetail from "./ProxyLogDetail";
import { TYPE_COLORS, LEVEL_COLORS, PROVIDER_COLORS } from "@/shared/constants/colors";
import {
TYPE_COLORS,
LEVEL_COLORS,
PROVIDER_COLORS,
neutralBadge,
} from "@/shared/constants/colors";
import {
formatTime,
formatDuration as formatLatency,
Expand Down Expand Up @@ -472,12 +477,8 @@ export default function ProxyLogger() {
)}

{uniqueProviders.map((p) => {
// Provider identity colours (brand palette in constants/colors), not status tones.
const pc = PROVIDER_COLORS[p] || {
bg: "#374151",
text: "#fff",
label: p.toUpperCase(),
};
// Provider identity tones (kit chart tokens in constants/colors), not status tones.
const pc = PROVIDER_COLORS[p] || neutralBadge(p.toUpperCase());
const isActive = selectedProvider === p;
return (
<Button
Expand All @@ -490,11 +491,13 @@ export default function ProxyLogger() {
"h-7 min-h-7 rounded-full border px-3 text-xs font-bold uppercase",
isActive
? "border-border-strong ring-1 ring-border-strong"
: "border-transparent opacity-70 hover:opacity-100"
: "border-transparent hover:bg-bg-subtle"
)}
// Active: tint + ink + hue border; inactive: the ink alone (AA on the page).
style={{
backgroundColor: isActive ? pc.bg : `${pc.bg}33`,
color: isActive ? pc.text : pc.bg,
backgroundColor: isActive ? pc.bg : undefined,
borderColor: isActive ? pc.border : undefined,
color: pc.text,
}}
>
{pc.label}
Expand Down Expand Up @@ -549,21 +552,15 @@ export default function ProxyLogger() {
</TableHeader>
<TableBody>
{sortedLogs.map((log) => {
// Proxy type / level keep their categorical palettes (constants/colors).
const typeColor = TYPE_COLORS[log.proxy?.type] || {
bg: "#6B7280",
text: "#fff",
label: log.proxy?.type || "-",
};
// Proxy type / level badges are kit tones (constants/colors).
const typeColor =
TYPE_COLORS[log.proxy?.type] || neutralBadge(log.proxy?.type || "-");
const levelColor = LEVEL_COLORS[log.level] || LEVEL_COLORS.direct;
const resolvedProviderLabel =
getProviderDisplayLabel(log.provider, providerNodes) ||
(log.provider || "-").toUpperCase();
const providerColor = PROVIDER_COLORS[log.provider] || {
bg: "#374151",
text: "#fff",
label: resolvedProviderLabel,
};
const providerColor =
PROVIDER_COLORS[log.provider] || neutralBadge(resolvedProviderLabel);
const isError = log.status === "error" || log.status === "timeout";
const egressAddress =
observedEgressAddresses({
Expand Down
9 changes: 3 additions & 6 deletions src/shared/components/RequestLoggerDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { sortRelatedLogs } from "./requestLoggerGroups";
import { useState, useEffect, useMemo, useRef } from "react";
import { useLocale, useTranslations } from "next-intl";
import { JsonView } from "@/shared/components/jsonView";
import { PROVIDER_COLORS, getProtocolColor } from "@/shared/constants/colors";
import { PROVIDER_COLORS, getProtocolColor, neutralBadge } from "@/shared/constants/colors";
import { formatDuration, formatApiKeyLabel, maskAccount } from "@/shared/utils/formatting";
import { formatErrorForDisplay, formatReasoningStat } from "@/shared/utils/formatting";
import { useTheme } from "@/shared/hooks/useTheme";
Expand Down Expand Up @@ -425,11 +425,8 @@ export default function RequestLoggerDetail({
const { startMs, endMs } = getRequestTimeRange(timingLog);
const protocolKey = log.sourceFormat || log.provider;
const protocol = getProtocolColor(protocolKey, log.provider);
const providerColor = PROVIDER_COLORS[log.provider] || {
bg: "#374151",
text: "#fff",
label: (log.provider || "-").toUpperCase(),
};
const providerColor =
PROVIDER_COLORS[log.provider] || neutralBadge((log.provider || "-").toUpperCase());
const providerLabel = log.providerDisplay || providerColor.label;

const [unblocking, setUnblocking] = useState(false);
Expand Down
Loading
Loading