init git
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Nuxt 3 Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install the dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<NuxtLoadingIndicator />
|
||||||
|
<OverlayPanel ref="popup">
|
||||||
|
<component :is="popup.is" />
|
||||||
|
</OverlayPanel>
|
||||||
|
<Sidebar v-model:visible="sidebar.visible" position="right" class="ml-auto" :showCloseIcon="false">
|
||||||
|
<component :is="sidebar.is" v-bind="sidebar.props" />
|
||||||
|
</Sidebar>
|
||||||
|
<DynamicDialog />
|
||||||
|
<Toast position="bottom-right" class="!rtl" />
|
||||||
|
<Menu ref="menuRef" :model="menu.items" popup />
|
||||||
|
<NuxtPage :page-key="route => route.fullPath" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { t } = useI18n()
|
||||||
|
const popup = ref()
|
||||||
|
const menuRef = ref()
|
||||||
|
const menu = reactive({ ref: menuRef, items: [] })
|
||||||
|
const toast = useToast()
|
||||||
|
const dialog = useDialog()
|
||||||
|
const sidebar = reactive({})
|
||||||
|
|
||||||
|
const { isMobile } = useDevice()
|
||||||
|
const {
|
||||||
|
breakpoint: device = isMobile ? 'mobile' : 'desktop'
|
||||||
|
} = useViewport()
|
||||||
|
|
||||||
|
|
||||||
|
dialog.show = (component, data = {}, props = {}) => dialog.open(component, {
|
||||||
|
props: {
|
||||||
|
modal: true,
|
||||||
|
position: device.value == 'desktop' ? 'center' : 'bottom',
|
||||||
|
closable: false,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
data
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('service', { device, popup, menu, toast, dialog, sidebar, t })
|
||||||
|
|
||||||
|
const categories = useCategoriesStore()
|
||||||
|
categories.get()
|
||||||
|
|
||||||
|
const user = useUserStore()
|
||||||
|
user.get()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.p-toast-message-text {
|
||||||
|
@apply ml-0 mr-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-sidebar {
|
||||||
|
@apply w-max;
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
@apply p-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@import "../fonts/iconsax/style.css";
|
||||||
|
@import "../fonts/poppins/style.css";
|
||||||
|
@import "../fonts/vazir/style.css";
|
||||||
|
@import "../fonts/iransans/style.css";
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
@layer tailwind-base {
|
||||||
|
@tailwind base;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer tailwind-utilities {
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
.ltr {
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-component {
|
||||||
|
@apply !font-vazir ltr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-inputtext,
|
||||||
|
.p-dropdown {
|
||||||
|
@apply !shrink-0 h-14 !rounded-[0.6rem] border-stone-300 !relative !z-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-calendar {
|
||||||
|
@apply w-max;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-password {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-checkbox-box {
|
||||||
|
@apply w-[1.1rem] h-[1.1rem] rounded border border-neutral-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button:not(.p-button-icon-only) {
|
||||||
|
@apply rounded-[0.6rem] h-14;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.p-dropdown-panel {
|
||||||
|
@apply mt-1 !rounded-xl rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-dropdown,
|
||||||
|
.p-inputtextarea {
|
||||||
|
@apply rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-inputtextarea {
|
||||||
|
@apply min-h-[3.5rem] h-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-accordion-header-text {
|
||||||
|
@apply text-[#333333] text-xl font-bold font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-accordion-header .left::before {
|
||||||
|
content: "\e931";
|
||||||
|
}
|
||||||
|
.p-accordion-header .up::before {
|
||||||
|
content: "\e940";
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
@apply w-2 h-2 cursor-pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
@apply bg-[#EBEBEB];
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
@apply bg-[#CDCDCD] hover:bg-neutral-300 rounded-[1.3rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
body.p-overflow-hidden {
|
||||||
|
/* @apply !pr-2; */
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
@apply static;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-monthpicker,
|
||||||
|
.p-yearpicker,
|
||||||
|
.p-datepicker-calendar-container,
|
||||||
|
.p-datepicker-header {
|
||||||
|
@apply rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-datepicker-prev,
|
||||||
|
.p-datepicker-next {
|
||||||
|
@apply rotate-180;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tooltip {
|
||||||
|
@apply rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
body:has(.p-dialog) {
|
||||||
|
@apply overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-blockui {
|
||||||
|
@apply z-[1] !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .p-button.p-button-link:enabled:hover .p-button-label{
|
||||||
|
@apply no-underline;
|
||||||
|
} */
|
||||||
|
|
||||||
|
html {
|
||||||
|
@apply text-[16px];
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-webkit-min-device-pixel-ratio: 1.01 ) and (min-width: 1024px) {
|
||||||
|
html {
|
||||||
|
@apply !text-[12.83px];
|
||||||
|
}
|
||||||
|
}
|
||||||
+10459
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 4.2 MiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,63 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: thin;
|
||||||
|
font-weight: 100;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Thin.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: 'ultra-light';
|
||||||
|
font-weight: 200;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-UltraLight.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: light;
|
||||||
|
font-weight: 300;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Light.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: medium;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Medium.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: 'semi-bold';
|
||||||
|
font-weight: 600;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-SemiBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: bold;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Bold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: 'extra-bold';
|
||||||
|
font-weight: 800;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-ExtraBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iran-sans';
|
||||||
|
font-style: black;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url('~/assets/fonts/iransans/IRANSansX-Black.ttf') format('truetype');
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,125 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: thin;
|
||||||
|
font-weight: 100;
|
||||||
|
src: url('Poppins-Thin.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
src: url('Poppins-ThinItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: 'extra-light';
|
||||||
|
font-weight: 200;
|
||||||
|
src: url('Poppins-ExtraLight.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
src: url('Poppins-ExtraLightItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: light;
|
||||||
|
font-weight: 300;
|
||||||
|
src: url('Poppins-Light.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
src: url('Poppins-LightItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('Poppins-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('Poppins-Italic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: medium;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('Poppins-Medium.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('Poppins-MediumItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: 'semi-bold';
|
||||||
|
font-weight: 600;
|
||||||
|
src: url('Poppins-SemiBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
src: url('Poppins-SemiBoldItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: bold;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url('Poppins-Bold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url('Poppins-BoldItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: 'extra-bold';
|
||||||
|
font-weight: 800;
|
||||||
|
src: url('Poppins-ExtraBold.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
src: url('Poppins-ExtraBoldItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: black;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url('Poppins-Black.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'poppins';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url('Poppins-BlackItalic.ttf') format('truetype');
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,65 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: thin;
|
||||||
|
font-weight: 100;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Thin-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Thin-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Thin-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Thin-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Thin-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Light-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Light-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Light-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Light-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Light-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Regular-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Regular-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Regular-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Regular-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Regular-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: medium;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Medium-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Medium-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Medium-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Medium-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Medium-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: bold;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Bold-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Bold-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Bold-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Bold-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Bold-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'vazir';
|
||||||
|
font-style: black;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Black-FD.eot');
|
||||||
|
src: url('~/assets/fonts/vazir/Vazir-Black-FD.eot') format('embedded-opentype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Black-FD.ttf') format('truetype'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Black-FD.woff') format('woff'),
|
||||||
|
url('~/assets/fonts/vazir/Vazir-Black-FD.woff2') format('woff2');
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<section class="breadcrumbs">
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, i) in items" :key="i">
|
||||||
|
<router-link :to="item.link">
|
||||||
|
{{ item.name }}
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({ items: { type: Array, default: [] } });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.breadcrumbs {
|
||||||
|
@apply w-full flex max-lg:px-6;
|
||||||
|
|
||||||
|
div {
|
||||||
|
@apply overflow-x-auto h-max;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar{
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
@apply flex items-center gap-3.5 lg:gap-6 w-max;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply relative text-[0.7em] lg:text-[1.1em];
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply text-[#999999] font-bold font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child)::after {
|
||||||
|
@apply content-['/'] absolute -left-2 lg:-left-3.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child a {
|
||||||
|
@apply text-[#666666];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<ul v-if="pages > 1" class="pagination">
|
||||||
|
<li v-for="i in [-1, 1]" :key="i">
|
||||||
|
<router-link
|
||||||
|
:to="{ query: { ...$route.query, page: page + i } }"
|
||||||
|
:class="{ 'pointer-events-none': page + i < 1 || page + i > pages }"
|
||||||
|
>
|
||||||
|
<Button :icon="getIcon(i)" link />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-for="(item, i) in items" :key="i" :style="{ order: i + 2 }">
|
||||||
|
<router-link
|
||||||
|
:to="{ query: { ...$route.query, page: item } }"
|
||||||
|
:class="{ 'pointer-events-none': item == page }"
|
||||||
|
>
|
||||||
|
<Button :label="item" link :disabled="item == page" />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li v-show="pages > 5" :style="{ order: pages / 2 > page ? 6 : 2 }">
|
||||||
|
<span>...</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(['pages'])
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const page = computed(() => +(route.query.page || 1))
|
||||||
|
|
||||||
|
const items = ref([])
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
items.value = [page.value]
|
||||||
|
let temp = 1
|
||||||
|
while (items.value.length < 5) {
|
||||||
|
if (page.value - temp > 0) items.value.unshift(page.value - temp)
|
||||||
|
if (page.value + temp <= props.pages) items.value.push(page.value + temp)
|
||||||
|
temp++
|
||||||
|
if (temp > 10) break
|
||||||
|
}
|
||||||
|
if (props.pages > 5) {
|
||||||
|
if (props.pages / 2 > page.value) items.value.push(props.pages)
|
||||||
|
else items.value.unshift(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
||||||
|
watch(() => page.value, init)
|
||||||
|
|
||||||
|
const getIcon = (i) => 'isax isax-arrow-' + (i > 0 ? 'right-3' : 'left-2')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.pagination {
|
||||||
|
box-shadow: 0px 2px 20px rgba(1, 86, 153, 0.08);
|
||||||
|
@apply bg-white rounded-lg gap-2 lg:gap-4 flex flex-row-reverse items-center justify-between px-2 lg:px-4;
|
||||||
|
@apply w-auto h-10 lg:h-[3.7rem];
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply h-full flex items-center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-5 h-5 lg:w-6 lg:h-6 p-0 rounded-sm #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm lg:text-base font-bold font-vazir lg:leading-tight text-[#8C8C8C] lg:mt-0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#8C8C8C] lg:mt-[0.2rem] text-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
@apply bg-[#379956] opacity-100;
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// &:has(.p-button-icon){
|
||||||
|
// @apply max-lg:bg-[#F2F2F2];
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
@apply text-[#8C8C8C] font-medium font-vazir leading-[1.7rem] mt-0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
@apply order-last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="about-us">
|
||||||
|
<div>
|
||||||
|
<img src="/images/logo.svg" alt="logo" />
|
||||||
|
<p>{{ $t("aboutUsDesc") }}</p>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in items" :key="item">
|
||||||
|
<i :class="`isax isax-${item.icon}`" />
|
||||||
|
<span>{{ $t(item.title) }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const items = reactive([
|
||||||
|
{ icon: "call", title: "aboutUsPhone" },
|
||||||
|
{ icon: "sms", title: "aboutUsPostalCode" },
|
||||||
|
{ icon: "location", title: "aboutUsAddress" },
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .about-us {
|
||||||
|
@apply flex flex-col gap-6 p-8 font-vazir;
|
||||||
|
@apply w-full h-auto bg-zinc-100 rounded-2xl border-2 border-neutral-200;
|
||||||
|
@apply sm:w-[32.7rem] sm:h-[31.3rem];
|
||||||
|
@apply lg:flex-row lg:w-[57.7rem] lg:h-auto;
|
||||||
|
@apply xl:flex-col xl:w-[32.7rem] xl:h-[31.3rem];
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply flex flex-col gap-6;
|
||||||
|
|
||||||
|
img {
|
||||||
|
@apply w-60 h-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
@apply w-auto sm:w-[28.1rem] text-zinc-800 text-lg leading-[1.9rem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply flex flex-col gap-4 mt-4;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply flex gap-3 h-max;
|
||||||
|
|
||||||
|
i {
|
||||||
|
@apply text-2xl h-[1.9rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
@apply text-zinc-800 text-base font-medium leading-[1.9rem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<div class="customer-services">
|
||||||
|
<h2>{{ $t("customer-services") }}</h2>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(service, i) in services" :key="i">
|
||||||
|
<a :href="service.url">
|
||||||
|
<span>{{ $t(service.title) }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const services = reactive([
|
||||||
|
{ url: "/contact-us", title: "contactUs" },
|
||||||
|
{ url: "/about-us", title: "aboutUs" },
|
||||||
|
{ url: "/search", title: "shop" },
|
||||||
|
{ url: "/blog", title: "media" },
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .customer-services {
|
||||||
|
@apply flex flex-col gap-4 w-max font-vazir items-center sm:items-start;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-zinc-800 text-xl font-bold leading-[1.9rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply flex gap-4 sm:flex-col justify-between sm:gap-2;
|
||||||
|
|
||||||
|
li {
|
||||||
|
a {
|
||||||
|
span {
|
||||||
|
@apply text-stone-500 text-[0.9em] leading-[1.9rem] hover:text-primary-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<footer>
|
||||||
|
<AppDesktopFooterAboutUs />
|
||||||
|
<div>
|
||||||
|
<AppDesktopFooterNewsletters />
|
||||||
|
<AppDesktopFooterSocialNetworks />
|
||||||
|
<div>
|
||||||
|
<AppDesktopFooterCustomerServices />
|
||||||
|
<AppDesktopFooterPurchaseGuide />
|
||||||
|
<AppDesktopFooterTrustSymbols />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer {
|
||||||
|
@apply w-full flex flex-col sm:items-center justify-center bg-[#F5F5F5];
|
||||||
|
@apply gap-4 px-3 py-12;
|
||||||
|
@apply xl:flex-row xl:gap-[6.7rem] 2xl:py-[6.3rem];
|
||||||
|
|
||||||
|
&>div:not([class]) {
|
||||||
|
@apply flex flex-col gap-6;
|
||||||
|
|
||||||
|
&>div:not([class]) {
|
||||||
|
@apply flex flex-col items-center sm:items-start sm:flex-row justify-center gap-8 mt-4 lg:justify-between xl:gap-6 xl:mt-10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<div class="newsletters">
|
||||||
|
<h2>{{ $t("newslettersDesc") }}</h2>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<i class="isax isax-sms" />
|
||||||
|
<span>|</span>
|
||||||
|
<input v-model="email" :class="{ '!ltr': email }" :placeholder="$t('emailAddress')" />
|
||||||
|
</div>
|
||||||
|
<Button :label="$t('submit')" :loading="loading" @click="submit()" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { toast, t } = inject('service')
|
||||||
|
const loading = ref(false)
|
||||||
|
const email = ref()
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
if (email.value.includes('@')) {
|
||||||
|
loading.value = true;
|
||||||
|
const { status, error } = await useFetch('/api/news', { method: 'post', body: { email: email.value } })
|
||||||
|
loading.value = false;
|
||||||
|
email.value = '';
|
||||||
|
|
||||||
|
if (status.value == 'success')
|
||||||
|
toast.add({
|
||||||
|
life: 3000,
|
||||||
|
severity: 'success',
|
||||||
|
summary: t('success'),
|
||||||
|
detail: t('submitedSuccessfully')
|
||||||
|
})
|
||||||
|
else
|
||||||
|
toast.add({
|
||||||
|
life: 3000,
|
||||||
|
severity: 'error',
|
||||||
|
summary: t('error'),
|
||||||
|
detail: error.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .newsletters {
|
||||||
|
@apply bg-zinc-100 rounded-xl border-2 border-neutral-200;
|
||||||
|
@apply flex flex-col items-center justify-between p-3 font-vazir;
|
||||||
|
@apply w-full h-auto gap-4 py-4;
|
||||||
|
@apply lg:w-[57.7rem] lg:h-[4.5rem] lg:flex-row;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-zinc-800 text-lg font-medium leading-[1.9rem] mr-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
@apply flex gap-2;
|
||||||
|
|
||||||
|
div {
|
||||||
|
@apply w-[16.9rem] md:w-[21.5rem] h-12 bg-neutral-200 rounded-lg flex gap-3 items-center p-3;
|
||||||
|
|
||||||
|
i {
|
||||||
|
@apply text-2xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@apply h-12 bg-transparent w-full rtl text-neutral-600 font-medium outline-none;
|
||||||
|
|
||||||
|
&:placeholder {
|
||||||
|
@apply text-neutral-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-[4.5rem] h-12 bg-[#47B556] rounded-md text-white text-base font-medium #{!important};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="purchase-guide">
|
||||||
|
<h2>{{ $t("purchaseGuideFromAM") }}</h2>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(guide, i) in guides" :key="i">
|
||||||
|
<a :href="guide.url">
|
||||||
|
<span>{{ $t(guide.title) }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const guides = reactive([
|
||||||
|
{ url: "/", title: "howToPlaceOrder" },
|
||||||
|
{ url: "/", title: "orderSendingProcedure" },
|
||||||
|
{ url: "/", title: "paymentMethods" },
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .purchase-guide {
|
||||||
|
@apply flex flex-col gap-4 sm:gap-[1.4rem] w-max font-vazir items-center sm:items-start;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-zinc-800 text-xl font-bold leading-[1.9rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply flex gap-4 sm:flex-col sm:gap-2;
|
||||||
|
|
||||||
|
li {
|
||||||
|
a {
|
||||||
|
span {
|
||||||
|
@apply text-stone-500 text-[0.9em] leading-[1.9rem] hover:text-primary-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="social-networks">
|
||||||
|
<h2>{{ $t("followUs") }}</h2>
|
||||||
|
<ul>
|
||||||
|
<li v-for="({url, icon}, i) in socials" :key="i">
|
||||||
|
<a :href="url" target="_blank">
|
||||||
|
<img :src="`/icons/${icon}.svg`" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const socials = reactive([
|
||||||
|
{ url: "/", icon: "linkedin" },
|
||||||
|
{ url: "/", icon: "telegram" },
|
||||||
|
{ url: "/", icon: "whatsapp" },
|
||||||
|
{ url: "/", icon: "instagram" },
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .social-networks {
|
||||||
|
@apply bg-zinc-100 rounded-xl border-2 border-neutral-200;
|
||||||
|
@apply flex flex-col items-center justify-between px-6;
|
||||||
|
@apply w-full h-auto gap-4 py-4;
|
||||||
|
@apply lg:w-[57.7rem] lg:h-[4.5rem] md:flex-row;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-zinc-800 text-lg font-medium font-vazir leading-[1.9rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply flex gap-2;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply w-max h-max;
|
||||||
|
a {
|
||||||
|
@apply w-10 h-10 bg-[#B2B2B2] hover:bg-[#43E97B] rounded-full flex items-center justify-center;
|
||||||
|
img {
|
||||||
|
@apply h-6 w-6 object-scale-down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div class="trust-symbols">
|
||||||
|
<h2>{{ $t('symbolOfTrust')}}</h2>
|
||||||
|
<div>
|
||||||
|
<picture v-for="(symbol, i) in symbols" :key="i">
|
||||||
|
<img :src="`/images/${symbol}.svg`" />
|
||||||
|
</picture>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const symbols = reactive(['samandehi', 'kasbokar'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
footer .trust-symbols{
|
||||||
|
@apply flex flex-col items-center gap-4;
|
||||||
|
@apply sm:items-start;
|
||||||
|
|
||||||
|
h2{
|
||||||
|
@apply text-zinc-800 text-xl font-bold font-vazir leading-[1.9rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
div{
|
||||||
|
@apply flex gap-4;
|
||||||
|
|
||||||
|
picture{
|
||||||
|
@apply flex w-24 h-32 bg-white rounded-lg border border-neutral-300;
|
||||||
|
|
||||||
|
img{
|
||||||
|
@apply m-auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<header class="header-desktop">
|
||||||
|
<router-link to="/">
|
||||||
|
<img src="/images/logo.svg" alt="Asan Market" />
|
||||||
|
</router-link>
|
||||||
|
<AppDesktopHeaderNavigation />
|
||||||
|
<router-link v-if="!logged" :to="{ path: '/auth/login' }">
|
||||||
|
<Button v-bind="btns.login.props" />
|
||||||
|
</router-link>
|
||||||
|
<div v-else>
|
||||||
|
<template v-for="({ props, component }, key) in btns.logged" :key="key">
|
||||||
|
<Button v-bind="props" @click="overlay($event, component)" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import init from '../../../../initialize/header'
|
||||||
|
const { btns } = init()
|
||||||
|
|
||||||
|
const logged = useCookie('token')
|
||||||
|
const { popup } = inject('service')
|
||||||
|
|
||||||
|
const overlay = (event, is) => {
|
||||||
|
popup.value.is = is
|
||||||
|
popup.value.toggle(event)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header-desktop {
|
||||||
|
box-shadow: 0px 2px 20px rgba(0.22, 75.27, 129.62, 0.14);
|
||||||
|
@apply w-full h-[3.3rem] lg:h-24 bg-white shadow border-b pl-3 lg:px-3 2xl:p-6 flex items-center justify-between;
|
||||||
|
@apply sticky top-0 z-10 xl:gap-4;
|
||||||
|
|
||||||
|
&>a>img {
|
||||||
|
@apply w-60 h-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>a {
|
||||||
|
@apply shrink-0;
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
@apply flex items-center text-white;
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-2xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply font-bold font-iran-sans tracking-widest whitespace-nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply flex items-center gap-6 2xl:gap-12 relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@apply content-['_'] w-0.5 h-[1.3rem] bg-[#DCDCDC] absolute left-[3.6rem] 2xl:left-[4.4rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply border-[#CCCCCC] h-12 rounded-[0.6rem] #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] text-lg font-medium font-vazir whitespace-nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#333333] text-2xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
@apply pl-6 #{!important};
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply ml-2.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@apply w-12 p-2 relative;
|
||||||
|
|
||||||
|
.p-badge {
|
||||||
|
@apply absolute w-4 h-4 bg-[#B3261E] top-0.5 right-0.5 flex items-center justify-center;
|
||||||
|
@apply text-white text-[0.7em] font-medium leading-none tracking-wide;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-blockui-container {
|
||||||
|
@apply absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<Transition>
|
||||||
|
<nav v-if="visible" class="mega-menu" @click.self="visible = false">
|
||||||
|
<TransitionGroup name="list" tag="section">
|
||||||
|
<template v-for="(list, i) in menu" :key="i">
|
||||||
|
<ul v-if="list?.length">
|
||||||
|
<li v-for="(item, j) in list" :key="j" @mouseover="open(item, i)">
|
||||||
|
<router-link :to="{ path: '/search', query: { category: item.link } }">
|
||||||
|
<Button v-bind="getProps(item, i)" />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
</TransitionGroup>
|
||||||
|
</nav>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const visible = defineModel()
|
||||||
|
const store = useCategoriesStore()
|
||||||
|
const menu = reactive([])
|
||||||
|
|
||||||
|
const getProps = (item, i) => {
|
||||||
|
const temp = { label: item.name, link: true }
|
||||||
|
if (i === 0) {
|
||||||
|
temp.iconPos = 'right'
|
||||||
|
temp.icon = 'isax ' + item.icon
|
||||||
|
// temp.disabled = menu[1] == item.sub
|
||||||
|
} else if (i === 1 && item.sub.length > 0) {
|
||||||
|
temp.icon = 'isax isax-arrow-left-2'
|
||||||
|
// temp.disabled = menu[2] == item.sub
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = (item, i) => {
|
||||||
|
if (i < 2) {
|
||||||
|
delete menu[i + 2]
|
||||||
|
menu[i + 1] = item.sub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let cat = store.items
|
||||||
|
while (true) {
|
||||||
|
menu.push(cat)
|
||||||
|
if (cat[0]?.sub) cat = cat[0].sub
|
||||||
|
else break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const route = useRoute()
|
||||||
|
watch(() => route.query, () => visible.value = false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.mega-menu {
|
||||||
|
@apply fixed inset-x-0 z-[1] bottom-0 top-24 bg-black/40;
|
||||||
|
|
||||||
|
&>section {
|
||||||
|
@apply flex h-[32.4rem] w-full bg-white shadow-inner;
|
||||||
|
|
||||||
|
ul:nth-of-type(1) {
|
||||||
|
@apply flex flex-col gap-2 py-3 px-4 w-[16.5rem] h-[26.8rem] z-[10];
|
||||||
|
|
||||||
|
li {
|
||||||
|
button {
|
||||||
|
@apply w-full h-12 justify-end;
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#292D32] text-lg font-medium font-vazir grow-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#292D32] text-2xl ml-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover * {
|
||||||
|
@apply text-primary-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
@apply opacity-100;
|
||||||
|
|
||||||
|
* {
|
||||||
|
@apply text-primary-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul:nth-of-type(2) {
|
||||||
|
@apply border-x-2 border-[#E5E5E5] w-[16.5rem] h-[32.4rem] flex flex-col;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply border-b border-[#E5E5E5];
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full h-[3.7rem] justify-between px-2.5;
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#292D32] text-lg font-vazir grow-0 ml-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#292D32] text-sm transition-transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover * {
|
||||||
|
@apply text-primary-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
@apply opacity-100 bg-[#FAFAFA];
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#333333] -rotate-90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul:nth-of-type(3) {
|
||||||
|
@apply flex flex-col;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply px-4;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full h-[3.8rem] justify-end;
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] text-lg font-normal font-vazir grow-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover * {
|
||||||
|
@apply text-primary-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-enter-active,
|
||||||
|
.list-leave-active {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-enter-from,
|
||||||
|
.list-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-enter-active,
|
||||||
|
.menu-leave-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
div {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-enter-from,
|
||||||
|
.menu-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
div {
|
||||||
|
transform: translateX(30px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-enter-active,
|
||||||
|
.v-leave-active {
|
||||||
|
transition: opacity 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-enter-from,
|
||||||
|
.v-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<ul class="mini-menu">
|
||||||
|
<li v-for="(item, i) in items" :key="i">
|
||||||
|
<router-link :to="item.to" @click="popup.hide()">
|
||||||
|
<Button v-bind="item.props" iconPos="right" severity="secondary" link />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Button :label="$t('logout')" icon="isax isax-logout-1" iconPos="right" severity="secondary" link
|
||||||
|
@click="logout()" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const items = reactive([
|
||||||
|
{
|
||||||
|
to: "/panel/profile",
|
||||||
|
props: { label: "پروفایل کاربری", icon: "isax isax-user-square" },
|
||||||
|
},
|
||||||
|
{ to: "/panel/favorites", props: { label: "علاقه مندی ها", icon: "isax isax-heart" } },
|
||||||
|
{
|
||||||
|
to: "/panel/comments",
|
||||||
|
props: { label: "نظرات من", icon: "isax isax-message-text4" },
|
||||||
|
},
|
||||||
|
{ to: "/panel/factors", props: { label: "فاکتورها", icon: "isax isax-receipt-2-1" } },
|
||||||
|
{
|
||||||
|
to: "/panel/moeen",
|
||||||
|
props: { label: "فاکتور معین", icon: "isax isax-archive-book4" },
|
||||||
|
},
|
||||||
|
{ to: "/panel/notifications", props: { label: "اعلان ها", icon: "isax isax-notification" } },
|
||||||
|
{
|
||||||
|
to: "/panel/orders",
|
||||||
|
props: { label: "سفارشات", icon: "isax isax-shopping-cart" },
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const { popup } = inject('service')
|
||||||
|
|
||||||
|
const { dialog } = inject('service')
|
||||||
|
const logout = () => {
|
||||||
|
popup.value.hide();
|
||||||
|
dialog.show(resolveComponent('PanelDialogLogout'))
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.mini-menu {
|
||||||
|
@apply flex flex-col gap-3 px-4 pt-[1.4rem] rtl shadow-[0px_2px_10px_#004b8229];
|
||||||
|
@apply w-[13.4rem] h-[27.8rem] bg-white rounded-2xl shadow border;
|
||||||
|
|
||||||
|
li {
|
||||||
|
button {
|
||||||
|
@apply h-10 py-1.5 justify-end #{!important};
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#333333] text-2xl ml-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] text-lg font-medium font-vazir grow-0 whitespace-nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-overlaypanel:has(.mini-menu) {
|
||||||
|
@apply -translate-x-8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<ul class="navigation">
|
||||||
|
<li>
|
||||||
|
<Button :label="$t('product-categories')" iconPos="right" severity="secondary" text icon="isax isax-menu-1"
|
||||||
|
@click="visible = !visible" />
|
||||||
|
</li>
|
||||||
|
<li v-for="(item, i) in items" :key="i">
|
||||||
|
<component :is="item.link.includes('http') ? 'a' : 'router-link'" :to="item.link" :href="item.link">
|
||||||
|
<Button iconPos="right" severity="secondary" text v-bind="item.props" />
|
||||||
|
</component>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Button iconPos="right" severity="secondary" text icon="isax isax-search-normal-1"
|
||||||
|
@click="$router.push('/search')" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<AppDesktopHeaderMegaMenu v-model="visible" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const items = ref([])
|
||||||
|
const visible = ref(false)
|
||||||
|
|
||||||
|
const { status, data, error } = await useFetch('/api/headers')
|
||||||
|
|
||||||
|
if (status.value == 'success')
|
||||||
|
items.value = data.value.map((item) => {
|
||||||
|
item.props = { label: item.title, icon: 'isax ' + item.icon }
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
else throw createError(error.value)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.navigation {
|
||||||
|
@apply flex items-center justify-center lg:gap-6 2xl:justify-between w-full max-w-[70.6rem];
|
||||||
|
|
||||||
|
li:first-child,
|
||||||
|
li:last-child {
|
||||||
|
@apply flex items-center relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child::after,
|
||||||
|
li:last-child::before {
|
||||||
|
@apply content-['_'] w-0.5 h-[1.3rem] bg-[#DCDCDC] absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child {
|
||||||
|
@apply -ml-1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@apply left-0 2xl:-left-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child {
|
||||||
|
@apply -mr-1;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
@apply 2xl:-right-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
|
||||||
|
button {
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#333333] text-xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.p-button-icon-only) .p-button-icon {
|
||||||
|
@apply ml-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] text-lg font-medium font-vazir whitespace-nowrap no-underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(n + 7):not(:last-child) {
|
||||||
|
@apply max-[1500px]:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(n + 6):not(:last-child) {
|
||||||
|
@apply max-[1380px]:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:nth-child(n + 5):not(:last-child) {
|
||||||
|
@apply max-xl:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:not(:last-child:first-child) {
|
||||||
|
@apply max-2xl:-mx-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div class="header-cart-list-item">
|
||||||
|
<span>{{ quantity }}x</span>
|
||||||
|
<img :src="data.coverPath" />
|
||||||
|
<div>
|
||||||
|
<h3>{{ data.category[data.category.length - 1]?.name }}</h3>
|
||||||
|
<h2>{{ data.title }}</h2>
|
||||||
|
<span>
|
||||||
|
<b>{{ numberFormat(data.specialPrice || data.price) }} </b>
|
||||||
|
{{ $t('priceUnit') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Button icon="isax isax-trash" severity="secondary" text @click="$emit('remove', data.id)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps(['data', 'quantity'])
|
||||||
|
|
||||||
|
const numberFormat = (number) =>
|
||||||
|
new Intl.NumberFormat('fa-IR', { maximumSignificantDigits: 3 }).format(number)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header-cart-list-item {
|
||||||
|
box-shadow: 0px 2px 12px #004b8226;
|
||||||
|
@apply flex p-2 pl-6 w-[26.9rem] h-[10.1rem] bg-white rounded-lg shadow border relative;
|
||||||
|
|
||||||
|
&>span {
|
||||||
|
@apply absolute left-5 top-4 text-xs font-poppins;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
@apply w-[9.2rem] h-[9.2rem] p-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
@apply w-max gap-1 flex flex-col py-4 font-vazir mr-6;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
@apply text-right text-neutral-400 text-[0.9em] font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply w-[13.1rem] h-14 text-right text-zinc-800 text-[1.1em] font-bold line-clamp-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
@apply text-zinc-800 text-[0.9em] mt-auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-10 h-10 mb-2 -mx-2 shrink-0 self-end text-2xl text-[#7F7F7F] rounded-full #{!important};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="header-cart-list">
|
||||||
|
<h3>{{ $t('itemsSubmittedInCart', { count: cart.count }) }}</h3>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li v-for="({ product, quantity }, i) in items" :key="i">
|
||||||
|
<AppDesktopHeaderCartItem :data="product" :quantity="quantity" @remove="remove" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<Button :label="$t('showCart')" @click="show()" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { popup } = inject('service')
|
||||||
|
const cart = useCartStore()
|
||||||
|
const items = computed(() => cart.items)
|
||||||
|
|
||||||
|
const emit = defineEmits(['hide'])
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const show = () => {
|
||||||
|
popup.value.hide()
|
||||||
|
router.push('/checkout/cart')
|
||||||
|
}
|
||||||
|
const remove = async (id) => {
|
||||||
|
await cart.update(id)
|
||||||
|
if (cart.count < 1) popup.value.hide()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header-cart-list {
|
||||||
|
box-shadow: 0px 2px 10px 0px rgba(0, 75, 130, 0.16);
|
||||||
|
@apply rtl w-[30.9rem] h-[40.6rem] flex flex-col gap-5 py-6 pl-2 bg-white rounded-2xl border overflow-hidden relative;
|
||||||
|
|
||||||
|
&>h3 {
|
||||||
|
@apply text-sky-700 text-[0.9em] font-medium font-vazir mb-2.5 mr-8 ml-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply overflow-y-auto h-[29.8rem];
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply w-full flex py-3 pr-8 pl-4 flex-col gap-3 items-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
@apply bg-sky-700 border-sky-700 mr-8 ml-6 text-xl font-bold font-vazir #{!important};
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
box-shadow: 0px -3px 16px 0px rgba(7, 50, 115, 0.16);
|
||||||
|
@apply absolute inset-x-0 -bottom-3 h-28 z-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<ul class="drawer-menu">
|
||||||
|
<li v-for="(item, i) in items" :key="i">
|
||||||
|
<router-link :to="item.link" @click="sidebar.visible = false">
|
||||||
|
<Button v-bind="item.props" iconPos="right" severity="secondary" text />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps(['menu'])
|
||||||
|
const { sidebar } = inject('service')
|
||||||
|
|
||||||
|
const items = ref([])
|
||||||
|
items.value = props.menu.map((item) => {
|
||||||
|
item.props = { label: item.title, icon: 'isax ' + item.icon }
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.drawer-menu {
|
||||||
|
@apply rtl w-60 flex flex-col gap-3 px-4 pt-[1.4rem];
|
||||||
|
|
||||||
|
li {
|
||||||
|
button {
|
||||||
|
@apply h-10 py-1.5 justify-end;
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-[#333333] text-2xl ml-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-[#333333] text-lg font-medium font-vazir grow-0 whitespace-nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<header class="header-mobile">
|
||||||
|
<div>
|
||||||
|
<Button v-if="h.back" v-bind="btns.back.props" @click="$router.go(-1)" />
|
||||||
|
<Button v-if="h.menu" v-bind="btns.menu.props" @click="sidebar.visible = true" />
|
||||||
|
<h2 v-if="h.title" v-text="h.title" />
|
||||||
|
<AppMobileSearchBox v-if="h.search" />
|
||||||
|
<span />
|
||||||
|
<template v-for="(opt, i) in h.options" :key="i">
|
||||||
|
<Button v-bind="opt.props" @click="opt.click" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<AppMobileToolbar v-if="h.toolbar" />
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { btns, navigation } = inject('mobile')
|
||||||
|
const { sidebar } = inject('service')
|
||||||
|
const { mobile } = inject('config')
|
||||||
|
const h = computed(() => mobile.header)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header-mobile {
|
||||||
|
box-shadow: 0px 2px 20px #004b8224;
|
||||||
|
@apply w-full h-max bg-white shadow border-b pl-3 flex flex-col sticky top-0 z-10;
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply h-[3.3rem] flex items-center;
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
@apply flex items-center text-[#292D32] shrink-0;
|
||||||
|
|
||||||
|
.p-button-icon {
|
||||||
|
@apply text-2xl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>h2{
|
||||||
|
@apply text-[#333333] text-sm font-medium font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>span {
|
||||||
|
@apply mr-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="bottom-navigation">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, i) in navigation" :key="i">
|
||||||
|
<router-link :to="item.to" v-ripple>
|
||||||
|
<Button v-bind="item.props" />
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { navigation } = inject('mobile');
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
Object.keys(navigation).forEach(key => {
|
||||||
|
const item = navigation[key]
|
||||||
|
if (item.to == route.path)
|
||||||
|
item.props.icon += '5'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.bottom-navigation {
|
||||||
|
@apply fixed inset-x-0 bottom-0 h-16 pb-2 bg-white z-10;
|
||||||
|
@apply shadow-[0px_-2px_5px_#0000000a] border-t border-[#F1F2F4];
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply w-full h-full flex justify-between items-center;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply flex justify-center flex-1;
|
||||||
|
|
||||||
|
a {
|
||||||
|
button span {
|
||||||
|
@apply text-[#7F7F7F] text-2xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.router-link-active button span {
|
||||||
|
@apply text-primary-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search-box" @click="active = true">
|
||||||
|
<i class="isax isax-search-normal-1" />
|
||||||
|
<template v-if="active">
|
||||||
|
<InputText v-model="q" :placeholder="$t('searchIn')" autofocus @blur="active = false"
|
||||||
|
@keypress.enter="search" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span>{{ $t("searchIn") }}</span>
|
||||||
|
<img src="/images/logo-search.svg" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const active = ref(false);
|
||||||
|
const q = ref(route.query.q || '');
|
||||||
|
|
||||||
|
const search = () => router.push({ path: '/search', query: { q: q.value } })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.search-box {
|
||||||
|
@apply grow flex gap-1.5 items-center h-10 bg-[#F2F2F2] rounded-[0.4rem] px-3;
|
||||||
|
|
||||||
|
input {
|
||||||
|
@apply h-full text-xs px-0 w-auto bg-transparent border-0 rtl focus:border-0 focus:shadow-none #{!important};
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
@apply text-lg ml-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
@apply text-[#5D5D5D] text-xs font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
@apply w-24 h-5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<ul>
|
||||||
|
<li v-for="({ label, link }, i) in items" :key="i">
|
||||||
|
<router-link :to="link">
|
||||||
|
<span>{{ label }}</span>
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const items = reactive([
|
||||||
|
{ link: '/panel/seller/store', label: 'فروشگاه', icon: 'isax isax-shop' },
|
||||||
|
{ link: '/panel/seller/products', label: 'همه کالاها', icon: 'isax isax-bag' },
|
||||||
|
{ link: '/panel/seller/new-product', label: 'معرفی کالا', icon: 'isax isax-bag-cross' },
|
||||||
|
{ link: '/panel/seller/orders', label: 'سفارشات', icon: 'isax isax-bag-tick-2' },
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.header-mobile>ul {
|
||||||
|
@apply w-full h-8 flex gap-6 px-6;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply translate-y-px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
|
||||||
|
@apply h-full w-max text-[#333333] text-xs font-vazir;
|
||||||
|
|
||||||
|
&.router-link-active {
|
||||||
|
@apply text-[#47B556] font-bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(.router-link-active) {
|
||||||
|
@apply border-b-2 border-[#47B556];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<form class="otp-code">
|
||||||
|
<h1>{{ $t("enterReceivedCode") }}</h1>
|
||||||
|
<ul ref="list">
|
||||||
|
<li v-for="(_, i) in 6" :key="i">
|
||||||
|
<InputNumber v-model="code[i]" @input="events.input($event, i)" @keyup="events.keyup($event, i)"
|
||||||
|
@focus="events.focus($event, i)" :disabled="inputs.length < 1" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<span :class="{ invisible: seconds < 1 }">
|
||||||
|
{{ $t("moreSecondReceiveCode", { seconds }) }}
|
||||||
|
</span>
|
||||||
|
<Button v-bind="btns.next.props" @click="events.next()" />
|
||||||
|
<div v-show="seconds < 1">
|
||||||
|
<p>{{ $t("notReceivedCode") }}</p>
|
||||||
|
<Button v-bind="btns.try.props" @click="events.try()" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import init from "../../initialize/auth/otp-code.js";
|
||||||
|
const { btns } = init();
|
||||||
|
|
||||||
|
const { t, toast } = inject('service')
|
||||||
|
|
||||||
|
let inputs = reactive([]);
|
||||||
|
const list = ref();
|
||||||
|
const code = ref([]);
|
||||||
|
const seconds = ref(0);
|
||||||
|
const form = computed(() => code.value.join(""));
|
||||||
|
|
||||||
|
const store = useOtpCodeStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const events = reactive({
|
||||||
|
next: async () => {
|
||||||
|
btns.next.props.loading = true
|
||||||
|
if (form.value.length == 6) {
|
||||||
|
const { status, error } = await store.check(form.value);
|
||||||
|
if (status.value == "success")
|
||||||
|
router.push({ query: { step: 2 } });
|
||||||
|
else {
|
||||||
|
code.value = []
|
||||||
|
let detail = t("error-500");
|
||||||
|
switch (error.value.statusCode) {
|
||||||
|
case 400:
|
||||||
|
detail = t("incorrect-code");
|
||||||
|
break;
|
||||||
|
case 429:
|
||||||
|
detail = t("error-429");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
toast.add({ severity: "error", summary: t("error"), detail, life: 3000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btns.next.props.loading = false
|
||||||
|
},
|
||||||
|
try: async () => {
|
||||||
|
btns.try.props.loading = true
|
||||||
|
|
||||||
|
const form = { number: store.number };
|
||||||
|
let result = {}
|
||||||
|
if (route.path.includes('register'))
|
||||||
|
result = await store.withoutToken(form)
|
||||||
|
else if (route.path.includes('restore'))
|
||||||
|
result = await store.forgotPassword(form
|
||||||
|
)
|
||||||
|
const { status, error } = result;
|
||||||
|
if (status.value == "success")
|
||||||
|
seconds.value = 60;
|
||||||
|
else
|
||||||
|
toast.add({ severity: "error", summary: t("error"), detail: error.value.message, life: 3000 });
|
||||||
|
btns.try.props.loading = false
|
||||||
|
|
||||||
|
},
|
||||||
|
input: (e, i) => {
|
||||||
|
if (e.value != null) inputs[i++].value = e.originalEvent.key;
|
||||||
|
if (i < 6) inputs[i].focus();
|
||||||
|
else {
|
||||||
|
inputs[5].blur();
|
||||||
|
events.next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyup: (e, i) => {
|
||||||
|
if (e.code == "Backspace" && i > 0) {
|
||||||
|
code.value[i - 1] = null;
|
||||||
|
inputs[i - 1].focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focus: (e, i) => {
|
||||||
|
const length = code.value.filter((c) => typeof c == "number").length;
|
||||||
|
if (length < i) inputs[length].focus();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
inputs.push(...list.value.querySelectorAll("input"));
|
||||||
|
setTimeout(() => inputs[0].focus(), 1);
|
||||||
|
seconds.value = 60;
|
||||||
|
setInterval(() => {
|
||||||
|
if (seconds.value > 0) seconds.value--;
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.auth .otp-code {
|
||||||
|
@apply flex flex-col h-max gap-3 lg:gap-4 items-center mx-auto;
|
||||||
|
|
||||||
|
&>h1 {
|
||||||
|
@apply w-full text-[#CCCCCC] font-black font-vazir text-right leading-[3rem] whitespace-nowrap;
|
||||||
|
@apply text-xl lg:text-3xl lg:text-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>ul {
|
||||||
|
@apply flex gap-2.5 mt-3 lg:mt-8 ltr;
|
||||||
|
|
||||||
|
li {
|
||||||
|
input {
|
||||||
|
@apply w-12 lg:w-10 h-10 p-0 rounded-lg border border-stone-300 text-center;
|
||||||
|
@apply focus:text-primary-600 text-stone-300 text-xl font-medium font-vazir leading-[1.9rem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>span {
|
||||||
|
@apply text-[#999999] text-xs lg:text-sm font-medium font-vazir mt-1 lg:mt-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
@apply w-full h-11 mt-3 lg:h-14 lg:mt-6 #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply flex items-center lg:mt-2 whitespace-nowrap;
|
||||||
|
|
||||||
|
p {
|
||||||
|
@apply text-[#999999] text-xs lg:text-sm font-medium font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full px-1 h-11 lg:h-14 #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<form class="completeInformation">
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, key) in fields" :key="key">
|
||||||
|
<component :is="item.is" :id="key" v-bind="item.props" v-model="form[key]" />
|
||||||
|
<label :for="key"> {{ $t(key) }} </label>
|
||||||
|
<small v-if="errors[key]">{{ errors[key] }}</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button v-bind="btn.props" @click="register()" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import iranCities from "../../initialize/iranCities"
|
||||||
|
import init from "../../initialize/auth/information";
|
||||||
|
const { fields, btn } = init();
|
||||||
|
|
||||||
|
const form = reactive({});
|
||||||
|
const errors = ref({});
|
||||||
|
|
||||||
|
const otpCode = useOtpCodeStore();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
form.phoneNumber = otpCode.number
|
||||||
|
form.otp = otpCode.code
|
||||||
|
})
|
||||||
|
|
||||||
|
const provinces = reactive(iranCities)
|
||||||
|
fields.state.props.options = provinces
|
||||||
|
|
||||||
|
watch(() => form.state, (v) => {
|
||||||
|
provinces.forEach(({ name, cities }) => {
|
||||||
|
if (name == v) {
|
||||||
|
fields.city.props.options = reactive(cities)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
fields.city.props.disabled = computed(() => fields.city.props.options.length < 1)
|
||||||
|
|
||||||
|
const route = useRouter();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
|
||||||
|
const register = async () => {
|
||||||
|
errors.value = {}
|
||||||
|
btn.props.loading = true
|
||||||
|
const { status, error } = await store.register(Object.assign({}, form));
|
||||||
|
if (status.value == "success") {
|
||||||
|
delete store.profile.password;
|
||||||
|
router.push("/panel/profile");
|
||||||
|
} else {
|
||||||
|
if (error.value.statusCode == 422)
|
||||||
|
errors.value = error.value.data
|
||||||
|
else
|
||||||
|
toast.add({
|
||||||
|
life: 50000,
|
||||||
|
severity: 'error',
|
||||||
|
summary: t('error'),
|
||||||
|
detail: error.value.data.message || error.value.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
btn.props.loading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(form, () => errors.value = {})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.auth .completeInformation {
|
||||||
|
@apply h-max flex flex-col m-auto;
|
||||||
|
@apply lg:mt-6 lg:gap-14;
|
||||||
|
|
||||||
|
&>div:nth-of-type(1) {
|
||||||
|
@apply w-max overflow-y-auto pl-4 lg:pl-7;
|
||||||
|
@apply h-[18.6rem] lg:h-[35.2rem];
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
@apply bg-transparent my-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
@apply w-1 lg:w-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
@apply bg-neutral-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply grid grid-cols-2 grow max-w-full py-4 px-px my-0;
|
||||||
|
@apply gap-y-6 gap-x-2 w-[21.4rem] lg:w-[27.1rem] lg:gap-x-3;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply w-full grow h-14 relative col-span-2;
|
||||||
|
|
||||||
|
label {
|
||||||
|
@apply w-max absolute right-3 top-4 px-1 bg-white transition-['top'];
|
||||||
|
@apply text-neutral-400 text-base font-medium font-vazir cursor-text pointer-events-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
@apply w-full rounded-[0.6rem] border shadow-none border-[#CCCCCC] text-zinc-800 font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-dropdown-label {
|
||||||
|
@apply font-vazir mt-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:focus),
|
||||||
|
&:has(textarea:focus),
|
||||||
|
&:has(input:not(:placeholder-shown)),
|
||||||
|
&:has(.p-dropdown-label[aria-label]),
|
||||||
|
&:has(textarea:not(:placeholder-shown)) {
|
||||||
|
label {
|
||||||
|
@apply -top-2 h-4;
|
||||||
|
@apply text-zinc-800 text-xs font-normal font-vazir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-of-type(1),
|
||||||
|
&:nth-of-type(2),
|
||||||
|
&:nth-of-type(3),
|
||||||
|
&:nth-of-type(4),
|
||||||
|
&:nth-of-type(8),
|
||||||
|
&:nth-of-type(9) {
|
||||||
|
@apply w-full col-span-1 max-w-[12.7rem] lg:max-w-[13.1rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-dropdown {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-calendar {
|
||||||
|
@apply w-full flex items-center relative z-0 font-['iconsax'] #{!important};
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
@apply text-xl absolute mb-0.5 left-3 z-[1] text-[#999999];
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@apply pl-10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
@apply text-red-500 font-vazir float-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(small) * {
|
||||||
|
@apply border-red-500 #{!important};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div:nth-of-type(2) {
|
||||||
|
@apply py-3 -mr-6 px-5 w-full min-w-[24.4rem] border-t border-gray-100 shadow-[0px_-3px_5px_#00000005];
|
||||||
|
@apply lg:border-0 lg:shadow-none lg:mr-0 lg:p-0;
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
@apply w-full h-11 lg:h-14 #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<form class="password">
|
||||||
|
<h1>{{ $t("chooseStrongPassword") }}</h1>
|
||||||
|
<ul>
|
||||||
|
<li v-for="(item, key) in fields" :key="key">
|
||||||
|
<Password v-model="form[key]" v-bind="item.props" :inputId="key" />
|
||||||
|
<label :for="key">{{ $t(key) }}</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<Button v-bind="btn.props" @click="next()" />
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import init from "../../initialize/auth/password";
|
||||||
|
const { fields, btn } = init();
|
||||||
|
const { t, toast } = inject('service')
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const form = reactive({ password: '', repassword: null });
|
||||||
|
const store = useUserStore();
|
||||||
|
const otpCode = useOtpCodeStore()
|
||||||
|
|
||||||
|
const next = async () => {
|
||||||
|
if (form.password.length < 8) {
|
||||||
|
toast.add({ severity: "error", summary: t("error"), detail: t('passwordMin8'), life: 3000 });
|
||||||
|
} else if (form.password != form.repassword) {
|
||||||
|
toast.add({ severity: "error", summary: t("error"), detail: t('passwordNotSame'), life: 3000 });
|
||||||
|
} else {
|
||||||
|
if (route.path.includes('register')) {
|
||||||
|
store.profile.password = form.password
|
||||||
|
router.push({ query: { step: 3 } });
|
||||||
|
} else if (route.path.includes('restore')) {
|
||||||
|
btn.props.loading = true
|
||||||
|
const body = Object.assign({}, form)
|
||||||
|
body.phoneNumber = otpCode.number
|
||||||
|
body.otp = otpCode.code
|
||||||
|
delete body.repassword
|
||||||
|
const { status, error } = await store.forgetPassword(body);
|
||||||
|
if (status.value == "success") {
|
||||||
|
toast.add({ severity: "success", summary: t("success"), detail: t('updatePasswordSuccessfull'), life: 3000 });
|
||||||
|
router.replace('/auth/login');
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let detail = error.value.data.msg
|
||||||
|
toast.add({ severity: "error", summary: t("error"), detail, life: 3000 });
|
||||||
|
}
|
||||||
|
btn.props.loading = false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.auth .password {
|
||||||
|
@apply flex flex-col m-auto gap-[1.9rem] lg:gap-[3.2rem];
|
||||||
|
|
||||||
|
&>h1 {
|
||||||
|
@apply w-full text-[#CCCCCC] font-black font-vazir text-right leading-[3rem] whitespace-nowrap;
|
||||||
|
@apply text-xl lg:text-3xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply flex flex-col gap-6 lg:mb-7;
|
||||||
|
|
||||||
|
li {
|
||||||
|
@apply w-full h-14 relative;
|
||||||
|
|
||||||
|
label {
|
||||||
|
@apply w-max absolute right-3 top-4 px-1 bg-white transition-['top'];
|
||||||
|
@apply text-neutral-400 text-base font-medium cursor-text font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-password {
|
||||||
|
input {
|
||||||
|
@apply w-full rounded-[0.6rem] border shadow-none border-[#CCCCCC] text-zinc-800 font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@apply text-[#CCCCCC] w-5 h-5 -mt-2.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:focus),
|
||||||
|
&:has(input:not(:placeholder-shown)) {
|
||||||
|
label {
|
||||||
|
@apply -top-2 h-4;
|
||||||
|
@apply text-zinc-800 text-xs font-normal font-vazir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full h-11 mt-1.5 lg:h-14 #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<form class="phone">
|
||||||
|
<h1>{{ $t("enterYourPhoneNumber") }}</h1>
|
||||||
|
<div>
|
||||||
|
<InputText v-bind="field.props" v-model="form.number" />
|
||||||
|
<label for="phone"> {{ $t("phoneNumber") }} </label>
|
||||||
|
</div>
|
||||||
|
<Button v-bind="btn.props" @click="send()" />
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import init from "../../initialize/auth/phone";
|
||||||
|
const { field, btn } = init();
|
||||||
|
|
||||||
|
const store = useOtpCodeStore();
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const form = reactive({ number: store.number });
|
||||||
|
|
||||||
|
const { toast, t } = inject('service')
|
||||||
|
|
||||||
|
const send = async () => {
|
||||||
|
btn.props.loading = true;
|
||||||
|
let result = {}
|
||||||
|
const body = Object.assign({}, form);
|
||||||
|
|
||||||
|
if (route.path.includes('register'))
|
||||||
|
result = await store.withoutToken(body)
|
||||||
|
else if (route.path.includes('restore'))
|
||||||
|
result = await store.forgotPassword(body
|
||||||
|
)
|
||||||
|
const { status, data, error } = result;
|
||||||
|
btn.props.loading = false;
|
||||||
|
|
||||||
|
if (status.value == "success")
|
||||||
|
router.push({ query: { step: 1 } });
|
||||||
|
else {
|
||||||
|
let detail = error.value.data.msg
|
||||||
|
if (error.value.statusCode == 422)
|
||||||
|
detail = Object.values(error.value.data).join('\n')
|
||||||
|
|
||||||
|
toast.add({ life: 3000, severity: 'error', summary: t('error'), detail })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.auth .phone {
|
||||||
|
@apply flex flex-col h-max m-auto;
|
||||||
|
@apply gap-[1.9rem] lg:gap-10;
|
||||||
|
|
||||||
|
&>h1 {
|
||||||
|
@apply text-[#CCCCCC] font-black font-vazir text-right whitespace-nowrap;
|
||||||
|
@apply text-xl lg:text-3xl leading-[3rem];
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
@apply w-full h-14 relative;
|
||||||
|
|
||||||
|
label {
|
||||||
|
@apply w-max absolute right-3 top-4 px-1 bg-white transition-['top'];
|
||||||
|
@apply text-neutral-400 text-base font-medium font-vazir cursor-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@apply w-full rounded-[0.6rem] border shadow-none border-[#CCCCCC] text-zinc-800 font-vazir;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:focus),
|
||||||
|
&:has(input:not(:placeholder-shown)) {
|
||||||
|
label {
|
||||||
|
@apply -top-2 h-4;
|
||||||
|
@apply text-zinc-800 text-xs font-normal font-vazir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply w-full mt-1.5 h-11 lg:h-14 lg:mt-5 #{!important};
|
||||||
|
|
||||||
|
.p-button-label {
|
||||||
|
@apply text-sm font-medium font-iran-sans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user