[needs-vps] fix(dashboard): align onboarding tier content (#7125)

* fix(dashboard): align onboarding welcome feature cards vertically

* fix(dashboard): align onboarding tier content

* chore: scope onboarding PR to UI fix

* i18n(pt-BR): add onboarding.tier.flowCaption + afterSetup keys

The two new tier keys added to en.json were missing from pt-BR.json, tripping
the i18n-pt-br no-drift test (#6695). Add their pt-BR translations.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Wibias
2026-07-17 06:01:29 +02:00
committed by GitHub
parent 3f8acbf835
commit 88507a6edc
6 changed files with 27 additions and 19 deletions

View File

@@ -0,0 +1 @@
- **fix(dashboard):** align onboarding tier descriptions and localize the tier step header and flow copy ([#7125](https://github.com/diegosouzapw/OmniRoute/pull/7125)) — thanks @Wibias

View File

@@ -5,7 +5,8 @@ import { useTranslations } from "next-intl";
import Image from "next/image";
export function TierFlowDiagram() {
const t = useTranslations("onboarding");
const t = useTranslations("onboarding.tier");
const tOnboarding = useTranslations("onboarding");
const { resolvedTheme } = useTheme();
const src =
resolvedTheme === "dark" ? "/images/tier-flow-dark.svg" : "/images/tier-flow-light.svg";
@@ -14,15 +15,14 @@ export function TierFlowDiagram() {
<div className="flex flex-col items-center gap-3 my-4">
<Image
src={src}
alt={t("tierFlowDiagramAlt")}
alt={tOnboarding("tierFlowDiagramAlt")}
width={800}
height={420}
priority
className="w-full max-w-2xl rounded-lg border border-white/[0.06]"
/>
<p className="text-xs text-text-muted max-w-xl text-center">
Requests flow through your subscription quotas first, then pay-per-token cheap providers,
then free-tier providers automatic, zero-config.
<p className="mx-auto max-w-md text-xs leading-relaxed text-text-muted text-center text-balance">
{t("flowCaption")}
</p>
</div>
);

View File

@@ -274,7 +274,12 @@ export default function OnboardingWizard() {
>
{currentStep.icon}
</span>
<h2 className="text-2xl font-bold text-text-main mb-1">{currentStep.title}</h2>
<h2 className="text-2xl font-bold text-text-main">{currentStep.title}</h2>
{currentStep.id === "tiers" && (
<p className="mx-auto mt-2 max-w-md text-sm leading-relaxed text-text-muted text-balance">
{t("tier.subtitle")}
</p>
)}
</div>
{/* Step Content */}
@@ -283,7 +288,7 @@ export default function OnboardingWizard() {
{currentStep.id === "welcome" && (
<div className="text-center space-y-4">
<p className="text-text-muted">{t("welcomeDesc")}</p>
<div className="grid grid-cols-3 gap-3 mt-6">
<div className="mt-6 grid grid-cols-3 gap-3 items-stretch">
{[
{ icon: "swap_horiz", label: t("multiProvider") },
{ icon: "monitoring", label: t("usageTracking") },
@@ -291,12 +296,14 @@ export default function OnboardingWizard() {
].map((f) => (
<div
key={f.icon}
className="bg-white/[0.03] rounded-xl p-3 text-center border border-white/[0.06]"
className="h-full bg-white/[0.03] rounded-xl p-3 text-center border border-white/[0.06]"
>
<span className="material-symbols-outlined text-primary text-[24px] mb-1 block">
{f.icon}
</span>
<span className="text-xs text-text-muted">{f.label}</span>
<div className="flex h-full flex-col items-center justify-center">
<span className="material-symbols-outlined text-primary text-[24px] mb-1 block">
{f.icon}
</span>
<span className="text-xs text-text-muted">{f.label}</span>
</div>
</div>
))}
</div>

View File

@@ -19,7 +19,7 @@ function TierCard({ number, colorClass, label, description, examples }: TierCard
<span className="text-2xl font-bold">{number}</span>
<span className="font-semibold text-sm">{label}</span>
</div>
<p className="text-xs text-text-muted mb-3">{description}</p>
<p className="min-h-16 text-xs text-text-muted mb-3">{description}</p>
<ul className="text-xs space-y-0.5 text-text-muted">
{examples.map((e) => (
<li key={e}>· {e}</li>
@@ -34,10 +34,6 @@ export function TierTour() {
return (
<div className="space-y-5">
<div className="text-center">
<p className="text-sm text-text-muted">{t("subtitle")}</p>
</div>
<TierFlowDiagram />
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
@@ -68,7 +64,7 @@ export function TierTour() {
<Link href="/dashboard/providers/new" className="underline hover:text-text-muted">
{t("configure")}
</Link>{" "}
after setup.
{t("afterSetup")}
</p>
</div>
);

View File

@@ -3905,6 +3905,8 @@
"apiKeyHelp": "An API key is a password for AI services. Get one from your provider's website (e.g., platform.openai.com, console.anthropic.com).",
"tier": {
"subtitle": "OmniRoute organises providers into three tiers so routing prefers the most reliable, lowest-cost path first.",
"flowCaption": "Requests flow through your subscription quotas first, then pay-per-token cheap providers, then free-tier providers — automatic, zero-config.",
"afterSetup": "after setup.",
"tier1": {
"label": "Premium clients",
"description": "First-class CLIs with native auth flows and reasoning models."

View File

@@ -3917,7 +3917,9 @@
"label": "Reserva e especialidade",
"description": "Endpoints hospedados localmente ou especializados usados como substitutos."
},
"configure": "Configurar provedores"
"configure": "Configurar provedores",
"flowCaption": "As requisições passam primeiro pelas suas cotas de assinatura, depois pelos provedores baratos por token e, por fim, pelos provedores gratuitos — automático, sem configuração.",
"afterSetup": "após a configuração."
},
"tierFlowDiagramAlt": "Diagrama de fallback de 3 camadas do OmniRoute",
"apiKeyMgmt": "Ger. de Chaves API"