@@ -3,6 +3,8 @@ import { ref, computed, shallowRef, watch } from 'vue'
33import type { VueUiXyDatasetItem } from ' vue-data-ui'
44import { VueUiXy } from ' vue-data-ui/vue-ui-xy'
55import { useDebounceFn , useElementSize } from ' @vueuse/core'
6+ import { useCssVariables } from ' ../composables/useColors'
7+ import { OKLCH_NEUTRAL_FALLBACK , transparentizeOklch } from ' ../utils/colors'
68
79const {
810 weeklyDownloads,
@@ -24,9 +26,19 @@ const rootEl = shallowRef<HTMLElement | null>(null)
2426const { width } = useElementSize (rootEl )
2527
2628onMounted (() => {
29+ rootEl .value = document .documentElement
2730 resolvedMode .value = colorMode .value === ' dark' ? ' dark' : ' light'
2831})
2932
33+ const { colors } = useCssVariables (
34+ [' --bg' , ' --bg-subtle' , ' --bg-elevated' , ' --fg-subtle' , ' --border' , ' --border-subtle' ],
35+ {
36+ element: rootEl ,
37+ watchHtmlAttributes: true ,
38+ watchResize: false , // set to true only if a var changes color on resize
39+ },
40+ )
41+
3042watch (
3143 () => colorMode .value ,
3244 value => {
@@ -49,7 +61,9 @@ const accentColorValueById = computed<Record<string, string>>(() => {
4961
5062const accent = computed (() => {
5163 const id = selectedAccentColor .value
52- return id ? (oklchToHex (accentColorValueById .value [id ]! ) ?? ' #8A8A8A' ) : ' #8A8A8A'
64+ return id
65+ ? (accentColorValueById .value [id ] ?? colors .value .fgSubtle ?? OKLCH_NEUTRAL_FALLBACK )
66+ : (colors .value .fgSubtle ?? OKLCH_NEUTRAL_FALLBACK )
5367})
5468
5569const mobileBreakpointWidth = 640
@@ -58,10 +72,6 @@ const isMobile = computed(() => {
5872 return width .value > 0 && width .value < mobileBreakpointWidth
5973})
6074
61- onMounted (() => {
62- rootEl .value = document .documentElement
63- })
64-
6575type ChartTimeGranularity = ' daily' | ' weekly' | ' monthly' | ' yearly'
6676type EvolutionData =
6777 | DailyDownloadPoint []
@@ -444,119 +454,127 @@ const loadFile = (link: string, filename: string) => {
444454 a .remove ()
445455}
446456
447- const config = computed (() => ({
448- theme: isDarkMode .value ? ' dark' : ' default' ,
449- chart: {
450- height: isMobile .value ? 850 : 600 ,
451- userOptions: {
452- buttons: {
453- pdf: false ,
454- labels: false ,
455- fullscreen: false ,
456- table: false ,
457- tooltip: false ,
458- },
459- callbacks: {
460- img : ({ imageUri }: { imageUri: string }) => {
461- loadFile (
462- imageUri ,
463- ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.png ` ,
464- )
457+ const config = computed (() => {
458+ return {
459+ theme: isDarkMode .value ? ' dark' : ' default' ,
460+ chart: {
461+ height: isMobile .value ? 850 : 600 ,
462+ userOptions: {
463+ buttons: {
464+ pdf: false ,
465+ labels: false ,
466+ fullscreen: false ,
467+ table: false ,
468+ tooltip: false ,
465469 },
466- csv : (csvStr : string ) => {
467- const blob = new Blob ([csvStr .replace (' data:text/csv;charset=utf-8,' , ' ' )])
468- const url = URL .createObjectURL (blob )
469- loadFile (
470- url ,
471- ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.csv ` ,
472- )
473- URL .revokeObjectURL (url )
470+ buttonTitles: {
471+ csv: $t (' package.downloads.download_file' , { fileType: ' CSV' }),
472+ img: $t (' package.downloads.download_file' , { fileType: ' PNG' }),
473+ pdf: $t (' package.downloads.download_file' , { fileType: ' PDF' }),
474+ annotator: $t (' package.downloads.toggle_annotator' ),
474475 },
475- svg : ({ blob }: { blob: Blob }) => {
476- const url = URL .createObjectURL (blob )
477- loadFile (
478- url ,
479- ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.svg ` ,
480- )
481- URL .revokeObjectURL (url )
476+ callbacks: {
477+ img : ({ imageUri }: { imageUri: string }) => {
478+ loadFile (
479+ imageUri ,
480+ ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.png ` ,
481+ )
482+ },
483+ csv : (csvStr : string ) => {
484+ const blob = new Blob ([csvStr .replace (' data:text/csv;charset=utf-8,' , ' ' )])
485+ const url = URL .createObjectURL (blob )
486+ loadFile (
487+ url ,
488+ ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.csv ` ,
489+ )
490+ URL .revokeObjectURL (url )
491+ },
492+ svg : ({ blob }: { blob: Blob }) => {
493+ const url = URL .createObjectURL (blob )
494+ loadFile (
495+ url ,
496+ ` ${packageName }-${selectedGranularity .value }_${startDate .value }_${endDate .value }.svg ` ,
497+ )
498+ URL .revokeObjectURL (url )
499+ },
482500 },
483501 },
484- } ,
485- backgroundColor: isDarkMode . value ? ' #0A0A0A ' : ' #FFFFFF ' ,
486- grid: {
487- stroke: isDarkMode . value ? ' #4A4A4A ' : ' #a3a3a3 ' ,
488- labels : {
489- axis: {
490- yLabel : $t (' package.downloads.y_axis_label ' , {
491- granularity: $t ( ` package.downloads.granularity_${ selectedGranularity . value } ` ),
492- }) ,
493- xLabel: packageName ,
494- yLabelOffsetX: 12 ,
495- fontSize: 24 ,
496- },
497- xAxisLabels: {
498- values: chartData . value ?. dates ,
499- showOnlyAtModulo: true ,
500- modulo: 12 ,
501- },
502- yAxis: {
503- formatter ,
504- useNiceScale: true ,
502+ backgroundColor: colors . value . bg ,
503+ grid: {
504+ stroke: colors . value . border ,
505+ labels: {
506+ axis : {
507+ yLabel: $t ( ' package.downloads.y_axis_label ' , {
508+ granularity : $t (` package.downloads.granularity_${ selectedGranularity . value } ` ),
509+ } ),
510+ xLabel: packageName ,
511+ yLabelOffsetX: 12 ,
512+ fontSize: 24 ,
513+ } ,
514+ xAxisLabels: {
515+ values: chartData . value ?. dates ,
516+ showOnlyAtModulo: true ,
517+ modulo: 12 ,
518+ } ,
519+ yAxis: {
520+ formatter ,
521+ useNiceScale: true ,
522+ } ,
505523 },
506524 },
507- },
508- highlighter: {
509- useLine: true ,
510- },
511- legend: {
512- show: false , // As long as a single package is displayed
513- },
514- tooltip: {
515- borderColor: ' transparent' ,
516- backdropFilter: false ,
517- backgroundColor: ' transparent' ,
518- customFormat : ({
519- absoluteIndex ,
520- datapoint ,
521- }: {
522- absoluteIndex: number
523- datapoint: Record <string , any >
524- }) => {
525- if (! datapoint ) return ' '
526- const displayValue = formatter ({ value: datapoint [0 ]?.value ?? 0 })
527- return ` <div class="flex flex-col font-mono text-xs p-3 border border-border rounded-md bg-white/10 dark:bg-[#0A0A0A]/10 backdrop-blur-md">
525+ highlighter: {
526+ useLine: true ,
527+ },
528+ legend: {
529+ show: false , // As long as a single package is displayed
530+ },
531+ tooltip: {
532+ borderColor: ' transparent' ,
533+ backdropFilter: false ,
534+ backgroundColor: ' transparent' ,
535+ customFormat : ({
536+ absoluteIndex ,
537+ datapoint ,
538+ }: {
539+ absoluteIndex: number
540+ datapoint: Record <string , any >
541+ }) => {
542+ if (! datapoint ) return ' '
543+ const displayValue = formatter ({ value: datapoint [0 ]?.value ?? 0 })
544+ return ` <div class="flex flex-col font-mono text-xs p-3 border border-border rounded-md bg-[var(--bg)]/10 backdrop-blur-md">
528545 <span class="text-fg-subtle">${chartData .value ?.dates [absoluteIndex ]}</span>
529546 <span class="text-xl">${displayValue }</span>
530547 </div>
531548 `
549+ },
532550 },
533- },
534- zoom: {
535- maxWidth: 500 ,
536- customFormat:
537- displayedGranularity . value !== ' weekly '
538- ? undefined
539- : ({ absoluteIndex , side } : { absoluteIndex : number ; side : ' left ' | ' right ' }) => {
540- const parts = extractDates ( chartData . value . dates [ absoluteIndex ] ?? ' ' )
541- return side === ' left ' ? parts [ 0 ] : parts . at ( - 1 )
542- } ,
543- highlightColor: isDarkMode . value ? ' #2A2A2A ' : ' #E1E5E8 ' ,
544- minimap: {
545- show: true ,
546- lineColor: ' #FAFAFA ' ,
547- selectedColor: accent . value ,
548- selectedColorOpacity: 0.06 ,
549- frameColor: isDarkMode . value ? ' #3A3A3A ' : ' #a3a3a3 ' ,
550- },
551- preview: {
552- fill: accent .value + 10 ,
553- stroke: accent . value + 60 ,
554- strokeWidth: 1 ,
555- strokeDasharray: 3 ,
551+ zoom: {
552+ maxWidth: 500 ,
553+ customFormat:
554+ displayedGranularity . value !== ' weekly '
555+ ? undefined
556+ : ({ absoluteIndex , side } : { absoluteIndex : number ; side : ' left ' | ' right ' }) => {
557+ const parts = extractDates ( chartData . value . dates [ absoluteIndex ] ?? ' ' )
558+ return side === ' left ' ? parts [ 0 ] : parts . at ( - 1 )
559+ },
560+ highlightColor: colors . value . bgElevated ,
561+ minimap: {
562+ show: true ,
563+ lineColor: ' #FAFAFA ' ,
564+ selectedColor: accent . value ,
565+ selectedColorOpacity: 0.06 ,
566+ frameColor: colors . value . border ,
567+ } ,
568+ preview: {
569+ fill: transparentizeOklch ( accent . value , isDarkMode . value ? 0.95 : 0.92 ),
570+ stroke: transparentizeOklch ( accent .value , 0.5 ) ,
571+ strokeWidth: 1 ,
572+ strokeDasharray: 3 ,
573+ } ,
556574 },
557575 },
558- },
559- }))
576+ }
577+ })
560578 </script >
561579
562580<template >
0 commit comments