init
This commit is contained in:
35
javascript-version/@core/components/MoreBtn.vue
Normal file
35
javascript-version/@core/components/MoreBtn.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
menuList: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
itemProps: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
iconSize: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IconBtn>
|
||||
<VIcon
|
||||
:size="props.iconSize"
|
||||
icon="bx-dots-vertical-rounded"
|
||||
/>
|
||||
|
||||
<VMenu
|
||||
v-if="props.menuList"
|
||||
activator="parent"
|
||||
>
|
||||
<VList
|
||||
:items="props.menuList"
|
||||
:item-props="props.itemProps"
|
||||
/>
|
||||
</VMenu>
|
||||
</IconBtn>
|
||||
</template>
|
||||
43
javascript-version/@core/components/ThemeSwitcher.vue
Normal file
43
javascript-version/@core/components/ThemeSwitcher.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<script setup>
|
||||
import { useTheme } from 'vuetify'
|
||||
|
||||
const props = defineProps({
|
||||
themes: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const {
|
||||
name: themeName,
|
||||
global: globalTheme,
|
||||
} = useTheme()
|
||||
|
||||
const {
|
||||
state: currentThemeName,
|
||||
next: getNextThemeName,
|
||||
index: currentThemeIndex,
|
||||
} = useCycleList(props.themes.map(t => t.name), { initialValue: themeName })
|
||||
|
||||
const changeTheme = () => {
|
||||
globalTheme.name.value = getNextThemeName()
|
||||
}
|
||||
|
||||
// Update icon if theme is changed from other sources
|
||||
watch(() => globalTheme.name.value, val => {
|
||||
currentThemeName.value = val
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IconBtn @click="changeTheme">
|
||||
<VIcon :icon="props.themes[currentThemeIndex].icon" />
|
||||
<VTooltip
|
||||
activator="parent"
|
||||
open-delay="1000"
|
||||
scroll-strategy="close"
|
||||
>
|
||||
<span class="text-capitalize">{{ currentThemeName }}</span>
|
||||
</VTooltip>
|
||||
</IconBtn>
|
||||
</template>
|
||||
@@ -0,0 +1,60 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'primary',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
stats: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
change: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardText class="d-flex align-center">
|
||||
<VAvatar
|
||||
size="44"
|
||||
rounded
|
||||
:color="props.color"
|
||||
variant="tonal"
|
||||
class="me-4"
|
||||
>
|
||||
<VIcon
|
||||
:icon="props.icon"
|
||||
size="30"
|
||||
/>
|
||||
</VAvatar>
|
||||
|
||||
<div>
|
||||
<span class="text-caption">{{ props.title }}</span>
|
||||
<div class="d-flex align-center flex-wrap">
|
||||
<span class="text-h6 font-weight-semibold">{{ kFormatter(props.stats) }}</span>
|
||||
<div
|
||||
v-if="props.change"
|
||||
:class="`${isPositive ? 'text-success' : 'text-error'} mt-1`"
|
||||
>
|
||||
<VIcon :icon="isPositive ? 'bx-chevron-up' : 'bx-chevron-down'" />
|
||||
<span class="text-caption font-weight-semibold">{{ Math.abs(props.change) }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
stats: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
change: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
||||
|
||||
const moreList = [
|
||||
{
|
||||
title: 'Yesterday',
|
||||
value: 'Yesterday',
|
||||
},
|
||||
{
|
||||
title: 'Last Week',
|
||||
value: 'Last Week',
|
||||
},
|
||||
{
|
||||
title: 'Last Month',
|
||||
value: 'Last Month',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardText class="d-flex align-center pb-4">
|
||||
<img
|
||||
width="42"
|
||||
:src="props.image"
|
||||
alt="image"
|
||||
>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<MoreBtn
|
||||
class="me-n3 mt-n4"
|
||||
:menu-list="moreList"
|
||||
/>
|
||||
</VCardText>
|
||||
|
||||
<VCardText>
|
||||
<p class="mb-1">
|
||||
{{ props.title }}
|
||||
</p>
|
||||
<h5 class="text-h5 text-no-wrap mb-3">
|
||||
{{ props.stats }}
|
||||
</h5>
|
||||
<span
|
||||
:class="isPositive ? 'text-success' : 'text-error'"
|
||||
class="d-flex align-center gap-1 text-sm"
|
||||
>
|
||||
<VIcon
|
||||
size="18"
|
||||
:icon="isPositive ? 'bx-up-arrow-alt' : 'bx-down-arrow-alt'"
|
||||
/>
|
||||
{{ isPositive ? Math.abs(props.change) : props.change }}%
|
||||
</span>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
||||
@@ -0,0 +1,80 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
stats: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
change: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'primary',
|
||||
},
|
||||
})
|
||||
|
||||
const isPositive = controlledComputed(() => props.change, () => Math.sign(props.change) === 1)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard class="overflow-visible">
|
||||
<div class="d-flex position-relative">
|
||||
<VCardText>
|
||||
<h6 class="text-base font-weight-semibold mb-4">
|
||||
{{ props.title }}
|
||||
</h6>
|
||||
<div class="d-flex align-center flex-wrap mb-4">
|
||||
<h5 class="text-h5 font-weight-semibold me-2">
|
||||
{{ props.stats }}
|
||||
</h5>
|
||||
<span
|
||||
class="text-caption"
|
||||
:class="isPositive ? 'text-success' : 'text-error'"
|
||||
>
|
||||
{{ isPositive ? `+${props.change}` : props.change }}%
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<VChip
|
||||
v-if="props.subtitle"
|
||||
size="small"
|
||||
:color="props.color"
|
||||
>
|
||||
{{ props.subtitle }}
|
||||
</VChip>
|
||||
</VCardText>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<div class="illustrator-img">
|
||||
<VImg
|
||||
v-if="props.image"
|
||||
:src="props.image"
|
||||
:width="110"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.illustrator-img {
|
||||
position: absolute;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 5%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user