mirror of
https://github.com/ArthurDanjou/artsite.git
synced 2026-01-14 13:54:05 +01:00
Compare commits
16 Commits
c3aafbf67e
...
4dc74c0011
| Author | SHA1 | Date | |
|---|---|---|---|
| 4dc74c0011 | |||
| f95a417b37 | |||
| 055c16e198 | |||
| 669eec60a1 | |||
| 4cda11a6a3 | |||
| df33efc731 | |||
| 305c91199a | |||
| ed3019d1b9 | |||
| 988e18b2f7 | |||
| 5d4f6ee9a4 | |||
| d13594e5d1 | |||
| 9aabe422b3 | |||
| e30d956f58 | |||
| 56c63d8db7 | |||
| c8116e10b8 | |||
| 9dc21f4287 |
@@ -4,15 +4,19 @@ 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))
|
||||
const yearsCollected = useTimeAgo(startDate).value
|
||||
const formattedDate = useDateFormat(startDate, 'MMM DD, YYYY').value
|
||||
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((stats.value!.coding.grand_total.total_seconds_including_other_language ?? 0) / 3600, 0)
|
||||
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))
|
||||
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>
|
||||
@@ -21,8 +25,12 @@ const topOS = computed(() => stats.value!.os.slice(0, 2))
|
||||
v-if="stats"
|
||||
class="space-y-6"
|
||||
>
|
||||
{{ rawHours }}
|
||||
{{ totalHours }}
|
||||
{{ usePrecision(rawHours, 0) }}
|
||||
{{ usePrecision(rawHours, 0) }}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<UCard>
|
||||
<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
|
||||
@@ -41,7 +49,7 @@ const topOS = computed(() => stats.value!.os.slice(0, 2))
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<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
|
||||
@@ -71,11 +79,14 @@ const topOS = computed(() => stats.value!.os.slice(0, 2))
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="col-span-1 lg:col-span-1 space-y-4">
|
||||
<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-primary-500 w-5 h-5"
|
||||
class="text-red-500 w-5 h-5"
|
||||
/>
|
||||
Top Languages
|
||||
</h4>
|
||||
@@ -91,18 +102,21 @@ const topOS = computed(() => stats.value!.os.slice(0, 2))
|
||||
</div>
|
||||
<UProgress
|
||||
v-model="lang.percent"
|
||||
color="primary"
|
||||
color="red"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-1 lg:col-span-1 space-y-4">
|
||||
<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-orange-500 w-5 h-5"
|
||||
class="text-green-500 w-5 h-5"
|
||||
/>
|
||||
Preferred Editors
|
||||
</h4>
|
||||
@@ -118,14 +132,17 @@ const topOS = computed(() => stats.value!.os.slice(0, 2))
|
||||
</div>
|
||||
<UProgress
|
||||
v-model="editor.percent"
|
||||
color="orange"
|
||||
color="green"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-1 lg:col-span-1 space-y-4">
|
||||
<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"
|
||||
|
||||
@@ -5,7 +5,7 @@ type: Academic Project
|
||||
description: An interactive data visualization project built with R, R Shiny, and ggplot2 for creating dynamic, explorable visualizations.
|
||||
publishedAt: 2026-01-05
|
||||
readingTime: 1
|
||||
status: In progress
|
||||
status: Completed
|
||||
tags:
|
||||
- R
|
||||
- R Shiny
|
||||
@@ -44,9 +44,11 @@ This project involves creating an interactive data visualization application usi
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
You can find the code here: [Data Visualisation](https://go.arthurdanjou.fr/dataviz)
|
||||
You can find the code here: [Data Visualisation Code](https://go.arthurdanjou.fr/datavis-code)
|
||||
|
||||
And the online application here: [Data Visualisation App](https://go.arthurdanjou.fr/datavis-app)
|
||||
|
||||
## 📄 Detailed Report
|
||||
|
||||
<iframe src="/projects/dataviz.pdf" width="100%" height="1000px">
|
||||
<iframe src="/projects/datavis.pdf" width="100%" height="1000px">
|
||||
</iframe>
|
||||
BIN
public/projects/datavis.pdf
Normal file
BIN
public/projects/datavis.pdf
Normal file
Binary file not shown.
@@ -1,42 +1,56 @@
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
const WAKATIME_HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
const fetchWakatime = async (url: string) => {
|
||||
try {
|
||||
return await $fetch<{ data: unknown[] }>(url, {
|
||||
headers: WAKATIME_HEADERS,
|
||||
timeout: 5000
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`[Wakatime Error] Failed to fetch ${url}`, err)
|
||||
return { data: [] }
|
||||
}
|
||||
}
|
||||
|
||||
const cachedWakatimeCoding = defineCachedFunction(async (event: H3Event) => {
|
||||
const config = useRuntimeConfig(event)
|
||||
|
||||
return await $fetch<{ data: unknown[] }>(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.coding}.json`)
|
||||
return await fetchWakatime(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.coding}.json`)
|
||||
}, {
|
||||
maxAge: 60,
|
||||
name: 'wakatime',
|
||||
maxAge: 60 * 50,
|
||||
name: 'stats',
|
||||
getKey: () => 'coding'
|
||||
})
|
||||
|
||||
const cachedWakatimeEditors = defineCachedFunction(async (event: H3Event) => {
|
||||
const config = useRuntimeConfig(event)
|
||||
|
||||
return await $fetch<{ data: unknown[] }>(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.editors}.json`)
|
||||
return await fetchWakatime(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.editors}.json`)
|
||||
}, {
|
||||
maxAge: 60,
|
||||
name: 'wakatime',
|
||||
maxAge: 60 * 60,
|
||||
name: 'stats',
|
||||
getKey: () => 'editors'
|
||||
})
|
||||
|
||||
const cachedWakatimeOs = defineCachedFunction(async (event: H3Event) => {
|
||||
const config = useRuntimeConfig(event)
|
||||
|
||||
return await $fetch<{ data: unknown[] }>(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.os}.json`)
|
||||
return await fetchWakatime(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.os}.json`)
|
||||
}, {
|
||||
maxAge: 60,
|
||||
name: 'wakatime',
|
||||
maxAge: 60 * 60,
|
||||
name: 'stats',
|
||||
getKey: () => 'os'
|
||||
})
|
||||
|
||||
const cachedWakatimeLanguages = defineCachedFunction(async (event: H3Event) => {
|
||||
const config = useRuntimeConfig(event)
|
||||
|
||||
return await $fetch<{ data: unknown[] }>(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.languages}.json`)
|
||||
return await fetchWakatime(`https://wakatime.com/share/${config.wakatime.userId}/${config.wakatime.languages}.json`)
|
||||
}, {
|
||||
maxAge: 60,
|
||||
name: 'wakatime',
|
||||
maxAge: 60 * 60,
|
||||
name: 'stats',
|
||||
getKey: () => 'languages'
|
||||
})
|
||||
|
||||
|
||||
5
worker-configuration.d.ts
vendored
5
worker-configuration.d.ts
vendored
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable */
|
||||
// Generated by Wrangler by running `wrangler types` (hash: 373e9a05bf207b93549ab53665d07e4b)
|
||||
// Generated by Wrangler by running `wrangler types` (hash: 8c48032b4b2801cdbac6e8dbc9d26203)
|
||||
// Runtime types generated with workerd@1.20251210.0 2025-12-13 nodejs_compat
|
||||
declare namespace Cloudflare {
|
||||
interface GlobalProps {
|
||||
mainModule: typeof import("./.output/server/index");
|
||||
}
|
||||
interface Env {
|
||||
CACHE: KVNamespace;
|
||||
STUDIO_GITHUB_CLIENT_ID: string;
|
||||
|
||||
Reference in New Issue
Block a user