From e7ad18e2d7bb32994e122dbd6f0fec446fd2731e Mon Sep 17 00:00:00 2001 From: Bartosz Kaszubowski Date: Mon, 13 Jul 2026 20:41:07 +0200 Subject: [PATCH 1/2] PackageVersions: add latest version buckets percentage share --- .../Package/Charts/VersionDownloadsChart.tsx | 12 +++-- .../Charts/VersionDownloadsChartModes.tsx | 54 ++++++++++++------- components/Package/Charts/utils.ts | 40 ++++++++++++++ 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/components/Package/Charts/VersionDownloadsChart.tsx b/components/Package/Charts/VersionDownloadsChart.tsx index 4d1f86a0e..240663012 100644 --- a/components/Package/Charts/VersionDownloadsChart.tsx +++ b/components/Package/Charts/VersionDownloadsChart.tsx @@ -7,13 +7,13 @@ import { useState } from 'react'; import { View } from 'react-native'; import { Label } from '~/common/styleguide'; -import ChartTooltip from '~/components/Package/Charts/ChartTooltip'; -import HoveredBarOutline from '~/components/Package/Charts/HoveredBarOutline'; import { type NpmPerVersionDownloads, type PackageVersionsData } from '~/types'; import { replaceQueryParam } from '~/util/queryParams'; import { NUMBER_FORMATTER, pluralize } from '~/util/strings'; import tw from '~/util/tailwind'; +import ChartTooltip from './ChartTooltip'; +import HoveredBarOutline from './HoveredBarOutline'; import { type VersionsAggregatedChartMode, type VersionsChartData, @@ -28,6 +28,7 @@ import { DEFAULT_CHART_MODE, getChartLeftMargin, getLargestSeriesLength, + getLatestVersionDownloadsPercentage, getPrimaryChartLabel, LABEL_TO_BAR_GAP, mapVersionDistTags, @@ -59,6 +60,7 @@ export default function VersionDownloadsChart({ npmDownloads, registryData }: Pr const series = chartSeriesByMode[mode]; const seriesByLabel = keyBy(series, item => item.label); const leftMargin = getChartLeftMargin(series); + const downloadsPercentage = getLatestVersionDownloadsPercentage(baseSeries, registryData, mode); if (!series.length) { return ( @@ -88,7 +90,11 @@ export default function VersionDownloadsChart({ npmDownloads, registryData }: Pr return ( // @ts-expect-error Ref type miss-match - + void; + downloadsPercentage: number; }; const CHART_MODES: { key: VersionsChartMode; label: string; shortLabel: string }[] = [ @@ -17,27 +18,42 @@ const CHART_MODES: { key: VersionsChartMode; label: string; shortLabel: string } { key: 'major', label: 'By major', shortLabel: 'Major' }, ]; -export default function VersionDownloadsChartModes({ mode, onModeChange }: Props) { +export default function VersionDownloadsChartModes({ + mode, + onModeChange, + downloadsPercentage, +}: Props) { const { isSmallScreen } = useLayout(); return ( - - {CHART_MODES.map(({ key, label, shortLabel }) => ( - - ))} + + + {CHART_MODES.map(({ key, label, shortLabel }) => ( + + ))} + + ); } diff --git a/components/Package/Charts/utils.ts b/components/Package/Charts/utils.ts index 74ee29eac..83e1530de 100644 --- a/components/Package/Charts/utils.ts +++ b/components/Package/Charts/utils.ts @@ -60,6 +60,46 @@ export function buildChartSeriesByMode(baseSeries: VersionsChartData[]): Version }; } +export function getLatestVersionDownloadsPercentage( + baseSeries: VersionsChartData[], + registryData: PackageVersionsData, + mode: VersionsChartMode +) { + const totalDownloads = sumBy(baseSeries, item => item.downloads); + + if (!totalDownloads) { + return 0; + } + + const latestVersion = registryData['dist-tags'].latest; + + if (!latestVersion) { + return 0; + } + + if (mode === 'version') { + return ( + ((baseSeries.find(item => item.label === latestVersion)?.downloads ?? 0) / totalDownloads) * + 100 + ); + } + + const latestAggregateLabel = getAggregatedSemverLabel(latestVersion, mode); + + if (!latestAggregateLabel) { + return ( + ((baseSeries.find(item => item.label === latestVersion)?.downloads ?? 0) / totalDownloads) * + 100 + ); + } + + const latestAggregateDownloads = sumBy(baseSeries, item => + getAggregatedSemverLabel(item.label, mode) === latestAggregateLabel ? item.downloads : 0 + ); + + return (latestAggregateDownloads / totalDownloads) * 100; +} + export function createVersionChartEntry( version: string, downloads = 0, From 090f67a68fd519f813d9e93dfa33e59a4e9afa57 Mon Sep 17 00:00:00 2001 From: Bartosz Kaszubowski Date: Mon, 13 Jul 2026 20:52:15 +0200 Subject: [PATCH 2/2] mobile/small screen display tweaks --- components/Package/Charts/VersionDownloadsChart.tsx | 7 ++++--- components/Package/Charts/VersionDownloadsChartModes.tsx | 6 +++--- components/Package/Charts/utils.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/components/Package/Charts/VersionDownloadsChart.tsx b/components/Package/Charts/VersionDownloadsChart.tsx index 240663012..df0f6c7e8 100644 --- a/components/Package/Charts/VersionDownloadsChart.tsx +++ b/components/Package/Charts/VersionDownloadsChart.tsx @@ -6,7 +6,7 @@ import { useRouter } from 'next/router'; import { useState } from 'react'; import { View } from 'react-native'; -import { Label } from '~/common/styleguide'; +import { Label, useLayout } from '~/common/styleguide'; import { type NpmPerVersionDownloads, type PackageVersionsData } from '~/types'; import { replaceQueryParam } from '~/util/queryParams'; import { NUMBER_FORMATTER, pluralize } from '~/util/strings'; @@ -47,6 +47,7 @@ const OTHER_BAR_GRADIENT_ID = 'version-downloads-chart-other'; export default function VersionDownloadsChart({ npmDownloads, registryData }: Props) { const isDark = tw.prefixMatch('dark'); + const { isSmallScreen } = useLayout(); const router = useRouter(); const routeMode = parseChartMode(router.query[CHART_MODE_QUERY_PARAM]); @@ -100,7 +101,7 @@ export default function VersionDownloadsChart({ npmDownloads, registryData }: Pr height={height} xScale={{ type: 'linear', domain: xDomain }} yScale={{ type: 'band', paddingInner: 0.23, paddingOuter: 0.15 }} - margin={{ top: 2, right: 12, bottom: 20, left: leftMargin }}> + margin={{ top: 2, right: 8, bottom: 20, left: leftMargin }}> NUMBER_FORMATTER.format(value)} diff --git a/components/Package/Charts/VersionDownloadsChartModes.tsx b/components/Package/Charts/VersionDownloadsChartModes.tsx index a35a777d9..5d6fe004a 100644 --- a/components/Package/Charts/VersionDownloadsChartModes.tsx +++ b/components/Package/Charts/VersionDownloadsChartModes.tsx @@ -25,15 +25,15 @@ export default function VersionDownloadsChartModes({ }: Props) { const { isSmallScreen } = useLayout(); return ( - - + + {CHART_MODES.map(({ key, label, shortLabel }) => (