You've already forked AstralRinth
forked from didirus/AstralRinth
@@ -45,6 +45,7 @@ export default {
|
|||||||
{ text: 'Copy Code', link: '/components/copy-code' },
|
{ text: 'Copy Code', link: '/components/copy-code' },
|
||||||
{ text: 'Notifications', link: '/components/notifications' },
|
{ text: 'Notifications', link: '/components/notifications' },
|
||||||
{ text: 'Share Modal', link: '/components/share-modal' },
|
{ text: 'Share Modal', link: '/components/share-modal' },
|
||||||
|
{ text: 'Analytics', link: '/components/analytics' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
108
docs/components/analytics.md
Normal file
108
docs/components/analytics.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Analytics
|
||||||
|
|
||||||
|
<DemoContainer>
|
||||||
|
<LineChart
|
||||||
|
:data="{
|
||||||
|
labels: [
|
||||||
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
|
'2021-01-16', '2021-01-17'
|
||||||
|
],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: 'Spirit',
|
||||||
|
color: 16711680,
|
||||||
|
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ad Astra',
|
||||||
|
color: 65280,
|
||||||
|
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tempad',
|
||||||
|
color: 255,
|
||||||
|
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<PieChart
|
||||||
|
:data="{
|
||||||
|
title: 'Downloads',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: 'Spirit',
|
||||||
|
color: 16711680, // Red in decimal (equivalent to #FF0000 in hexadecimal)
|
||||||
|
data: 120, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ad Astra',
|
||||||
|
color: 65280, // Green in decimal (equivalent to #00FF00 in hexadecimal)
|
||||||
|
data: 150, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tempad',
|
||||||
|
color: 255, // Blue in decimal (equivalent to #0000FF in hexadecimal)
|
||||||
|
data: 180, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</DemoContainer>
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<LineChart
|
||||||
|
:formatLabel="(label) => doFormattingThings(label)"
|
||||||
|
:data="{
|
||||||
|
labels: [
|
||||||
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
|
'2021-01-16', '2021-01-17'
|
||||||
|
],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: 'Spirit',
|
||||||
|
color: 16711680,
|
||||||
|
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ad Astra',
|
||||||
|
color: 65280,
|
||||||
|
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tempad',
|
||||||
|
color: 255,
|
||||||
|
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
```vue
|
||||||
|
<PieChart
|
||||||
|
:data="{
|
||||||
|
title: 'Downloads',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: 'Spirit',
|
||||||
|
color: 16711680, // Red in decimal (equivalent to #FF0000 in hexadecimal)
|
||||||
|
data: 120, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ad Astra',
|
||||||
|
color: 65280, // Green in decimal (equivalent to #00FF00 in hexadecimal)
|
||||||
|
data: 150, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tempad',
|
||||||
|
color: 255, // Blue in decimal (equivalent to #0000FF in hexadecimal)
|
||||||
|
data: 180, // Example download numbers for the three dates
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
```
|
||||||
125
lib/components/base/LineChart.vue
Normal file
125
lib/components/base/LineChart.vue
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<Line :options="chartOptions" :data="chartData" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Line } from 'vue-chartjs'
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
Filler,
|
||||||
|
} from 'chart.js'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, PointElement, LineElement, CategoryScale, LinearScale, Filler)
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
formatLabels: {
|
||||||
|
type: Function,
|
||||||
|
default: (label) => dayjs(label).format('MMM D'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const decimalToRgba = (decimalColor, alpha = 0.75) => {
|
||||||
|
const red = (decimalColor >> 16) & 255
|
||||||
|
const green = (decimalColor >> 8) & 255
|
||||||
|
const blue = decimalColor & 255
|
||||||
|
|
||||||
|
return `rgba(${red}, ${green}, ${blue}, ${alpha})`
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartData = ref({
|
||||||
|
labels: props.data.labels.map((date) => props.formatLabels(date)),
|
||||||
|
datasets: props.data.data.map((project) => ({
|
||||||
|
label: project.title,
|
||||||
|
backgroundColor: decimalToRgba(project.color, 0.75),
|
||||||
|
borderColor: decimalToRgba(project.color),
|
||||||
|
data: project.data,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
|
||||||
|
const chartOptions = ref({
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
grid: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
interaction: {
|
||||||
|
mode: 'x',
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
align: 'start',
|
||||||
|
labels: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
font: {
|
||||||
|
size: 12,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
position: 'nearest',
|
||||||
|
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue(
|
||||||
|
'--color-raised-bg'
|
||||||
|
),
|
||||||
|
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
||||||
|
borderWidth: 1,
|
||||||
|
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--color-contrast'),
|
||||||
|
titleFont: {
|
||||||
|
size: 14,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
bodyFont: {
|
||||||
|
size: 12,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
boxPadding: 8,
|
||||||
|
intersect: false,
|
||||||
|
padding: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
The data for the graph should look like this
|
||||||
|
|
||||||
|
downloads, views, likes = {
|
||||||
|
dates: [ '2021-01-01', '2021-01-02', '2021-01-03' ], // Last 2 weeks
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
title: projectName,
|
||||||
|
color: projectColor,
|
||||||
|
data: [ ... ],
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
93
lib/components/base/PieChart.vue
Normal file
93
lib/components/base/PieChart.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Pie } from 'vue-chartjs'
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
PieController,
|
||||||
|
ArcElement,
|
||||||
|
Legend,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
} from 'chart.js'
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, PieController, ArcElement, Legend, CategoryScale, LinearScale)
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const decimalToRgba = (decimalColor, alpha = 0.75) => {
|
||||||
|
const red = (decimalColor >> 16) & 255
|
||||||
|
const green = (decimalColor >> 8) & 255
|
||||||
|
const blue = decimalColor & 255
|
||||||
|
|
||||||
|
return `rgba(${red}, ${green}, ${blue}, ${alpha})`
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartData = ref({
|
||||||
|
labels: props.data.data.map((project) => project.title),
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: props.data.title,
|
||||||
|
backgroundColor: props.data.data.map((project) => decimalToRgba(project.color)),
|
||||||
|
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
||||||
|
data: props.data.data.map((project) => project.data),
|
||||||
|
fill: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const chartOptions = ref({
|
||||||
|
responsive: true,
|
||||||
|
elements: {
|
||||||
|
point: {
|
||||||
|
radius: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
font: {
|
||||||
|
size: 12,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
position: 'nearest',
|
||||||
|
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue(
|
||||||
|
'--color-raised-bg'
|
||||||
|
),
|
||||||
|
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
||||||
|
borderWidth: 1,
|
||||||
|
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--color-contrast'),
|
||||||
|
titleFont: {
|
||||||
|
size: 16,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
||||||
|
bodyFont: {
|
||||||
|
size: 12,
|
||||||
|
family: 'Inter',
|
||||||
|
},
|
||||||
|
boxPadding: 8,
|
||||||
|
intersect: false,
|
||||||
|
padding: 12,
|
||||||
|
displayColors: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Pie :options="chartOptions" :data="chartData" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@@ -24,6 +24,8 @@ export { default as ModalConfirm } from './base/ModalConfirm.vue'
|
|||||||
export { default as Breadcrumbs } from './base/Breadcrumbs.vue'
|
export { default as Breadcrumbs } from './base/Breadcrumbs.vue'
|
||||||
export { default as DropdownButton } from './base/DropdownButton.vue'
|
export { default as DropdownButton } from './base/DropdownButton.vue'
|
||||||
export { default as ShareModal } from './base/ShareModal.vue'
|
export { default as ShareModal } from './base/ShareModal.vue'
|
||||||
|
export { default as LineChart } from './base/LineChart.vue'
|
||||||
|
export { default as PieChart } from './base/PieChart.vue'
|
||||||
|
|
||||||
export { default as Categories } from './search/Categories.vue'
|
export { default as Categories } from './search/Categories.vue'
|
||||||
export { default as SearchFilter } from './search/SearchFilter.vue'
|
export { default as SearchFilter } from './search/SearchFilter.vue'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "omorphia",
|
"name": "omorphia",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.4.38",
|
"version": "0.4.39",
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"lib"
|
"lib"
|
||||||
@@ -25,12 +25,14 @@
|
|||||||
"docs:preview": "vitepress preview docs"
|
"docs:preview": "vitepress preview docs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"chart.js": "^4.3.3",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"floating-vue": "^2.0.0-beta.20",
|
"floating-vue": "^2.0.0-beta.20",
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"qrcode.vue": "^3.4.0",
|
"qrcode.vue": "^3.4.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
"vue-chartjs": "^5.2.0",
|
||||||
"vue-router": "^4.2.1",
|
"vue-router": "^4.2.1",
|
||||||
"vue-select": "^4.0.0-beta.6",
|
"vue-select": "^4.0.0-beta.6",
|
||||||
"xss": "^1.0.14"
|
"xss": "^1.0.14"
|
||||||
|
|||||||
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
@@ -1,6 +1,9 @@
|
|||||||
lockfileVersion: '6.0'
|
lockfileVersion: '6.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
chart.js:
|
||||||
|
specifier: ^4.3.3
|
||||||
|
version: 4.3.3
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
version: 1.11.7
|
version: 1.11.7
|
||||||
@@ -19,6 +22,9 @@ dependencies:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.3.4
|
specifier: ^3.3.4
|
||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
|
vue-chartjs:
|
||||||
|
specifier: ^5.2.0
|
||||||
|
version: 5.2.0(chart.js@4.3.3)(vue@3.3.4)
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(vue@3.3.4)
|
version: 4.2.1(vue@3.3.4)
|
||||||
@@ -552,6 +558,10 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec': 1.4.14
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@kurkle/color@0.3.2:
|
||||||
|
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@nodelib/fs.scandir@2.1.5:
|
/@nodelib/fs.scandir@2.1.5:
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -1040,6 +1050,13 @@ packages:
|
|||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/chart.js@4.3.3:
|
||||||
|
resolution: {integrity: sha512-aTk7pBw+x6sQYhon/NR3ikfUJuym/LdgpTlgZRe2PaEhjUMKBKyNaFCMVRAyTEWYFNO7qRu7iQVqOw/OqzxZxQ==}
|
||||||
|
engines: {pnpm: '>=7'}
|
||||||
|
dependencies:
|
||||||
|
'@kurkle/color': 0.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/chokidar@3.5.3:
|
/chokidar@3.5.3:
|
||||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
@@ -2309,6 +2326,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vue-chartjs@5.2.0(chart.js@4.3.3)(vue@3.3.4):
|
||||||
|
resolution: {integrity: sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==}
|
||||||
|
peerDependencies:
|
||||||
|
chart.js: ^4.1.1
|
||||||
|
vue: ^3.0.0-0 || ^2.7.0
|
||||||
|
dependencies:
|
||||||
|
chart.js: 4.3.3
|
||||||
|
vue: 3.3.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vue-demi@0.14.5(vue@3.3.4):
|
/vue-demi@0.14.5(vue@3.3.4):
|
||||||
resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
|
resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|||||||
Reference in New Issue
Block a user