mirror of
https://github.com/ArthurDanjou/artsite.git
synced 2026-01-14 13:54:05 +01:00
179 lines
5.8 KiB
Vue
179 lines
5.8 KiB
Vue
<script lang="ts" setup>
|
|
import type { Stats } from '~~/types'
|
|
import { usePrecision } from '@vueuse/math'
|
|
|
|
const { data: stats } = await useAsyncData<Stats>('stats', () => $fetch('/api/stats'))
|
|
|
|
const startDate = computed(() => new Date(stats.value?.coding?.range?.start ?? new Date()))
|
|
const rawHours = computed(() => {
|
|
const seconds = stats.value?.coding?.grand_total?.total_seconds_including_other_language ?? 0
|
|
return seconds / 3600
|
|
})
|
|
|
|
const totalHours = usePrecision(rawHours, 0)
|
|
const yearsCollected = useTimeAgo(startDate)
|
|
const formattedDate = useDateFormat(startDate, 'MMM DD, YYYY')
|
|
|
|
const topLanguages = computed(() => stats.value?.languages.slice(0, 4) ?? [])
|
|
const topEditors = computed(() => stats.value?.editors.slice(0, 3) ?? [])
|
|
const topOS = computed(() => stats.value?.os.slice(0, 2) ?? [])
|
|
</script>
|
|
|
|
<template>
|
|
<ClientOnly>
|
|
<div
|
|
v-if="stats"
|
|
class="space-y-6"
|
|
>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<UCard v-if="totalHours">
|
|
<div class="flex items-center gap-4">
|
|
<div class="p-3 bg-primary-200 dark:bg-primary-900 rounded-lg text-primary-500 flex items-center justify-center">
|
|
<UIcon
|
|
name="i-ph-clock-duotone"
|
|
class="w-8 h-8"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider">
|
|
Total Coding Time
|
|
</p>
|
|
<h3 class="text-3xl font-bold font-mono text-neutral-900 dark:text-white">
|
|
{{ totalHours }} <span class="text-lg text-neutral-500 font-normal">hours</span>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard v-if="formattedDate && yearsCollected">
|
|
<div class="flex items-center gap-4">
|
|
<div class="p-3 bg-emerald-100 dark:bg-emerald-900/20 rounded-lg text-emerald-500 flex items-center justify-center">
|
|
<UIcon
|
|
name="i-ph-calendar-check-duotone"
|
|
class="w-8 h-8"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-neutral-500 dark:text-neutral-400 uppercase tracking-wider">
|
|
Data Collected Since
|
|
</p>
|
|
<div class="flex items-baseline gap-2">
|
|
<h3 class="text-xl font-bold text-neutral-900 dark:text-white">
|
|
{{ formattedDate }}
|
|
</h3>
|
|
<UBadge
|
|
color="neutral"
|
|
variant="soft"
|
|
size="sm"
|
|
>
|
|
{{ yearsCollected }}
|
|
</UBadge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<div
|
|
v-if="topLanguages.length"
|
|
class="col-span-1 lg:col-span-1 space-y-4"
|
|
>
|
|
<h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
|
|
<UIcon
|
|
name="i-ph-code-block-duotone"
|
|
class="text-red-500 w-5 h-5"
|
|
/>
|
|
Top Languages
|
|
</h4>
|
|
<div class="space-y-3">
|
|
<div
|
|
v-for="lang in topLanguages"
|
|
:key="lang.name"
|
|
class="space-y-1"
|
|
>
|
|
<div class="flex justify-between text-xs text-neutral-600 dark:text-neutral-300">
|
|
<span>{{ lang.name }}</span>
|
|
<span>{{ lang.percent }}%</span>
|
|
</div>
|
|
<UProgress
|
|
v-model="lang.percent"
|
|
color="red"
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="topEditors.length"
|
|
class="col-span-1 lg:col-span-1 space-y-4"
|
|
>
|
|
<h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
|
|
<UIcon
|
|
name="i-ph-terminal-window-duotone"
|
|
class="text-green-500 w-5 h-5"
|
|
/>
|
|
Preferred Editors
|
|
</h4>
|
|
<div class="space-y-3">
|
|
<div
|
|
v-for="editor in topEditors"
|
|
:key="editor.name"
|
|
class="space-y-1"
|
|
>
|
|
<div class="flex justify-between text-xs text-neutral-600 dark:text-neutral-300">
|
|
<span>{{ editor.name }}</span>
|
|
<span>{{ editor.percent }}%</span>
|
|
</div>
|
|
<UProgress
|
|
v-model="editor.percent"
|
|
color="green"
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="topOS.length"
|
|
class="col-span-1 lg:col-span-1 space-y-4"
|
|
>
|
|
<h4 class="text-sm font-semibold text-neutral-900 dark:text-white flex items-center gap-2">
|
|
<UIcon
|
|
name="i-ph-desktop-duotone"
|
|
class="text-blue-500 w-5 h-5"
|
|
/>
|
|
Operating Systems
|
|
</h4>
|
|
<div class="space-y-3">
|
|
<div
|
|
v-for="osItem in topOS"
|
|
:key="osItem.name"
|
|
class="space-y-1"
|
|
>
|
|
<div class="flex justify-between text-xs text-neutral-600 dark:text-neutral-300">
|
|
<span>{{ osItem.name }}</span>
|
|
<span>{{ osItem.percent }}%</span>
|
|
</div>
|
|
<UProgress
|
|
v-model="osItem.percent"
|
|
color="blue"
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-else
|
|
class="grid grid-cols-1 md:grid-cols-2 gap-4"
|
|
>
|
|
<USkeleton class="h-24 w-full" />
|
|
<USkeleton class="h-24 w-full" />
|
|
</div>
|
|
</ClientOnly>
|
|
</template>
|