fix(stats): rotate dense chart labels

This commit is contained in:
Adam
2026-05-29 13:21:16 -05:00
parent b956e9a06f
commit ce4e0e8a4e
3 changed files with 80 additions and 12 deletions

View File

@@ -1065,10 +1065,66 @@
flex-direction: column; flex-direction: column;
} }
[data-page="stats"] [data-slot="top-models-axis"] > div[data-label-hidden="true"]:not([data-active="true"])
[data-slot="axis-label"],
[data-page="stats"] [data-slot="market-labels"] button[data-label-hidden="true"]:not([data-active="true"])
[data-slot="market-axis-label"] {
visibility: hidden;
}
[data-page="stats"] [data-slot="axis-date-mobile"] { [data-page="stats"] [data-slot="axis-date-mobile"] {
display: none; display: none;
} }
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] {
grid-template-rows: 40px minmax(0, 1fr);
}
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] {
grid-template-rows: 40px minmax(0, 1fr);
}
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"]
[data-slot="top-models-axis"]
> div {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 40px;
font-weight: 600;
}
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-labels"] button {
position: relative;
align-items: center;
justify-content: center;
height: 40px;
line-height: 1.2;
}
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="axis-label"],
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-axis-label"] {
position: absolute;
left: 50%;
width: max-content;
max-width: 72px;
transform: rotate(-90deg) translateX(-50%);
transform-origin: left center;
}
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="axis-total"],
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="axis-date-full"],
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-total"],
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-date-full"] {
display: none;
}
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="axis-date-mobile"],
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-date-mobile"] {
display: block;
}
[data-page="stats"] [data-slot="top-models-bars"] { [data-page="stats"] [data-slot="top-models-bars"] {
width: calc(100% + var(--top-models-bar-gap)); width: calc(100% + var(--top-models-bar-gap));
margin-inline: calc(var(--top-models-bar-gap) / -2); margin-inline: calc(var(--top-models-bar-gap) / -2);

View File

@@ -370,7 +370,7 @@ function formatUpdatedAtLabel(value: { date: string; time: string }) {
function TopModelsSection(props: { data: StatsHomeData["usage"] }) { function TopModelsSection(props: { data: StatsHomeData["usage"] }) {
const [product, setProduct] = createSignal<UsageProduct>("All Users") const [product, setProduct] = createSignal<UsageProduct>("All Users")
const [range, setRange] = createSignal<UsageRange>("1W") const [range, setRange] = createSignal<UsageRange>("2M")
const [sheet, setSheet] = createSignal<"product" | "range">() const [sheet, setSheet] = createSignal<"product" | "range">()
const data = createMemo(() => props.data[product()][range()]) const data = createMemo(() => props.data[product()][range()])
@@ -585,6 +585,7 @@ function TopModelsChart(props: { data: UsagePoint[]; range: UsageRange }) {
<div <div
data-component="top-models-chart" data-component="top-models-chart"
data-range={props.range} data-range={props.range}
data-dense-labels={isDenseColumnRange(props.range) ? "true" : undefined}
role="img" role="img"
aria-label="Stacked top model usage chart" aria-label="Stacked top model usage chart"
> >
@@ -593,6 +594,7 @@ function TopModelsChart(props: { data: UsagePoint[]; range: UsageRange }) {
{(day, index) => ( {(day, index) => (
<div <div
data-active={activeIndex() === index() ? "true" : undefined} data-active={activeIndex() === index() ? "true" : undefined}
data-label-hidden={isColumnLabelHidden(index(), props.data.length) ? "true" : undefined}
data-mobile-hidden={isTopModelsMobileAxisHidden(index(), props.data.length) ? "true" : undefined} data-mobile-hidden={isTopModelsMobileAxisHidden(index(), props.data.length) ? "true" : undefined}
> >
<span data-slot="axis-label"> <span data-slot="axis-label">
@@ -755,6 +757,16 @@ function isTopModelsMobileAxisHidden(index: number, count: number) {
return count > 7 && index % 2 === 1 return count > 7 && index % 2 === 1
} }
function isColumnLabelHidden(index: number, count: number) {
if (count <= 20) return false
const interval = Math.ceil(count / 8)
return index !== count - 1 && index % interval !== 0
}
function isDenseColumnRange(range: UsageRange) {
return range === "1M" || range === "2M"
}
function formatTopModelsMobileDate(label: string, range: UsageRange) { function formatTopModelsMobileDate(label: string, range: UsageRange) {
if (range === "1M" || range === "2M") return label.split(" - ")[0] ?? label if (range === "1M" || range === "2M") return label.split(" - ")[0] ?? label
return label return label
@@ -771,7 +783,7 @@ function formatTokens(value: number) {
function LeaderboardSection(props: { data: StatsHomeData["leaderboard"] }) { function LeaderboardSection(props: { data: StatsHomeData["leaderboard"] }) {
const [product, setProduct] = createSignal<UsageProduct>("All Users") const [product, setProduct] = createSignal<UsageProduct>("All Users")
const [range, setRange] = createSignal<UsageRange>("1W") const [range, setRange] = createSignal<UsageRange>("2M")
const data = createMemo(() => props.data[product()][range()]) const data = createMemo(() => props.data[product()][range()])
return ( return (
@@ -870,7 +882,7 @@ function formatChange(value: number) {
} }
function MarketShareSection(props: { data: StatsHomeData["market"] }) { function MarketShareSection(props: { data: StatsHomeData["market"] }) {
const [range, setRange] = createSignal<UsageRange>("1W") const [range, setRange] = createSignal<UsageRange>("2M")
const [activeIndex, setActiveIndex] = createSignal(2) const [activeIndex, setActiveIndex] = createSignal(2)
const [activeAuthor, setActiveAuthor] = createSignal<string>() const [activeAuthor, setActiveAuthor] = createSignal<string>()
const [inspecting, setInspecting] = createSignal(false) const [inspecting, setInspecting] = createSignal(false)
@@ -898,6 +910,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
<> <>
<MarketShare <MarketShare
data={data()} data={data()}
range={range()}
activeIndex={selectedIndex()} activeIndex={selectedIndex()}
activeAuthor={activeAuthor()} activeAuthor={activeAuthor()}
inspecting={inspecting()} inspecting={inspecting()}
@@ -944,6 +957,7 @@ function MarketShareSection(props: { data: StatsHomeData["market"] }) {
function MarketShare(props: { function MarketShare(props: {
data: MarketDay[] data: MarketDay[]
range: UsageRange
activeIndex: number activeIndex: number
activeAuthor: string | undefined activeAuthor: string | undefined
inspecting: boolean inspecting: boolean
@@ -953,6 +967,8 @@ function MarketShare(props: {
return ( return (
<div <div
data-component="market-share" data-component="market-share"
data-range={props.range}
data-dense-labels={isDenseColumnRange(props.range) ? "true" : undefined}
role="img" role="img"
aria-label="Market share by model author" aria-label="Market share by model author"
style={{ "--market-count": props.data.length } as JSX.CSSProperties} style={{ "--market-count": props.data.length } as JSX.CSSProperties}
@@ -963,6 +979,7 @@ function MarketShare(props: {
<button <button
type="button" type="button"
data-active={props.inspecting && props.activeIndex === index() ? "true" : undefined} data-active={props.inspecting && props.activeIndex === index() ? "true" : undefined}
data-label-hidden={isColumnLabelHidden(index(), props.data.length) ? "true" : undefined}
data-mobile-hidden={isMarketMobileLabelHidden(index(), props.data.length) ? "true" : undefined} data-mobile-hidden={isMarketMobileLabelHidden(index(), props.data.length) ? "true" : undefined}
onClick={() => props.onActiveIndexChange(index())} onClick={() => props.onActiveIndexChange(index())}
onPointerEnter={() => props.onActiveIndexChange(index())} onPointerEnter={() => props.onActiveIndexChange(index())}

View File

@@ -330,13 +330,9 @@ function createBuckets(window: DateWindow, range: UsageRange): Bucket[] {
const count = const count =
range === "1D" range === "1D"
? 1 ? 1
: range === "2W" : range === "1W" || range === "2W" || range === "1M" || range === "2M" || range === "3M"
? 14 ? Math.ceil(span / DAY_MS)
: range === "1M" : Math.max(1, Math.min(7, Math.ceil(span / DAY_MS)))
? 4
: range === "2M"
? 8
: Math.max(1, Math.min(7, Math.ceil(span / DAY_MS)))
const size = span / count const size = span / count
return Array.from({ length: count }, (_, index) => { return Array.from({ length: count }, (_, index) => {
const start = window.start + index * size const start = window.start + index * size
@@ -443,14 +439,13 @@ function periodKeyTime(value: string) {
return Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])) return Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
} }
function formatBucketLabel(start: number, end: number, range: UsageRange) { function formatBucketLabel(start: number, _end: number, range: UsageRange) {
const date = new Date(start) const date = new Date(start)
if (range === "YTD") return months[date.getUTCMonth()] if (range === "YTD") return months[date.getUTCMonth()]
if (range === "ALL") if (range === "ALL")
return date.getUTCFullYear() === new Date().getUTCFullYear() return date.getUTCFullYear() === new Date().getUTCFullYear()
? months[date.getUTCMonth()] ? months[date.getUTCMonth()]
: String(date.getUTCFullYear()) : String(date.getUTCFullYear())
if (range === "1M" || range === "2M") return `${formatDay(start)} - ${formatDay(end - DAY_MS)}`
return formatDay(start) return formatDay(start)
} }