added visitors chart to shortener detail page

pull/3/head
TZGyn 2 years ago
parent be9a1ccec5
commit 8850a7b270
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -8,6 +8,7 @@
"name": "link-shortener-svelte",
"version": "0.0.1",
"dependencies": {
"apexcharts": "^3.44.0",
"argon2": "^0.31.2",
"bits-ui": "^0.9.8",
"clsx": "^2.0.0",
@ -965,6 +966,11 @@
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true
},
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -1026,6 +1032,20 @@
"node": ">= 8"
}
},
"node_modules/apexcharts": {
"version": "3.44.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.44.0.tgz",
"integrity": "sha512-u7Xzrbcxc2yWznN78Jh5NMCYVAsWDfBjRl5ea++rVzFAqjU2hLz4RgKIFwYOBDRQtW1e/Qz8azJTqIJ1+Vu9Qg==",
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
@ -3952,6 +3972,89 @@
"zod": "3.x"
}
},
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"dependencies": {
"svg.js": "^2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
"dependencies": {
"svg.js": ">=2.3.x"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"dependencies": {
"svg.js": "^2.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js/node_modules/svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"dependencies": {
"svg.js": "^2.6.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/tabbable": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",

@ -32,6 +32,7 @@
},
"type": "module",
"dependencies": {
"apexcharts": "^3.44.0",
"argon2": "^0.31.2",
"bits-ui": "^0.9.8",
"clsx": "^2.0.0",

@ -75,4 +75,8 @@
body {
@apply bg-background text-foreground;
}
.dark svg text {
fill: white;
}
}

@ -1,4 +1,5 @@
import { db } from '$lib/db'
import { redirect } from '@sveltejs/kit'
import type { PageServerLoad } from './$types'
export const load = (async (event) => {
@ -16,5 +17,9 @@ export const load = (async (event) => {
},
})
if (!shortener) {
throw redirect(303, '/')
}
return { shortener }
}) satisfies PageServerLoad

@ -1,7 +1,26 @@
<script lang="ts">
import type { PageData } from './$types'
import { Separator } from '$lib/components/ui/separator'
import BarChart from './BarChart.svelte'
import * as Card from '$lib/components/ui/card'
export let data: PageData
</script>
{JSON.stringify(data.shortener)}
<div class="flex justify-between p-8">
<div class="text-4xl font-bold">{data.shortener.link}</div>
</div>
<Separator />
<div class="flex flex-col gap-4 overflow-y-scroll p-4">
<Card.Root>
<Card.Header>
<Card.Title>Clicks</Card.Title>
<Card.Description
>Number of visit(s) over this year</Card.Description>
</Card.Header>
<Card.Content>
<BarChart />
</Card.Content>
</Card.Root>
</div>

@ -0,0 +1,72 @@
<script lang="ts">
import type { ApexOptions } from 'apexcharts'
import { mode } from 'mode-watcher'
import { onMount } from 'svelte'
let options = {
series: [
{
name: 'Clicks',
data: [400, 430, 448, 470, 540, 580, 690, 1100, 1200, 1380],
},
],
chart: {
type: 'bar',
height: 500,
toolbar: {
show: false,
},
},
plotOptions: {
bar: {
borderRadius: 4,
horizontal: false,
},
},
dataLabels: {
enabled: false,
},
xaxis: {
categories: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
labels: {
show: false,
},
},
tooltip: {
theme: 'dark',
},
} satisfies ApexOptions
$: options.tooltip.theme = $mode === 'dark' ? 'dark' : 'light'
let container: HTMLElement | undefined
const renderChart = async (options: ApexOptions) => {
if (container) {
container.innerHTML = ''
}
var chart = new apexChart(container, options)
chart.render()
}
$: container && apexChart && renderChart(options)
let apexChart: typeof ApexCharts
onMount(async () => {
apexChart = (await import('apexcharts')).default
})
</script>
<div bind:this={container}></div>
Loading…
Cancel
Save