fix(stats): scroll dense mobile charts
This commit is contained in:
@@ -2858,6 +2858,37 @@
|
|||||||
height: 400px;
|
height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"],
|
||||||
|
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: visible;
|
||||||
|
overscroll-behavior-x: contain;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"]::-webkit-scrollbar,
|
||||||
|
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"]::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] {
|
||||||
|
--top-models-mobile-bar-width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="top-models-axis"],
|
||||||
|
[data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"] [data-slot="top-models-bars"] {
|
||||||
|
min-width: calc(var(--top-models-count) * (var(--top-models-mobile-bar-width) + var(--top-models-bar-gap)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] {
|
||||||
|
--market-mobile-bar-width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-labels"],
|
||||||
|
[data-page="stats"] [data-component="market-share"][data-dense-labels="true"] [data-slot="market-bars"] {
|
||||||
|
min-width: calc(var(--market-count) * (var(--market-mobile-bar-width) + var(--market-gap)));
|
||||||
|
}
|
||||||
|
|
||||||
[data-page="stats"] [data-slot="top-models-axis"] > div {
|
[data-page="stats"] [data-slot="top-models-axis"] > div {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -596,18 +596,23 @@ function TopModelsChart(props: {
|
|||||||
activeModel: string | undefined
|
activeModel: string | undefined
|
||||||
onActiveModelChange: (model: string | undefined) => void
|
onActiveModelChange: (model: string | undefined) => void
|
||||||
}) {
|
}) {
|
||||||
|
let chartRef: HTMLDivElement | undefined
|
||||||
const [activeIndex, setActiveIndex] = createSignal<number>()
|
const [activeIndex, setActiveIndex] = createSignal<number>()
|
||||||
const maxTotal = createMemo(() => getTopModelsMaxTotal(props.data))
|
const maxTotal = createMemo(() => getTopModelsMaxTotal(props.data))
|
||||||
const segmentOrder = createMemo(() => getTopModelsSegmentOrder(props.data))
|
const segmentOrder = createMemo(() => getTopModelsSegmentOrder(props.data))
|
||||||
const activePoint = createMemo(() => props.data[activeIndex() ?? -1])
|
const activePoint = createMemo(() => props.data[activeIndex() ?? -1])
|
||||||
|
|
||||||
|
createEffect(() => scrollDenseChartToEnd(chartRef, props.range, props.data.length))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={chartRef}
|
||||||
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}
|
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"
|
||||||
|
style={{ "--top-models-count": props.data.length } as JSX.CSSProperties}
|
||||||
>
|
>
|
||||||
<div data-slot="top-models-axis" aria-hidden="true">
|
<div data-slot="top-models-axis" aria-hidden="true">
|
||||||
<For each={props.data}>
|
<For each={props.data}>
|
||||||
@@ -817,6 +822,13 @@ function isDenseColumnRange(range: UsageRange) {
|
|||||||
return range === "1M" || range === "2M"
|
return range === "1M" || range === "2M"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scrollDenseChartToEnd(element: HTMLDivElement | undefined, range: UsageRange, count: number) {
|
||||||
|
if (!element || count <= 0 || !isDenseColumnRange(range) || typeof window === "undefined") return
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
element.scrollLeft = element.scrollWidth - element.clientWidth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -1000,8 +1012,13 @@ function MarketShare(props: {
|
|||||||
onActiveIndexChange: (index: number) => void
|
onActiveIndexChange: (index: number) => void
|
||||||
onActiveAuthorChange: (author: string) => void
|
onActiveAuthorChange: (author: string) => void
|
||||||
}) {
|
}) {
|
||||||
|
let chartRef: HTMLDivElement | undefined
|
||||||
|
|
||||||
|
createEffect(() => scrollDenseChartToEnd(chartRef, props.range, props.data.length))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={chartRef}
|
||||||
data-component="market-share"
|
data-component="market-share"
|
||||||
data-range={props.range}
|
data-range={props.range}
|
||||||
data-dense-labels={isDenseColumnRange(props.range) ? "true" : undefined}
|
data-dense-labels={isDenseColumnRange(props.range) ? "true" : undefined}
|
||||||
|
|||||||
Reference in New Issue
Block a user