Skip to content

Commit fa130e8

Browse files
committed
chore: wip
1 parent d15a4dd commit fa130e8

File tree

1 file changed

+232
-6
lines changed
  • storage/framework/defaults/views/dashboard/blog/tags

1 file changed

+232
-6
lines changed

storage/framework/defaults/views/dashboard/blog/tags/index.vue

Lines changed: 232 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,74 @@
11
<script lang="ts" setup>
22
import { ref, computed } from 'vue'
33
import { useHead } from '@vueuse/head'
4+
import { Line, Bar, Doughnut } from 'vue-chartjs'
5+
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, PointElement, LineElement, ArcElement } from 'chart.js'
6+
7+
// Register ChartJS components
8+
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, PointElement, LineElement, ArcElement)
49
510
useHead({
611
title: 'Dashboard - Blog Tags',
712
})
813
14+
// Chart options
15+
const lineChartOptions = {
16+
responsive: true,
17+
maintainAspectRatio: false,
18+
scales: {
19+
y: {
20+
beginAtZero: true,
21+
ticks: {
22+
precision: 0
23+
}
24+
}
25+
},
26+
plugins: {
27+
legend: {
28+
position: 'top' as const,
29+
}
30+
}
31+
}
32+
33+
const barChartOptions = {
34+
responsive: true,
35+
maintainAspectRatio: false,
36+
scales: {
37+
y: {
38+
beginAtZero: true,
39+
ticks: {
40+
precision: 0
41+
}
42+
}
43+
},
44+
plugins: {
45+
legend: {
46+
position: 'top' as const,
47+
}
48+
}
49+
}
50+
51+
const doughnutChartOptions = {
52+
responsive: true,
53+
maintainAspectRatio: false,
54+
plugins: {
55+
legend: {
56+
position: 'top' as const,
57+
}
58+
}
59+
}
60+
61+
// Time range selector
62+
const timeRanges = [
63+
{ label: 'Today', value: 'today' },
64+
{ label: 'Last 7 days', value: '7days' },
65+
{ label: 'Last 30 days', value: '30days' },
66+
{ label: 'Last 90 days', value: '90days' },
67+
{ label: 'Last year', value: 'year' },
68+
{ label: 'All time', value: 'all' }
69+
]
70+
const selectedTimeRange = ref('30days')
71+
972
// Sample tags data
1073
const tags = ref([
1174
{
@@ -268,16 +331,94 @@ const filteredTags = computed(() => {
268331
})
269332
})
270333
334+
// Monthly chart data
335+
const monthlyChartData = computed(() => {
336+
// Generate sample data for tag growth over time
337+
const tagGrowthData = {
338+
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
339+
datasets: [
340+
{
341+
label: 'New Tags',
342+
backgroundColor: 'rgba(75, 192, 192, 0.2)',
343+
borderColor: 'rgba(75, 192, 192, 1)',
344+
borderWidth: 2,
345+
pointBackgroundColor: 'rgba(75, 192, 192, 1)',
346+
data: [2, 3, 1, 4, 2, 5, 3, 2, 4, 6, 3, 2]
347+
}
348+
]
349+
}
350+
351+
// Generate sample data for posts per tag
352+
const postsPerTagData = {
353+
labels: tags.value.slice(0, 8).map(tag => tag.name),
354+
datasets: [
355+
{
356+
label: 'Posts',
357+
backgroundColor: 'rgba(54, 162, 235, 0.6)',
358+
borderColor: 'rgba(54, 162, 235, 1)',
359+
borderWidth: 1,
360+
data: tags.value.slice(0, 8).map(tag => tag.postCount)
361+
}
362+
]
363+
}
364+
365+
// Generate sample data for tag distribution
366+
const tagColors = [
367+
'rgba(255, 99, 132, 0.6)',
368+
'rgba(54, 162, 235, 0.6)',
369+
'rgba(255, 206, 86, 0.6)',
370+
'rgba(75, 192, 192, 0.6)',
371+
'rgba(153, 102, 255, 0.6)',
372+
'rgba(255, 159, 64, 0.6)',
373+
'rgba(199, 199, 199, 0.6)',
374+
'rgba(83, 102, 255, 0.6)'
375+
]
376+
377+
const tagDistributionData = {
378+
labels: tags.value.slice(0, 8).map(tag => tag.name),
379+
datasets: [
380+
{
381+
backgroundColor: tagColors,
382+
borderColor: tagColors.map(color => color.replace('0.6', '1')),
383+
borderWidth: 1,
384+
data: tags.value.slice(0, 8).map(tag => tag.postCount)
385+
}
386+
]
387+
}
388+
389+
return {
390+
tagGrowthChartData: tagGrowthData,
391+
postsPerTagChartData: postsPerTagData,
392+
tagDistributionChartData: tagDistributionData
393+
}
394+
})
395+
271396
// Tag statistics
272397
const tagStats = computed(() => {
273398
const totalTags = tags.value.length
274399
const totalPosts = tags.value.reduce((sum, tag) => sum + tag.postCount, 0)
275400
const mostUsedTag = [...tags.value].sort((a, b) => b.postCount - a.postCount)[0]
401+
const leastUsedTag = [...tags.value].sort((a, b) => a.postCount - b.postCount)[0]
402+
const avgPostsPerTag = totalPosts / totalTags
403+
const topTagPercentage = mostUsedTag ? Math.round((mostUsedTag.postCount / totalPosts) * 100) : 0
404+
405+
// Find newest tag
406+
let newestTag = tags.value[0] || { name: 'None', createdAt: '' }
407+
408+
for (const tag of tags.value) {
409+
if (new Date(tag.createdAt) > new Date(newestTag.createdAt)) {
410+
newestTag = tag
411+
}
412+
}
276413
277414
return {
278415
totalTags,
279416
totalPosts,
280-
mostUsedTag
417+
mostUsedTag,
418+
leastUsedTag,
419+
avgPostsPerTag: avgPostsPerTag.toFixed(1),
420+
topTagPercentage,
421+
newestTag
281422
}
282423
})
283424
@@ -457,8 +598,20 @@ const paginationRange = computed(() => {
457598
</button>
458599
</div>
459600

460-
<!-- Tag Statistics -->
461-
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
601+
<!-- Time Range Selector -->
602+
<div class="flex justify-end">
603+
<div class="relative inline-block w-full sm:w-auto">
604+
<select
605+
v-model="selectedTimeRange"
606+
class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6 dark:bg-blue-gray-800 dark:text-white dark:ring-gray-700"
607+
>
608+
<option v-for="range in timeRanges" :key="range.value" :value="range.value">{{ range.label }}</option>
609+
</select>
610+
</div>
611+
</div>
612+
613+
<!-- Enhanced Tag Statistics -->
614+
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
462615
<!-- Total Tags -->
463616
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
464617
<div class="px-4 py-5 sm:p-6">
@@ -477,6 +630,9 @@ const paginationRange = computed(() => {
477630
<div class="text-lg font-medium text-gray-900 dark:text-white">
478631
{{ tagStats.totalTags }}
479632
</div>
633+
<div class="mt-1 text-sm text-green-600 dark:text-green-400">
634+
<span>{{ tagStats.newestTag.name }} added recently</span>
635+
</div>
480636
</dd>
481637
</dl>
482638
</div>
@@ -502,6 +658,9 @@ const paginationRange = computed(() => {
502658
<div class="text-lg font-medium text-gray-900 dark:text-white">
503659
{{ tagStats.totalPosts }}
504660
</div>
661+
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
662+
<span>{{ tagStats.avgPostsPerTag }} avg per tag</span>
663+
</div>
505664
</dd>
506665
</dl>
507666
</div>
@@ -526,9 +685,37 @@ const paginationRange = computed(() => {
526685
<dd>
527686
<div class="text-lg font-medium text-gray-900 dark:text-white">
528687
{{ tagStats.mostUsedTag ? tagStats.mostUsedTag.name : 'None' }}
529-
<span v-if="tagStats.mostUsedTag" class="text-sm text-gray-500 dark:text-gray-400">
530-
({{ tagStats.mostUsedTag.postCount }} posts)
531-
</span>
688+
</div>
689+
<div class="mt-1 text-sm text-green-600 dark:text-green-400">
690+
<span v-if="tagStats.mostUsedTag">{{ tagStats.mostUsedTag.postCount }} posts ({{ tagStats.topTagPercentage }}%)</span>
691+
</div>
692+
</dd>
693+
</dl>
694+
</div>
695+
</div>
696+
</div>
697+
</div>
698+
699+
<!-- Least Used Tag -->
700+
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
701+
<div class="px-4 py-5 sm:p-6">
702+
<div class="flex items-center">
703+
<div class="flex-shrink-0 bg-blue-500 rounded-md p-3">
704+
<svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
705+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
706+
</svg>
707+
</div>
708+
<div class="ml-5 w-0 flex-1">
709+
<dl>
710+
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
711+
Least Used Tag
712+
</dt>
713+
<dd>
714+
<div class="text-lg font-medium text-gray-900 dark:text-white">
715+
{{ tagStats.leastUsedTag ? tagStats.leastUsedTag.name : 'None' }}
716+
</div>
717+
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
718+
<span v-if="tagStats.leastUsedTag">{{ tagStats.leastUsedTag.postCount }} posts</span>
532719
</div>
533720
</dd>
534721
</dl>
@@ -538,6 +725,39 @@ const paginationRange = computed(() => {
538725
</div>
539726
</div>
540727

728+
<!-- Charts -->
729+
<div class="grid grid-cols-1 gap-5 lg:grid-cols-3">
730+
<!-- Tag Growth Chart -->
731+
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
732+
<div class="px-4 py-5 sm:p-6">
733+
<h3 class="text-base font-semibold text-gray-900 dark:text-white">Tag Growth</h3>
734+
<div class="mt-4" style="height: 250px;">
735+
<Line :data="monthlyChartData.tagGrowthChartData" :options="lineChartOptions" />
736+
</div>
737+
</div>
738+
</div>
739+
740+
<!-- Posts Per Tag Chart -->
741+
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
742+
<div class="px-4 py-5 sm:p-6">
743+
<h3 class="text-base font-semibold text-gray-900 dark:text-white">Posts Per Tag</h3>
744+
<div class="mt-4" style="height: 250px;">
745+
<Bar :data="monthlyChartData.postsPerTagChartData" :options="barChartOptions" />
746+
</div>
747+
</div>
748+
</div>
749+
750+
<!-- Tag Distribution Chart -->
751+
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
752+
<div class="px-4 py-5 sm:p-6">
753+
<h3 class="text-base font-semibold text-gray-900 dark:text-white">Tag Distribution</h3>
754+
<div class="mt-4" style="height: 250px;">
755+
<Doughnut :data="monthlyChartData.tagDistributionChartData" :options="doughnutChartOptions" />
756+
</div>
757+
</div>
758+
</div>
759+
</div>
760+
541761
<!-- Filters and Search -->
542762
<div class="mt-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
543763
<div class="relative max-w-sm">
@@ -584,6 +804,12 @@ const paginationRange = computed(() => {
584804

585805
<!-- Tags Table -->
586806
<div class="mt-6 flow-root">
807+
<div class="sm:flex sm:items-center sm:justify-between mb-4">
808+
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">All Tags</h3>
809+
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
810+
A list of all blog tags including name, description, and post count.
811+
</p>
812+
</div>
587813
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
588814
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
589815
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">

0 commit comments

Comments
 (0)