@@ -93,17 +93,37 @@ const compactNumberFormatter = useCompactNumberFormatter()
9393// Show loading indicator immediately to maintain stable layout
9494const showLoadingIndicator = computed (() => pending .value )
9595
96+ const loadFile = (link : string , filename : string ) => {
97+ const a = document .createElement (' a' )
98+ a .href = link
99+ a .download = filename
100+ a .click ()
101+ a .remove ()
102+ }
103+
104+ const sanitise = (value : string ) =>
105+ value
106+ .replace (/ ^ @/ , ' ' )
107+ .replace (/ [\\ /:"*?<>|] / g , ' -' )
108+ .replace (/ \/ / g , ' -' )
109+
110+ function buildExportFilename(extension : string ): string {
111+ const range = ` ${startDate .value }_${endDate .value } `
112+
113+ const label = props .packageName
114+ return ` ${sanitise (label ?? ' ' )}_${range }.${extension } `
115+ }
116+
96117const chartConfig = computed (() => {
97118 return {
98119 theme: isDarkMode .value ? ' dark' : ' default' ,
99120 chart: {
100- height: isMobile .value ? 500 : 400 ,
121+ height: isMobile .value ? 750 : 500 ,
101122 backgroundColor: colors .value .bg ,
102123 padding: {
103124 top: 24 ,
104125 right: 24 ,
105126 bottom: xAxisLabels .value .length > 10 ? 84 : 72 , // Space for rotated labels + watermark
106- left: isMobile .value ? 60 : 80 ,
107127 },
108128 userOptions: {
109129 buttons: {
@@ -113,9 +133,43 @@ const chartConfig = computed(() => {
113133 table: false ,
114134 tooltip: false ,
115135 },
136+ buttonTitles: {
137+ csv: $t (' package.trends.download_file' , { fileType: ' CSV' }),
138+ img: $t (' package.trends.download_file' , { fileType: ' PNG' }),
139+ svg: $t (' package.trends.download_file' , { fileType: ' SVG' }),
140+ annotator: $t (' package.trends.toggle_annotator' ),
141+ },
142+ callbacks: {
143+ img : ({ imageUri }: { imageUri: string }) => {
144+ loadFile (imageUri , buildExportFilename (' png' ))
145+ },
146+ csv : (csvStr : string ) => {
147+ const PLACEHOLDER_CHAR = ' \0 '
148+ const multilineDateTemplate = $t (' package.trends.date_range_multiline' , {
149+ start: PLACEHOLDER_CHAR ,
150+ end: PLACEHOLDER_CHAR ,
151+ })
152+ .replaceAll (PLACEHOLDER_CHAR , ' ' )
153+ .trim ()
154+ const blob = new Blob ([
155+ csvStr
156+ .replace (' data:text/csv;charset=utf-8,' , ' ' )
157+ .replaceAll (` \n ${multilineDateTemplate }` , ` ${multilineDateTemplate } ` ),
158+ ])
159+ const url = URL .createObjectURL (blob )
160+ loadFile (url , buildExportFilename (' csv' ))
161+ URL .revokeObjectURL (url )
162+ },
163+ svg : ({ blob }: { blob: Blob }) => {
164+ const url = URL .createObjectURL (blob )
165+ loadFile (url , buildExportFilename (' svg' ))
166+ URL .revokeObjectURL (url )
167+ },
168+ },
116169 },
117170 grid: {
118171 stroke: colors .value .border ,
172+ showHorizontalLines: true ,
119173 labels: {
120174 fontSize: isMobile .value ? 24 : 16 ,
121175 color: pending .value ? colors .value .border : colors .value .fgSubtle ,
@@ -133,9 +187,8 @@ const chartConfig = computed(() => {
133187 xAxisLabels: {
134188 show: xAxisLabels .value .length <= 25 ,
135189 values: xAxisLabels .value ,
136- fontSize: isMobile . value ? 16 : 14 ,
190+ fontSize: 16 ,
137191 color: colors .value .fgSubtle ,
138- rotation: xAxisLabels .value .length > 10 ? 45 : 0 ,
139192 },
140193 },
141194 },
@@ -170,7 +223,7 @@ const chartConfig = computed(() => {
170223 return ` <div class="font-mono text-xs p-3 border border-border rounded-md bg-[var(--bg)]/10 backdrop-blur-md">
171224 <div class="flex flex-col gap-2">
172225 <div class="flex items-center justify-between gap-4">
173- <span class="text-3xs uppercase tracking-wide text-[var(--fg)]/70">
226+ <span class="text-3xs tracking-wide text-[var(--fg)]/70">
174227 ${chartItem .name }
175228 </span>
176229 <span class="text-base text-[var(--fg)] font-mono tabular-nums">
@@ -415,7 +468,7 @@ const endDate = computed(() => {
415468 role =" region"
416469 aria-labelledby =" version-distribution-title"
417470 class =" relative"
418- :class =" isMobile ? 'min-h-[500px ]' : 'min-h-[400px]'"
471+ :class =" isMobile ? 'min-h-[260px ]' : 'min-h-[400px]'"
419472 >
420473 <!-- Chart content -->
421474 <ClientOnly v-if =" xyDataset.length > 0 && !error" >
0 commit comments