@veristone/nuxt-v-app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/app/app.vue +7 -0
- package/app/assets/css/v-app.css +313 -0
- package/app/components/V/A/Badge.vue +75 -0
- package/app/components/V/A/Btn/Add.vue +17 -0
- package/app/components/V/A/Btn/Back.vue +25 -0
- package/app/components/V/A/Btn/ConfirmDelete.vue +45 -0
- package/app/components/V/A/Btn/Edit.vue +35 -0
- package/app/components/V/A/Btn/Export.vue +28 -0
- package/app/components/V/A/Btn/Refresh.vue +21 -0
- package/app/components/V/A/Btn/Submit.vue +45 -0
- package/app/components/V/A/Btn/View.vue +23 -0
- package/app/components/V/A/Card.legacy.vue +291 -0
- package/app/components/V/A/Card.vue +108 -0
- package/app/components/V/A/CompanyMenu.vue +83 -0
- package/app/components/V/A/Data/KeyValue.vue +98 -0
- package/app/components/V/A/Data/StatusBadge.vue +44 -0
- package/app/components/V/A/DataField.vue +140 -0
- package/app/components/V/A/DataGrid.vue +43 -0
- package/app/components/V/A/DataTable.vue +144 -0
- package/app/components/V/A/EmptyState.vue +154 -0
- package/app/components/V/A/Fmt/Currency.vue +36 -0
- package/app/components/V/A/Fmt/DateTime.vue +34 -0
- package/app/components/V/A/Fmt/Percent.vue +47 -0
- package/app/components/V/A/LoadingState.vue +140 -0
- package/app/components/V/A/MetricCard.vue +129 -0
- package/app/components/V/A/Modal/Base.vue +195 -0
- package/app/components/V/A/Modal/Confirm.vue +92 -0
- package/app/components/V/A/Modal/Form.vue +105 -0
- package/app/components/V/A/Navigation.vue +110 -0
- package/app/components/V/A/QuickActions.vue +169 -0
- package/app/components/V/A/Slide.vue +109 -0
- package/app/components/V/A/Slideover.vue +259 -0
- package/app/components/V/A/State/Empty.vue +20 -0
- package/app/components/V/A/State/Error.vue +34 -0
- package/app/components/V/A/State/Loading.vue +33 -0
- package/app/components/V/A/StatsCard.vue +215 -0
- package/app/components/V/A/StatusBadge.vue +215 -0
- package/app/components/V/A/Table.vue +674 -0
- package/app/components/V/A/UserMenu.vue +127 -0
- package/app/components/V/A/WelcomeHeader.vue +96 -0
- package/app/components/V/Modal.vue +36 -0
- package/app/components/Va/Blocks/VaBlockGridCharts.vue +32 -0
- package/app/components/Va/Blocks/VaBlockGridKPI.vue +32 -0
- package/app/components/Va/Blocks/VaBlockGridTables.vue +23 -0
- package/app/components/Va/Blocks/VaBlockKpiGrid.vue +8 -0
- package/app/components/Va/Blocks/VaBlockSessionFilterBar.vue +8 -0
- package/app/components/Va/Cards/VaCardDonutChart.vue +59 -0
- package/app/components/Va/Cards/VaCardHeader.vue +10 -0
- package/app/components/Va/Cards/VaCardKpi.vue +17 -0
- package/app/components/Va/Cards/VaCardKpi2.vue +55 -0
- package/app/components/Va/Cards/VaCardLatestOrders.vue +82 -0
- package/app/components/Va/Cards/VaCardPopularProducts.vue +88 -0
- package/app/components/Va/Cards/VaCardRevenueBarChart.vue +49 -0
- package/app/components/Va/Cards/VaCardSubtitle.vue +5 -0
- package/app/components/Va/Cards/VaCardTitle.vue +5 -0
- package/app/components/Va/Cards/VaCardWithActiveUsers.vue +41 -0
- package/app/components/Va/Cards/VaCardWithChart.vue +135 -0
- package/app/components/Va/Cards/VaCardWithChartBlock.vue +26 -0
- package/app/components/Va/Cards/VaCardWithIndicator.vue +39 -0
- package/app/components/Va/Cards/VaCardWithProgressCircle.vue +34 -0
- package/app/components/Va/Cards/types.ts +11 -0
- package/app/components/Va/Charts/VaChartAppPerformanceBar.vue +118 -0
- package/app/components/Va/Charts/VaChartAppPerformanceBarChart.vue +118 -0
- package/app/components/Va/Charts/VaChartAreaMini.vue +127 -0
- package/app/components/Va/Charts/VaChartBarMini.vue +68 -0
- package/app/components/Va/Charts/VaChartCardinalMulti.vue +108 -0
- package/app/components/Va/Charts/VaChartColorBarChart.vue +78 -0
- package/app/components/Va/Charts/VaChartDonutHalf.vue +35 -0
- package/app/components/Va/Charts/VaChartDonutMini.vue +77 -0
- package/app/components/Va/Charts/VaChartExpensesBar.vue +58 -0
- package/app/components/Va/Charts/VaChartFinanceSummary.vue +96 -0
- package/app/components/Va/Charts/VaChartGoogleSearchConsole.vue +90 -0
- package/app/components/Va/Charts/VaChartIncomeBar.vue +82 -0
- package/app/components/Va/Charts/VaChartLegend.vue +25 -0
- package/app/components/Va/Charts/VaChartLineMini.vue +205 -0
- package/app/components/Va/Charts/VaChartRealtimeTraffic.vue +182 -0
- package/app/components/Va/Charts/VaChartRevenue.vue +43 -0
- package/app/components/Va/Charts/VaChartRevenueLine.vue +42 -0
- package/app/components/Va/Charts/VaChartRevenuevsCost.vue +84 -0
- package/app/components/Va/Charts/VaChartSearchIntent.vue +179 -0
- package/app/components/Va/Charts/VaChartSpendingTrend.vue +127 -0
- package/app/components/Va/Charts/VaChartStackedHorizontal.vue +64 -0
- package/app/components/Va/Charts/VaChartStepMinimal.vue +109 -0
- package/app/components/Va/Charts/VaChartStockComparisonLine.vue +86 -0
- package/app/components/Va/Charts/VaChartStocksPortfolioLine.vue +161 -0
- package/app/components/Va/Charts/VaChartStocksSectorLine.vue +223 -0
- package/app/components/Va/Charts/VaChartTasksCategories.vue +96 -0
- package/app/components/Va/Charts/VaChartTasksProgress.vue +130 -0
- package/app/components/Va/Charts/VaChartTrafficOverview.vue +112 -0
- package/app/components/Va/Charts/VaChartWebPerformanceLineChart.vue +114 -0
- package/app/components/Va/Charts/VaChartWinLostBar.vue +110 -0
- package/app/components/Va/Charts/VaChartWinLostDonut.vue +107 -0
- package/app/components/Va/Charts/VaChartWinLostLine.vue +111 -0
- package/app/components/Va/Charts/types.ts +10 -0
- package/app/components/Va/Dashboard/Navigation/types.ts +8 -0
- package/app/components/Va/Dashboard/VaDashboardKPICard.vue +31 -0
- package/app/components/Va/Dashboard/VaDashboardNavigation.vue +50 -0
- package/app/components/Va/Dashboard/VaDashboardPricePlan.vue +102 -0
- package/app/components/Va/Dashboard/VaDashboardUsageChart.vue +84 -0
- package/app/components/Va/Dashboard/VaDashboardUsageRequestChart.vue +46 -0
- package/app/components/Va/Layout/NotificationsSlideover.vue +169 -0
- package/app/components/Va/Layout/SideNav/types.ts +5 -0
- package/app/components/Va/Layout/SideNav.vue +108 -0
- package/app/components/Va/Layout/TeamsMenu.vue +57 -0
- package/app/components/Va/Layout/UserMenu.vue +57 -0
- package/app/composables/useDashboard.ts +25 -0
- package/app/composables/useVAAnimation.ts +324 -0
- package/app/composables/useVAUtils.ts +118 -0
- package/app/composables/useVCrud.ts +647 -0
- package/app/composables/useVFetch.ts +46 -0
- package/app/composables/useVFileUpload.ts +45 -0
- package/app/composables/useVToast.ts +73 -0
- package/app/composables/useXATableColumns.ts +456 -0
- package/app/data/BillingStats.ts +65 -0
- package/app/data/SearchData.ts +58 -0
- package/app/data/TasksData.ts +101 -0
- package/app/data/dashboardData.ts +113 -0
- package/app/layouts/default.vue +171 -0
- package/app/layouts/legacy.vue +61 -0
- package/app/pages/playground/base.vue +498 -0
- package/app/pages/playground/blocks.vue +108 -0
- package/app/pages/playground/buttons.vue +237 -0
- package/app/pages/playground/cards.vue +326 -0
- package/app/pages/playground/charts.vue +338 -0
- package/app/pages/playground/dashboard.vue +315 -0
- package/app/pages/playground/formatters.vue +329 -0
- package/app/pages/playground/index.vue +109 -0
- package/app/pages/playground/layout.vue +159 -0
- package/app/pages/playground/modals.vue +606 -0
- package/app/pages/playground/states.vue +282 -0
- package/app/pages/playground/tables.vue +618 -0
- package/app/pages/test-layout.vue +10 -0
- package/nuxt.config.ts +12 -0
- package/package.json +71 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const LegendPosition = {
|
|
3
|
+
Top: "top",
|
|
4
|
+
Bottom: "bottom",
|
|
5
|
+
Left: "left",
|
|
6
|
+
Right: "right",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
interface BarChartCategory {
|
|
10
|
+
name: string;
|
|
11
|
+
color: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
defineProps<{
|
|
15
|
+
title: string;
|
|
16
|
+
totalValue: string;
|
|
17
|
+
data: Record<string, string | number>[];
|
|
18
|
+
categories: Record<string, BarChartCategory>;
|
|
19
|
+
yAxis: string[];
|
|
20
|
+
xFormatter: (i: number) => string;
|
|
21
|
+
yFormatter: (i: number) => string;
|
|
22
|
+
}>();
|
|
23
|
+
</script>
|
|
24
|
+
<template>
|
|
25
|
+
<UCard>
|
|
26
|
+
<div class="mb-8">
|
|
27
|
+
<div class="flex items-center justify-between">
|
|
28
|
+
<h3 class="text-base font-normal text-lg text-highlighted mb-1">{{ title }}</h3>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="text-default font-medium dark:font-semibold text-2xl">{{ totalValue }}</div>
|
|
31
|
+
</div>
|
|
32
|
+
<BarChart
|
|
33
|
+
:data="data"
|
|
34
|
+
:height="328"
|
|
35
|
+
:categories="categories"
|
|
36
|
+
:y-axis="yAxis"
|
|
37
|
+
:group-padding="0"
|
|
38
|
+
:bar-padding="0.2"
|
|
39
|
+
:x-num-ticks="6"
|
|
40
|
+
:y-num-ticks="5"
|
|
41
|
+
:radius="4"
|
|
42
|
+
:x-formatter="xFormatter"
|
|
43
|
+
:y-formatter="yFormatter"
|
|
44
|
+
:legend-position="LegendPosition.Bottom"
|
|
45
|
+
:hide-legend="false"
|
|
46
|
+
:y-grid-line="false"
|
|
47
|
+
/>
|
|
48
|
+
</UCard>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
defineProps<{
|
|
3
|
+
metric: string
|
|
4
|
+
current: number | string
|
|
5
|
+
percentChange: number
|
|
6
|
+
}>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<UCard>
|
|
11
|
+
<div class="space-y-2">
|
|
12
|
+
<VaCardSubtitle>
|
|
13
|
+
{{ metric }}
|
|
14
|
+
</VaCardSubtitle>
|
|
15
|
+
|
|
16
|
+
<div class="flex items-center justify-start gap-4">
|
|
17
|
+
<VaCardTitle>
|
|
18
|
+
{{ current }}
|
|
19
|
+
</VaCardTitle>
|
|
20
|
+
|
|
21
|
+
<div class="flex items-center flex-col items-start text-sm">
|
|
22
|
+
<div class="flex items-center gap-1">
|
|
23
|
+
<UIcon
|
|
24
|
+
:name="
|
|
25
|
+
percentChange > 0 ? 'i-lucide-arrow-up' : 'i-lucide-arrow-down'
|
|
26
|
+
"
|
|
27
|
+
:class="percentChange > 0 ? 'text-success' : 'text-danger'"
|
|
28
|
+
/>
|
|
29
|
+
<div
|
|
30
|
+
:class="percentChange > 0 ? 'text-success' : 'text-danger'"
|
|
31
|
+
class="mr-1"
|
|
32
|
+
>
|
|
33
|
+
{{ percentChange }}%
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<span class="text-dimmed">from previous month</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</UCard>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BulletLegendItemInterface, ChartData } from './types'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
name: string
|
|
6
|
+
value: number | string
|
|
7
|
+
}>()
|
|
8
|
+
|
|
9
|
+
const categories: Record<string, BulletLegendItemInterface> = {
|
|
10
|
+
users: {
|
|
11
|
+
name: 'Users',
|
|
12
|
+
color: '#00c16a'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const data: ChartData[] = [
|
|
17
|
+
{
|
|
18
|
+
date: 'Jan 23',
|
|
19
|
+
users: 234,
|
|
20
|
+
sessions: 1432,
|
|
21
|
+
churn: 5.2
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
date: 'Feb 23',
|
|
25
|
+
users: 431,
|
|
26
|
+
sessions: 1032,
|
|
27
|
+
churn: 4.3
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
date: 'Mar 23',
|
|
31
|
+
users: 543,
|
|
32
|
+
sessions: 1089,
|
|
33
|
+
churn: 5.1
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
date: 'Apr 23',
|
|
37
|
+
users: 489,
|
|
38
|
+
sessions: 988,
|
|
39
|
+
churn: 5.4
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
date: 'May 23',
|
|
43
|
+
users: 391,
|
|
44
|
+
sessions: 642,
|
|
45
|
+
churn: 5.5
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
date: 'Jun 23',
|
|
49
|
+
users: 582,
|
|
50
|
+
sessions: 786,
|
|
51
|
+
churn: 4.8
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
date: 'Jul 23',
|
|
55
|
+
users: 482,
|
|
56
|
+
sessions: 673,
|
|
57
|
+
churn: 4.5
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
date: 'Aug 23',
|
|
61
|
+
users: 389,
|
|
62
|
+
sessions: 761,
|
|
63
|
+
churn: 0
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
date: 'Sep 23',
|
|
67
|
+
users: 521,
|
|
68
|
+
sessions: 793,
|
|
69
|
+
churn: 0
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
date: 'Oct 23',
|
|
73
|
+
users: 434,
|
|
74
|
+
sessions: 543,
|
|
75
|
+
churn: 0
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
date: 'Nov 23',
|
|
79
|
+
users: 332,
|
|
80
|
+
sessions: 678,
|
|
81
|
+
churn: 0
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
date: 'Dec 23',
|
|
85
|
+
users: 275,
|
|
86
|
+
sessions: 873,
|
|
87
|
+
churn: 0
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<template>
|
|
93
|
+
<UCard>
|
|
94
|
+
<VaCardHeader>
|
|
95
|
+
<VaCardSubtitle>
|
|
96
|
+
{{ name }}
|
|
97
|
+
</VaCardSubtitle>
|
|
98
|
+
<template #action>
|
|
99
|
+
<UButton
|
|
100
|
+
icon="i-lucide-ellipsis-vertical"
|
|
101
|
+
size="sm"
|
|
102
|
+
variant="subtle"
|
|
103
|
+
/>
|
|
104
|
+
</template>
|
|
105
|
+
</VaCardHeader>
|
|
106
|
+
<div class="space-y-2">
|
|
107
|
+
<VaCardTitle>
|
|
108
|
+
{{ value }}
|
|
109
|
+
</VaCardTitle>
|
|
110
|
+
<h5 class="text-sm text-muted">
|
|
111
|
+
{{ name }}
|
|
112
|
+
</h5>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="mt-6">
|
|
115
|
+
<AreaChart
|
|
116
|
+
:data="data"
|
|
117
|
+
:categories="categories"
|
|
118
|
+
:min-max-ticks-only="true"
|
|
119
|
+
:y-num-ticks="1"
|
|
120
|
+
:x-formatter="(i: number) => `${data![i]!.date}`"
|
|
121
|
+
:y-formatter="() => ''"
|
|
122
|
+
:hide-legend="true"
|
|
123
|
+
:hide-x-axis="true"
|
|
124
|
+
:height="80"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div>
|
|
129
|
+
<div class="text-sm space-x-1">
|
|
130
|
+
<span class="text-success-600">+20% ($36)</span>
|
|
131
|
+
<span class="text-muted">•</span><span class="text-muted">vs Last Months</span>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</UCard>
|
|
135
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
defineProps<{
|
|
3
|
+
title: string
|
|
4
|
+
text: string
|
|
5
|
+
}>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<UCard
|
|
10
|
+
class="flex items-center relative pb-8"
|
|
11
|
+
variant="soft"
|
|
12
|
+
>
|
|
13
|
+
<div class="mb-16">
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="space-y-1 absolute left-4 bottom-4 right-4">
|
|
18
|
+
<h3 class="font-semibold">
|
|
19
|
+
{{ title }}
|
|
20
|
+
</h3>
|
|
21
|
+
<p class="text-muted">
|
|
22
|
+
{{ text }}
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
</UCard>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
defineProps<{
|
|
3
|
+
metric: string
|
|
4
|
+
current: number | string
|
|
5
|
+
percentChange: number
|
|
6
|
+
}>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<UCard>
|
|
11
|
+
<div class="text-xs uppercase tracking-wider text-muted font-medium">
|
|
12
|
+
{{ metric }}
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="mt-2 flex items-center justify-start gap-6">
|
|
16
|
+
<p class="font-semibold text-3xl text-highlighted tracking-wide">
|
|
17
|
+
{{ current }}
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<div class="flex items-center flex-col items-start text-sm">
|
|
21
|
+
<div class="flex items-center gap-1">
|
|
22
|
+
<UIcon
|
|
23
|
+
:name="
|
|
24
|
+
percentChange > 0 ? 'i-lucide-arrow-up' : 'i-lucide-arrow-down'
|
|
25
|
+
"
|
|
26
|
+
:class="percentChange > 0 ? 'text-emerald-500' : 'text-red-500'"
|
|
27
|
+
/>
|
|
28
|
+
<div
|
|
29
|
+
:class="percentChange > 0 ? 'text-emerald-500' : 'text-red-500'"
|
|
30
|
+
class="mr-1"
|
|
31
|
+
>
|
|
32
|
+
{{ percentChange }}%
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<span class="text-(--ui-text-dimmed)">from previous month</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</UCard>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface DashboardItem {
|
|
3
|
+
title: string
|
|
4
|
+
value: number | string
|
|
5
|
+
progress: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
defineProps<DashboardItem>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<UCard
|
|
13
|
+
variant="subtle"
|
|
14
|
+
:ui="{ footer: 'sm:py-3 bg-elevated' }"
|
|
15
|
+
>
|
|
16
|
+
<div class="flex items-center gap-4">
|
|
17
|
+
<div class="transition-transform duration-300 group-hover:scale-105">
|
|
18
|
+
<ProgressCircle
|
|
19
|
+
:value="progress"
|
|
20
|
+
:size="60"
|
|
21
|
+
:stroke-width="5"
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="flex-1 space-y-1">
|
|
25
|
+
<div class="text-sm text-toned dark:text-muted">
|
|
26
|
+
{{ title }}
|
|
27
|
+
</div>
|
|
28
|
+
<p class="text-2xl text-highlighted font-semibold">
|
|
29
|
+
{{ value }}
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</UCard>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
getDailyPerformanceData,
|
|
4
|
+
getWeeklyPerformanceData,
|
|
5
|
+
getMonthlyPerformanceData
|
|
6
|
+
} from '~/data/AppPerformance'
|
|
7
|
+
|
|
8
|
+
defineProps<{
|
|
9
|
+
categories: Record<string, BulletLegendItemInterface>
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const isSettingsOpen = ref<boolean>(false)
|
|
13
|
+
|
|
14
|
+
function toggleSettings() {
|
|
15
|
+
isSettingsOpen.value = !isSettingsOpen.value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const dataViewOptions = [
|
|
19
|
+
{
|
|
20
|
+
label: 'Daily',
|
|
21
|
+
value: 'daily'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
label: 'Weekly',
|
|
25
|
+
value: 'weekly'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Monthly',
|
|
29
|
+
value: 'monthly'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const selectedDataView = ref('daily')
|
|
34
|
+
|
|
35
|
+
const performanceData = computed(() => {
|
|
36
|
+
switch (selectedDataView.value) {
|
|
37
|
+
case 'weekly':
|
|
38
|
+
return getWeeklyPerformanceData.value
|
|
39
|
+
case 'monthly':
|
|
40
|
+
return getMonthlyPerformanceData.value
|
|
41
|
+
case 'daily':
|
|
42
|
+
default:
|
|
43
|
+
return getDailyPerformanceData.value
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const xFormatter = (i: number): string =>
|
|
48
|
+
String(performanceData.value[i]?.date ?? '')
|
|
49
|
+
|
|
50
|
+
function handleDataViewChange(value: string) {
|
|
51
|
+
console.log('Data view changed to:', value)
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<UCard
|
|
57
|
+
:ui="{
|
|
58
|
+
body: 'sm:p-4 p-0'
|
|
59
|
+
}"
|
|
60
|
+
>
|
|
61
|
+
<template #header>
|
|
62
|
+
<div class="w-full flex items-center justify-between">
|
|
63
|
+
<h2 class="text-lg font-medium text-highlighted">
|
|
64
|
+
App Performance
|
|
65
|
+
</h2>
|
|
66
|
+
<UButton
|
|
67
|
+
variant="ghost"
|
|
68
|
+
:icon="`i-lucide-${!isSettingsOpen ? 'settings' : 'x'}`"
|
|
69
|
+
@click="toggleSettings"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
73
|
+
|
|
74
|
+
<div
|
|
75
|
+
v-if="isSettingsOpen"
|
|
76
|
+
class="h-[304px] p-4"
|
|
77
|
+
>
|
|
78
|
+
<div class="w-full space-y-4">
|
|
79
|
+
<label class="block text-sm font-medium text-highlighted mb-2">
|
|
80
|
+
Settings
|
|
81
|
+
</label>
|
|
82
|
+
<USelect
|
|
83
|
+
v-model="selectedDataView"
|
|
84
|
+
:items="dataViewOptions"
|
|
85
|
+
placeholder="Select data view"
|
|
86
|
+
class="w-full focus:ring-0"
|
|
87
|
+
@update:model-value="handleDataViewChange"
|
|
88
|
+
/>
|
|
89
|
+
<UButton
|
|
90
|
+
variant="soft"
|
|
91
|
+
class="w-full flex items-center justify-center"
|
|
92
|
+
label="Filter data"
|
|
93
|
+
@click="toggleSettings"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div
|
|
99
|
+
v-if="!isSettingsOpen"
|
|
100
|
+
class="pt-2"
|
|
101
|
+
>
|
|
102
|
+
<BarChart
|
|
103
|
+
:data="performanceData"
|
|
104
|
+
:height="240"
|
|
105
|
+
y-label="Count"
|
|
106
|
+
:x-num-ticks="6"
|
|
107
|
+
:y-num-ticks="5"
|
|
108
|
+
:categories="categories"
|
|
109
|
+
:x-formatter="xFormatter"
|
|
110
|
+
:y-grid-line="false"
|
|
111
|
+
:radius="20"
|
|
112
|
+
:bar-padding="0.35"
|
|
113
|
+
:y-axis="['downloads', 'subscriptions']"
|
|
114
|
+
:legend-position="LegendPosition.TopRight"
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</UCard>
|
|
118
|
+
</template>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
getDailyPerformanceData,
|
|
4
|
+
getWeeklyPerformanceData,
|
|
5
|
+
getMonthlyPerformanceData
|
|
6
|
+
} from '~/data/AppPerformance'
|
|
7
|
+
|
|
8
|
+
defineProps<{
|
|
9
|
+
categories: Record<string, BulletLegendItemInterface>
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const isSettingsOpen = ref<boolean>(false)
|
|
13
|
+
|
|
14
|
+
function toggleSettings() {
|
|
15
|
+
isSettingsOpen.value = !isSettingsOpen.value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const dataViewOptions = [
|
|
19
|
+
{
|
|
20
|
+
label: 'Daily',
|
|
21
|
+
value: 'daily'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
label: 'Weekly',
|
|
25
|
+
value: 'weekly'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Monthly',
|
|
29
|
+
value: 'monthly'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const selectedDataView = ref('daily')
|
|
34
|
+
|
|
35
|
+
const performanceData = computed(() => {
|
|
36
|
+
switch (selectedDataView.value) {
|
|
37
|
+
case 'weekly':
|
|
38
|
+
return getWeeklyPerformanceData.value
|
|
39
|
+
case 'monthly':
|
|
40
|
+
return getMonthlyPerformanceData.value
|
|
41
|
+
case 'daily':
|
|
42
|
+
default:
|
|
43
|
+
return getDailyPerformanceData.value
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const xFormatter = (i: number): string =>
|
|
48
|
+
String(performanceData.value[i]?.date ?? '')
|
|
49
|
+
|
|
50
|
+
function handleDataViewChange(value: string) {
|
|
51
|
+
console.log('Data view changed to:', value)
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<UCard
|
|
57
|
+
:ui="{
|
|
58
|
+
body: 'sm:p-4 p-0'
|
|
59
|
+
}"
|
|
60
|
+
>
|
|
61
|
+
<template #header>
|
|
62
|
+
<div class="w-full flex items-center justify-between">
|
|
63
|
+
<h2 class="text-lg font-medium text-highlighted">
|
|
64
|
+
App Performance
|
|
65
|
+
</h2>
|
|
66
|
+
<UButton
|
|
67
|
+
variant="ghost"
|
|
68
|
+
:icon="`i-lucide-${!isSettingsOpen ? 'settings' : 'x'}`"
|
|
69
|
+
@click="toggleSettings"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
73
|
+
|
|
74
|
+
<div
|
|
75
|
+
v-if="isSettingsOpen"
|
|
76
|
+
class="h-[304px] p-4"
|
|
77
|
+
>
|
|
78
|
+
<div class="w-full space-y-4">
|
|
79
|
+
<label class="block text-sm font-medium text-highlighted mb-2">
|
|
80
|
+
Settings
|
|
81
|
+
</label>
|
|
82
|
+
<USelect
|
|
83
|
+
v-model="selectedDataView"
|
|
84
|
+
:items="dataViewOptions"
|
|
85
|
+
placeholder="Select data view"
|
|
86
|
+
class="w-full focus:ring-0"
|
|
87
|
+
@update:model-value="handleDataViewChange"
|
|
88
|
+
/>
|
|
89
|
+
<UButton
|
|
90
|
+
variant="soft"
|
|
91
|
+
class="w-full flex items-center justify-center"
|
|
92
|
+
label="Filter data"
|
|
93
|
+
@click="toggleSettings"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div
|
|
99
|
+
v-if="!isSettingsOpen"
|
|
100
|
+
class="pt-2"
|
|
101
|
+
>
|
|
102
|
+
<BarChart
|
|
103
|
+
:data="performanceData"
|
|
104
|
+
:height="240"
|
|
105
|
+
y-label="Count"
|
|
106
|
+
:x-num-ticks="6"
|
|
107
|
+
:y-num-ticks="5"
|
|
108
|
+
:categories="categories"
|
|
109
|
+
:x-formatter="xFormatter"
|
|
110
|
+
:y-grid-line="false"
|
|
111
|
+
:radius="20"
|
|
112
|
+
:bar-padding="0.35"
|
|
113
|
+
:y-axis="['downloads', 'subscriptions']"
|
|
114
|
+
:legend-position="LegendPosition.TopRight"
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
</UCard>
|
|
118
|
+
</template>
|