diff --git a/packages/stats/app/src/routes/[lab]/index.tsx b/packages/stats/app/src/routes/[lab]/index.tsx index 4152f51c42..0ec67cd8d6 100644 --- a/packages/stats/app/src/routes/[lab]/index.tsx +++ b/packages/stats/app/src/routes/[lab]/index.tsx @@ -1,5 +1,6 @@ import "../index.css" import { Meta, Title } from "@solidjs/meta" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { getStatsLabData, type LabUsageModelEntry, @@ -118,10 +119,10 @@ export default function StatsLab() {
}> - }> + }> {(data) => ( <> - + @@ -141,97 +142,90 @@ export default function StatsLab() { function LabLoading() { const i18n = useI18n() - const language = useLanguage() return (
-
-
- - {i18n.t("footer.modelData")} - -

- - {i18n.t("lab.loadingTitle")} - -

-

{i18n.t("lab.loadingDescription")}

-
-
+ +
) } -function LabNotFound(props: { lab: string }) { +function LabNotFound(props: { lab: string; labs: ModelCatalogLab[] }) { const i18n = useI18n() - const language = useLanguage() + const labName = () => formatCatalogLabName(props.lab) return (
- + + +

{i18n.t("lab.notFound")}

) } -function LabHero(props: { lab: ModelCatalogLab; stats: StatsLabData | null }) { - const i18n = useI18n() - const language = useLanguage() - const latest = createMemo( - () => - props.lab.models - .map((model) => model.releaseDate) - .filter((value): value is string => value !== undefined) - .toSorted((a, b) => new Date(b).getTime() - new Date(a).getTime())[0], - ) - const featuredModels = createMemo(() => props.lab.models.slice(0, 3).map((model) => model.name)) - +function LabHero(props: { lab: ModelCatalogLab; labs: ModelCatalogLab[] }) { return (
- - {i18n.t("footer.modelData")} + + +
+ ) +} + +function LabHeroBreadcrumb(props: { label: string; labs?: ModelCatalogLab[] }) { + const language = useLanguage() + const labs = () => props.labs ?? [] + return ( + + ) +} + +function LabHeroTitleRow(props: { icon?: string; label: string }) { + return ( +
+ + {(icon) => + +

{props.label}

+ ) } @@ -424,11 +418,6 @@ function formatCatalogDate(value: string | undefined, locale: string, unknown: s }).format(new Date(Date.UTC(year, month, day))) } -function formatList(values: string[], locale = "en") { - if (values.length <= 1) return values[0] ?? "" - return new Intl.ListFormat(locale, { style: "long", type: "conjunction" }).format(values) -} - function formatPercent(value: number) { return `${trimNumber(value, value >= 10 ? 1 : 2)}%` } @@ -460,3 +449,10 @@ function isLabUsageLabelHidden(index: number, count: number) { const cadence = count > 45 ? 7 : count > 28 ? 4 : 2 return index % cadence !== 0 && index !== count - 1 } + +function getProviderIconId(provider: string) { + const id = provider.toLowerCase().replace(/[^a-z0-9]+/g, "") + if (id === "moonshot") return "moonshotai" + if (id === "zhipu") return "zhipuai" + return id +} diff --git a/packages/stats/app/src/routes/index.css b/packages/stats/app/src/routes/index.css index f7f039c16c..c0bd0228c2 100644 --- a/packages/stats/app/src/routes/index.css +++ b/packages/stats/app/src/routes/index.css @@ -2844,6 +2844,210 @@ line-height: 1.5; } +[data-page="stats"] [data-section="lab-hero"] { + align-content: start; + gap: 24px; + min-height: 312px; + padding: 128px 40px 40px; + box-shadow: none; +} + +[data-page="stats"] [data-component="lab-hero-breadcrumb"] { + display: flex; + align-items: center; + gap: 8px; + height: 24px; + min-width: 0; +} + +[data-page="stats"] [data-slot="lab-hero-crumb"] { + display: inline-flex; + align-items: center; + gap: 4px; + max-width: min(100%, 280px); + height: 24px; + box-sizing: border-box; + padding: 0 8px; + overflow: hidden; + background: var(--stats-layer-2); + color: var(--stats-hero-muted); + font-size: 13px; + font-weight: 500; + line-height: 1.1; + text-decoration: none; + white-space: nowrap; +} + +[data-page="stats"] [data-component="lab-hero-menu"] { + position: relative; + display: inline-block; +} + +[data-page="stats"] [data-component="lab-hero-menu"] summary { + cursor: pointer; + list-style: none; +} + +[data-page="stats"] [data-component="lab-hero-menu"] summary::-webkit-details-marker { + display: none; +} + +[data-page="stats"] [data-slot="lab-hero-crumb"][data-current="true"] { + padding-right: 4px; +} + +[data-page="stats"] a[data-slot="lab-hero-crumb"]:hover, +[data-page="stats"] a[data-slot="lab-hero-crumb"]:focus-visible, +[data-page="stats"] summary[data-slot="lab-hero-crumb"]:hover, +[data-page="stats"] summary[data-slot="lab-hero-crumb"]:focus-visible { + color: var(--stats-text); + outline: none; + text-decoration: none; +} + +[data-page="stats"] [data-slot="lab-hero-crumb"] span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; +} + +[data-page="stats"] [data-slot="lab-hero-crumb"] svg { + flex: 0 0 auto; + width: 16px; + height: 16px; + color: var(--stats-faint); +} + +[data-page="stats"] [data-component="lab-hero-menu"][open] [data-slot="lab-hero-crumb"] svg { + transform: rotate(180deg); +} + +[data-page="stats"] [data-slot="lab-hero-options"] { + position: absolute; + top: calc(100% + 8px); + left: 50%; + z-index: 5; + display: grid; + width: max-content; + min-width: 180px; + max-width: min(280px, calc(100vw - 48px)); + max-height: min(360px, calc(100vh - 160px)); + padding: 6px; + overflow: auto; + border: 1px solid var(--stats-line); + background: var(--stats-bg); + box-shadow: 0 12px 32px #0000001a; + transform: translateX(-50%); +} + +[data-page="stats"] [data-slot="lab-hero-option"] { + display: flex; + align-items: center; + min-width: 0; + height: 30px; + padding: 0 8px; + overflow: hidden; + color: var(--stats-muted); + font-size: 13px; + font-weight: 500; + line-height: 1.2; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-page="stats"] [data-slot="lab-hero-option"]:hover, +[data-page="stats"] [data-slot="lab-hero-option"]:focus-visible { + background: var(--stats-layer-2); + color: var(--stats-text); + outline: none; + text-decoration: none; +} + +[data-page="stats"] [data-slot="lab-hero-option"][data-current="true"] { + background: var(--stats-layer-2); + color: var(--stats-text); +} + +[data-page="stats"] [data-slot="lab-hero-separator"] { + display: inline-flex; + align-items: center; + justify-content: center; + width: 8px; + height: 24px; + color: var(--stats-faint); + font-size: 13px; + font-weight: 500; + line-height: 1.1; +} + +[data-page="stats"] [data-slot="lab-hero-title-row"] { + display: flex; + align-items: center; + gap: 40px; + height: 96px; + min-width: 0; + overflow: hidden; +} + +[data-page="stats"] [data-slot="lab-hero-avatar"] { + display: grid; + place-items: center; + flex: 0 0 auto; + width: 64px; + height: 64px; + background: var(--stats-accent-text); + box-shadow: inset 0 0 0 1px #0000001a; + color: #ffffff; +} + +[data-page="stats"] [data-slot="lab-hero-avatar"][data-empty="true"] { + background: var(--stats-layer-2); +} + +[data-page="stats"] [data-slot="lab-hero-avatar"] svg { + width: 42px; + height: 42px; +} + +[data-page="stats"] [data-section="lab-hero"] h1 { + flex: 0 1 auto; + min-width: 0; + max-width: 100%; + overflow: hidden; + color: var(--stats-text); + font-size: 64px; + font-weight: 500; + line-height: 96px; + letter-spacing: 0; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-page="stats"] [data-slot="lab-hero-pattern"] { + flex: 1 1 0; + min-width: 64px; + height: 64px; + overflow: hidden; + background: color-mix(in srgb, var(--stats-text) 10%, transparent); + mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E"); + mask-position: center top; + mask-repeat: repeat; + mask-size: 6px 6px; + -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E"); + -webkit-mask-position: center top; + -webkit-mask-repeat: repeat; + -webkit-mask-size: 6px 6px; +} + +[data-page="stats"] [data-slot="lab-hero-state"] { + max-width: 480px; + color: var(--stats-muted); + font-size: 13px; + font-weight: 400; + line-height: 1.5; +} + [data-page="stats"] [data-slot="model-weight-link"] { width: fit-content; color: var(--stats-muted); @@ -3659,6 +3863,11 @@ [data-page="stats"] [data-section="model-panel"] { padding: 64px 32px; } + + [data-page="stats"] [data-section="lab-hero"] { + min-height: 280px; + padding: 104px 32px 40px; + } } @media (max-width: 58rem) { @@ -3843,8 +4052,7 @@ width: 100%; } - [data-page="stats"] [data-section="model-hero"], - [data-page="stats"] [data-section="lab-hero"] { + [data-page="stats"] [data-section="model-hero"] { gap: 20px; } @@ -3852,8 +4060,42 @@ gap: 24px; } - [data-page="stats"] [data-section="model-hero"] h1, + [data-page="stats"] [data-section="lab-hero"] { + gap: 20px; + min-height: 232px; + padding: 72px 24px 40px; + } + + [data-page="stats"] [data-slot="lab-hero-title-row"] { + gap: 16px; + height: 72px; + } + + [data-page="stats"] [data-slot="lab-hero-avatar"] { + width: 48px; + height: 48px; + } + + [data-page="stats"] [data-slot="lab-hero-avatar"] svg { + width: 32px; + height: 32px; + } + [data-page="stats"] [data-section="lab-hero"] h1 { + font-size: 42px; + line-height: 72px; + } + + [data-page="stats"] [data-slot="lab-hero-pattern"] { + height: 48px; + min-width: 48px; + } + + [data-page="stats"] [data-slot="lab-hero-options"] { + max-width: calc(100vw - 48px); + } + + [data-page="stats"] [data-section="model-hero"] h1 { font-size: 38px; line-height: 1; } @@ -4161,6 +4403,34 @@ } } +@media (max-width: 30rem) { + [data-page="stats"] [data-slot="lab-hero-pattern"] { + display: none; + } + + [data-page="stats"] [data-section="lab-hero"] h1 { + flex: 1 1 auto; + } +} + +@media (max-width: 24rem) { + [data-page="stats"] [data-slot="lab-hero-title-row"] { + height: auto; + min-height: 72px; + } + + [data-page="stats"] [data-slot="lab-hero-avatar"] { + display: none; + } + + [data-page="stats"] [data-section="lab-hero"] h1 { + overflow: visible; + line-height: 1.05; + text-overflow: clip; + white-space: normal; + } +} + @media (max-width: 40rem) { [data-page="stats"] [data-slot="footer-grid"] { grid-template-columns: 1fr;