diff --git a/packages/console/app/src/asset/go-ornate-dark.svg b/packages/console/app/src/asset/go-ornate-dark.svg
deleted file mode 100644
index 9b617c6777..0000000000
--- a/packages/console/app/src/asset/go-ornate-dark.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/packages/console/app/src/asset/go-ornate-light.svg b/packages/console/app/src/asset/go-ornate-light.svg
deleted file mode 100644
index 79991973d6..0000000000
--- a/packages/console/app/src/asset/go-ornate-light.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/packages/console/app/src/component/go-plan-chart.css b/packages/console/app/src/component/go-plan-chart.css
index 5cdea42213..ae0c277aef 100644
--- a/packages/console/app/src/component/go-plan-chart.css
+++ b/packages/console/app/src/component/go-plan-chart.css
@@ -1,13 +1,5 @@
@import "@opencode-ai/ui/v2/styles/colors.css";
-@font-face {
- font-family: "Inter";
- src: url("@opencode-ai/ui/fonts/Inter.ttf") format("truetype");
- font-style: normal;
- font-weight: 100 900;
- font-display: swap;
-}
-
[data-page="go"] {
--go-console-bg: var(--v2-grey-50);
--go-console-surface: var(--v2-grey-100);
@@ -35,7 +27,7 @@
padding: 2rem var(--padding) 3rem;
background: var(--go-console-bg);
color: var(--go-console-text);
- font-family: "Inter", sans-serif;
+ font-family: var(--font-mono);
font-size: 0.8125rem;
font-weight: 440;
line-height: 1.25rem;
@@ -61,12 +53,23 @@
color: var(--go-console-muted);
line-height: 1.25rem;
}
- [data-slot="tier-switch"] {
+ [data-slot="legend"] {
display: flex;
align-items: center;
- gap: 0.25rem;
+ gap: 1rem;
+ margin: 0;
+ padding: 0 0 0.375rem;
+ list-style: none;
+ color: var(--go-console-secondary);
+ font-weight: 530;
+ white-space: nowrap;
}
- [data-slot="tier-switch"] i {
+ [data-slot="legend"] li {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ }
+ [data-slot="legend"] i {
width: 3px;
height: 12px;
border-radius: 1px;
@@ -90,27 +93,6 @@
cursor: pointer;
white-space: nowrap;
}
- [data-slot="tier-switch"] button {
- color: var(--go-console-secondary);
- border-radius: 4px;
- transition:
- background-color 180ms ease,
- opacity 180ms ease;
- }
- [data-slot="tier-switch"] button[aria-pressed="false"] {
- opacity: 0.4;
- font-weight: 440;
- }
- [data-slot="tier-switch"] button[aria-pressed="false"]:is(:hover, :focus-visible) {
- opacity: 0.75;
- }
- [data-slot="tier-switch"] button[aria-pressed="true"] {
- background: var(--go-console-surface);
- color: var(--go-console-text);
- }
- [data-slot="tier-switch"] button:hover {
- color: var(--go-console-text);
- }
[data-slot="expand"][aria-expanded="true"] svg {
transform: rotate(180deg);
}
@@ -148,28 +130,48 @@
border-start-end-radius: 6px;
border-end-end-radius: 6px;
}
+ tbody tr > * {
+ transition: background-color 120ms ease;
+ }
+ tbody tr:hover > * {
+ background: var(--go-console-surface);
+ }
+ tbody tr > :first-child {
+ border-start-start-radius: 6px;
+ border-end-start-radius: 6px;
+ }
+ tbody tr > :last-child {
+ border-start-end-radius: 6px;
+ border-end-end-radius: 6px;
+ }
tbody th {
padding: 0.5rem 1rem;
text-align: start;
font-weight: 400;
color: var(--go-console-text);
}
- [data-slot="model"] {
- display: inline-flex;
+ [data-slot="labels"] {
+ display: flex;
flex-wrap: wrap;
- align-items: center;
- gap: 0.375rem;
+ gap: 0.25rem;
+ margin-top: 0.25rem;
}
- [data-slot="model"] small {
+ [data-slot="labels"] :is(small, a) {
border: 1px solid var(--go-console-border);
padding: 0 0.25rem;
font-size: 0.625rem;
+ line-height: 1rem;
}
- [data-slot="model"] a {
- display: inline-flex;
- align-items: center;
- color: var(--go-console-muted);
+ [data-slot="labels"] a {
+ color: inherit;
text-decoration: none;
+ transition:
+ background-color 180ms ease,
+ border-color 180ms ease;
+ }
+ [data-slot="labels"] a:hover {
+ background: var(--go-console-track);
+ border-color: var(--go-console-track);
}
[data-slot="bars"] {
position: relative;
@@ -178,32 +180,20 @@
position: absolute;
inset-block: 0;
border-inline-start: 1px dashed var(--go-console-border);
- transition: inset-inline-start 600ms cubic-bezier(0.22, 1, 0.36, 1);
}
[data-slot="track"] {
position: relative;
- display: flex;
- gap: 0.25rem;
- height: 0.5rem;
+ display: grid;
+ grid-template-rows: 0.5rem 0.5rem;
+ row-gap: 0.5rem;
margin: 0.5rem 0;
}
- [data-slot="track"] > [data-tier] {
- position: relative;
+ [data-slot="lane"] {
+ display: flex;
+ gap: 0.25rem;
+ }
+ [data-slot="lane"] > [data-tier] {
border-radius: 2px;
- background: linear-gradient(var(--v2-yellow-500), var(--v2-yellow-600));
- transition: width 600ms cubic-bezier(0.22, 1, 0.36, 1);
- }
- [data-slot="track"] > [data-tier]::after {
- content: "";
- position: absolute;
- inset: 0;
- border-radius: inherit;
- background: linear-gradient(var(--v2-orange-500), var(--v2-orange-600));
- opacity: 0;
- transition: opacity 300ms ease;
- }
- [data-slot="track"] > [data-tier="plus"]::after {
- opacity: 1;
}
[data-slot="remainder"] {
flex: 1;
@@ -215,12 +205,13 @@
text-align: end;
white-space: nowrap;
}
+ :is(thead th, [data-slot="number"]):last-child {
+ padding-inline-start: 0.5rem;
+ }
[data-slot="number"] span {
display: block;
- line-height: 1.25rem;
- }
- [data-slot="plan-value"] {
- animation: go-plan-value-in 300ms ease-out both;
+ /* 13px digits are ~9.5px tall, so this leaves the same ~8px visual gap as the bars. */
+ line-height: 1.1rem;
}
[data-slot="axis"] {
position: relative;
@@ -232,7 +223,6 @@
position: absolute;
top: 0.25rem;
transform: translateX(-50%);
- transition: inset-inline-start 600ms cubic-bezier(0.22, 1, 0.36, 1);
}
&:dir(rtl) [data-slot="axis"] span {
transform: translateX(50%);
@@ -262,27 +252,95 @@
flex-direction: column;
}
}
- @media (prefers-reduced-motion: reduce) {
- [data-slot="tier-switch"] button,
+ /* Phones stack each model name above its bar so the table fits without horizontal scrolling. */
+ @media (max-width: 40rem) {
+ /* Rows share the table's columns through subgrid, so number columns size to their unwrapped headers. */
+ table {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto auto;
+ min-width: 0;
+ }
+ thead,
+ tbody,
+ tfoot {
+ display: contents;
+ }
+ colgroup,
+ tfoot td:not([data-slot="axis"]) {
+ display: none;
+ }
+ tr {
+ display: grid;
+ grid-column: 1 / -1;
+ grid-template-columns: subgrid;
+ align-items: center;
+ }
+ thead tr {
+ border: 1px solid var(--go-console-border);
+ border-radius: 6px;
+ }
+ thead th,
+ thead th:is(:first-child, :last-child) {
+ border: 0;
+ padding-inline: 0.375rem;
+ font-size: 0.75rem;
+ }
+ /* The bars are too narrow to label 100 and 1K apart from 10K. */
[data-slot="gridline"],
- [data-slot="track"] > [data-tier],
- [data-slot="track"] > [data-tier]::after,
- [data-slot="axis"] span {
- transition: none;
+ [data-slot="axis"] span:not(:last-child) {
+ display: none;
}
- [data-slot="plan-value"] {
- animation: none;
+ thead th:first-child {
+ padding-inline-start: 1rem;
+ }
+ thead th:last-child,
+ [data-slot="number"]:last-child {
+ padding-inline-end: 1rem;
+ }
+ tbody th {
+ grid-column: 1 / -1;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.25rem 0.5rem;
+ padding-block-end: 0;
+ }
+ [data-slot="labels"] {
+ margin-top: 0;
+ }
+ /* Bars extend under the requests column's spare header width, stopping short of the right-aligned numbers. */
+ [data-slot="bars"],
+ [data-slot="axis"] {
+ grid-column: 1 / 3;
+ margin-inline: 1rem 4rem;
+ }
+ [data-slot="bars"] {
+ grid-row: 2;
+ }
+ [data-slot="bars"] + [data-slot="number"] {
+ grid-row: 2;
+ grid-column: 2;
+ }
+ [data-slot="number"]:last-child {
+ grid-row: 2;
+ grid-column: 3;
+ }
+ [data-slot="number"] {
+ padding-inline: 0.375rem;
+ }
+ /* Rows are grids here, so highlight the row itself instead of each cell. */
+ tbody tr {
+ padding-block: 0.375rem;
+ border-radius: 6px;
+ transition: background-color 120ms ease;
+ }
+ tbody tr:hover {
+ background: var(--go-console-surface);
+ }
+ tbody tr > *,
+ tbody tr:hover > * {
+ border-radius: 0;
+ background: none;
}
}
}
-
-@keyframes go-plan-value-in {
- from {
- opacity: 0.3;
- transform: translateY(3px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
diff --git a/packages/console/app/src/component/go-plan-chart.tsx b/packages/console/app/src/component/go-plan-chart.tsx
index 0efbb34702..45dd4f786f 100644
--- a/packages/console/app/src/component/go-plan-chart.tsx
+++ b/packages/console/app/src/component/go-plan-chart.tsx
@@ -5,22 +5,17 @@ import { useLanguage } from "~/context/language"
import { goPlanModels } from "./go-models"
const ticks = [100, 1000, 10000]
+const max = Math.max(...goPlanModels.map((model) => model.plusRequests).filter(Number.isFinite))
export function GoPlanChart(props: { href: string }) {
const i18n = useI18n()
const language = useLanguage()
const id = createUniqueId()
const [expanded, setExpanded] = createSignal(false)
- const [tier, setTier] = createSignal<"go" | "go-plus">("go")
const models = createMemo(() => goPlanModels.filter((model) => expanded() || model.featured))
- const max = createMemo(() =>
- Math.max(
- ...goPlanModels.map((model) => (tier() === "go" ? model.requests : model.plusRequests)).filter(Number.isFinite),
- ),
- )
const position = (requests: number) =>
Number.isFinite(requests)
- ? 4 + Math.pow(Math.log10(Math.max(requests / 100, 1)) / Math.log10(max() / 100), 2.2) * 78
+ ? 4 + Math.pow(Math.log10(Math.max(requests / 100, 1)) / Math.log10(max / 100), 2.2) * 78
: 100
const format = createMemo(() => new Intl.NumberFormat(language.tag(language.locale())))
const currency = createMemo(
@@ -40,24 +35,24 @@ export function GoPlanChart(props: { href: string }) {
{i18n.t("go.plans.limits")}
{i18n.t("go.plans.description")}
-
-
-
-
+
+
-
-
-
+
+
+
@@ -73,60 +68,55 @@ export function GoPlanChart(props: { href: string }) {
{(model) => (
|
-
- {model.name}
-
- {i18n.t("go.graph.new")}
-
-
- {i18n.t("go.graph.limitedTime")}
-
-
-
-
-
-
-
+ {model.name}
+
+
+
+ {i18n.t("go.graph.new")}
+
+
+ {i18n.t("go.graph.limitedTime")}
+
+
+
+ {i18n.t("go.graph.limitedRegions")}
+
+
+
+
|
{(tick) => }
-
-
+
+ {/* The Go bar is a linear fraction of the Plus bar so the multiplier reads true on the log scale. */}
+
+
+
+
+
+
+
|
-
- {(selected) => (
-
- {format().format(selected === "go" ? model.requests : model.plusRequests)}
-
- )}
-
+ {format().format(model.requests)}
+ {format().format(model.plusRequests)}
|
-
- {(selected) => (
-
- {Number.isFinite(selected === "go" ? model.allowance : model.plusAllowance)
- ? currency().format(selected === "go" ? model.allowance : model.plusAllowance)
- : "∞"}
-
- )}
-
+ {Number.isFinite(model.allowance) ? currency().format(model.allowance) : "∞"}
+ {Number.isFinite(model.plusAllowance) ? currency().format(model.plusAllowance) : "∞"}
|
)}
diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx
index ed83a1934b..00bea727b9 100644
--- a/packages/console/app/src/component/icon.tsx
+++ b/packages/console/app/src/component/icon.tsx
@@ -141,13 +141,9 @@ export function IconAnthropic(props: JSX.SvgSVGAttributes) {
export function IconXai(props: JSX.SvgSVGAttributes) {
return (
-