mirror of
https://github.com/modrinth/code.git
synced 2026-08-26 17:44:50 +00:00
feat: various analytics updates (#6330)
* feat: add button to view user analytics * feat: add "Your projects" preset selection * feat: fix revenue rounding for values under 1 and show full values for all statcards with tooltip * fix: sum rounded value instead of raw value for tooltip total if it's under 1 * fix: show decimal in playtime statcard if under 1 hrs * feat: disable playtime statcard for purely plugin projects * refactor: pnpm prepr
This commit is contained in:
@@ -38,7 +38,8 @@
|
||||
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<div
|
||||
class="text-2xl font-semibold leading-none md:text-4xl"
|
||||
v-tooltip="!disabled ? statTooltip : undefined"
|
||||
class="w-fit text-2xl font-semibold leading-none md:text-4xl"
|
||||
:class="{
|
||||
'text-primary': disabled,
|
||||
'text-contrast': !disabled,
|
||||
@@ -114,6 +115,7 @@ import { analyticsStatCardMessages } from '../analytics-messages'
|
||||
const props = defineProps<{
|
||||
label: string
|
||||
statLabel: string
|
||||
statTooltip?: string
|
||||
vsPrevPeriodPercent: string | null
|
||||
icon: string
|
||||
active?: boolean
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
:key="card.key"
|
||||
:label="card.label"
|
||||
:stat-label="card.statLabel"
|
||||
:stat-tooltip="card.statTooltip"
|
||||
:vs-prev-period-percent="card.vsPrevPeriodPercent"
|
||||
:icon="card.icon"
|
||||
:active="activeStat === card.key"
|
||||
@@ -47,6 +48,7 @@ import {
|
||||
} from '~/providers/analytics/analytics'
|
||||
|
||||
import { analyticsStatCardMessages, formatAnalyticsStatLabel } from '../analytics-messages.ts'
|
||||
import { formatAnalyticsTableFullPlaytime } from '../analytics-table/analytics-table-formatting.ts'
|
||||
import StatCard from './StatCard.vue'
|
||||
|
||||
const MONETIZATION_BANNER_DISMISSED_KEY = 'analytics-monetization-banner-dismissed'
|
||||
@@ -77,6 +79,38 @@ const compactNumberFormatter = computed(
|
||||
}),
|
||||
)
|
||||
|
||||
const underDollarRevenueFormatter = computed(
|
||||
() =>
|
||||
new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}),
|
||||
)
|
||||
|
||||
const preciseRevenueFormatter = computed(
|
||||
() =>
|
||||
new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: 5,
|
||||
maximumFractionDigits: 5,
|
||||
}),
|
||||
)
|
||||
|
||||
const tooltipRevenueFormatter = computed(
|
||||
() =>
|
||||
new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}),
|
||||
)
|
||||
|
||||
const underHourPlaytimeFormatter = computed(
|
||||
() =>
|
||||
new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}),
|
||||
)
|
||||
|
||||
function formatStatNumber(value: number): string {
|
||||
const rounded = Math.round(value)
|
||||
|
||||
@@ -87,6 +121,45 @@ function formatStatNumber(value: number): string {
|
||||
return formatNumber(rounded)
|
||||
}
|
||||
|
||||
function formatFullStatNumber(value: number): string {
|
||||
return formatNumber(Math.round(value))
|
||||
}
|
||||
|
||||
function formatRevenueNumber(value: number): string {
|
||||
if (Math.abs(value) > 0 && Math.abs(value) < 1) {
|
||||
return underDollarRevenueFormatter.value.format(value)
|
||||
}
|
||||
|
||||
return formatStatNumber(value)
|
||||
}
|
||||
|
||||
function formatRevenueValue(value: number): string {
|
||||
return formatMessage(analyticsStatCardMessages.revenueValue, {
|
||||
value: formatRevenueNumber(value),
|
||||
})
|
||||
}
|
||||
|
||||
function formatPreciseRevenueValue(value: number): string {
|
||||
return formatMessage(analyticsStatCardMessages.revenueValue, {
|
||||
value:
|
||||
Math.abs(value) < 1
|
||||
? preciseRevenueFormatter.value.format(value)
|
||||
: tooltipRevenueFormatter.value.format(value),
|
||||
})
|
||||
}
|
||||
|
||||
function formatPlaytimeTooltip(value: number): string {
|
||||
return formatAnalyticsTableFullPlaytime(value, formatMessage)
|
||||
}
|
||||
|
||||
function formatPlaytimeNumber(value: number): string {
|
||||
if (Math.abs(value) > 0 && Math.abs(value) < 1) {
|
||||
return underHourPlaytimeFormatter.value.format(value)
|
||||
}
|
||||
|
||||
return formatStatNumber(value)
|
||||
}
|
||||
|
||||
function formatPercent(value: number): string {
|
||||
const rounded = Math.round(value * 10) / 10
|
||||
if (rounded === 0) {
|
||||
@@ -105,7 +178,7 @@ function formatSignedStatNumber(value: number): string {
|
||||
function formatSignedRevenue(value: number): string {
|
||||
const signPrefix = value > 0 ? '+' : value < 0 ? '-' : ''
|
||||
return `${signPrefix}${formatMessage(analyticsStatCardMessages.revenueValue, {
|
||||
value: formatStatNumber(Math.abs(value)),
|
||||
value: formatRevenueNumber(Math.abs(value)),
|
||||
})}`
|
||||
}
|
||||
|
||||
@@ -169,6 +242,7 @@ const statCards = computed<
|
||||
key: AnalyticsDashboardStat
|
||||
label: string
|
||||
statLabel: string
|
||||
statTooltip?: string
|
||||
vsPrevPeriodPercent: string | null
|
||||
icon: string
|
||||
disabled: boolean
|
||||
@@ -178,6 +252,7 @@ const statCards = computed<
|
||||
key: 'views',
|
||||
label: formatAnalyticsStatLabel('views', formatMessage),
|
||||
statLabel: formatStatNumber(currentTotals.value.views),
|
||||
statTooltip: formatFullStatNumber(currentTotals.value.views),
|
||||
vsPrevPeriodPercent: formatPreviousPeriodComparison(
|
||||
'views',
|
||||
percentChanges.value.views,
|
||||
@@ -191,6 +266,7 @@ const statCards = computed<
|
||||
key: 'downloads',
|
||||
label: formatAnalyticsStatLabel('downloads', formatMessage),
|
||||
statLabel: formatStatNumber(currentTotals.value.downloads),
|
||||
statTooltip: formatFullStatNumber(currentTotals.value.downloads),
|
||||
vsPrevPeriodPercent: formatPreviousPeriodComparison(
|
||||
'downloads',
|
||||
percentChanges.value.downloads,
|
||||
@@ -203,9 +279,8 @@ const statCards = computed<
|
||||
{
|
||||
key: 'revenue',
|
||||
label: formatAnalyticsStatLabel('revenue', formatMessage),
|
||||
statLabel: formatMessage(analyticsStatCardMessages.revenueValue, {
|
||||
value: formatStatNumber(currentTotals.value.revenue),
|
||||
}),
|
||||
statLabel: formatRevenueValue(currentTotals.value.revenue),
|
||||
statTooltip: formatPreciseRevenueValue(currentTotals.value.revenue),
|
||||
vsPrevPeriodPercent: formatPreviousPeriodComparison(
|
||||
'revenue',
|
||||
percentChanges.value.revenue,
|
||||
@@ -219,8 +294,9 @@ const statCards = computed<
|
||||
key: 'playtime',
|
||||
label: formatAnalyticsStatLabel('playtime', formatMessage),
|
||||
statLabel: formatMessage(analyticsStatCardMessages.playtimeHours, {
|
||||
hours: formatStatNumber(currentTotals.value.playtime / 3600),
|
||||
hours: formatPlaytimeNumber(currentTotals.value.playtime / 3600),
|
||||
}),
|
||||
statTooltip: formatPlaytimeTooltip(currentTotals.value.playtime),
|
||||
vsPrevPeriodPercent: formatPreviousPeriodComparison(
|
||||
'playtime',
|
||||
percentChanges.value.playtime,
|
||||
|
||||
Reference in New Issue
Block a user