Skip to content

Commit

Permalink
💄 Improve Dashboard Design (#117)
Browse files Browse the repository at this point in the history
* refactor orders section

* ✨ implement recent orders list

* ✨ add trending products section
refactor products section
add new render functions

* 💄 improve card ui

* 💄 change default font to Inter

* 💄 improve dashboard design for dark-mode

* fix linting issues
  • Loading branch information
doroudi authored Nov 30, 2024
1 parent bd379d4 commit 919dec6
Show file tree
Hide file tree
Showing 32 changed files with 320 additions and 175 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
<!-- End Google Tag Manager -->
</head>

<body class="font-sans">
<body class="font-inter">
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WBTQRDWN" height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
Expand Down
2 changes: 2 additions & 0 deletions locales/ar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ dashboard:
sells: المبيعات
visits: الزيارات
activeOrders: الطلبات النشطة
recentOrders: الطلبات الأخيرة
trendingProducts: المنتجات الرائجة
categories:
title: الفئات
createButton: إنشاء
Expand Down
2 changes: 2 additions & 0 deletions locales/ch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ dashboard:
sells: 销售
visits: 访问
activeOrders: 活跃订单
recentOrders: 近期订单
trendingProducts: 热门产品
categories:
title: 分类
createButton: 创建
Expand Down
2 changes: 2 additions & 0 deletions locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ dashboard:
sells: Verkäufe
visits: Besuche
activeOrders: Aktive Bestellungen
recentOrders: Aktuelle Bestellungen
trendingProducts: Trendige Produkte
categories:
title: Kategorien
createButton: Erstellen
Expand Down
5 changes: 4 additions & 1 deletion locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ch: Chinese
English: English
Persian: Persian
home: Home
currencySign: $
common:
notFound: Not Found
404Error: 404 Error
Expand Down Expand Up @@ -97,7 +98,9 @@ dashboard:
products: Products
sells: Sells
visits: Visits
activeOrders: ActiveOrders
activeOrders: Active Orders
recentOrders: Recent Orders
trendingProducts: Trending Products
categories:
title: Categories
createButton: Create
Expand Down
3 changes: 3 additions & 0 deletions locales/fa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ar: Arabic
de: German
ch: Chinese
home: خانه
currencySign: ريال
common:
notFound: پیدا نشد
404Error: 404 خطای
Expand Down Expand Up @@ -63,6 +64,8 @@ dashboard:
sells: فروش
visits: بازدید ها
activeOrders: سفارش های فعال
recentOrders: سفارش های اخیر
trendingProducts: محصولات پربازدید
forgot:
button: بازیابی
haveNotAccount: اکانت ندارید؟
Expand Down
2 changes: 2 additions & 0 deletions locales/tr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ dashboard:
sells: Satışlar
visits: Ziyaretler
activeOrders: Aktif Siparişler
recentOrders: Son siparişler
trendingProducts: trend olan Ürünler
categories:
title: Kategoriler
createButton: Oluştur
Expand Down
5 changes: 5 additions & 0 deletions src/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ declare global {
const refDefault: typeof import('@vueuse/core')['refDefault']
const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl']
const render: typeof import('./composables/render')['default']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
Expand Down Expand Up @@ -229,6 +230,7 @@ declare global {
const useOnline: typeof import('@vueuse/core')['useOnline']
const useOptions: typeof import('./composables/options')['useOptions']
const useOrderStore: typeof import('./store/order.store')['useOrderStore']
const useOrders: typeof import('./composables/orders')['useOrders']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
const useParallax: typeof import('@vueuse/core')['useParallax']
const useParentElement: typeof import('@vueuse/core')['useParentElement']
Expand All @@ -247,6 +249,7 @@ declare global {
const useProductStore: typeof import('./store/product.store')['useProductStore']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useRender: typeof import('./composables/render')['default']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useReviewStore: typeof import('./store/review.store')['useReviewStore']
const useRoute: typeof import('vue-router/auto')['useRoute']
Expand Down Expand Up @@ -415,6 +418,7 @@ declare module 'vue' {
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']>
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']>
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']>
readonly render: UnwrapRef<typeof import('./composables/render')['default']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
Expand Down Expand Up @@ -551,6 +555,7 @@ declare module 'vue' {
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']>
readonly useOptions: UnwrapRef<typeof import('./composables/options')['useOptions']>
readonly useOrderStore: UnwrapRef<typeof import('./store/order.store')['useOrderStore']>
readonly useOrders: UnwrapRef<typeof import('./composables/orders')['useOrders']>
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']>
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']>
readonly useParentElement: UnwrapRef<typeof import('@vueuse/core')['useParentElement']>
Expand Down
8 changes: 5 additions & 3 deletions src/common/api/api-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ export class ApiService {
}

async getPagedList<T>(url = '', options: PagedAndSortedRequest = defaultOptions): Promise<PagedListResult<T>> {
const skipCount = (options.page - 1) * options.itemsPerPage
const maxResultCount = options.itemsPerPage
const params = { skipCount, maxResultCount, ...options } as any
const skipCount = (options.page - 1) * options.pageSize
const params = { skipCount, ...options } as any
const response = await this.httpClient.get<PagedListResult<T>>(`${this.apiBase}/${url}`, { params })
response.data.pageCount = Math.ceil(response.data.totalCount / options.pageSize)
options.itemCount = response.data.totalCount
options.pageCount = response.data.pageCount
return response.data as PagedListResult<T>
}

Expand Down
9 changes: 3 additions & 6 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ declare module 'vue' {
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDataTable: typeof import('naive-ui')['NDataTable']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDrawer: typeof import('naive-ui')['NDrawer']
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
NDropdown: typeof import('naive-ui')['NDropdown']
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NIcon: typeof import('naive-ui')['NIcon']
Expand All @@ -51,25 +49,24 @@ declare module 'vue' {
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
Notifications: typeof import('./components/Notifications.vue')['default']
NPageHeader: typeof import('naive-ui')['NPageHeader']
NPopselect: typeof import('naive-ui')['NPopselect']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']
NSwitch: typeof import('naive-ui')['NSwitch']
NTooltip: typeof import('naive-ui')['NTooltip']
NTreeSelect: typeof import('naive-ui')['NTreeSelect']
NUpload: typeof import('naive-ui')['NUpload']
OrderManagement: typeof import('./components/Orders/OrderManagement.vue')['default']
PersianIcon: typeof import('./components/CountryIcons/PersianIcon.vue')['default']
ProductsManagement: typeof import('./components/Products/ProductsManagement.vue')['default']
RecentOrders: typeof import('./components/Dahboard/RecentOrders.vue')['default']
RecentReviews: typeof import('./components/Dahboard/RecentReviews.vue')['default']
ReviewManagement: typeof import('./components/Review/ReviewManagement.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Sidebar: typeof import('./components/Sidebar.vue')['default']
ThemeSwitch: typeof import('./components/ThemeSwitch.vue')['default']
TrendingProducts: typeof import('./components/Dahboard/TrendingProducts.vue')['default']
TurkishIcon: typeof import('./components/CountryIcons/TurkishIcon.vue')['default']
UserProfile: typeof import('./components/UserProfile.vue')['default']
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/BarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const series = ref([
</script>

<template>
<VueApexCharts type="bar" :options="chartOptions" height="430" :series="series" />
<VueApexCharts type="bar" :options="chartOptions" height="460" :series="series" />
</template>

<style lang="scss" scoped>
Expand Down
29 changes: 23 additions & 6 deletions src/components/Card.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script setup>
defineProps({
noShadow: { type: Boolean, default: false },
shadow: { type: Boolean, default: false },
bottomBorder: { type: Boolean, default: false },
color: { type: String, required: false },
title: { type: String, required: false },
})
const slots = useSlots()
</script>
Expand All @@ -10,11 +13,19 @@ const slots = useSlots()
<div v-if="slots.header" class="py-3">
<slot name="header" />
</div>
<div class="card-container my-1" :class="{ 'no-shadow': noShadow }">
<div class="card-content bg-white dark:bg-slate-800 rounded-md shadow-lg p-3 relative z-10">
<div class="card-container my-1" :class="{ shadow }">
<div
class="card-content bg-white dark:bg-slate-900 rounded-md shadow-lg drop-shadow-md p-3 relative z-10"
:class="{ 'bottom-border': bottomBorder }" :style="color ? { 'border-color': color } : ''"
>
<div v-if="slots.title">
<slot name="title" />
</div>
<div v-else-if="title">
<h3 class="title text-dark-400 dark:text-light-800">
{{ title }}
</h3>
</div>
<div v-if="slots.subtitle">
<slot name="subtitle" />
</div>
Expand All @@ -28,7 +39,7 @@ const slots = useSlots()
.card-container {
position: relative;
&:before {
&.shadow:before {
content: "";
width: 92%;
box-shadow: 0 3px 20px #00000010;
Expand All @@ -45,8 +56,14 @@ const slots = useSlots()
background-color: rgb(var(--color-slate-50) / var(--tw-bg-opacity));
}
&.no-shadow:before {
display: none;
.bottom-border {
border-bottom: solid 3px;
}
.title {
font-size:1.1rem;
font-weight: 500;
margin: .1rem 0.5rem 1.2rem 0.5rem;
}
}
</style>
44 changes: 21 additions & 23 deletions src/components/Dahboard/DashboardPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ function random(min: number, max: number): number {

<template>
<div class="margin-outside flex flex-wrap pb-3">
<DashboardCard :title="t('dashboard.registers')" :progress="10" :value="random(1000, 4000)">
<DashboardCard color="#84cc16" :title="t('dashboard.registers')" :progress="10" :value="random(1000, 4000)">
<NIcon class="icon text-lime-500">
<UserIcon />
</NIcon>
</DashboardCard>
<DashboardCard :title="t('dashboard.products')" :progress="10" :value="random(100, 1000)">
<DashboardCard color="#ef4444" :title="t('dashboard.products')" :progress="10" :value="random(100, 1000)">
<NIcon class="icon text-red-500">
<BoxIcon />
</NIcon>
</DashboardCard>
<DashboardCard :title="t('dashboard.sells')" :progress="-50" :value="random(1000, 4000)">
<DashboardCard color="#22d3ee" :title="t('dashboard.sells')" :progress="-50" :value="random(1000, 4000)">
<NIcon class="icon text-cyan-400">
<BasketIcon />
</NIcon>
</DashboardCard>
<DashboardCard :title="t('dashboard.visits')" :progress="-1" :value="random(1000, 4000)">
<DashboardCard color="#f59e0b" :title="t('dashboard.visits')" :progress="-1" :value="random(1000, 4000)">
<NIcon class="icon text-amber-500">
<StatIcon />
</NIcon>
Expand All @@ -40,34 +40,32 @@ function random(min: number, max: number): number {
<div>
<div class="flex flex-col lg:flex-row margin-outside pb-3">
<div class="flex flex-col w-full lg:w-1/3">
<Card class="px-2" no-shadow>
<template #title>
<h3 class="font-700 mt-1 mb-4">
{{ t('dashboard.summary') }}
</h3>
</template>
<Card class="p-2" :title="t('dashboard.summary')">
<LineChart />
</Card>
<Card class="px-2" no-shadow>
<template #title>
<h3 class="font-700 mt-1 mb-4">
{{ t('dashboard.summary') }}
</h3>
</template>
<Card class="p-2" :title="t('dashboard.summary')">
<DonutChart />
</Card>
</div>
<div class="w-full lg:w-2/3 px-2">
<Card no-shadow>
<template #title>
<h3 class="font-700 mt-1 mb-4">
{{ t('dashboard.summary') }}
</h3>
</template>
<div class="w-full lg:w-2/3 p-2">
<Card :title="t('dashboard.summary')">
<BarChart />
</Card>
</div>
</div>

<div class="flex flex-wrap margin-outside">
<div class="w-full lg:w-1/2 px-2">
<Card :title="t('dashboard.recentOrders')">
<RecentOrders />
</Card>
</div>
<div class="w-full lg:w-1/2 px-2">
<Card :title="t('dashboard.trendingProducts')">
<TrendingProducts />
</Card>
</div>
</div>
</div>
</template>

Expand Down
45 changes: 45 additions & 0 deletions src/components/Dahboard/RecentOrders.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script setup lang="ts">
import { type DataTableColumns } from 'naive-ui/es/components'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import { OrderStatus } from '~/models/Order'
import useRender from '~/composables/render'
const { t } = useI18n()
const store = useOrderStore()
const { getStatusColor } = useOrders()
const { renderPrice, renderTag } = useRender()
onMounted(getItems)
function getItems() {
store.getRecentOrders(7)
}
const columns: DataTableColumns<RowData> = [
{
title: 'Customer',
key: 'customer',
},
{
title: 'Price',
key: 'price',
render: row => renderPrice(row.totalPrice, t('currencySign')),
},
{
title: 'Status',
key: 'status',
fixed: 'right',
width: 80,
render: row => renderTag(row.status, getStatusColor(row.status), OrderStatus),
},
]
</script>

<template>
<div>
<n-data-table
:bordered="false" :columns="columns" :data="store.orders" :loading="store.isLoading"
:scroll-x="500"
/>
</div>
</template>
Empty file.
Loading

0 comments on commit 919dec6

Please sign in to comment.