Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions app/components/Package/VersionDistribution.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import {
drawNpmxLogoAndTaglineWatermark,
} from '~/composables/useChartWatermark'
import TooltipApp from '~/components/Tooltip/App.vue'
import { copyAltTextForVersionsBarChart } from '~/utils/charts'

const props = defineProps<{
packageName: string
inModal?: boolean
}>()

const { accentColors, selectedAccentColor } = useAccentColor()
const { copy, copied } = useClipboard()

const colorMode = useColorMode()
const resolvedMode = shallowRef<'light' | 'dark'>('light')
const rootEl = shallowRef<HTMLElement | null>(null)
Expand Down Expand Up @@ -190,14 +193,14 @@ const chartConfig = computed<VueUiXyConfig>(() => {
fullscreen: false,
table: false,
tooltip: false,
altCopy: false, // TODO: set to true to enable the alt copy feature
altCopy: true,
},
buttonTitles: {
csv: $t('package.trends.download_file', { fileType: 'CSV' }),
img: $t('package.trends.download_file', { fileType: 'PNG' }),
svg: $t('package.trends.download_file', { fileType: 'SVG' }),
annotator: $t('package.trends.toggle_annotator'),
altCopy: undefined, // TODO: set to proper translation key
altCopy: $t('package.trends.copy_alt.button_label'), // Do not make this text dependant on the `copied` variable, since this would re-render the component, which is undesirable if the minimap was used to select a time frame.
},
callbacks: {
img: args => {
Expand Down Expand Up @@ -230,10 +233,19 @@ const chartConfig = computed<VueUiXyConfig>(() => {
loadFile(url, buildExportFilename('svg'))
URL.revokeObjectURL(url)
},
// altCopy: ({ dataset: dst, config: cfg }: { dataset: Array<VueUiXyDatasetItem>; config: VueUiXyConfig}) => {
// // TODO: implement a reusable copy-alt-text-to-clipboard feature based on the dataset & configuration
// console.log({ dst, cfg})
// }
altCopy: ({ dataset: dst, config: cfg }) =>
copyAltTextForVersionsBarChart({
dataset: dst,
config: {
...cfg,
datapointLabels: xAxisLabels.value,
dateRangeLabel: dateRangeLabel.value,
semverGroupingMode: groupingMode.value,
copy,
$t,
numberFormatter: compactNumberFormatter.value.format,
},
}),
},
},
grid: {
Expand Down Expand Up @@ -575,6 +587,16 @@ const chartConfig = computed<VueUiXyConfig>(() => {
aria-hidden="true"
/>
</template>
<template #optionAltCopy>
<span
class="w-6 h-6"
:class="
copied ? 'i-lucide:check text-accent' : 'i-lucide:person-standing text-fg-subtle'
"
style="pointer-events: none"
aria-hidden="true"
/>
</template>
</VueUiXy>
</div>

Expand Down
78 changes: 77 additions & 1 deletion app/utils/charts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { AltCopyArgs, VueUiXyConfig, VueUiXyDatasetLineItem } from 'vue-data-ui'
import type {
AltCopyArgs,
VueUiXyConfig,
VueUiXyDatasetBarItem,
VueUiXyDatasetLineItem,
} from 'vue-data-ui'
import type { ChartTimeGranularity } from '~/types/chart'

export function sum(numbers: number[]): number {
Expand Down Expand Up @@ -413,6 +418,11 @@ export type TrendLineDataset = {
[key: string]: unknown
} | null

export type VersionsBarDataset = {
bars: VueUiXyDatasetBarItem[]
[key: string]: unknown
} | null

export type TrendTranslateKey = number | 'package.trends.y_axis_label' | (string & {})

export type TrendTranslateFunction = {
Expand All @@ -431,6 +441,12 @@ export type TrendLineConfig = VueUiXyConfig & {
numberFormatter: (value: number) => string
}

export type VersionsBarConfig = Omit<
TrendLineConfig,
'formattedDates' | 'hasEstimation' | 'formattedDatasetValues' | 'granularity'
> & { datapointLabels: string[]; dateRangeLabel: string; semverGroupingMode: string }

// Used for TrendsChart.vue
export function createAltTextForTrendLineChart({
dataset,
config,
Expand Down Expand Up @@ -519,3 +535,63 @@ export async function copyAltTextForTrendLineChart({
const altText = createAltTextForTrendLineChart({ dataset, config })
await config.copy(altText)
}

// Used for VersionDistribution.vue
export function createAltTextForVersionsBarChart({
dataset,
config,
}: AltCopyArgs<VersionsBarDataset, VersionsBarConfig>) {
if (!dataset) return ''

const series = dataset.bars[0]?.series ?? []
const versions = series.map((value, index) => ({
index,
name: config.datapointLabels[index] ?? '-',
rawDownloads: value ?? 0,
downloads: config.numberFormatter(value ?? 0),
}))

const versionWithMaxDownloads =
versions.length > 0
? versions.reduce((max, current) => (current.rawDownloads > max.rawDownloads ? current : max))
: undefined

const per_version_analysis = versions
.toReversed()
.filter(v => v.index !== versionWithMaxDownloads?.index)
.map(v =>
config.$t(`package.versions.copy_alt.per_version_analysis`, {
version: v?.name ?? '-',
downloads: v?.downloads ?? '-',
}),
)
.join(', ')

const semver_grouping_mode =
config.semverGroupingMode === 'major'
? config.$t('package.versions.grouping_major')
: config.$t('package.versions.grouping_minor')

const altText = `${config.$t('package.versions.copy_alt.general_description', {
package_name: dataset?.bars[0]?.name ?? '-',
versions_count: versions?.length,
semver_grouping_mode: semver_grouping_mode.toLocaleLowerCase(),
first_version: versions[0]?.name ?? '-',
last_version: versions.at(-1)?.name ?? '-',
date_range_label: config.dateRangeLabel ?? '-',
max_downloaded_version: versionWithMaxDownloads?.name ?? '-',
max_version_downloads: versionWithMaxDownloads?.downloads ?? '-',
per_version_analysis,
watermark: config.$t('package.trends.copy_alt.watermark'),
})}`

return altText
}

export async function copyAltTextForVersionsBarChart({
dataset,
config,
}: AltCopyArgs<VersionsBarDataset, VersionsBarConfig>) {
const altText = createAltTextForVersionsBarChart({ dataset, config })
await config.copy(altText)
}
6 changes: 5 additions & 1 deletion i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@
"filter_help": "Semver range filter help",
"filter_tooltip": "Filter versions using a {link}. For example, ^3.0.0 shows all 3.x versions.",
"filter_tooltip_link": "semver range",
"no_matches": "No versions match this range"
"no_matches": "No versions match this range",
"copy_alt": {
"per_version_analysis": "{version} version was downloaded {downloads} times",
"general_description": "Bar chart showing per-version downloads for {versions_count} {semver_grouping_mode} versions of the {package_name} package, {date_range_label} from the {first_version} version to the {last_version} version. The most downloaded version is {max_downloaded_version} with {max_version_downloads} downloads. {per_version_analysis} {watermark}."
}
},
"dependencies": {
"title": "Dependency ({count}) | Dependencies ({count})",
Expand Down
6 changes: 5 additions & 1 deletion i18n/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@
"filter_help": "Infos sur le filtre de plage semver",
"filter_tooltip": "Filtrer les versions avec une {link}. Par exemple, ^3.0.0 affiche toutes les versions 3.x.",
"filter_tooltip_link": "plage semver",
"no_matches": "Aucune version ne correspond à cette plage"
"no_matches": "Aucune version ne correspond à cette plage",
"copy_alt": {
"per_version_analysis": "La version {version} a été téléchargée {downloads} fois",
"general_description": "Graphique en barres montrant les téléchargements par version pour {versions_count} versions {semver_grouping_mode} du paquet {package_name}, {date_range_label} de la version {first_version} à la version {last_version}. La version la plus téléchargée est {max_downloaded_version} avec {max_version_downloads} téléchargements. {per_version_analysis} {watermark}."
}
},
"dependencies": {
"title": "Dépendances ({count})",
Expand Down
12 changes: 12 additions & 0 deletions i18n/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,18 @@
},
"no_matches": {
"type": "string"
},
"copy_alt": {
"type": "object",
"properties": {
"per_version_analysis": {
"type": "string"
},
"general_description": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
Expand Down
6 changes: 5 additions & 1 deletion lunaria/files/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@
"filter_help": "Semver range filter help",
"filter_tooltip": "Filter versions using a {link}. For example, ^3.0.0 shows all 3.x versions.",
"filter_tooltip_link": "semver range",
"no_matches": "No versions match this range"
"no_matches": "No versions match this range",
"copy_alt": {
"per_version_analysis": "{version} version was downloaded {downloads} times",
"general_description": "Bar chart showing per-version downloads for {versions_count} {semver_grouping_mode} versions of the {package_name} package, {date_range_label} from the {first_version} version to the {last_version} version. The most downloaded version is {max_downloaded_version} with {max_version_downloads} downloads. {per_version_analysis} {watermark}."
}
},
"dependencies": {
"title": "Dependency ({count}) | Dependencies ({count})",
Expand Down
6 changes: 5 additions & 1 deletion lunaria/files/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@
"filter_help": "Semver range filter help",
"filter_tooltip": "Filter versions using a {link}. For example, ^3.0.0 shows all 3.x versions.",
"filter_tooltip_link": "semver range",
"no_matches": "No versions match this range"
"no_matches": "No versions match this range",
"copy_alt": {
"per_version_analysis": "{version} version was downloaded {downloads} times",
"general_description": "Bar chart showing per-version downloads for {versions_count} {semver_grouping_mode} versions of the {package_name} package, {date_range_label} from the {first_version} version to the {last_version} version. The most downloaded version is {max_downloaded_version} with {max_version_downloads} downloads. {per_version_analysis} {watermark}."
}
},
"dependencies": {
"title": "Dependency ({count}) | Dependencies ({count})",
Expand Down
6 changes: 5 additions & 1 deletion lunaria/files/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@
"filter_help": "Infos sur le filtre de plage semver",
"filter_tooltip": "Filtrer les versions avec une {link}. Par exemple, ^3.0.0 affiche toutes les versions 3.x.",
"filter_tooltip_link": "plage semver",
"no_matches": "Aucune version ne correspond à cette plage"
"no_matches": "Aucune version ne correspond à cette plage",
"copy_alt": {
"per_version_analysis": "La version {version} a été téléchargée {downloads} fois",
"general_description": "Graphique en barres montrant les téléchargements par version pour {versions_count} versions {semver_grouping_mode} du paquet {package_name}, {date_range_label} de la version {first_version} à la version {last_version}. La version la plus téléchargée est {max_downloaded_version} avec {max_version_downloads} téléchargements. {per_version_analysis} {watermark}."
}
},
"dependencies": {
"title": "Dépendances ({count})",
Expand Down
Loading