Skip to content
Draft
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
25 changes: 15 additions & 10 deletions app/components/Package/TrendsChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ import { useDebounceFn, useElementSize } from '@vueuse/core'
import { useCssVariables } from '~/composables/useColors'
import { OKLCH_NEUTRAL_FALLBACK, transparentizeOklch } from '~/utils/colors'
import { getFrameworkColor, isListedFramework } from '~/utils/frameworks'
import type {
ChartTimeGranularity,
DailyDataPoint,
DateRangeFields,
EvolutionData,
EvolutionOptions,
MonthlyDataPoint,
WeeklyDataPoint,
YearlyDataPoint,
} from '~/types/chart'

const props = defineProps<{
// For single package downloads history
Expand Down Expand Up @@ -103,14 +113,7 @@ const accent = computed(() => {
const mobileBreakpointWidth = 640
const isMobile = computed(() => width.value > 0 && width.value < mobileBreakpointWidth)

type ChartTimeGranularity = 'daily' | 'weekly' | 'monthly' | 'yearly'
const DEFAULT_GRANULARITY: ChartTimeGranularity = 'weekly'
type EvolutionData = DailyDataPoint[] | WeeklyDataPoint[] | MonthlyDataPoint[] | YearlyDataPoint[]

type DateRangeFields = {
startDate?: string
endDate?: string
}

function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null
Expand Down Expand Up @@ -315,7 +318,9 @@ const effectivePackageNames = computed<string[]>(() => {
return single ? [single] : []
})

const selectedGranularity = shallowRef<ChartTimeGranularity>(DEFAULT_GRANULARITY)
const selectedGranularity = defineModel<ChartTimeGranularity>('granularity', {
default: DEFAULT_GRANULARITY,
})
const displayedGranularity = shallowRef<ChartTimeGranularity>(DEFAULT_GRANULARITY)

const isEndDateOnPeriodEnd = computed(() => {
Expand Down Expand Up @@ -345,8 +350,8 @@ const shouldRenderEstimationOverlay = computed(
() => !pending.value && isEstimationGranularity.value,
)

const startDate = shallowRef<string>('') // YYYY-MM-DD
const endDate = shallowRef<string>('') // YYYY-MM-DD
const startDate = defineModel<string>('startDate', { default: '' })
const endDate = defineModel<string>('endDate', { default: '' })
const hasUserEditedDates = shallowRef(false)

/**
Expand Down
26 changes: 21 additions & 5 deletions app/components/Package/WeeklyDownloadStats.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { VueUiSparkline } from 'vue-data-ui/vue-ui-sparkline'
import { useCssVariables } from '~/composables/useColors'
import type { ChartTimeGranularity, WeeklyDataPoint } from '~/types/chart'
import { OKLCH_NEUTRAL_FALLBACK, lightenOklch } from '~/utils/colors'
const props = defineProps<{
Expand All @@ -10,10 +11,19 @@ const props = defineProps<{
const chartModal = useModal('chart-modal')
const hasChartModalTransitioned = shallowRef(false)
const isChartModalOpen = shallowRef(false)
const modal = useRouteQuery<'downloads' | undefined>('modal')
const granularity = useRouteQuery<ChartTimeGranularity | undefined>('granularity')
const startDate = useRouteQuery<string | undefined>('start')
const endDate = useRouteQuery<string | undefined>('end')
const isChartModalOpen = computed<boolean>(() => modal.value === 'downloads')
function handleModalClose() {
isChartModalOpen.value = false
modal.value = undefined
granularity.value = undefined
startDate.value = undefined
endDate.value = undefined
hasChartModalTransitioned.value = false
}
Expand Down Expand Up @@ -93,7 +103,7 @@ const hasWeeklyDownloads = computed(() => weeklyDownloads.value.length > 0)
async function openChartModal() {
if (!hasWeeklyDownloads.value) return
isChartModalOpen.value = true
modal.value = 'downloads'
hasChartModalTransitioned.value = false
// ensure the component renders before opening the dialog
await nextTick()
Expand All @@ -119,8 +129,11 @@ async function loadWeeklyDownloads() {
}
}
onMounted(() => {
loadWeeklyDownloads()
onMounted(async () => {
await loadWeeklyDownloads()
if (isChartModalOpen.value && hasWeeklyDownloads.value) {
openChartModal()
}
})
watch(
Expand Down Expand Up @@ -283,6 +296,9 @@ const config = computed(() => {
:inModal="true"
:packageName="props.packageName"
:createdIso="createdIso"
v-model:granularity="granularity"
v-model:startDate="startDate"
v-model:endDate="endDate"
show-facet-selector
/>
</Transition>
Expand Down
48 changes: 8 additions & 40 deletions app/composables/useCharts.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,19 @@
import type { MaybeRefOrGetter } from 'vue'
import { toValue } from 'vue'
import type {
DailyDataPoint,
DailyRawPoint,
EvolutionOptions,
MonthlyDataPoint,
WeeklyDataPoint,
YearlyDataPoint,
} from '~/types/chart'
import { fetchNpmDownloadsRange } from '~/utils/npm/api'

export type PackumentLikeForTime = {
time?: Record<string, string>
}

export type DailyDataPoint = { value: number; day: string; timestamp: number }
export type WeeklyDataPoint = {
value: number
weekKey: string
weekStart: string
weekEnd: string
timestampStart: number
timestampEnd: number
}
export type MonthlyDataPoint = { value: number; month: string; timestamp: number }
export type YearlyDataPoint = { value: number; year: string; timestamp: number }

type EvolutionOptionsBase = {
startDate?: string
endDate?: string
}

export type EvolutionOptionsDay = EvolutionOptionsBase & {
granularity: 'day'
}
export type EvolutionOptionsWeek = EvolutionOptionsBase & {
granularity: 'week'
weeks?: number
}
export type EvolutionOptionsMonth = EvolutionOptionsBase & {
granularity: 'month'
months?: number
}
export type EvolutionOptionsYear = EvolutionOptionsBase & {
granularity: 'year'
}

export type EvolutionOptions =
| EvolutionOptionsDay
| EvolutionOptionsWeek
| EvolutionOptionsMonth
| EvolutionOptionsYear

type DailyRawPoint = { day: string; value: number }

function toIsoDateString(date: Date): string {
return date.toISOString().slice(0, 10)
}
Expand Down
52 changes: 52 additions & 0 deletions app/types/chart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export type ChartTimeGranularity = 'daily' | 'weekly' | 'monthly' | 'yearly'

export type DateRangeFields = {
startDate?: string
endDate?: string
}

export type DailyDataPoint = { value: number; day: string; timestamp: number }
export type WeeklyDataPoint = {
value: number
weekKey: string
weekStart: string
weekEnd: string
timestampStart: number
timestampEnd: number
}
export type MonthlyDataPoint = { value: number; month: string; timestamp: number }
export type YearlyDataPoint = { value: number; year: string; timestamp: number }

export type EvolutionData =
| DailyDataPoint[]
| WeeklyDataPoint[]
| MonthlyDataPoint[]
| YearlyDataPoint[]

export type EvolutionOptionsBase = {
startDate?: string
endDate?: string
}

export type EvolutionOptionsDay = EvolutionOptionsBase & {
granularity: 'day'
}
export type EvolutionOptionsWeek = EvolutionOptionsBase & {
granularity: 'week'
weeks?: number
}
export type EvolutionOptionsMonth = EvolutionOptionsBase & {
granularity: 'month'
months?: number
}
export type EvolutionOptionsYear = EvolutionOptionsBase & {
granularity: 'year'
}

export type EvolutionOptions =
| EvolutionOptionsDay
| EvolutionOptionsWeek
| EvolutionOptionsMonth
| EvolutionOptionsYear

export type DailyRawPoint = { day: string; value: number }
Loading