├── .env
├── public
├── _redirects
└── favicon.ico
├── env.d.ts
├── src
├── types
│ ├── vue-apexcharts.d.ts
│ ├── vue3-print-nb.d.ts
│ ├── vue_tabler_icon.d.ts
│ └── themeTypes
│ │ └── ThemeType.ts
├── scss
│ ├── components
│ │ ├── _VShadow.scss
│ │ ├── _VNavigationDrawer.scss
│ │ ├── _VTabs.scss
│ │ ├── _VTextField.scss
│ │ ├── _VInput.scss
│ │ ├── _VCard.scss
│ │ ├── _VField.scss
│ │ └── _VButtons.scss
│ ├── style.scss
│ ├── layout
│ │ ├── _topbar.scss
│ │ ├── _container.scss
│ │ └── _sidebar.scss
│ ├── _override.scss
│ ├── _variables.scss
│ └── pages
│ │ └── _dashboards.scss
├── .vscode
│ └── settings.json
├── assets
│ └── images
│ │ ├── cover
│ │ ├── cover-1.webp
│ │ ├── cover-2.webp
│ │ ├── cover-3.webp
│ │ ├── cover-4.webp
│ │ ├── cover-5.webp
│ │ ├── cover-6.webp
│ │ ├── cover-7.webp
│ │ ├── cover-8.webp
│ │ ├── cover-9.webp
│ │ ├── cover-10.webp
│ │ ├── cover-11.webp
│ │ ├── cover-12.webp
│ │ ├── cover-13.webp
│ │ ├── cover-14.webp
│ │ ├── cover-15.webp
│ │ ├── cover-16.webp
│ │ ├── cover-17.webp
│ │ ├── cover-18.webp
│ │ ├── cover-19.webp
│ │ ├── cover-20.webp
│ │ ├── cover-21.webp
│ │ ├── cover-22.webp
│ │ ├── cover-23.webp
│ │ ├── cover-24.webp
│ │ ├── cover-25.webp
│ │ └── cover-26.webp
│ │ ├── logos
│ │ ├── it-logo.png
│ │ ├── it-logo-mid.png
│ │ ├── it-logo-min.png
│ │ ├── logo.svg
│ │ └── logolight.svg
│ │ ├── avatar
│ │ ├── avatar-1.webp
│ │ ├── avatar-2.webp
│ │ ├── avatar-3.webp
│ │ ├── avatar-4.webp
│ │ ├── avatar-5.webp
│ │ ├── avatar-6.webp
│ │ ├── avatar-7.webp
│ │ ├── avatar-8.webp
│ │ ├── avatar-9.webp
│ │ ├── avatar-10.webp
│ │ ├── avatar-11.webp
│ │ ├── avatar-12.webp
│ │ ├── avatar-13.webp
│ │ ├── avatar-14.webp
│ │ ├── avatar-15.webp
│ │ ├── avatar-16.webp
│ │ ├── avatar-17.webp
│ │ ├── avatar-18.webp
│ │ ├── avatar-19.webp
│ │ ├── avatar-20.webp
│ │ ├── avatar-21.webp
│ │ ├── avatar-22.webp
│ │ ├── avatar-23.webp
│ │ ├── avatar-24.webp
│ │ └── avatar-25.webp
│ │ ├── customer
│ │ ├── avatar-0.webp
│ │ ├── avatar-1.png
│ │ ├── avatar-10.png
│ │ ├── avatar-11.png
│ │ ├── avatar-12.png
│ │ ├── avatar-2.png
│ │ ├── avatar-3.png
│ │ ├── avatar-4.png
│ │ ├── avatar-5.png
│ │ ├── avatar-6.png
│ │ ├── avatar-7.png
│ │ ├── avatar-8.png
│ │ └── avatar-9.png
│ │ ├── product
│ │ ├── avatar-0.webp
│ │ ├── product-0.webp
│ │ ├── product-1.webp
│ │ ├── product-10.webp
│ │ ├── product-11.webp
│ │ ├── product-12.webp
│ │ ├── product-13.webp
│ │ ├── product-14.webp
│ │ ├── product-15.webp
│ │ ├── product-16.webp
│ │ ├── product-17.webp
│ │ ├── product-18.webp
│ │ ├── product-19.webp
│ │ ├── product-2.webp
│ │ ├── product-20.webp
│ │ ├── product-21.webp
│ │ ├── product-22.webp
│ │ ├── product-23.webp
│ │ ├── product-24.webp
│ │ ├── product-25.webp
│ │ ├── product-26.webp
│ │ ├── product-27.webp
│ │ ├── product-28.webp
│ │ ├── product-29.webp
│ │ ├── product-3.webp
│ │ ├── product-30.webp
│ │ ├── product-31.webp
│ │ ├── product-4.webp
│ │ ├── product-5.webp
│ │ ├── product-6.webp
│ │ ├── product-7.webp
│ │ ├── product-8.webp
│ │ └── product-9.webp
│ │ ├── maintenance
│ │ ├── coming-soon.webp
│ │ ├── img-error-text.svg
│ │ ├── img-error-purple.svg
│ │ └── img-error-bg.svg
│ │ ├── icons
│ │ └── icon-card.svg
│ │ └── auth
│ │ └── social-google.svg
├── App.vue
├── layouts
│ ├── full
│ │ ├── vertical-sidebar
│ │ │ ├── NavGroup
│ │ │ │ └── NavGroup.vue
│ │ │ ├── IconSet.vue
│ │ │ ├── NavItem
│ │ │ │ └── NavItem.vue
│ │ │ ├── NavCollapse
│ │ │ │ └── NavCollapse.vue
│ │ │ ├── VerticalSidebar.vue
│ │ │ └── sidebarItem.ts
│ │ ├── logo
│ │ │ ├── LogoMain.vue
│ │ │ └── Logo.vue
│ │ ├── footer
│ │ │ └── FooterPanel.vue
│ │ ├── vertical-header
│ │ │ ├── SearchBarPanel.vue
│ │ │ ├── ProfileDD.vue
│ │ │ └── VerticalHeader.vue
│ │ ├── FullLayout.vue
│ │ └── customizer
│ │ │ └── CustomizerPanel.vue
│ └── blank
│ │ └── BlankLayout.vue
├── components
│ └── shared
│ │ ├── UiMainContainer.vue
│ │ ├── UiChildCard.vue
│ │ ├── UiTitleCard.vue
│ │ ├── NotificeBar.vue
│ │ ├── ConfirmDialog.vue
│ │ ├── UiParentCard.vue
│ │ └── BaseBreadcrumb.vue
├── config.ts
├── stores
│ ├── counter.ts
│ ├── authUser.ts
│ ├── customizer.ts
│ ├── customers.ts
│ ├── blogs.ts
│ ├── orders.ts
│ ├── auth.ts
│ └── products.ts
├── views
│ ├── notfound
│ │ ├── Loading.vue
│ │ └── NotFound.vue
│ ├── pages
│ │ ├── maintenance
│ │ │ ├── comingsoon
│ │ │ │ └── ComingSoon.vue
│ │ │ └── error
│ │ │ │ └── Error404Page.vue
│ │ └── CustomerView.vue
│ ├── utilities
│ │ ├── icons
│ │ │ ├── TablerIcons.vue
│ │ │ └── MaterialIcons.vue
│ │ ├── shadows
│ │ │ └── ShadowPage.vue
│ │ ├── colors
│ │ │ └── ColorPage.vue
│ │ └── typography
│ │ │ └── TypographyPage.vue
│ ├── StarterPage.vue
│ ├── dashboards
│ │ ├── components
│ │ │ ├── TotalIncome.vue
│ │ │ ├── HelpSupport.vue
│ │ │ ├── IncomeOverview.vue
│ │ │ ├── TotalEarning.vue
│ │ │ ├── TransactionHistory.vue
│ │ │ ├── WidgetFive.vue
│ │ │ ├── AnalyticsReport.vue
│ │ │ ├── TotalGrowth.vue
│ │ │ ├── RecentOrder.vue
│ │ │ ├── UniqueVisitor.vue
│ │ │ ├── TotalOrder.vue
│ │ │ └── SalesReport.vue
│ │ └── Dashboard.vue
│ └── authentication
│ │ ├── auth
│ │ ├── LoginPage.vue
│ │ └── RegisterPage.vue
│ │ └── authForms
│ │ ├── AuthLogin.vue
│ │ └── AuthRegister.vue
├── utils
│ ├── locales
│ │ └── format.ts
│ └── helpers
│ │ └── fetch-wrapper.ts
├── plugins
│ ├── mdi-icon.ts
│ └── vuetify.ts
├── main.ts
├── router
│ ├── PublicRoutes.ts
│ ├── index.ts
│ └── MainRoutes.ts
├── theme
│ └── LightTheme.ts
└── types.d.ts
├── config
├── prod.env.js
├── test.env.js
├── dev.env.js
├── nginx.conf
└── index.js
├── screenshots
├── screenshot-1.jpg
├── screenshot-2.jpg
├── screenshot-2.png
├── screenshot-3.jpg
├── screenshot-3.png
├── screenshot-4.jpg
├── screenshot-4.png
├── screenshot-5.jpg
├── screenshot-6.jpg
└── v3
│ ├── Screenshot-1.png
│ ├── Screenshot-2.png
│ ├── Screenshot-3.png
│ ├── Screenshot-4.png
│ ├── Screenshot-5.png
│ ├── Screenshot-6.png
│ └── Screenshot-7.png
├── .prettierrc
├── tsconfig.vite-config.json
├── tsconfig.json
├── eslint.config.js
├── Dockerfile
├── index.html
├── .gitignore
├── vite.config.ts
├── package.json
└── README.md
/.env:
--------------------------------------------------------------------------------
1 | API_URL="http://localhost"
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 |
--------------------------------------------------------------------------------
/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/types/vue-apexcharts.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'vue3-apexcharts';
2 |
--------------------------------------------------------------------------------
/src/types/vue3-print-nb.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'vue3-print-nb';
2 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/scss/components/_VShadow.scss:
--------------------------------------------------------------------------------
1 | .elevation-10 {
2 | box-shadow: $box-shadow !important;
3 | }
4 |
--------------------------------------------------------------------------------
/screenshots/screenshot-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-1.jpg
--------------------------------------------------------------------------------
/screenshots/screenshot-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-2.jpg
--------------------------------------------------------------------------------
/screenshots/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-2.png
--------------------------------------------------------------------------------
/screenshots/screenshot-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-3.jpg
--------------------------------------------------------------------------------
/screenshots/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-3.png
--------------------------------------------------------------------------------
/screenshots/screenshot-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-4.jpg
--------------------------------------------------------------------------------
/screenshots/screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-4.png
--------------------------------------------------------------------------------
/screenshots/screenshot-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-5.jpg
--------------------------------------------------------------------------------
/screenshots/screenshot-6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/screenshot-6.jpg
--------------------------------------------------------------------------------
/src/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "vue3snippets.enable-compile-vue-file-on-did-save-code": false
3 | }
4 |
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-1.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-2.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-3.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-4.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-5.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-6.png
--------------------------------------------------------------------------------
/screenshots/v3/Screenshot-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/screenshots/v3/Screenshot-7.png
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-1.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-2.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-3.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-4.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-5.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-5.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-6.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-6.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-7.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-8.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-8.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-9.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-9.webp
--------------------------------------------------------------------------------
/src/assets/images/logos/it-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/logos/it-logo.png
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-1.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-2.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-3.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-4.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-5.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-5.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-6.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-6.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-7.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-8.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-8.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-9.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-9.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-10.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-10.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-11.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-12.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-12.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-13.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-13.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-14.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-14.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-15.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-15.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-16.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-16.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-17.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-17.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-18.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-18.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-19.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-19.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-20.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-20.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-21.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-21.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-22.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-22.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-23.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-23.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-24.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-24.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-25.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-25.webp
--------------------------------------------------------------------------------
/src/assets/images/cover/cover-26.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/cover/cover-26.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-10.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-10.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-11.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-12.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-12.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-13.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-13.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-14.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-14.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-15.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-15.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-16.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-16.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-17.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-17.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-18.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-18.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-19.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-19.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-20.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-20.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-21.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-21.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-22.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-22.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-23.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-23.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-24.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-24.webp
--------------------------------------------------------------------------------
/src/assets/images/avatar/avatar-25.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/avatar/avatar-25.webp
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-0.webp
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-1.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-10.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-11.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-12.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-2.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-3.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-4.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-5.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-6.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-7.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-8.png
--------------------------------------------------------------------------------
/src/assets/images/customer/avatar-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/customer/avatar-9.png
--------------------------------------------------------------------------------
/src/assets/images/logos/it-logo-mid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/logos/it-logo-mid.png
--------------------------------------------------------------------------------
/src/assets/images/logos/it-logo-min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/logos/it-logo-min.png
--------------------------------------------------------------------------------
/src/assets/images/product/avatar-0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/avatar-0.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-0.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-1.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-10.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-10.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-11.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-12.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-12.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-13.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-13.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-14.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-14.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-15.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-15.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-16.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-16.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-17.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-17.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-18.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-18.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-19.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-19.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-2.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-20.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-20.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-21.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-21.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-22.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-22.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-23.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-23.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-24.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-24.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-25.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-25.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-26.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-26.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-27.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-27.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-28.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-28.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-29.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-29.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-3.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-30.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-30.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-31.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-31.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-4.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-5.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-5.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-6.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-6.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-7.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-8.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-8.webp
--------------------------------------------------------------------------------
/src/assets/images/product/product-9.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/product/product-9.webp
--------------------------------------------------------------------------------
/src/scss/components/_VNavigationDrawer.scss:
--------------------------------------------------------------------------------
1 | .v-navigation-drawer__scrim.fade-transition-leave-to {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/images/maintenance/coming-soon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/harryho/vue-crm/HEAD/src/assets/images/maintenance/coming-soon.webp
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/config/test.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var devEnv = require('./dev.env')
3 |
4 | module.exports = merge(devEnv, {
5 | NODE_ENV: '"testing"'
6 | })
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": true,
3 | "printWidth": 140,
4 | "singleQuote": true,
5 | "trailingComma": "none",
6 | "tabWidth": 2,
7 | "useTabs": false
8 | }
9 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/tsconfig.vite-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/node22/tsconfig.json",
3 | "include": ["vite.config.*"],
4 | "compilerOptions": {
5 | "composite": true,
6 | "allowJs": true,
7 | "types": ["node"]
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/NavGroup/NavGroup.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | {{ props.item.header }}
7 |
8 |
--------------------------------------------------------------------------------
/src/layouts/blank/BlankLayout.vue:
--------------------------------------------------------------------------------
1 | // ===============================|| Blank Layout ||=============================== //
2 |
3 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/src/scss/components/_VTabs.scss:
--------------------------------------------------------------------------------
1 | .theme-tab {
2 | &.v-tabs {
3 | .v-tab {
4 | border-radius: $border-radius-root !important;
5 | min-width: auto !important;
6 | &.v-tab-item--selected {
7 | background: rgb(var(--v-theme-primary));
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/types/vue_tabler_icon.d.ts:
--------------------------------------------------------------------------------
1 | import { VNodeChild } from 'vue';
2 | declare module '@vue/runtime-dom' {
3 | export interface HTMLAttributes {
4 | $children?: VNodeChild;
5 | }
6 | export interface SVGAttributes {
7 | $children?: VNodeChild;
8 | strokeWidth?: string | number;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/shared/UiMainContainer.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 | // ===============================|| Ui Main Container||=============================== //
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | export type ConfigProps = {
2 | Sidebar_drawer: boolean;
3 | Customizer_drawer: boolean;
4 | mini_sidebar: boolean;
5 | fontTheme: string;
6 | inputBg: boolean;
7 | };
8 |
9 | const config: ConfigProps = {
10 | Sidebar_drawer: true,
11 | Customizer_drawer: false,
12 | mini_sidebar: false,
13 | fontTheme: 'Roboto',
14 | inputBg: false
15 | };
16 |
17 | export default config;
18 |
--------------------------------------------------------------------------------
/src/stores/counter.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | export const useCounterStore = defineStore({
4 | id: 'counter',
5 | state: () => ({
6 | counter: 0
7 | }),
8 | getters: {
9 | doubleCount: (state) => state.counter * 2
10 | },
11 | actions: {
12 | increment() {
13 | this.counter++;
14 | },
15 | decrement() {
16 | this.counter--;
17 | }
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/src/scss/components/_VTextField.scss:
--------------------------------------------------------------------------------
1 | .v-text-field input {
2 | font-size: 0.875rem;
3 | }
4 | .v-input--density-default {
5 | .v-field__input {
6 | min-height: 51px;
7 | }
8 | }
9 |
10 | .v-field__outline {
11 | color: rgb(var(--v-theme-inputBorder));
12 | }
13 | .inputWithbg {
14 | .v-field--variant-outlined {
15 | background-color: rgba(0, 0, 0, 0.025);
16 | border-radius: 12px !important;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/scss/components/_VInput.scss:
--------------------------------------------------------------------------------
1 | .v-input--density-default,
2 | .v-field--variant-solo,
3 | .v-field--variant-filled {
4 | --v-input-control-height: 51px;
5 | --v-input-padding-top: 14px;
6 | }
7 | .v-input--density-comfortable {
8 | --v-input-control-height: 56px;
9 | --v-input-padding-top: 17px;
10 | }
11 | .v-label {
12 | font-size: 0.975rem;
13 | }
14 | .v-switch .v-label,
15 | .v-checkbox .v-label {
16 | opacity: 1;
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/shared/UiChildCard.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | {{ props.title }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/scss/components/_VCard.scss:
--------------------------------------------------------------------------------
1 | // Outline Card
2 | .v-card--variant-outlined {
3 | border-color: rgba(var(--v-theme-borderLight), 0.36);
4 | .v-divider {
5 | border-color: rgba(var(--v-theme-borderLight), 0.36);
6 | }
7 | }
8 |
9 | .v-card-text {
10 | padding: $card-text-spacer;
11 | }
12 |
13 | .v-card {
14 | width: 100%;
15 | overflow: visible;
16 | }
17 |
18 | .v-card-item {
19 | padding: $card-item-spacer-xy;
20 | }
21 |
--------------------------------------------------------------------------------
/src/scss/components/_VField.scss:
--------------------------------------------------------------------------------
1 | .v-field--variant-outlined .v-field__outline__start.v-locale--is-ltr,
2 | .v-locale--is-ltr .v-field--variant-outlined .v-field__outline__start {
3 | border-radius: $border-radius-root 0 0 $border-radius-root;
4 | }
5 |
6 | .v-field--variant-outlined .v-field__outline__end.v-locale--is-ltr,
7 | .v-locale--is-ltr .v-field--variant-outlined .v-field__outline__end {
8 | border-radius: 0 $border-radius-root $border-radius-root 0;
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.dom.json",
3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/types/.d.ts"],
4 | "compilerOptions": {
5 | "module": "ESNext",
6 | "ignoreDeprecations": "5.0",
7 | "baseUrl": ".",
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | },
11 | "allowJs": true
12 | },
13 |
14 | "references": [
15 | {
16 | "path": "./tsconfig.vite-config.json"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/IconSet.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import globals from 'globals';
2 | import pluginJs from '@eslint/js';
3 | import tseslint from 'typescript-eslint';
4 | import pluginVue from 'eslint-plugin-vue';
5 |
6 | export default [
7 | {
8 | languageOptions: {
9 | globals: globals.browser,
10 | parserOptions: {
11 | parser: '@typescript-eslint/parser'
12 | }
13 | }
14 | },
15 | pluginJs.configs.recommended,
16 | ...tseslint.configs.recommended,
17 | ...pluginVue.configs['flat/essential']
18 | ];
19 |
--------------------------------------------------------------------------------
/src/layouts/full/logo/LogoMain.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 
14 |
Vue Demo V3
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/shared/UiTitleCard.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 | {{ props.title }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/scss/components/_VButtons.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Light Buttons
3 | //
4 |
5 | .v-btn {
6 | &.bg-lightsecondary {
7 | &:hover,
8 | &:active,
9 | &:focus {
10 | background-color: rgb(var(--v-theme-secondary)) !important;
11 | color: $white !important;
12 | }
13 | }
14 | }
15 |
16 | .v-btn {
17 | text-transform: capitalize;
18 | letter-spacing: $btn-letter-spacing;
19 | }
20 | .v-btn--icon.v-btn--density-default {
21 | width: calc(var(--v-btn-height) + 6px);
22 | height: calc(var(--v-btn-height) + 6px);
23 | }
24 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ###### Build #####
2 | FROM node:12-slim AS node
3 | LABEL author="Harry Ho"
4 | WORKDIR /
5 | COPY . .
6 | RUN npm install
7 | RUN npm run build -- --prod
8 |
9 |
10 | ###### Build the Delivery #####
11 | FROM nginx:alpine
12 | LABEL author="Harry Ho"
13 | WORKDIR /var/cache/nginx
14 | COPY --from=node /dist /usr/share/nginx/html
15 | COPY ./config/nginx.conf /etc/nginx/conf.d/default.conf
16 |
17 |
18 | # ########################
19 | # # docker build . -t vue-demo:3.0
20 | # # docker run --rm -d --publish 8080:80 --name vd3 vue-demo:3.0
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/views/notfound/Loading.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
25 |
26 |
--------------------------------------------------------------------------------
/src/stores/authUser.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 |
5 | const baseUrl = `${import.meta.env.VITE_API_URL}/users`;
6 |
7 | export const useUsersStore = defineStore({
8 | id: 'Customers',
9 | state: () => ({
10 | users: {}
11 | }),
12 | actions: {
13 | async getAll() {
14 | this.users = { loading: true };
15 | fetchWrapper
16 | .get(baseUrl)
17 | .then((users) => (this.users = users))
18 | .catch((error) => (this.users = { error }));
19 | }
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/src/scss/style.scss:
--------------------------------------------------------------------------------
1 | @import './variables';
2 | @import 'vuetify/styles/main.sass';
3 | @import './override';
4 | @import './layout/container';
5 | @import './layout/sidebar';
6 | @import './layout/topbar';
7 |
8 | @import './components/VButtons';
9 | @import './components/VCard';
10 | @import './components/VField';
11 | @import './components/VInput';
12 | @import './components/VNavigationDrawer';
13 | @import './components/VShadow';
14 | @import './components/VTextField';
15 | @import './components/VTabs';
16 |
17 | @import './pages/dashboards';
18 |
19 | @import 'vue3-perfect-scrollbar/style.css';
20 |
--------------------------------------------------------------------------------
/src/layouts/full/logo/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 
8 |
Vue Demo V3
9 |
10 |
11 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/config/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 0.0.0.0:80;
3 | listen [::]:80;
4 | default_type application/octet-stream;
5 |
6 | gzip on;
7 | gzip_comp_level 6;
8 | gzip_vary on;
9 | gzip_min_length 1000;
10 | gzip_proxied any;
11 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
12 | gzip_buffers 16 8k;
13 | client_max_body_size 256M;
14 |
15 | root /usr/share/nginx/html;
16 |
17 | location / {
18 | try_files $uri $uri/ /index.html =404;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/layouts/full/footer/FooterPanel.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
16 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/src/utils/locales/format.ts:
--------------------------------------------------------------------------------
1 | export function formatToCurrencyString(price: number):string{
2 |
3 | return new Intl.NumberFormat('en-AU', {
4 | style: 'currency',
5 | currency: 'AUD',
6 | minimumFractionDigits: 2,
7 | maximumFractionDigits: 2
8 | }).format(price)
9 | }
10 |
11 | export function formatToCurrencyNumber(price: number):number {
12 |
13 | return Number(price.toFixed(2))
14 | }
15 |
16 |
17 | export function toTitleCase(str:string) :string{
18 | str = str.replace('-',' ').replace(',',' ')
19 | return str.split(' ').map(word => {
20 | return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
21 | }).join(' ');
22 | }
--------------------------------------------------------------------------------
/src/plugins/mdi-icon.ts:
--------------------------------------------------------------------------------
1 | import {
2 | mdiClose, mdiHome, mdiEyeOff, mdiEye,
3 | mdiCrownCircleOutline, mdiCertificateOutline,
4 | mdiShoppingOutline, mdiPencilCircleOutline, mdiDeleteCircleOutline,
5 | mdiPlusCircleOutline, mdiCommentMultiple, mdiShareVariant, mdiGithub
6 | } from '@mdi/js';
7 |
8 | export const icons = {
9 | close: mdiClose,
10 | home: mdiHome,
11 | eyeOff: mdiEyeOff,
12 | eye: mdiEye,
13 | vip: mdiCrownCircleOutline,
14 | standard: mdiCertificateOutline,
15 | pendingShopping: mdiShoppingOutline,
16 | edit: mdiPencilCircleOutline,
17 | delete: mdiDeleteCircleOutline,
18 | new: mdiPlusCircleOutline,
19 | share: mdiShareVariant,
20 | comments: mdiCommentMultiple,
21 | github: mdiGithub
22 | };
23 |
--------------------------------------------------------------------------------
/src/components/shared/NotificeBar.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 | {{ props.text }}
21 |
22 |
23 | Close
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/views/pages/maintenance/comingsoon/ComingSoon.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
WIP. It won't be too long.
13 |
14 |
15 |
Go Back to Home
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
15 | Vue Demo V3
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/assets/images/icons/icon-card.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import { createPinia } from 'pinia';
3 | import App from './App.vue';
4 | import { router } from './router';
5 | import vuetify from './plugins/vuetify';
6 | import { VDateInput } from 'vuetify/labs/components';
7 | import '@/scss/style.scss';
8 | import { PerfectScrollbarPlugin } from 'vue3-perfect-scrollbar';
9 | import VueApexCharts from 'vue3-apexcharts';
10 | import VueTablerIcons from 'vue-tabler-icons';
11 |
12 | import { fakeBackend } from '@/utils/helpers/fake-backend';
13 |
14 | // print
15 | import print from 'vue3-print-nb';
16 |
17 | const app = createApp(App);
18 | fakeBackend();
19 | app.use(router);
20 | app.use(PerfectScrollbarPlugin);
21 | app.use(createPinia());
22 | app.use(VueTablerIcons);
23 | app.use(print);
24 | app.use(VueApexCharts);
25 | app.use(vuetify).mount('#app');
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # These are some examples of commonly ignored file patterns.
2 | # You should customize this list as applicable to your project.
3 | # Learn more about .gitignore:
4 | # https://www.atlassian.com/git/tutorials/saving-changes/gitignore
5 |
6 | # Node artifact files
7 | node_modules/
8 | dist/
9 |
10 | # Compiled Java class files
11 | *.class
12 |
13 | # Compiled Python bytecode
14 | *.py[cod]
15 |
16 | # Log files
17 | *.log
18 |
19 | # Package files
20 | *.jar
21 |
22 | # Maven
23 | target/
24 | dist/
25 |
26 | # JetBrains IDE
27 | .idea/
28 |
29 | # Unit test reports
30 | TEST*.xml
31 |
32 | # Generated by MacOS
33 | .DS_Store
34 |
35 | # Generated by Windows
36 | Thumbs.db
37 |
38 | # Applications
39 | *.app
40 | *.exe
41 | *.war
42 |
43 | # Large media files
44 | *.mp4
45 | *.tiff
46 | *.avi
47 | *.flv
48 | *.mov
49 | *.wmv
50 |
51 |
--------------------------------------------------------------------------------
/src/router/PublicRoutes.ts:
--------------------------------------------------------------------------------
1 | const PublicRoutes = {
2 | path: '/',
3 | component: () => import('@/layouts/blank/BlankLayout.vue'),
4 | meta: {
5 | requiresAuth: false
6 | },
7 | children: [
8 | {
9 | name: 'Login',
10 | path: '/login',
11 | component: () => import('@/views/authentication/auth/LoginPage.vue')
12 | },
13 | {
14 | name: 'Register',
15 | path: '/register',
16 | component: () => import('@/views/authentication/auth/RegisterPage.vue')
17 | },
18 | {
19 | name: 'Not Found',
20 | path: '/notfound',
21 | component: () => import('@/views/notfound/NotFound.vue')
22 | },
23 | {
24 | name: 'Loading',
25 | path: '/loading',
26 | component: () => import('@/views/notfound/Loading.vue')
27 | }
28 | ]
29 | };
30 |
31 | export default PublicRoutes;
32 |
--------------------------------------------------------------------------------
/src/stores/customizer.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 | import config from '@/config';
3 |
4 | export const useCustomizerStore = defineStore({
5 | id: 'customizer',
6 | state: () => ({
7 | Sidebar_drawer: config.Sidebar_drawer,
8 | Customizer_drawer: config.Customizer_drawer,
9 | mini_sidebar: config.mini_sidebar,
10 | fontTheme: config.fontTheme,
11 | inputBg: config.inputBg
12 | }),
13 |
14 | getters: {},
15 | actions: {
16 | SET_SIDEBAR_DRAWER() {
17 | this.Sidebar_drawer = !this.Sidebar_drawer;
18 | },
19 | SET_MINI_SIDEBAR(payload: boolean) {
20 | this.mini_sidebar = payload;
21 | },
22 | SET_CUSTOMIZER_DRAWER(payload: boolean) {
23 | this.Customizer_drawer = payload;
24 | },
25 | SET_FONT(payload: string) {
26 | this.fontTheme = payload;
27 | }
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/src/scss/layout/_topbar.scss:
--------------------------------------------------------------------------------
1 | .profileBtn {
2 | height: 50px !important;
3 | margin: 0 20px 0 10px !important;
4 | }
5 |
6 | .search-sheet {
7 | position: absolute;
8 | z-index: 9;
9 | }
10 |
11 | .circle {
12 | position: relative;
13 | overflow: hidden;
14 | &.sm-circle {
15 | &::before {
16 | content: '';
17 | position: absolute;
18 | width: 200px;
19 | height: 200px;
20 | border: 3px solid rgb(var(--v-theme-warning));
21 | border-radius: 50%;
22 | top: 125px;
23 | right: -70px;
24 | }
25 | }
26 |
27 | &.lg-circle {
28 | &::after {
29 | content: '';
30 | position: absolute;
31 | width: 200px;
32 | height: 200px;
33 | border: 19px solid rgb(var(--v-theme-warning));
34 | border-radius: 50%;
35 | top: 65px;
36 | right: -150px;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/views/utilities/icons/TablerIcons.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/types/themeTypes/ThemeType.ts:
--------------------------------------------------------------------------------
1 | export type ThemeTypes = {
2 | name: string;
3 | dark: boolean;
4 | variables?: object;
5 | colors: {
6 | primary?: string;
7 | secondary?: string;
8 | info?: string;
9 | success?: string;
10 | accent?: string;
11 | warning?: string;
12 | error?: string;
13 | lightprimary?: string;
14 | lightsecondary?: string;
15 | lightsuccess?: string;
16 | lighterror?: string;
17 | lightwarning?: string;
18 | darkprimary?: string;
19 | darksecondary?: string;
20 | darkText?: string;
21 | lightText?: string;
22 | borderLight?: string;
23 | inputBorder?: string;
24 | containerBg?: string;
25 | surface?: string;
26 | background?: string;
27 | 'on-surface-variant'?: string;
28 | facebook?: string;
29 | twitter?: string;
30 | linkedin?: string;
31 | gray100?: string;
32 | primary200?: string;
33 | secondary200?: string;
34 | };
35 | };
36 |
--------------------------------------------------------------------------------
/src/views/utilities/icons/MaterialIcons.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/components/shared/ConfirmDialog.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
17 |
18 |
23 |
24 |
25 |
26 |
27 | Confirm
28 |
29 |
30 |
31 | Cancel
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/components/shared/UiParentCard.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 | // ===============================|| Ui Parent Card||=============================== //
16 |
17 |
18 |
19 |
20 | {{ props.title }}
21 |
22 |
24 |
25 | New
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/plugins/vuetify.ts:
--------------------------------------------------------------------------------
1 | import { createVuetify } from 'vuetify';
2 | import { aliases, mdi } from 'vuetify/iconsets/mdi-svg';
3 | import { icons } from './mdi-icon'; // Import icons from separate file
4 | import * as components from 'vuetify/components';
5 | import * as directives from 'vuetify/directives';
6 | import { PurpleTheme } from '@/theme/LightTheme';
7 | import * as labsComponents from 'vuetify/labs/components'
8 |
9 | export default createVuetify({
10 | components:{
11 | ...components,
12 | ...labsComponents,
13 | },
14 | directives,
15 | icons: {
16 | defaultSet: 'mdi',
17 | aliases: {
18 | ...aliases,
19 | ...icons
20 | },
21 | sets: {
22 | mdi
23 | }
24 | },
25 | theme: {
26 | defaultTheme: 'PurpleTheme',
27 | themes: {
28 | PurpleTheme
29 | }
30 | },
31 | defaults: {
32 | VBtn: {},
33 | VCard: {
34 | rounded: 'md'
35 | },
36 | VTextField: {
37 | rounded: 'lg'
38 | },
39 | VTooltip: {
40 | // set v-tooltip default location to top
41 | location: 'top'
42 | }
43 | }
44 | });
45 |
--------------------------------------------------------------------------------
/src/views/utilities/shadows/ShadowPage.vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {{ n - 1 }}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/views/notfound/NotFound.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
Opps!!!
15 |
16 | This page you are looking for could not be found.
17 |
Go To Login
18 |
19 |
20 |
21 |
22 |
23 |
44 |
--------------------------------------------------------------------------------
/src/theme/LightTheme.ts:
--------------------------------------------------------------------------------
1 | import type { ThemeTypes } from '@/types/themeTypes/ThemeType';
2 |
3 | const PurpleTheme: ThemeTypes = {
4 | name: 'PurpleTheme',
5 | dark: false,
6 | variables: {
7 | 'border-color': '#1e88e5',
8 | 'carousel-control-size': 10
9 | },
10 | colors: {
11 | primary: '#1e88e5',
12 | secondary: '#5e35b1',
13 | info: '#03c9d7',
14 | success: '#00c853',
15 | accent: '#FFAB91',
16 | warning: '#ffc107',
17 | error: '#f44336',
18 | lightprimary: '#eef2f6',
19 | lightsecondary: '#ede7f6',
20 | lightsuccess: '#b9f6ca',
21 | lighterror: '#f9d8d8',
22 | lightwarning: '#fff8e1',
23 | darkText: '#212121',
24 | lightText: '#616161',
25 | darkprimary: '#1565c0',
26 | darksecondary: '#4527a0',
27 | borderLight: '#d0d0d0',
28 | inputBorder: '#787878',
29 | containerBg: '#eef2f6',
30 | surface: '#fff',
31 | 'on-surface-variant': '#fff',
32 | facebook: '#4267b2',
33 | twitter: '#1da1f2',
34 | linkedin: '#0e76a8',
35 | gray100: '#fafafa',
36 | primary200: '#90caf9',
37 | secondary200: '#b39ddb'
38 | }
39 | };
40 |
41 | export { PurpleTheme };
42 |
--------------------------------------------------------------------------------
/src/views/StarterPage.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | Lorem ipsum dolor sit amen, consenter nipissing eli, sed do elusion tempos incident ut laborers et doolie magna alissa. Ut enif ad
28 | minim venice, quin nostrum exercitation illampu laborings nisi ut liquid ex ea commons construal. Duos aube grue dolor in
29 | reprehended in voltage veil esse colum doolie eu fujian bulla parian. Exceptive sin ocean cuspidate non president, sunk in culpa qui
30 | officiate descent molls anim id est labours.
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/assets/images/auth/social-google.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'url';
2 | import { defineConfig,normalizePath } from 'vite';
3 | import vue from '@vitejs/plugin-vue';
4 | import vuetify from 'vite-plugin-vuetify';
5 | import { viteStaticCopy } from 'vite-plugin-static-copy'
6 | import path from 'node:path'
7 |
8 | // https://vitejs.dev/config/
9 | export default defineConfig({
10 | plugins: [
11 | viteStaticCopy({
12 | targets: [
13 | {
14 | src: [ normalizePath(path.resolve(__dirname, './src/assets/images'))+ '/[!.]*', ],
15 | dest: './assets/images'
16 | }
17 | ]
18 | }),
19 | vue({
20 | template: {
21 | compilerOptions: {
22 | isCustomElement: (tag) => ['v-list-recognize-title'].includes(tag)
23 | }
24 | }
25 | }),
26 | vuetify({
27 | autoImport: true
28 | })
29 | ],
30 | resolve: {
31 | alias: {
32 | '@': fileURLToPath(new URL('./src', import.meta.url))
33 | }
34 | },
35 | css: {
36 | preprocessorOptions: {
37 | scss: {}
38 | }
39 | },
40 | assetsInclude:[''],
41 | build: {
42 | chunkSizeWarningLimit: 1024 * 1024 // Set the limit to 1 MB
43 | },
44 | optimizeDeps: {
45 | exclude: ['vuetify'],
46 | entries: ['./src/**/*.vue']
47 | }
48 | });
49 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/TotalIncome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
$203k
12 | Total Income
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
$203k
26 | Total Income
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-header/SearchBarPanel.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/scss/_override.scss:
--------------------------------------------------------------------------------
1 | html {
2 | .bg-success {
3 | color: white !important;
4 | }
5 | }
6 |
7 | .v-row + .v-row {
8 | margin-top: 0px;
9 | }
10 |
11 | .v-divider {
12 | opacity: 1;
13 | border-color: rgba(var(--v-theme-borderLight), 0.36);
14 | }
15 |
16 | .v-selection-control {
17 | flex: unset;
18 | }
19 |
20 | .customizer-btn .icon {
21 | animation: progress-circular-rotate 1.4s linear infinite;
22 | transform-origin: center center;
23 | transition: all 0.2s ease-in-out;
24 | }
25 |
26 | .no-spacer {
27 | .v-list-item__spacer {
28 | display: none !important;
29 | }
30 | }
31 |
32 | @keyframes progress-circular-rotate {
33 | 100% {
34 | transform: rotate(270deg);
35 | }
36 | }
37 |
38 | // apexchart css
39 | .apexcharts-canvas {
40 | .apexcharts-tooltip-rangebar {
41 | padding: 0px 8px 5px;
42 | }
43 | .apexcharts-tooltip-title {
44 | margin-bottom: 0;
45 | }
46 | .apexcharts-tooltip {
47 | &.apexcharts-theme-light {
48 | color: rgb(var(--v-theme-darkText));
49 | }
50 | }
51 | .apexcharts-tooltip-series-group {
52 | &.apexcharts-active,
53 | &:last-child {
54 | padding-bottom: 0;
55 | }
56 | }
57 | .apexcharts-menu {
58 | .apexcharts-menu-item {
59 | &:hover {
60 | background: rgb(var(--v-theme-gray100));
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/NavItem/NavItem.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
21 |
22 | {{ item.title }}
23 |
24 |
27 |
28 |
29 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/views/utilities/colors/ColorPage.vue:
--------------------------------------------------------------------------------
1 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | class: {{ color }}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/HelpSupport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Help & Support Chat
7 | Typical replay within 5 min
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Need Help?
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/views/pages/maintenance/error/Error404Page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
Something is wrong
14 |
15 | The page you are looking was moved, removed,
renamed, or might never exist!
16 |
17 |
Home
18 |
19 |
20 |
21 |
22 |
43 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'assets',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'assets',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/layouts/full/FullLayout.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/views/authentication/auth/LoginPage.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Hi, Welcome Back
22 | Enter your credentials to continue
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
47 |
--------------------------------------------------------------------------------
/src/views/authentication/auth/RegisterPage.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Sign up
22 | Enter credentials to continue
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
47 |
--------------------------------------------------------------------------------
/src/components/shared/BaseBreadcrumb.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 | // ===============================|| Theme Breadcrumb ||=============================== //
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ props.title }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
54 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/NavCollapse/NavCollapse.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ item.title }}
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/IncomeOverview.vue:
--------------------------------------------------------------------------------
1 |
69 |
70 |
71 |
72 |
73 |
This Week Statistics
74 | $7,650
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/VerticalSidebar.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
52 |
53 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router';
2 | import MainRoutes from './MainRoutes';
3 | import PublicRoutes from './PublicRoutes';
4 | import { useAuthStore } from '@/stores/auth';
5 |
6 | export const router = createRouter({
7 | // history: createWebHistory(import.meta.env.BASE_URL),
8 | history: createWebHistory(),
9 | routes: [
10 | {
11 | path: '/:pathMatch(.*)*',
12 | redirect: '/loading',
13 | // component: () => import('@/views/pages/maintenance/error/Error404Page.vue')
14 | },
15 | MainRoutes,
16 | PublicRoutes
17 | ]
18 | });
19 |
20 | interface User {
21 | // Define the properties and their types for the user data here
22 | // For example:
23 | id: number;
24 | name: string;
25 | }
26 |
27 | // Assuming you have a type/interface for your authentication store
28 | interface AuthStore {
29 | user: User | null;
30 | returnUrl: string | null;
31 | login(username: string, password: string): Promise;
32 | logout(): void;
33 | }
34 |
35 | router.beforeEach(async (to, from, next) => {
36 | // redirect to login page if not logged in and trying to access a restricted page
37 | const publicPages = ['/'];
38 | const auth: AuthStore = useAuthStore();
39 |
40 | const isPublicPage = publicPages.includes(to.path);
41 | const authRequired = !isPublicPage && to.matched.some((record) => record.meta.requiresAuth);
42 |
43 | // User not logged in and trying to access a restricted page
44 | if (authRequired && !auth.user) {
45 | auth.returnUrl = to.fullPath; // Save the intended page
46 | next('/login');
47 | } else if (auth.user && to.path === '/login') {
48 | // User logged in and trying to access the login page
49 | next({
50 | query: {
51 | ...to.query,
52 | redirect: auth.returnUrl !== '/' ? to.fullPath : undefined
53 | }
54 | });
55 | } else {
56 | // All other scenarios, either public page or authorized access
57 | next();
58 | }
59 | });
60 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-demo",
3 | "version": "1.3.0",
4 | "private": true,
5 | "author": "CodedThemes",
6 | "type": "module",
7 | "scripts": {
8 | "dev": "vite",
9 | "build": "vue-tsc --noEmit && vite build",
10 | "build-stage": "vue-tsc --noEmit && vite build --base=/stage/",
11 | "build-prod": "vue-tsc --noEmit && vite build --base=/",
12 | "preview": "vite preview --port 5050",
13 | "typecheck": "vue-tsc --noEmit",
14 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-pattern .gitignore"
15 | },
16 | "dependencies": {
17 | "@ant-design/icons-vue": "^7.0.1",
18 | "@mdi/js": "^7.4.47",
19 | "@tsconfig/node22": "^22.0.0",
20 | "@typescript-eslint/parser": "^8.19.0",
21 | "apexcharts": "4.3.0",
22 | "axios": "1.7.9",
23 | "axios-mock-adapter": "2.1.0",
24 | "chance": "1.1.12",
25 | "date-fns": "4.1.0",
26 | "lodash": "^4.17.21",
27 | "pinia": "2.3.0",
28 | "remixicon": "4.6.0",
29 | "vee-validate": "4.15.0",
30 | "vite-plugin-vuetify": "2.0.4",
31 | "vue": "3.5.13",
32 | "vue-router": "4.5.0",
33 | "vue-tabler-icons": "2.21.0",
34 | "vue3-apexcharts": "1.8.0",
35 | "vue3-perfect-scrollbar": "2.0.0",
36 | "vue3-print-nb": "0.1.4",
37 | "vuetify": "3.8.0",
38 | "webpack-plugin-vuetify": "3.0.3",
39 | "yup": "1.6.1"
40 | },
41 | "devDependencies": {
42 | "@eslint/js": "^9.17.0",
43 | "@types/chance": "1.1.6",
44 | "@types/node": "22.10.4",
45 | "@vitejs/plugin-vue": "5.2.1",
46 | "@vue/eslint-config-prettier": "10.1.0",
47 | "@vue/tsconfig": "0.7.0",
48 | "eslint": "9.17.0",
49 | "eslint-plugin-vue": "9.32.0",
50 | "prettier": "3.4.2",
51 | "sass": "1.79.6",
52 | "sass-loader": "16.0.4",
53 | "typescript": "5.7.2",
54 | "typescript-eslint": "^8.19.0",
55 | "vite": "6.0.7",
56 | "vite-plugin-static-copy": "^2.3.0",
57 | "vue-cli-plugin-vuetify": "2.5.8",
58 | "vue-tsc": "2.2.0"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/utils/helpers/fetch-wrapper.ts:
--------------------------------------------------------------------------------
1 | import { useAuthStore } from '@/stores/auth';
2 |
3 | export const fetchWrapper = {
4 | get: request('GET'),
5 | post: request('POST'),
6 | put: request('PUT'),
7 | delete: request('DELETE')
8 | };
9 |
10 | interface temp {
11 | method: string;
12 | headers: Record;
13 | body?: string;
14 | }
15 |
16 | interface UserData {
17 | username: string;
18 | password: string;
19 | }
20 |
21 | function request(method: string) {
22 | return (url: string, body?: object) => {
23 | const requestOptions: temp = {
24 | method,
25 | headers: authHeader(url)
26 | };
27 | if (body) {
28 | requestOptions.headers['Content-Type'] = 'application/json';
29 | requestOptions.body = JSON.stringify(body);
30 | }
31 | return fetch(url, requestOptions).then(handleResponse);
32 | };
33 | }
34 |
35 | // helper functions
36 |
37 | function authHeader(url: string): Record {
38 | // return auth header with jwt if user is logged in and request is to the api url
39 | const { user } = useAuthStore();
40 | const isLoggedIn = !!user?.token;
41 | const isApiUrl = true // url.startsWith(import.meta.env.VITE_API_URL);
42 | if (isLoggedIn && isApiUrl) {
43 | return { Authorization: `Bearer ${user.token}` };
44 | } else {
45 | return {};
46 | }
47 | }
48 |
49 | function handleResponse(response: Response): Promise {
50 | return response.text().then((text: string) => {
51 | const data = text && JSON.parse(text);
52 |
53 | if (!response.ok) {
54 | const { user, logout } = useAuthStore();
55 | if ([401, 403].includes(response.status) && user) {
56 | // auto logout if 401 Unauthorized or 403 Forbidden response returned from api
57 | logout();
58 | }
59 |
60 | const error: string = (data && data.message) || response.statusText;
61 | return Promise.reject(error);
62 | }
63 |
64 | // Ensure data is of type UserData
65 | return data as any;
66 | });
67 | }
68 |
--------------------------------------------------------------------------------
/src/stores/customers.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 | import { ThreedCubeSphereIcon } from 'vue-tabler-icons';
5 | import type { Customer } from '@/types';
6 |
7 | const baseUrl = `${import.meta.env.VITE_API_URL}/customers`;
8 |
9 |
10 | export const useCustomersStore = defineStore("Customers", {
11 |
12 | state: () => ({
13 | customers: [] as Array,
14 | loading: false,
15 | filter: '',
16 | customer: {} as Customer
17 | }),
18 | getters: {
19 | filteredData(): Customer[] {
20 | return this.customers;
21 | },
22 | },
23 | actions: {
24 | async getAll() {
25 | this.loading = true;
26 | this.customers = await fetchWrapper.get(baseUrl)
27 | this.loading = false;
28 | },
29 | async delteCustomer(id: string) {
30 | const res = await fetchWrapper.delete(`${baseUrl}/${id}`)
31 | if (res.error) {
32 | console.log(res.error)
33 | }
34 | return res
35 | },
36 | async getCustomerById(id: string) {
37 | this.loading = true
38 | this.customer = await fetchWrapper.get(`${baseUrl}/${id}`)
39 | this.loading = false
40 | },
41 | async saveCustomer(customer: Customer) {
42 | let res
43 | if (customer.id)
44 | res = await fetchWrapper.put(`${baseUrl}/${customer.id}`, customer)
45 | else
46 | res = await fetchWrapper.post(`${baseUrl}`, customer)
47 | return res
48 | },
49 | async newCustomer() {
50 | this.loading = true
51 | setTimeout(() => {
52 | this.customer = {
53 | id: '',
54 | firstname: '',
55 | lastname: '',
56 | fullname: '',
57 | email: '',
58 | avatar: '',
59 | mobile: '',
60 | phone: '',
61 | membership: '',
62 | rewards: 0,
63 | hasItemInShoppingCart: false
64 | }
65 | this.loading = false
66 | }
67 | , 500)
68 |
69 | }
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/src/stores/blogs.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 | import type { Blog } from '@/types';
5 | import { formatToCurrencyNumber } from '@/utils/locales/format';
6 |
7 | const baseUrl = `${import.meta.env.VITE_API_URL}/blogs`;
8 |
9 |
10 | export const useBlogsStore = defineStore("Blogs", {
11 | state: () => ({
12 | blogs: [] as Array,
13 | loading: false,
14 | filter: '',
15 | pageSize: 10,
16 | currentPage: 1,
17 | blog: {} as Blog
18 | }),
19 | getters: {
20 | filteredData(state): Blog[] {
21 | const filtered = this.blogs.filter(p =>
22 | !this.filter ? true : p.title.toLowerCase().indexOf(this.filter.toLowerCase()) > -1);
23 | const paginated = filtered.slice((state.currentPage - 1) * this.pageSize, state.currentPage *this.pageSize)
24 | return paginated
25 |
26 | },
27 | totalPages(): number {
28 | return Math.ceil(this.blogs.length / this.pageSize);
29 | },
30 | totalCount(): number {
31 | return this.blogs.length
32 | }
33 | },
34 | actions: {
35 | async getAll() {
36 | this.loading = true;
37 | this.blogs = await fetchWrapper.get(baseUrl)
38 | this.loading = false;
39 | },
40 | async delteBlog(id: string) {
41 | const res = await fetchWrapper.delete(`${baseUrl}/${id}`)
42 | if (res.error) {
43 | console.log(res.error)
44 | }
45 | return res
46 | },
47 | async getBlogById(id: string) {
48 | this.loading = true
49 | const c = await fetchWrapper.get(`${baseUrl}/${id}`)
50 | this.blog = { ...c,
51 | price: formatToCurrencyNumber(c.price),
52 | retailPrice: formatToCurrencyNumber(c.retailPrice*1.1),
53 | }
54 | this.loading = false
55 | },
56 | async saveBlog(blog: Blog) {
57 | let res
58 | if (blog.id)
59 | res = await fetchWrapper.put(`${baseUrl}/${blog.id}`, blog)
60 | else
61 | res = await fetchWrapper.post(`${baseUrl}`, blog)
62 | return res
63 |
64 | }
65 | }
66 | });
67 |
--------------------------------------------------------------------------------
/src/stores/orders.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 | import { ThreedCubeSphereIcon } from 'vue-tabler-icons';
5 | import type { Address, Order } from '@/types';
6 |
7 | const baseUrl = `${import.meta.env.VITE_API_URL}/orders`;
8 |
9 |
10 | export const useOrdersStore = defineStore("Orders", {
11 |
12 | state: () => ({
13 | orders: [] as Array,
14 | loading: false,
15 | filter: '',
16 | order: {} as Order
17 | }),
18 | getters: {
19 | filteredData(): Order[] {
20 | return this.orders;
21 | },
22 | getStepVal(): string {
23 | return (['packing','shipping','customs-clearance','delivered']
24 | .findIndex(s=> s===this.order.delivery)+1).toString()
25 | }
26 | },
27 | actions: {
28 | async getAll() {
29 | this.loading = true;
30 | this.orders = await fetchWrapper.get(baseUrl)
31 | this.loading = false;
32 | },
33 | async delteOrder(id: string) {
34 | const res = await fetchWrapper.delete(`${baseUrl}/${id}`)
35 | if (res.error) {
36 | console.log(res.error)
37 | }
38 | return res
39 | },
40 | async getOrderById(id: string) {
41 | this.loading = true
42 | const c = await fetchWrapper.get(`${baseUrl}/${id}`)
43 | this.order = c
44 | this.loading = false
45 | },
46 | async saveOrder(order: Order) {
47 | let res
48 | if (order.id)
49 | res = await fetchWrapper.put(`${baseUrl}/${order.id}`, order)
50 | else
51 | res = await fetchWrapper.post(`${baseUrl}`, order)
52 | return res
53 | },
54 | async newOrder() {
55 | this.loading = true
56 | setTimeout(() => {
57 | this.order = {
58 | id: '',
59 | reference: '',
60 | customer: '',
61 | lineItems: [],
62 | amount: 0,
63 | billingDate: '',
64 | shippingDate: '',
65 | shippingAddress: {} as Address,
66 | delivery: '',
67 | }
68 | this.loading = false
69 | }
70 | , 500)
71 |
72 | }
73 | }
74 | });
75 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/TotalEarning.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | {{ item.title }}
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | $500.00
42 |
43 | Total Earning
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/TransactionHistory.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
{{ history.title }}
48 | {{ history.subtitle }}
49 |
50 |
51 |
{{ history.price }}
52 | {{ history.pricepercent }}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/stores/auth.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 | import { router } from '@/router';
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 | import type { AuthUser } from '@/utils/helpers/fake-backend';
5 |
6 | const baseUrl = `${import.meta.env.VITE_API_URL}/users`;
7 |
8 | export const useAuthStore = defineStore({
9 | id: 'auth',
10 | state: () => ({
11 | // initialize state from local storage to enable user to stay logged in
12 | /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
13 | // @ts-ignore
14 | user: JSON.parse(localStorage.getItem('user')),
15 | returnUrl: null,
16 | loading: false,
17 |
18 | }),
19 | actions: {
20 | async login(username: string, password: string) {
21 | const user = await fetchWrapper.post(`${baseUrl}/authenticate`, { username, password });
22 |
23 | // update pinia state
24 | this.user = user;
25 | // store user details and jwt in local storage to keep user logged in between page refreshes
26 | localStorage.setItem('user', JSON.stringify(user));
27 | // redirect to previous url or default to home page
28 | router.push(this.returnUrl || '/dashboard');
29 | },
30 | async register(username: string, password: string) {
31 | const user = await fetchWrapper.post(`${baseUrl}/authenticate`, { username, password });
32 |
33 | // update pinia state
34 | this.user = user;
35 | // store user details and jwt in local storage to keep user logged in between page refreshes
36 | localStorage.setItem('user', JSON.stringify(user));
37 | // redirect to previous url or default to home page
38 | router.push(this.returnUrl || '/dashboard');
39 | },
40 | logout() {
41 | this.user = null;
42 | localStorage.removeItem('user');
43 | router.push('/login');
44 | },
45 | isAuthenticated() {
46 | this.loading = true
47 | /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
48 | // @ts-ignore
49 | const user = JSON.parse(localStorage.getItem('user')) as AuthUser
50 | this.loading = false
51 | return user && user.id && user.username? true:false
52 |
53 | }
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/WidgetFive.vue:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
{{ card5.name }}
51 |
52 | {{ card5.earn }}
53 |
54 |
55 |
56 |
57 | {{ card5.percent }}
58 |
59 |
60 | You made an extra {{ card5.text }} this year
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-sidebar/sidebarItem.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CircleIcon,
3 | WindmillIcon,
4 | TypographyIcon,
5 | ShadowIcon,
6 | PaletteIcon,
7 | KeyIcon,
8 | BugIcon,
9 | DashboardIcon,
10 | BrandChromeIcon,
11 | Stack3Icon,
12 | UsersIcon,
13 | HelpIcon,
14 | TruckDeliveryIcon,
15 | ArticleIcon,
16 | TemplateIcon,
17 | UserDollarIcon
18 | } from 'vue-tabler-icons';
19 |
20 | export interface menu {
21 | header?: string;
22 | title?: string;
23 | icon?: object;
24 | to?: string;
25 | divider?: boolean;
26 | chip?: string;
27 | chipColor?: string;
28 | chipVariant?: string;
29 | chipIcon?: string;
30 | children?: menu[];
31 | disabled?: boolean;
32 | type?: string;
33 | subCaption?: string;
34 | }
35 |
36 | const sidebarItem: menu[] = [
37 | { header: 'Home' },
38 | {
39 | title: 'Dashboard',
40 | icon: DashboardIcon,
41 | to: '/dashboard'
42 | },
43 | {
44 | title: 'Customer',
45 | icon: UsersIcon,
46 | to: '/customer'
47 | },
48 | {
49 | title: 'Product',
50 | icon: Stack3Icon,
51 | to: '/product'
52 | },
53 | {
54 | title: 'Order',
55 | icon: TruckDeliveryIcon,
56 | to: '/order'
57 | },
58 | { divider: true },
59 | { header: 'Marketing' }
60 | ,
61 | {
62 | title: 'Blog',
63 | icon: TemplateIcon,
64 | to: '/blog'
65 | },
66 |
67 | // { divider: true },
68 | // { header: 'Utilities' },
69 | // {
70 | // title: 'Typography',
71 | // icon: TypographyIcon,
72 | // to: '/utils/typography'
73 | // },
74 | // {
75 | // title: 'Shadows',
76 | // icon: ShadowIcon,
77 | // to: '/utils/shadows'
78 | // },
79 | // {
80 | // title: 'Colors',
81 | // icon: PaletteIcon,
82 | // to: '/utils/colors'
83 | // },
84 |
85 | // {
86 | // title: 'Icons',
87 | // icon: WindmillIcon,
88 | // to: '/forms/radio',
89 | // children: [
90 | // {
91 | // title: 'Tabler Icons',
92 | // icon: CircleIcon,
93 | // to: '/icons/tabler'
94 | // },
95 | // {
96 | // title: 'Material Icons',
97 | // icon: CircleIcon,
98 | // to: '/icons/material'
99 | // }
100 | // ]
101 | // }
102 | ];
103 |
104 | export default sidebarItem;
105 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/AnalyticsReport.vue:
--------------------------------------------------------------------------------
1 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
{{ item.name }}
92 | {{ item.percent }}
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/src/scss/layout/_container.scss:
--------------------------------------------------------------------------------
1 | html {
2 | overflow-y: auto;
3 | }
4 | .v-main {
5 | margin-right: 20px;
6 | }
7 | @media (max-width: 1279px) {
8 | .v-main {
9 | margin: 0 10px;
10 | }
11 | }
12 | .spacer {
13 | padding: 100px 0;
14 | }
15 | @media (max-width: 800px) {
16 | .spacer {
17 | padding: 40px 0;
18 | }
19 | }
20 |
21 | .page-wrapper {
22 | // min-height: calc(100vh - 100px);
23 | min-height: calc(100vh - 150px);
24 | padding: 15px;
25 | border-radius: $border-radius-root;
26 | background: rgb(var(--v-theme-containerBg));
27 | }
28 | $sizes: (
29 | 'display-1': 44px,
30 | 'display-2': 40px,
31 | 'display-3': 30px,
32 | 'h1': 36px,
33 | 'h2': 30px,
34 | 'h3': 21px,
35 | 'h4': 18px,
36 | 'h5': 16px,
37 | 'h6': 14px,
38 | 'text-8': 8px,
39 | 'text-10': 10px,
40 | 'text-13': 13px,
41 | 'text-18': 18px,
42 | 'text-20': 20px,
43 | 'text-24': 24px,
44 | 'body-text-1': 10px
45 | );
46 |
47 | @each $pixel, $size in $sizes {
48 | .#{$pixel} {
49 | font-size: $size;
50 | line-height: $size + 10;
51 | }
52 | }
53 |
54 | .customizer-btn {
55 | position: fixed;
56 | top: 25%;
57 | right: 10px;
58 | border-radius: 50% 50% 4px;
59 | .icon {
60 | animation: progress-circular-rotate 1.4s linear infinite;
61 | transform-origin: center center;
62 | transition: all 0.2s ease-in-out;
63 | }
64 | }
65 |
66 | .text-white {
67 | color: rgb(255, 255, 255) !important;
68 | }
69 |
70 | // font family
71 |
72 | body {
73 | .Poppins {
74 | font-family: 'Poppins', sans-serif !important;
75 | }
76 |
77 | .Inter {
78 | font-family: 'Inter', sans-serif !important;
79 | }
80 | }
81 |
82 | @keyframes blink {
83 | 50% {
84 | opacity: 0;
85 | }
86 | 100% {
87 | opacity: 1;
88 | }
89 | }
90 | @keyframes bounce {
91 | 0%,
92 | 20%,
93 | 53%,
94 | to {
95 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
96 | transform: translateZ(0);
97 | }
98 | 40%,
99 | 43% {
100 | animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
101 | transform: translate3d(0, -5px, 0);
102 | }
103 | 70% {
104 | animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
105 | transform: translate3d(0, -7px, 0);
106 | }
107 | 80% {
108 | transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
109 | transform: translateZ(0);
110 | }
111 | 90% {
112 | transform: translate3d(0, -2px, 0);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/types.d.ts:
--------------------------------------------------------------------------------
1 | export interface Entity {
2 | id: number;
3 | text?: string;
4 | value?: number;
5 | }
6 |
7 | export interface Category extends Entity {
8 | categoryName: string;
9 | parentId: string;
10 | }
11 |
12 | export interface UserInfo extends Entity {
13 | messages: string[];
14 | notifications: string[];
15 | tasks: string[];
16 | }
17 |
18 | export interface User {//extends Entity {
19 | id: string;
20 | firstname: string;
21 | lastname: string;
22 | email: string;
23 | avatar: string;
24 | mobile: string;
25 | homephone: string;
26 | workphone: string;
27 | }
28 |
29 | export interface Customer {
30 | id: string;
31 | firstname: string;
32 | lastname: string;
33 | fullname: string;
34 | email: string;
35 | avatar: string;
36 | mobile: string;
37 | phone: string;
38 | membership: string;
39 | rewards: 0;
40 | hasItemInShoppingCart: false
41 | }
42 |
43 | export interface Address {
44 | street: string;
45 | city: string;
46 | zipcode: string;
47 | country: string;
48 | }
49 |
50 | export interface Order {
51 | id: string;
52 | reference: string;
53 | customer: string;
54 | lineItems: Product[];
55 | amount: number;
56 | billingDate: string;
57 | shippingDate: string;
58 | shippingAddress: Address;
59 | delivery: string;
60 | }
61 |
62 | export interface Product {
63 | id: string;
64 | name: string;
65 | category: string;
66 | unitInStock: string;
67 | price: number;
68 | retailPrice: number;
69 | colors?: [];
70 | imageUri?: string;
71 | releaseDate?: string;
72 | status?: string
73 | }
74 |
75 | export interface State {
76 | items: Entity[];
77 | pagination: Pagination;
78 | loading: boolean;
79 | mode: string;
80 | snackbar: boolean;
81 | notice: string;
82 | customer: Customer;
83 | orders: Order[];
84 | orderList: Order[];
85 | }
86 |
87 |
88 | export type SearchFilter = {
89 | equal?: TODO,
90 | contain?: TODO,
91 | startsWith?: TODO,
92 | endsWith?: TODO,
93 | lessThan?: TODO,
94 | greaterThan?: TODO,
95 | lessThanOrEqual?: TODO,
96 | greaterThanOrEqual?: TODO,
97 | filters?: TODO
98 |
99 | }
100 |
101 | export interface Blog {
102 | id: string;
103 | title: string;
104 | description: string;
105 | coverUrl: string;
106 | totalViews: string;
107 | totalComments:string;
108 | totalShares: string;
109 | totalFavorites: string;
110 | postedAt: string;
111 | author: {
112 | name: string;
113 | avatar: string;
114 | },
115 | }
--------------------------------------------------------------------------------
/src/stores/products.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | import { fetchWrapper } from '@/utils/helpers/fetch-wrapper';
4 | import type { Product } from '@/types';
5 | import { formatToCurrencyNumber } from '@/utils/locales/format';
6 |
7 | const baseUrl = `${import.meta.env.VITE_API_URL}/products`;
8 |
9 |
10 |
11 | export const useProductsStore = defineStore("Products", {
12 | state: () => ({
13 | products: [] as Array,
14 | loading: false,
15 | filter: '',
16 | pageSize: 10,
17 | currentPage: 1,
18 | product: {} as Product
19 | }),
20 | getters: {
21 | filteredData(state): Product[] {
22 | const filtered = this.products.filter(p =>
23 | !this.filter ? true : p.name.toLowerCase().indexOf(this.filter.toLowerCase()) > -1);
24 | const paginated = filtered.slice((state.currentPage - 1) * this.pageSize, state.currentPage * this.pageSize)
25 | return paginated
26 |
27 | },
28 | totalPages(): number {
29 | return Math.ceil(this.products.length / this.pageSize);
30 | },
31 | totalCount(): number {
32 | return this.products.length
33 | }
34 | },
35 | actions: {
36 | async getAll() {
37 | this.loading = true;
38 | const list = await fetchWrapper.get(baseUrl)
39 | this.products = list
40 | this.loading = false;
41 | },
42 | async delteProduct(id: string) {
43 | const res = await fetchWrapper.delete(`${baseUrl}/${id}`)
44 | if (res.error) {
45 | console.log(res.error)
46 | }
47 | return res
48 | },
49 | async getProductById(id: string) {
50 | this.loading = true
51 | const c = await fetchWrapper.get(`${baseUrl}/${id}`)
52 | this.product = {
53 | ...c,
54 | price: formatToCurrencyNumber(c.price),
55 | retailPrice: formatToCurrencyNumber(c.price * 1.1),
56 | }
57 | this.loading = false
58 | },
59 | async saveProduct(product: Product) {
60 | let res
61 | if (product.id)
62 | res = await fetchWrapper.put(`${baseUrl}/${product.id}`, product)
63 | else
64 | res = await fetchWrapper.post(`${baseUrl}`, product)
65 | return res
66 | },
67 | async newProduct() {
68 | this.loading = true
69 | setTimeout(() => {
70 | this.product = {
71 | id: '',
72 | name: '',
73 | category: '',
74 | unitInStock: '',
75 | price: 0,
76 | retailPrice: 0,
77 | // category: Category,
78 | imageUri: '',
79 | releaseDate: ''
80 | }
81 | this.loading = false
82 | }
83 | , 500)
84 |
85 | }
86 | }
87 | });
88 |
--------------------------------------------------------------------------------
/src/assets/images/maintenance/img-error-text.svg:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/src/views/dashboards/Dashboard.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-header/ProfileDD.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Good Morning, John Doe
17 |
Project admin
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
Start DND Mode
33 |
34 |
35 |
36 |
37 |
38 |
Allow Notifications
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Account Settings
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Social Profile
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Logout
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/scss/layout/_sidebar.scss:
--------------------------------------------------------------------------------
1 | /*This is for the logo*/
2 | .leftSidebar {
3 | border: 0px;
4 | box-shadow: none !important;
5 | .logo {
6 | padding-left: 7px;
7 | }
8 | }
9 | /*This is for the Vertical sidebar*/
10 | .scrollnavbar {
11 | height: calc(100vh - 100px);
12 | .smallCap {
13 | padding: 0px 0 0 4px !important;
14 | font-size: 0.875rem;
15 | font-weight: 500;
16 | }
17 | .v-list {
18 | color: rgb(var(--v-theme-lightText));
19 | }
20 | /*General Menu css*/
21 | .v-list-group__items .v-list-item,
22 | .v-list-item {
23 | border-radius: $border-radius-root;
24 | padding-inline-start: calc(12px + var(--indent-padding) / 2) !important;
25 | &:hover {
26 | color: rgb(var(--v-theme-secondary));
27 | }
28 | .v-list-item__prepend {
29 | margin-inline-end: 13px;
30 | }
31 | .v-list-item__append {
32 | font-size: 0.875rem;
33 | .v-icon {
34 | margin-inline-start: 13px;
35 | }
36 | }
37 | .v-list-item-title {
38 | font-size: 0.875rem;
39 | }
40 | }
41 | .v-list-group__items .v-list-item {
42 | margin-inline-start: calc(2px + var(--indent-padding) / 2);
43 | padding-inline-start: 16px !important;
44 | }
45 | .leftPadding {
46 | margin-left: 4px;
47 | }
48 | /*This is for the dropdown*/
49 | .v-list {
50 | .v-list-item--active {
51 | .v-list-item-title {
52 | font-weight: 500;
53 | }
54 | }
55 | .sidebarchip .v-icon {
56 | margin-inline-start: -3px;
57 | }
58 | .v-list-group {
59 | .v-list-item:hover > .v-list-item__overlay,
60 | .v-list-item--active > .v-list-item__overlay {
61 | background-color: transparent;
62 | }
63 | .v-list-item:focus-visible > .v-list-item__overlay {
64 | opacity: 0;
65 | }
66 | }
67 | > .v-list-group {
68 | position: relative;
69 | > .v-list-item--active,
70 | > .v-list-item:hover {
71 | background: rgb(var(--v-theme-secondary), 0.05);
72 | }
73 |
74 | &:after {
75 | content: '';
76 | position: absolute;
77 | left: 21px;
78 | top: 46px;
79 | height: calc(100% - 46px);
80 | width: 1px;
81 | opacity: 1;
82 | background: rgb(var(--v-theme-primary), 0.15);
83 | }
84 | }
85 | }
86 | }
87 | .v-navigation-drawer--rail {
88 | .scrollnavbar .v-list .v-list-group__items,
89 | .hide-menu {
90 | opacity: 0;
91 | }
92 | .leftPadding {
93 | margin-left: 0px;
94 | }
95 | }
96 | @media only screen and (min-width: 1170px) {
97 | .mini-sidebar {
98 | .logo {
99 | width: 40px;
100 | overflow: hidden;
101 | }
102 | .leftSidebar:hover {
103 | box-shadow: $box-shadow !important;
104 | }
105 | .v-navigation-drawer--expand-on-hover:hover {
106 | .logo {
107 | width: 100%;
108 | }
109 | .v-list .v-list-group__items,
110 | .hide-menu {
111 | opacity: 1;
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/router/MainRoutes.ts:
--------------------------------------------------------------------------------
1 | const MainRoutes = {
2 | path: '/main',
3 | meta: {
4 | requiresAuth: true
5 | },
6 | redirect: '/main/dashboard',
7 | component: () => import('@/layouts/full/FullLayout.vue'),
8 | children: [
9 | {
10 | name: 'LandingPage',
11 | path: '/',
12 | component: () => import('@/views/dashboards/Dashboard.vue')
13 | },
14 | {
15 | name: 'Dashboard',
16 | path: '/dashboard',
17 | component: () => import('@/views/dashboards/Dashboard.vue')
18 | },
19 | {
20 | name: 'Customer',
21 | path: '/customer',
22 | component: () => import('@/views/pages/CustomerView.vue')
23 | },
24 | {
25 | name: 'Edit Customer',
26 | path: '/customer/:id',
27 | component: () => import('@/views/pages/CustomerForm.vue')
28 | },
29 |
30 | {
31 | name: 'New Customer',
32 | path: '/customer/new',
33 | component: () => import('@/views/pages/CustomerForm.vue')
34 | },
35 | {
36 | name: 'Product',
37 | path: '/product',
38 | component: () => import('@/views/pages/ProductView.vue')
39 | },
40 | {
41 | name: 'Edit Product',
42 | path: '/product/:id',
43 | component: () => import('@/views/pages/ProductForm.vue')
44 | },
45 |
46 | {
47 | name: 'New Product',
48 | path: '/product/new',
49 | component: () => import('@/views/pages/ProductForm.vue')
50 | },
51 | {
52 | name: 'Order',
53 | path: '/order',
54 | component: () => import('@/views/pages/OrderView.vue')
55 | },
56 | {
57 | name: 'Edit Order',
58 | path: '/order/:id',
59 | component: () => import('@/views/pages/OrderForm.vue')
60 | },
61 |
62 | {
63 | name: 'New Order',
64 | path: '/order/new',
65 | component: () => import('@/views/pages/OrderForm.vue')
66 | },
67 | {
68 | name: 'Blog',
69 | path: '/blog',
70 | component: () => import('@/views/pages/BlogView.vue')
71 | },
72 | {
73 | name: 'Error 404',
74 | path: '/error',
75 | component: () => import('@/views/pages/maintenance/error/Error404Page.vue')
76 | }
77 | // ,
78 | // {
79 | // name: 'Tabler Icons',
80 | // path: '/icons/tabler',
81 | // component: () => import('@/views/utilities/icons/TablerIcons.vue')
82 | // },
83 | // {
84 | // name: 'Material Icons',
85 | // path: '/icons/material',
86 | // component: () => import('@/views/utilities/icons/MaterialIcons.vue')
87 | // },
88 | // {
89 | // name: 'Typography',
90 | // path: '/utils/typography',
91 | // component: () => import('@/views/utilities/typography/TypographyPage.vue')
92 | // },
93 | // {
94 | // name: 'Shadows',
95 | // path: '/utils/shadows',
96 | // component: () => import('@/views/utilities/shadows/ShadowPage.vue')
97 | // },
98 | // {
99 | // name: 'Colors',
100 | // path: '/utils/colors',
101 | // component: () => import('@/views/utilities/colors/ColorPage.vue')
102 | // },
103 | ]
104 | };
105 |
106 | export default MainRoutes;
107 |
--------------------------------------------------------------------------------
/src/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:math';
2 | @use 'sass:map';
3 | @use 'sass:meta';
4 | @use 'vuetify/lib/styles/tools/functions' as *;
5 |
6 | // This will false all colors which is not necessory for theme
7 | $color-pack: false;
8 |
9 | // Global font size and border radius
10 | $font-size-root: 1rem;
11 | $border-radius-root: 12px;
12 | $body-font-family: 'Roboto', sans-serif !default;
13 | $heading-font-family: $body-font-family !default;
14 | $btn-font-weight: 400 !default;
15 | $btn-letter-spacing: 0 !default;
16 |
17 | // Global Radius as per breakeven point
18 | $rounded: () !default;
19 | $rounded: map-deep-merge(
20 | (
21 | 0: 0,
22 | 'sm': $border-radius-root * 0.5,
23 | null: $border-radius-root,
24 | 'md': $border-radius-root * 1,
25 | 'lg': $border-radius-root * 2,
26 | 'xl': $border-radius-root * 6,
27 | 'pill': 9999px,
28 | 'circle': 50%,
29 | 'shaped': $border-radius-root * 6 0
30 | ),
31 | $rounded
32 | );
33 | // Global Typography
34 | $typography: () !default;
35 | $typography: map-deep-merge(
36 | (
37 | 'h1': (
38 | 'size': 2.125rem,
39 | 'weight': 700,
40 | 'line-height': 3.5rem,
41 | 'font-family': inherit
42 | ),
43 | 'h2': (
44 | 'size': 1.5rem,
45 | 'weight': 700,
46 | 'line-height': 2.5rem,
47 | 'font-family': inherit
48 | ),
49 | 'h3': (
50 | 'size': 1.25rem,
51 | 'weight': 600,
52 | 'line-height': 2rem,
53 | 'font-family': inherit
54 | ),
55 | 'h4': (
56 | 'size': 1rem,
57 | 'weight': 600,
58 | 'line-height': 1.5rem,
59 | 'font-family': inherit
60 | ),
61 | 'h5': (
62 | 'size': 0.875rem,
63 | 'weight': 500,
64 | 'line-height': 1.2rem,
65 | 'font-family': inherit
66 | ),
67 | 'h6': (
68 | 'size': 0.75rem,
69 | 'weight': 500,
70 | 'font-family': inherit
71 | ),
72 | 'subtitle-1': (
73 | 'size': 0.875rem,
74 | 'weight': 500,
75 | 'line-height': 1rem,
76 | 'font-family': inherit
77 | ),
78 | 'subtitle-2': (
79 | 'size': 0.75rem,
80 | 'weight': 400,
81 | 'line-height': 1rem,
82 | 'font-family': inherit
83 | ),
84 | 'body-1': (
85 | 'size': 0.875rem,
86 | 'weight': 400,
87 | 'font-family': inherit
88 | ),
89 | 'body-2': (
90 | 'size': 0.75rem,
91 | 'weight': 400,
92 | 'font-family': inherit
93 | ),
94 | 'button': (
95 | 'size': 0.875rem,
96 | 'weight': 500,
97 | 'font-family': inherit,
98 | 'text-transform': uppercase
99 | ),
100 | 'caption': (
101 | 'size': 0.75rem,
102 | 'weight': 400,
103 | 'font-family': inherit
104 | ),
105 | 'overline': (
106 | 'size': 0.75rem,
107 | 'weight': 500,
108 | 'font-family': inherit,
109 | 'text-transform': uppercase
110 | )
111 | ),
112 | $typography
113 | );
114 |
115 | // Custom Variables
116 | // colors
117 | $white: #fff !default;
118 |
119 | // cards
120 | $card-item-spacer-xy: 20px 24px !default;
121 | $card-text-spacer: 24px !default;
122 | $card-title-size: 18px !default;
123 | // Global Shadow
124 | $box-shadow: 1px 0 20px rgb(0 0 0 / 8%);
125 |
--------------------------------------------------------------------------------
/src/assets/images/maintenance/img-error-purple.svg:
--------------------------------------------------------------------------------
1 |
43 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/TotalGrowth.vue:
--------------------------------------------------------------------------------
1 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | Total Growth
107 | $2,324.00
108 |
109 |
110 |
123 |
124 |
125 |
126 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/src/views/utilities/typography/TypographyPage.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | {{ name }}
46 |
47 |
Class
48 |
{{ cls }}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
Left aligned on all viewport sizes.
56 |
Center aligned on all viewport sizes.
57 |
Right aligned on all viewport sizes.
58 |
59 |
Left aligned on viewports SM (small) or wider.
60 |
Left aligned on viewports MD (medium) or wider.
61 |
Left aligned on viewports LG (large) or wider.
62 |
Left aligned on viewports XL (extra-large) or wider.
63 |
64 |
65 |
66 |
67 |
Non-underlined link
68 |
69 |
Line-through text
70 |
71 |
Overline text
72 |
73 |
Underline text
74 |
75 |
76 |
77 |
78 |
High-emphasis has an opacity of 87% in light theme and 100% in dark.
79 |
Medium-emphasis text and hint text have opacities of 60% in light theme and 70% in dark.
80 |
Disabled text has an opacity of 38% in light theme and 50% in dark.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 11# Vue Demo App V3
2 |
3 | > A reusable Vue.js starter project for real-world business based on Vue 3 with Vuetify 3 and Pinia.
4 |
5 | The goal of this project is to build a reusable starter project for real-world business. To achieve this target, we need a solution which includes state management (Pinia), fake restful API and elegant UI design (Vuetify).
6 |
7 |
8 | ### Live Demo
9 |
10 | [Latest Demo App](https://vue-app-demo.harryho.org?timestamp=v3): The demo is just a proof of concept. It doesn't have back-end API and all features of master branch.
11 |
12 | [Previous version Demo App](https://vue-demo-v2.harryho.org?timestamp=v2): The demo is just a proof of concept. It doesn't have back-end API and all features of master branch. Source code is availabe on a different [branch](https://github.com/harryho/vue-crm/tree/v2-vtf2)
13 |
14 |
15 | ### Screenshots
16 |
17 | #### Latest Version
18 | 
19 |
20 |
21 | 
22 |
23 | 
24 |
25 |
26 |
27 | #### Previous Version
28 |
29 |
30 | 
31 |
32 | 
33 |
34 |
37 |
38 | ## Build Setup
39 |
40 | ``` bash
41 |
42 | # Clone project
43 | git clone https://github.com/harryho/vue-crm.git
44 |
45 |
46 | # install dependences for Vue 2 CRM
47 | cd vue-crm
48 | npm install
49 |
50 |
51 | # serve with hot reload at localhost:8080
52 | npm run dev
53 |
54 |
55 | ```
56 |
57 | ## Docker
58 |
59 |
60 | ```bash
61 | ## Run / Test release without building new image
62 | npm run build
63 |
64 | # Launch nginx image to test latest release
65 | docker pull nginx:alpine
66 | docker run -p 8080:80 -v \
67 | /dist:/usr/share/nginx/html nginx:alpine
68 |
69 |
70 | # Build release image
71 | docker build . -t vue-demo:3.0
72 |
73 | # Launch the development image in the backgroud
74 | docker run --rm -d --publish 8080:80 --name vd3 vue-demo:3.0
75 |
76 | # Check the log
77 | docker logs vd3 -f
78 |
79 | ```
80 |
81 |
82 | For detailed explanation on how things work, checkout following links
83 |
84 | * [vue](https://vuex.vuejs.org/en/)
85 | * [vuetifyjs](https://dev.vuetifyjs.com/)
86 | * [Pinia](https://pinia.vuejs.org/)
87 |
88 |
89 | #### Change log
90 |
91 | * Mar 2025 - Uplift to Vue 3 + Vuetify 3 + Pinia is done.
92 |
93 | * Dec 2024 - Uplift to Vue 3 + Vuetify 3
94 |
95 | * 2 May 2020 - Merge the branch vuetify-ts to master
96 |
97 | After the merge, the whole project moved to new techncial stack - TypeScript. Also, the VuetifyJs is upgraded to 2.x version.
98 |
99 |
100 | * 6 Dec 2018 - Create an archived branch json-server
101 |
102 | This branch was the master which used Json-Server as fake API. Considering the hiccup of setting Json-Server up and maintenance, it will be replaced by fake service ( Readonly fake API). You still can find and clone this branch with the name __json-server__, but it is no longer updated. It is an archived branch.
103 |
104 |
105 | * 27 May 2018 - Rebase demo branch to master
106 |
107 | New master doesn't rely on Json-Server as fake API. It will only have Readonly fake API. It means any new or updated data will be stored to any physical file. All test data will be rolled back after system restart.
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/scss/pages/_dashboards.scss:
--------------------------------------------------------------------------------
1 | .bubble-shape {
2 | position: relative;
3 | &:before {
4 | content: '';
5 | position: absolute;
6 | width: 210px;
7 | height: 210px;
8 | border-radius: 50%;
9 | top: -125px;
10 | right: -15px;
11 | opacity: 0.5;
12 | }
13 | &:after {
14 | content: '';
15 | position: absolute;
16 | width: 210px;
17 | height: 210px;
18 | border-radius: 50%;
19 | top: -85px;
20 | right: -95px;
21 | }
22 |
23 | &.bubble-primary-shape {
24 | &::before {
25 | background: rgb(var(--v-theme-darkprimary));
26 | }
27 | &::after {
28 | background: rgb(var(--v-theme-darkprimary));
29 | }
30 | }
31 |
32 | &.bubble-secondary-shape {
33 | &::before {
34 | background: rgb(var(--v-theme-darksecondary));
35 | }
36 | &::after {
37 | background: rgb(var(--v-theme-darksecondary));
38 | }
39 | }
40 | }
41 |
42 | .z-1 {
43 | z-index: 1;
44 | position: relative;
45 | }
46 | .bubble-shape-sm {
47 | position: relative;
48 | &::before {
49 | content: '';
50 | position: absolute;
51 | width: 210px;
52 | height: 210px;
53 | border-radius: 50%;
54 | top: -160px;
55 | right: -130px;
56 | }
57 | &.bubble-primary {
58 | &::before {
59 | background: linear-gradient(140.9deg, rgb(var(--v-theme-lightprimary)) -14.02%, rgba(var(--v-theme-darkprimary), 0) 77.58%);
60 | }
61 | }
62 | &::after {
63 | content: '';
64 | position: absolute;
65 | width: 210px;
66 | height: 210px;
67 | border-radius: 50%;
68 | top: -30px;
69 | right: -180px;
70 | }
71 | &.bubble-primary {
72 | &::after {
73 | background: linear-gradient(210.04deg, rgb(var(--v-theme-lightprimary)) -50.94%, rgba(var(--v-theme-darkprimary), 0) 83.49%);
74 | }
75 | }
76 |
77 | &.bubble-warning {
78 | &::before {
79 | background: linear-gradient(140.9deg, rgb(var(--v-theme-warning)) -14.02%, rgba(144, 202, 249, 0) 70.5%);
80 | }
81 | }
82 |
83 | &.bubble-warning {
84 | &::after {
85 | background: linear-gradient(210.04deg, rgb(var(--v-theme-warning)) -50.94%, rgba(144, 202, 249, 0) 83.49%);
86 | }
87 | }
88 | }
89 |
90 | .rounded-square {
91 | width: 20px;
92 | height: 20px;
93 | }
94 |
95 | .icon-scale {
96 | position: absolute;
97 | left: -17px;
98 | bottom: -27px;
99 | transform: rotate(25deg);
100 | }
101 |
102 | .tabBtn {
103 | .v-btn--variant-outlined:not(.v-tab--selected) {
104 | border: none;
105 | color: rgb(var(--v-theme-lightText));
106 | }
107 | }
108 |
109 | .headerWithBtn {
110 | .v-card-item {
111 | padding: 14px;
112 | }
113 | }
114 |
115 | .widget-gradient {
116 | position: relative;
117 | &::before,
118 | &::after {
119 | content: '';
120 | width: 100%;
121 | height: 100%;
122 | position: absolute;
123 | background: linear-gradient(90deg, rgba(255, 255, 255, 0.0001) 22.07%, rgba(255, 255, 255, 0.15) 83.21%);
124 | transform: matrix(0.9, 0.44, -0.44, 0.9, 0, 0);
125 | }
126 | &:after {
127 | top: 50%;
128 | right: -20px;
129 | }
130 | &::before {
131 | right: -70px;
132 | bottom: 80%;
133 | }
134 | }
135 | .hover-icon-card {
136 | .hover-icon {
137 | transition: 0.5s;
138 | }
139 | &:hover {
140 | .hover-icon {
141 | opacity: 1;
142 | transform: scale(1.2);
143 | transition: 0.5s;
144 | }
145 | }
146 | }
147 | .widget-progress {
148 | .v-progress-linear {
149 | .v-progress-linear__background {
150 | background-color: rgb(var(--v-theme-lightsuccess)) !important;
151 | opacity: 1;
152 | }
153 | }
154 | }
155 | .readMedia {
156 | position: absolute;
157 | bottom: -7px;
158 | right: 0;
159 | width: 182px;
160 | height: 144px;
161 | }
162 |
--------------------------------------------------------------------------------
/src/layouts/full/vertical-header/VerticalHeader.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/RecentOrder.vue:
--------------------------------------------------------------------------------
1 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | | Tracking no. |
86 | Product name |
87 | Total order |
88 | Status |
89 | Total amount |
90 |
91 |
92 |
93 |
94 | |
95 | {{ item.number }}
96 | |
97 | {{ item.name }} |
98 | {{ item.order }} |
99 |
100 |
101 |
102 | Rejected
103 |
104 |
105 |
106 | Approved
107 |
108 |
109 |
110 | Pending
111 |
112 | |
113 | {{ item.amount }} |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/assets/images/maintenance/img-error-bg.svg:
--------------------------------------------------------------------------------
1 |
35 |
--------------------------------------------------------------------------------
/src/views/authentication/authForms/AuthLogin.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 | Sign in with Google
31 |
32 |
33 |
34 | OR
35 |
36 |
37 |
38 | Sign in with Email address
39 |
87 |
88 |
89 | Don't Have an account?
90 |
91 |
92 |
124 |
--------------------------------------------------------------------------------
/src/assets/images/logos/logo.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/logos/logolight.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/views/authentication/authForms/AuthRegister.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 | Sign up with Google
30 |
31 |
32 |
33 | OR
34 |
35 |
36 |
37 | Sign up with Email address
38 |
39 |
40 |
41 |
49 |
50 |
51 |
59 |
60 |
61 |
72 |
86 |
87 |
99 | Sign Up
100 |
101 |
102 |
103 | Already have an account?
104 |
105 |
106 |
133 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/UniqueVisitor.vue:
--------------------------------------------------------------------------------
1 |
131 |
132 |
133 |
134 |
135 |
136 |
Unique Visitor
137 |
138 |
139 | Month
140 | Week
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/TotalOrder.vue:
--------------------------------------------------------------------------------
1 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | Month
133 | Year
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | $108
143 |
144 |
145 |
146 |
147 | Total Order
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | $961
159 |
160 |
161 |
162 |
163 | Total Order
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/src/views/pages/CustomerView.vue:
--------------------------------------------------------------------------------
1 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
92 |
93 |
94 |
95 |
96 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/views/dashboards/components/SalesReport.vue:
--------------------------------------------------------------------------------
1 |
162 |
163 |
164 |
165 |
166 |
167 |
Sales Report
168 |
169 |
178 |
179 |
180 |
181 |
182 |
183 |
Net Profit
184 | $1560
185 |
186 |
187 |
188 |
189 |
190 |
201 |
--------------------------------------------------------------------------------
/src/layouts/full/customizer/CustomizerPanel.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Theme customizer
28 |
29 | Reset
30 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | Font Style
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
Input Background
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
139 |
--------------------------------------------------------------------------------