first commit

This commit is contained in:
Inshal
2024-05-29 22:34:28 +05:00
commit e63fc41a20
1470 changed files with 174828 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<script setup>
import illustrationJohn2 from '@images/cards/illustration-john-2.png'
</script>
<template>
<VCard class="overflow-visible mt-sm-10 mt-md-0">
<VRow no-gutters>
<VCol
cols="12"
sm="6"
order="2"
order-sm="1"
>
<VCardItem>
<VCardTitle>
<h4 class="text-h4 text-wrap">
Congratulations <strong>John!</strong> <span class="text-high-emphasis">🎉</span>
</h4>
</VCardTitle>
</VCardItem>
<VCardText class="pt-sm-4">
<div class="mb-0 text-body-1 me-2">
You have done 72% <span class="text-high-emphasis">😎</span> more sales today.
Check your new raising badge in your profile.
</div>
</VCardText>
</VCol>
<VCol
cols="12"
sm="6"
order="1"
order-sm="2"
class="text-center"
>
<img
:src="illustrationJohn2"
:height="$vuetify.display.xs ? '165' : '200'"
:class="$vuetify.display.xs ? 'position-relative' : 'position-absolute'"
class="john-illustration flip-in-rtl mt-6 mt-sm-0"
>
</VCol>
</VRow>
</VCard>
</template>
<style lang="scss" scoped>
.john-illustration {
inset-block-end: -0.0625rem;
inset-inline-end: 0;
}
</style>

View File

@@ -0,0 +1,337 @@
<script setup>
import avatar1 from '@images/avatars/avatar-1.png'
import avatar2 from '@images/avatars/avatar-2.png'
import avatar3 from '@images/avatars/avatar-3.png'
import avatar4 from '@images/avatars/avatar-4.png'
import avatar5 from '@images/avatars/avatar-5.png'
import avatar6 from '@images/avatars/avatar-6.png'
import avatar7 from '@images/avatars/avatar-7.png'
import avatar8 from '@images/avatars/avatar-8.png'
const now = new Date()
const currentMonth = now.toLocaleString('default', { month: '2-digit' })
// 👉 Invoice balance variant resolver
const resolveInvoiceBalanceVariant = (balance, total) => {
if (balance === total)
return {
status: 'Unpaid',
chip: { color: 'error' },
}
if (balance === 0)
return {
status: 'Paid',
chip: { color: 'success' },
}
return {
status: balance,
chip: { variant: 'text' },
}
}
const resolveInvoiceStatusVariantAndIcon = status => {
if (status === 'Partial Payment')
return {
variant: 'warning',
icon: 'ri-line-chart-line',
}
if (status === 'Paid')
return {
variant: 'success',
icon: 'ri-check-line',
}
if (status === 'Downloaded')
return {
variant: 'info',
icon: 'ri-arrow-down-line',
}
if (status === 'Draft')
return {
variant: 'secondary',
icon: 'ri-save-line',
}
if (status === 'Sent')
return {
variant: 'primary',
icon: 'ri-mail-line',
}
if (status === 'Past Due')
return {
variant: 'error',
icon: 'ri-error-warning-line',
}
return {
variant: 'secondary',
icon: 'ri-close-line',
}
}
const invoices = [
{
id: 5024,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-28`,
client: {
address: '276 Michael Gardens Apt. 004',
company: 'Shea, Velez and Garcia LLC',
companyEmail: 'zjohnson@nichols-powers.com',
country: 'Philippines',
contact: '(817) 700-2984',
name: 'Christopher Allen',
},
service: 'Software Development',
total: 2787,
avatar: avatar1,
invoiceStatus: 'Partial Payment',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-25`,
},
{
id: 5025,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-21`,
client: {
address: '633 Bell Well Apt. 057',
company: 'Adams, Simmons and Brown Group',
companyEmail: 'kayla09@thomas.com',
country: 'Martinique',
contact: '(266) 611-9482',
name: 'Joseph Oliver',
},
service: 'UI/UX Design & Development',
total: 5591,
avatar: avatar2,
invoiceStatus: 'Downloaded',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-07`,
},
{
id: 5026,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-24`,
client: {
address: '1068 Lopez Fall',
company: 'Williams-Lawrence and Sons',
companyEmail: 'melvindavis@allen.info',
country: 'Mexico',
contact: '(739) 745-9728',
name: 'Megan Roberts',
},
service: 'Template Customization',
total: 2783,
avatar: avatar3,
invoiceStatus: 'Draft',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-22`,
},
{
id: 5027,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-13`,
client: {
address: '86691 Mackenzie Light Suite 568',
company: 'Deleon Inc LLC',
companyEmail: 'gjordan@fernandez-coleman.com',
country: 'Costa Rica',
contact: '(682) 804-6506',
name: 'Mary Garcia',
},
service: 'Template Customization',
total: 2719,
avatar: avatar4,
invoiceStatus: 'Sent',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-04`,
},
{
id: 5028,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-18`,
client: {
address: '86580 Sarah Bridge',
company: 'Farmer, Johnson and Anderson Group',
companyEmail: 'robertscott@garcia.com',
country: 'Cameroon',
contact: '(775) 366-0411',
name: 'Crystal Mays',
},
service: 'Template Customization',
total: 3325,
avatar: avatar5,
invoiceStatus: 'Paid',
balance: 361,
dueDate: `${ now.getFullYear() }-${ currentMonth }-02`,
},
{
id: 5029,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-29`,
client: {
address: '49709 Edwin Ports Apt. 353',
company: 'Sherman-Johnson PLC',
companyEmail: 'desiree61@kelly.com',
country: 'Macedonia',
contact: '(510) 536-6029',
name: 'Nicholas Tanner',
},
service: 'Template Customization',
total: 3851,
avatar: avatar6,
invoiceStatus: 'Paid',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-25`,
},
{
id: 5030,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-07`,
client: {
address: '3856 Mathis Squares Apt. 584',
company: 'Byrd LLC PLC',
companyEmail: 'jeffrey25@martinez-hodge.com',
country: 'Congo',
contact: '(253) 230-4657',
name: 'Justin Richardson',
},
service: 'Template Customization',
total: 5565,
avatar: avatar7,
invoiceStatus: 'Draft',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-06`,
},
{
id: 5031,
issuedDate: `${ now.getFullYear() }-${ currentMonth }-21`,
client: {
address: '141 Adrian Ridge Suite 550',
company: 'Stone-Zimmerman Group',
companyEmail: 'john77@anderson.net',
country: 'Falkland Islands (Malvinas)',
contact: '(612) 546-3485',
name: 'Jennifer Summers',
},
service: 'Template Customization',
total: 3313,
avatar: avatar8,
invoiceStatus: 'Partial Payment',
balance: 0,
dueDate: `${ now.getFullYear() }-${ currentMonth }-09`,
},
]
const headers = [
{
title: '#ID',
key: 'id',
},
{
title: 'Status',
key: 'status',
sortable: false,
},
{
title: 'Client',
key: 'client.name',
},
{
title: 'Total',
key: 'total',
},
{
title: 'Balance',
key: 'balance',
},
]
</script>
<template>
<VCard>
<VDataTable
:headers="headers"
:items="invoices"
class="text-no-wrap"
>
<!-- id -->
<template #item.id="{ item }">
<RouterLink :to="{ name: 'apps-invoice-preview-id', params: { id: item.id } }">
#{{ item.id }}
</RouterLink>
</template>
<!-- trending -->
<template #item.status="{ item }">
<VTooltip>
<template #activator="{ props }">
<VAvatar
:size="28"
v-bind="props"
:color="resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).variant"
variant="tonal"
>
<VIcon
:size="16"
:icon="resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).icon"
/>
</VAvatar>
</template>
<p class="mb-0">
{{ item.invoiceStatus }}
</p>
<p class="mb-0">
Balance: {{ item.balance }}
</p>
<p class="mb-0">
Due date: {{ item.dueDate }}
</p>
</VTooltip>
</template>
<!-- client -->
<template #item.client.name="{ item }">
<div class="d-flex align-center">
<VAvatar
size="34"
:color="!item.avatar.length ? resolveInvoiceStatusVariantAndIcon(item.invoiceStatus).variant : undefined"
:variant="!item.avatar.length ? 'tonal' : undefined"
class="me-3"
>
<VImg
v-if="item.avatar.length"
:src="item.avatar"
/>
<span v-else>{{ avatarText(item.client.name) }}</span>
</VAvatar>
<div class="d-flex flex-column">
<RouterLink
:to="{ name: 'pages-user-profile-tab', params: { tab: 'profile' } }"
class="text-h6 font-weight-medium mb-0"
>
{{ item.client.name }}
</RouterLink>
<span class="text-body-2">{{ item.client.companyEmail }}</span>
</div>
</div>
</template>
<!-- Total -->
<template #item.total="{ item }">
${{ item.total }}
</template>
<!-- Balance -->
<template #item.balance="{ item }">
<VChip
v-if="typeof ((resolveInvoiceBalanceVariant(item.balance, item.total)).status) === 'string'"
:color="resolveInvoiceBalanceVariant(item.balance, item.total).chip.color"
size="small"
>
{{ (resolveInvoiceBalanceVariant(item.balance, item.total)).status }}
</VChip>
<h6
v-else
class="text-h6 font-weight-regular"
>
{{ Number((resolveInvoiceBalanceVariant(item.balance, item.total)).status) > 0 ? `$${(resolveInvoiceBalanceVariant(item.balance, item.total)).status}` : `-$${Math.abs(Number((resolveInvoiceBalanceVariant(item.balance, item.total)).status))}` }}
</h6>
</template>
<template #bottom />
</VDataTable>
</VCard>
</template>

View File

@@ -0,0 +1,128 @@
<script setup>
import avatar1 from '@images/avatars/avatar-1.png'
import avatar2 from '@images/avatars/avatar-2.png'
import avatar3 from '@images/avatars/avatar-3.png'
import avatar4 from '@images/avatars/avatar-4.png'
import avatar7 from '@images/avatars/avatar-7.png'
import avatar8 from '@images/avatars/avatar-8.png'
const meetingSchedules = [
{
profile: avatar4,
with: 'Call with Woods',
dateTime: '21 Jul | 08:20-10:30',
type: 'Business',
},
{
profile: avatar8,
with: 'Call with hilda',
dateTime: '24 Jul | 11:30-12:00',
type: 'Meditation',
},
{
profile: avatar7,
with: 'Conference call',
dateTime: '28 Jul | 05:00-6:45',
type: 'Dinner',
},
{
profile: avatar3,
with: 'Meeting with Mark',
dateTime: '03 Aug | 07:00-8:30',
type: 'Meetup',
},
{
profile: avatar2,
with: 'Meeting in Oakland',
dateTime: '14 Aug | 04:15-05:30',
type: 'Dinner',
},
{
profile: avatar1,
with: 'Meeting with Carl',
dateTime: '05 Oct | 10:00-12:45',
type: 'Business',
},
]
const meetingTypeUiColors = {
Business: 'primary',
Meditation: 'success',
Meetup: 'secondary',
Dinner: 'error',
}
</script>
<template>
<VCard>
<!-- SECTION Card Header and Menu -->
<VCardItem>
<!-- 👉 Title -->
<VCardTitle>Meeting Schedule</VCardTitle>
<!-- 👉 menu -->
<template #append>
<div class="me-n3">
<MoreBtn />
</div>
</template>
</VCardItem>
<!-- !SECTION -->
<!-- SECTION Meting Schedule -->
<VCardText>
<VList
lines="two"
class="card-list"
>
<VListItem
v-for="meeting in meetingSchedules"
:key="meeting.type"
>
<!-- 👉 Avatar -->
<template #prepend>
<VAvatar
start
:size="38"
:image="meeting.profile"
/>
</template>
<!-- 👉 Title and Subtitle -->
<VListItemTitle class="font-weight-medium mb-1">
{{ meeting.with }}
</VListItemTitle>
<VListItemSubtitle class="me-2">
<VIcon
size="16"
start
icon="ri-calendar-line"
/>
{{ meeting.dateTime }}
</VListItemSubtitle>
<!-- 👉 Business Types -->
<template #append>
<VListItemAction>
<VChip
size="small"
:color="meetingTypeUiColors[meeting.type]"
>
{{ meeting.type }}
</VChip>
</VListItemAction>
</template>
</VListItem>
</VList>
</VCardText>
<!-- !SECTION -->
</VCard>
</template>
<style lang="scss" scoped>
.card-list {
--v-card-list-gap: 1rem;
}
</style>

View File

@@ -0,0 +1,111 @@
<script setup>
const series = [{
data: [
40,
60,
50,
60,
90,
40,
50,
],
}]
const options = {
chart: {
parentHeightOffset: 0,
toolbar: { show: false },
},
grid: {
show: false,
padding: {
top: -5,
left: -10,
right: -7,
bottom: -12,
},
},
plotOptions: {
bar: {
borderRadius: 4,
distributed: true,
columnWidth: '60%',
},
},
legend: { show: false },
dataLabels: { enabled: false },
colors: [
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary))',
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary),0.1)',
'rgba(var(--v-theme-primary),0.1)',
],
states: {
hover: { filter: { type: 'none' } },
active: { filter: { type: 'none' } },
},
xaxis: {
tickPlacement: 'on',
labels: { show: false },
axisTicks: { show: false },
axisBorder: { show: false },
categories: [
'S',
'M',
'T',
'W',
'T',
'F',
'S',
],
},
yaxis: { show: false },
tooltip: { enabled: false },
}
</script>
<template>
<VCard>
<VRow no-gutters>
<VCol cols="6">
<VCardItem>
<VCardTitle>New Visitors</VCardTitle>
</VCardItem>
<VCardText class="mt-5">
<p class="text-body-1 mb-2">
48% new visitors <br>
this week.
</p>
<div class="d-flex align-center">
<h4 class="text-h4">
12,480
</h4>
<VIcon
icon="ri-arrow-up-s-line"
size="24"
color="success"
/>
<span class="text-success font-weight-medium">28</span>
</div>
</VCardText>
</VCol>
<VCol cols="6">
<VCardText>
<VueApexCharts
type="bar"
:options="options"
:series="series"
:height="160"
/>
</VCardText>
</VCol>
</VRow>
</VCard>
</template>

View File

@@ -0,0 +1,352 @@
<script setup>
import { useTheme } from 'vuetify'
import { hexToRgb } from '@layouts/utils'
const vuetifyTheme = useTheme()
const options = computed(() => {
const currentTheme = ref(vuetifyTheme.current.value.colors)
const variableTheme = ref(vuetifyTheme.current.value.variables)
const disabledColor = `rgba(${ hexToRgb(currentTheme.value['on-surface']) },${ variableTheme.value['disabled-opacity'] })`
const borderColor = `rgba(${ hexToRgb(String(variableTheme.value['border-color'])) },${ variableTheme.value['border-opacity'] })`
return {
chart: {
stacked: true,
parentHeightOffset: 0,
toolbar: { show: false },
},
plotOptions: {
bar: {
borderRadius: 8,
columnWidth: '30%',
borderRadiusApplication: 'around',
borderRadiusWhenStacked: 'all',
},
},
xaxis: {
axisTicks: { show: false },
crosshairs: { opacity: 0 },
axisBorder: { show: false },
categories: [
2015,
2016,
2017,
2018,
2019,
2020,
2021,
],
labels: {
style: {
fontSize: '13px',
colors: disabledColor,
fontFamily: 'inter',
},
},
},
yaxis: {
labels: {
style: {
fontSize: '13px',
colors: disabledColor,
fontFamily: 'inter',
},
formatter: value => value > 999 ? `${ (value / 1000).toFixed(0) }k` : `${ value }`,
},
},
colors: [
'rgba(var(--v-theme-primary),1)',
currentTheme.value.success,
currentTheme.value.secondary,
],
grid: {
xaxis: { lines: { show: false } },
borderColor,
strokeDashArray: 7,
padding: { bottom: -10 },
},
legend: { show: false },
dataLabels: { enabled: false },
stroke: {
width: 6,
curve: 'smooth',
lineCap: 'round',
colors: [currentTheme.value.surface],
},
states: {
hover: { filter: { type: 'none' } },
active: { filter: { type: 'none' } },
},
responsive: [
{
breakpoint: 1560,
options: { plotOptions: { bar: { columnWidth: '35%' } } },
},
{
breakpoint: 1441,
options: {
plotOptions: {
bar: {
columnWidth: '40%',
borderRadius: 8,
},
},
},
},
{
breakpoint: 1280,
charts: { height: 200 },
options: {
plotOptions: {
bar: {
columnWidth: '40%',
borderRadius: 8,
},
},
},
},
{
breakpoint: 1160,
options: {
plotOptions: {
bar: {
columnWidth: '40%',
borderRadius: 6,
},
},
},
},
{
breakpoint: 960,
options: {
plotOptions: {
bar: {
columnWidth: '30%',
borderRadius: 6,
},
},
},
},
{
breakpoint: 800,
chart: {
height: 250,
offsetX: -10,
},
options: { plotOptions: { bar: { columnWidth: '40%' } } },
},
{
breakpoint: 650,
options: {
plotOptions: {
bar: {
columnWidth: '50%',
borderRadius: 6,
},
},
},
},
{
breakpoint: 600,
options: {
plotOptions: {
bar: {
columnWidth: '35%',
borderRadius: 6,
},
},
},
},
{
breakpoint: 480,
options: {
chart: {
height: 250,
offsetX: -10,
},
plotOptions: { bar: { columnWidth: '45%' } },
xaxis: {
labels: {
rotate: 315,
rotateAlways: true,
},
},
},
},
{
breakpoint: 420,
options: { plotOptions: { bar: { columnWidth: '60%' } } },
},
],
}
})
const series = [
{
name: 'Revenue',
data: [
29000,
22000,
25000,
18500,
29000,
20000,
34500,
],
},
{
name: 'Transactions',
data: [
0,
16000,
11000,
15500,
0,
12500,
9500,
],
},
{
name: 'Total Profit',
data: [
0,
0,
0,
14000,
0,
11500,
12000,
],
},
]
const lastThreeTransactions = [
{
avatar: {
icon: 'ri-pie-chart-2-line',
color: 'success',
},
title: '$48,568.20',
subtitle: 'Total Profit',
},
{
avatar: {
icon: 'ri-money-dollar-circle-line',
color: 'primary',
},
title: '$38,453.25',
subtitle: 'Total Income',
},
{
avatar: {
icon: 'ri-bank-card-line',
color: 'secondary',
},
title: '$2,453.45',
subtitle: 'Total Expense',
},
]
</script>
<template>
<VCard>
<VRow no-gutters>
<VCol
cols="12"
sm="8"
class="responsive-border"
>
<VCardItem>
<VCardTitle>
Total Profit
</VCardTitle>
</VCardItem>
<VCardText>
<VueApexCharts
type="bar"
:options="options"
:series="series"
:height="292"
/>
</VCardText>
</VCol>
<VCol
cols="12"
sm="4"
>
<VCardItem>
<VCardTitle>
$482.85k
</VCardTitle>
<VCardSubtitle>Last month balance $234.40k</VCardSubtitle>
<template #append>
<div class="mt-n7 me-n3">
<MoreBtn density="compact" />
</div>
</template>
</VCardItem>
<VCardText class="pt-12">
<VList class="card-list mt-2">
<VListItem
v-for="transaction in lastThreeTransactions"
:key="transaction.title"
>
<template #prepend>
<VAvatar
:color="transaction.avatar.color"
variant="tonal"
rounded
>
<VIcon :icon="transaction.avatar.icon" />
</VAvatar>
</template>
<VListItemTitle class="font-weight-medium">
{{ transaction.title }}
</VListItemTitle>
<VListItemSubtitle>
<div class="text-body-1">
{{ transaction.subtitle }}
</div>
</VListItemSubtitle>
</VListItem>
</VList>
<VBtn
block
class="mt-4"
>
View Report
</VBtn>
</VCardText>
</VCol>
</VRow>
</VCard>
</template>
<style lang="scss">
$responsive-border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
@media screen and (min-width: 600px) {
.responsive-border {
border-inline-end: $responsive-border;
}
}
@media screen and (max-width: 599px) {
.responsive-border {
border-block-end: $responsive-border;
}
}
</style>
<style lang="scss" scoped>
.card-list {
--v-card-list-gap: 1rem;
}
</style>

View File

@@ -0,0 +1,86 @@
<script setup>
import { useTheme } from 'vuetify'
const vuetifyTheme = useTheme()
const series = [{
data: [
28,
58,
40,
68,
],
}]
const chartOptions = computed(() => {
const currentTheme = vuetifyTheme.current.value.colors
return {
grid: {
show: false,
padding: {
left: -2,
top: -10,
},
},
chart: {
parentHeightOffset: 0,
type: 'line',
dropShadow: {
enabled: true,
top: 10,
blur: 4,
color: currentTheme.primary,
opacity: 0.09,
},
toolbar: { show: false },
},
markers: {
size: 6,
colors: 'transparent',
strokeColors: 'transparent',
strokeWidth: 4,
discrete: [{
seriesIndex: 0,
dataPointIndex: series[0].data.length - 1,
fillColor: currentTheme.surface,
strokeColor: currentTheme.primary,
size: 6,
}],
hover: { size: 7 },
},
stroke: {
width: 5,
curve: 'smooth',
lineCap: 'round',
},
xaxis: {
axisBorder: { show: false },
axisTicks: { show: false },
labels: { show: false },
},
yaxis: { labels: { show: false } },
tooltip: { enabled: false },
colors: [currentTheme.primary],
}
})
</script>
<template>
<VCard>
<VCardText>
<h4 class="text-h4">
$35.4k
</h4>
<VueApexCharts
:options="chartOptions"
:series="series"
:height="110"
/>
<h6 class="text-h6 text-center">
Total Revenue
</h6>
</VCardText>
</VCard>
</template>

View File

@@ -0,0 +1,118 @@
<script setup>
import { useTheme } from 'vuetify'
const vuetifyTheme = useTheme()
const currentTheme = computed(() => vuetifyTheme.current.value.colors)
const chartOptions = computed(() => {
return {
chart: {
sparkline: { enabled: true },
animations: { enabled: false },
},
stroke: {
width: 5,
colors: [currentTheme.value.surface],
},
legend: { show: false },
tooltip: { enabled: true },
dataLabels: { enabled: false },
colors: [
currentTheme.value.primary,
currentTheme.value.info,
currentTheme.value.warning,
currentTheme.value.error,
],
labels: [
'Comments',
'Replies',
'Shares',
'Likes',
],
series: [
45,
10,
18,
27,
],
grid: {
padding: {
top: -7,
bottom: 5,
},
},
states: {
hover: { filter: { type: 'none' } },
active: { filter: { type: 'none' } },
},
plotOptions: {
pie: {
expandOnClick: false,
donut: {
size: '75%',
labels: {
show: true,
value: {
fontSize: '1.125rem',
fontFamily: 'Inter',
fontWeight: 500,
offsetY: -18,
color: 'rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity))',
formatter: o => `${ Number.parseInt(o) }%`,
},
name: {
offsetY: 18,
fontFamily: 'Inter',
},
total: {
label: '1 Quarter',
show: true,
color: 'rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))',
fontSize: '0.8125rem',
fontWeight: 400,
formatter: () => '28%',
},
},
},
},
},
}
})
</script>
<template>
<VCard class="overflow-visible">
<VCardText class="d-flex justify-space-between align-center gap-3">
<div>
<h5 class="text-h5 mb-1">
Total Sales
</h5>
<div class="text-body-1 mb-3">
Calculated in last 7 days
</div>
<div class="d-flex align-center">
<h4 class="text-h4">
$25,980
</h4>
<div class="d-flex align-center">
<VIcon
icon="ri-arrow-up-s-line"
size="24"
color="success"
/>
<span class="text-body-1 text-success">15.6%</span>
</div>
</div>
</div>
<VueApexCharts
type="donut"
:options="chartOptions"
:height="110"
:series="[45, 10, 18, 27]"
:width="110"
/>
</VCardText>
</VCard>
</template>

View File

@@ -0,0 +1,60 @@
<script setup>
import { useTheme } from 'vuetify'
import { hexToRgb } from '@layouts/utils'
const vuetifyTheme = useTheme()
const series = [78]
const chartOptions = computed(() => {
const currentTheme = vuetifyTheme.current.value.colors
const variableTheme = vuetifyTheme.current.value.variables
return {
chart: { sparkline: { enabled: true } },
colors: [currentTheme.info],
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
hollow: { size: '65%' },
dataLabels: {
name: { show: false },
value: {
fontSize: '1.125rem',
fontWeight: '500',
offsetY: 0,
color: `rgba(${ hexToRgb(currentTheme['on-surface']) },${ variableTheme['medium-emphasis-opacity'] })`,
},
},
track: { background: currentTheme['track-bg'] },
},
},
stroke: { lineCap: 'round' },
responsive: [{
breakpoint: 450,
options: { plotOptions: { radialBar: { hollow: { size: '52%' } } } },
}],
}
})
</script>
<template>
<VCard>
<VCardText>
<h4 class="text-h4">
135k
</h4>
<VueApexCharts
id="stats-radial-bar-chart"
:options="chartOptions"
:series="series"
type="radialBar"
:height="150"
/>
<h6 class="text-h6 text-center mt-6">
Total sales
</h6>
</VCardText>
</VCard>
</template>

View File

@@ -0,0 +1,133 @@
<script setup>
import { kFormatter } from '@core/utils/formatters'
import arrowGrowth from '@images/cards/arrow-growth.png'
import atmCard from '@images/cards/atm-card.png'
import creditCard from '@images/cards/credit-card.png'
import paypal from '@images/cards/paypal.png'
import wallet from '@images/cards/wallet.png'
const transactions = [
{
gateway: 'PayPal',
for: 'Received Money',
amount: 2482,
img: paypal,
imgHeight: 22,
},
{
gateway: 'Credit Card',
for: 'DigitalOcean',
amount: -1250,
img: creditCard,
imgHeight: 15,
},
{
gateway: 'Mastercard',
for: 'Netflix',
amount: -99,
img: atmCard,
imgHeight: 15,
},
{
gateway: 'Wallet',
for: 'Mac\'D',
amount: -82,
img: wallet,
imgHeight: 18,
},
{
gateway: 'Transfer',
for: 'Refund',
amount: 8934,
img: arrowGrowth,
imgHeight: 12,
},
]
const transactionsColors = {
'PayPal': 'error',
'Credit Card': 'success',
'Mastercard': 'warning',
'Wallet': 'primary',
'Transfer': 'info',
}
const formateAmount = amount => {
return Math.sign(amount) === 1 ? `+${ kFormatter(amount) }` : `-${ Math.abs(amount) }`
}
</script>
<template>
<VCard>
<!-- SECTION Card Header and Menu -->
<VCardItem>
<!-- 👉 Title -->
<VCardTitle>Transactions</VCardTitle>
<!-- 👉 menu -->
<template #append>
<div class="me-n3">
<MoreBtn />
</div>
</template>
</VCardItem>
<!-- !SECTION -->
<!-- SECTION Transactions List -->
<VCardText>
<VList class="card-list">
<VListItem
v-for="transaction in transactions"
:key="transaction.for"
>
<!-- 👉 Avatar -->
<template #prepend>
<VAvatar
rounded
variant="tonal"
:color="transactionsColors[transaction.gateway]"
>
<img
:src="transaction.img"
:height="transaction.imgHeight"
>
</VAvatar>
</template>
<!-- 👉 Title and Subtitle -->
<VListItemTitle>
<h6 class="text-h6">
{{ transaction.gateway }}
</h6>
</VListItemTitle>
<VListItemSubtitle>
<div class="text-body-1">
{{ transaction.for }}
</div>
</VListItemSubtitle>
<!-- 👉 Amounts -->
<template #append>
<VListItemAction>
<h6 class="text-h6 me-2">
{{ formateAmount(transaction.amount) }}
</h6>
<VIcon
:size="24"
:color="Math.sign(transaction.amount) === 1 ? 'success' : 'error'"
:icon="Math.sign(transaction.amount) === 1 ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'"
/>
</VListItemAction>
</template>
</VListItem>
</VList>
</VCardText>
<!-- !SECTION -->
</VCard>
</template>
<style lang="scss" scoped>
.card-list {
--v-card-list-gap: 1.25rem;
}
</style>

View File

@@ -0,0 +1,145 @@
<script setup>
const chartOptions = {
chart: {
type: 'bar',
parentHeightOffset: 0,
toolbar: { show: false },
sparkline: { enabled: true },
},
grid: { show: false },
colors: ['rgba(var(--v-theme-primary))'],
plotOptions: {
bar: {
barHeight: '85%',
columnWidth: '35px',
borderRadius: 3,
distributed: true,
},
},
legend: { show: false },
dataLabels: { enabled: false },
xaxis: {
labels: { show: false },
axisBorder: { show: false },
axisTicks: { show: false },
},
yaxis: { show: false },
tooltip: { enabled: false },
}
const series = [{
name: '2020',
data: [
50,
40,
110,
80,
40,
60,
40,
],
}]
const websiteStatistics = [
{
title: 'Direct',
color: 'success',
traffic: '86,471',
percentage: '-15',
},
{
title: 'Organic Search',
color: 'primary',
traffic: '57,484',
percentage: '+85',
},
{
title: 'Referral',
color: 'warning',
traffic: '2,534',
percentage: '+48',
},
{
title: 'Mail',
color: 'error',
traffic: '977',
percentage: '-36',
},
]
</script>
<template>
<VCard>
<VCardItem class="position-relative">
<VCardTitle>Transactions</VCardTitle>
<template #append>
<div class="me-n3">
<MoreBtn />
</div>
</template>
</VCardItem>
<VCardText>
<div class="d-flex align-center justify-space-between">
<div>
<h1 class="text-h1 mb-2">
4,590
</h1>
<div class="text-body-2">
Total Traffic
</div>
</div>
<div>
<VueApexCharts
:options="chartOptions"
:series="series"
height="80"
width="120"
/>
</div>
</div>
</VCardText>
<VCardText>
<div
v-for="(data, index) in websiteStatistics"
:key="data.title"
>
<div class="d-flex py-3 align-center">
<div
class="bubble"
:class="`bg-${data.color}`"
/>
<div class="text-body-1 text-high-emphasis">
{{ data.title }}
</div>
<VSpacer />
<h6 class="text-h6 me-8">
{{ data.traffic }}
</h6>
<h6 class="text-h6 me-2">
{{ data.percentage.slice(1) }}%
</h6>
<VIcon
:size="24"
:color="data.percentage.charAt(0) === '+' ? 'success' : 'error'"
>
{{ data.percentage.charAt(0) === '+' ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line' }}
</VIcon>
</div>
<VDivider v-if="index !== websiteStatistics.length - 1" />
</div>
</VCardText>
</VCard>
</template>
<style lang="scss" scoped>
.bubble {
border-radius: 50%;
block-size: 1rem;
inline-size: 1rem;
margin-inline-end: 0.5rem;
}
</style>