first commit
This commit is contained in:
98
app/components/home/HomeStats.vue
Normal file
98
app/components/home/HomeStats.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<script setup lang="ts">
|
||||
import type { Period, Range, Stat } from '~/types'
|
||||
|
||||
const props = defineProps<{
|
||||
period: Period
|
||||
range: Range
|
||||
}>()
|
||||
|
||||
function formatCurrency(value: number): string {
|
||||
return value.toLocaleString('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
maximumFractionDigits: 0
|
||||
})
|
||||
}
|
||||
|
||||
const baseStats = [{
|
||||
title: 'Customers',
|
||||
icon: 'i-lucide-users',
|
||||
minValue: 400,
|
||||
maxValue: 1000,
|
||||
minVariation: -15,
|
||||
maxVariation: 25
|
||||
}, {
|
||||
title: 'Conversions',
|
||||
icon: 'i-lucide-chart-pie',
|
||||
minValue: 1000,
|
||||
maxValue: 2000,
|
||||
minVariation: -10,
|
||||
maxVariation: 20
|
||||
}, {
|
||||
title: 'Revenue',
|
||||
icon: 'i-lucide-circle-dollar-sign',
|
||||
minValue: 200000,
|
||||
maxValue: 500000,
|
||||
minVariation: -20,
|
||||
maxVariation: 30,
|
||||
formatter: formatCurrency
|
||||
}, {
|
||||
title: 'Orders',
|
||||
icon: 'i-lucide-shopping-cart',
|
||||
minValue: 100,
|
||||
maxValue: 300,
|
||||
minVariation: -5,
|
||||
maxVariation: 15
|
||||
}]
|
||||
|
||||
const { data: stats } = await useAsyncData<Stat[]>('stats', async () => {
|
||||
return baseStats.map((stat) => {
|
||||
const value = randomInt(stat.minValue, stat.maxValue)
|
||||
const variation = randomInt(stat.minVariation, stat.maxVariation)
|
||||
|
||||
return {
|
||||
title: stat.title,
|
||||
icon: stat.icon,
|
||||
value: stat.formatter ? stat.formatter(value) : value,
|
||||
variation
|
||||
}
|
||||
})
|
||||
}, {
|
||||
watch: [() => props.period, () => props.range],
|
||||
default: () => []
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UPageGrid class="lg:grid-cols-4 gap-4 sm:gap-6 lg:gap-px">
|
||||
<UPageCard
|
||||
v-for="(stat, index) in stats"
|
||||
:key="index"
|
||||
:icon="stat.icon"
|
||||
:title="stat.title"
|
||||
to="/customers"
|
||||
variant="subtle"
|
||||
:ui="{
|
||||
container: 'gap-y-1.5',
|
||||
wrapper: 'items-start',
|
||||
leading: 'p-2.5 rounded-full bg-primary/10 ring ring-inset ring-primary/25 flex-col',
|
||||
title: 'font-normal text-muted text-xs uppercase'
|
||||
}"
|
||||
class="lg:rounded-none first:rounded-l-lg last:rounded-r-lg hover:z-1"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-2xl font-semibold text-highlighted">
|
||||
{{ stat.value }}
|
||||
</span>
|
||||
|
||||
<UBadge
|
||||
:color="stat.variation > 0 ? 'success' : 'error'"
|
||||
variant="subtle"
|
||||
class="text-xs"
|
||||
>
|
||||
{{ stat.variation > 0 ? '+' : '' }}{{ stat.variation }}%
|
||||
</UBadge>
|
||||
</div>
|
||||
</UPageCard>
|
||||
</UPageGrid>
|
||||
</template>
|
||||
Reference in New Issue
Block a user