Initialize the user app and load home banners from the API.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
max_line_length = 100
|
||||
@@ -0,0 +1,2 @@
|
||||
VITE_API_BASE_URL=https://parche.montest.ir/server/api
|
||||
VITE_USE_MOCK_AUTH=false
|
||||
@@ -0,0 +1,10 @@
|
||||
VITE_API_BASE_URL=https://parche.montest.ir/server/api
|
||||
|
||||
# سرور محلی (بعد از migrate + seed):
|
||||
# VITE_API_BASE_URL=http://127.0.0.1:3000/api
|
||||
#
|
||||
# یا با پروکسی Vite:
|
||||
# VITE_API_BASE_URL=/server/api
|
||||
|
||||
VITE_USE_MOCK_AUTH=false
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Cypress
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Vitest
|
||||
__screenshots__/
|
||||
|
||||
# Vite
|
||||
*.timestamp-*-*.mjs
|
||||
|
||||
# env
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["eslint", "typescript", "unicorn", "oxc", "vue"],
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"EditorConfig.EditorConfig",
|
||||
"oxc.oxc-vscode",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# fabric-trade
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Recommended Browser Setup
|
||||
|
||||
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
|
||||
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
|
||||
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
|
||||
- Firefox:
|
||||
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
|
||||
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="unocss" />
|
||||
@@ -0,0 +1,26 @@
|
||||
import { globalIgnores } from 'eslint/config'
|
||||
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
|
||||
import pluginVue from 'eslint-plugin-vue'
|
||||
import pluginOxlint from 'eslint-plugin-oxlint'
|
||||
import skipFormatting from 'eslint-config-prettier/flat'
|
||||
|
||||
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
|
||||
// import { configureVueProject } from '@vue/eslint-config-typescript'
|
||||
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
|
||||
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
|
||||
|
||||
export default defineConfigWithVueTs(
|
||||
{
|
||||
name: 'app/files-to-lint',
|
||||
files: ['**/*.{vue,ts,mts,tsx}'],
|
||||
},
|
||||
|
||||
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
|
||||
|
||||
...pluginVue.configs['flat/essential'],
|
||||
vueTsConfigs.recommended,
|
||||
|
||||
...pluginOxlint.buildFromOxlintConfigFile('.oxlintrc.json'),
|
||||
|
||||
skipFormatting,
|
||||
)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fa" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#17379f">
|
||||
<title>سامانه سفارش عمده پارچه</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+6307
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "fabric-trade",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build",
|
||||
"lint": "run-s \"lint:*\"",
|
||||
"lint:oxlint": "oxlint . --fix",
|
||||
"lint:eslint": "eslint . --fix --cache",
|
||||
"format": "prettier --write --experimental-cli src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@unocss/vite": "^66.7.5",
|
||||
"@vueuse/core": "^14.4.0",
|
||||
"jalaali-js": "^2.0.0",
|
||||
"lodash-es": "^4.18.1",
|
||||
"pinia": "^4.0.2",
|
||||
"unocss": "^66.7.5",
|
||||
"vue": "^3.5.40",
|
||||
"vue-router": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node24": "^24.0.4",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^24.13.3",
|
||||
"@vitejs/plugin-vue": "^6.0.8",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.6",
|
||||
"@vue/eslint-config-typescript": "^14.9.0",
|
||||
"@vue/tsconfig": "^0.9.1",
|
||||
"eslint": "^10.7.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-oxlint": "~1.73.0",
|
||||
"eslint-plugin-vue": "~10.9.2",
|
||||
"jiti": "^2.7.0",
|
||||
"npm-run-all2": "^9.0.2",
|
||||
"oxlint": "~1.74.0",
|
||||
"prettier": "3.9.5",
|
||||
"typescript": "~6.0.0",
|
||||
"vite": "^8.1.5",
|
||||
"vite-plugin-vue-devtools": "^8.1.5",
|
||||
"vue-eslint-parser": "^10.4.1",
|
||||
"vue-tsc": "^3.3.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^22.18.0 || >=24.12.0"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
+72
@@ -0,0 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterView, useRouter } from 'vue-router'
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
import { clamp } from 'lodash-es'
|
||||
import DefaultLayout from '@/layouts/DefaultLayout.vue'
|
||||
import ConfirmDialog from '@/components/ui/ConfirmDialog.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useCartStore } from '@/stores/cart'
|
||||
import { useOrderStore } from '@/stores/order'
|
||||
import { useCatalogStore } from '@/stores/catalog'
|
||||
import { useNotificationStore } from '@/stores/notification'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const cartStore = useCartStore()
|
||||
const orderStore = useOrderStore()
|
||||
const catalogStore = useCatalogStore()
|
||||
const notificationStore = useNotificationStore()
|
||||
const router = useRouter()
|
||||
|
||||
const transitionName = ref('page-fade')
|
||||
|
||||
function routeDepth(path: string) {
|
||||
return path.split('/').filter(Boolean).length
|
||||
}
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
if (!from.name) {
|
||||
transitionName.value = 'page-fade'
|
||||
return
|
||||
}
|
||||
|
||||
const delta = clamp(routeDepth(to.path) - routeDepth(from.path), -1, 1)
|
||||
if (delta > 0) transitionName.value = 'page-forward'
|
||||
else if (delta < 0) transitionName.value = 'page-back'
|
||||
else transitionName.value = 'page-fade'
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await authStore.hydrate()
|
||||
if (authStore.isAuthenticated) {
|
||||
await Promise.all([
|
||||
catalogStore.loadCompanies(),
|
||||
cartStore.hydrate(),
|
||||
orderStore.hydrate(),
|
||||
notificationStore.hydrate(),
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
// خبرهای سفارش از سمت ادمین میآید، پس شمارندهٔ زنگ بهآرامی تازه میشود
|
||||
useIntervalFn(
|
||||
() => {
|
||||
if (authStore.isAuthenticated) void notificationStore.refreshUnreadCount()
|
||||
},
|
||||
60_000,
|
||||
{ immediate: false },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultLayout>
|
||||
<RouterView v-slot="{ Component, route }">
|
||||
<Transition :name="transitionName" mode="out-in">
|
||||
<div :key="route.path" class="page-transition page-shell">
|
||||
<component :is="Component" />
|
||||
</div>
|
||||
</Transition>
|
||||
</RouterView>
|
||||
</DefaultLayout>
|
||||
<ConfirmDialog />
|
||||
</template>
|
||||
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,209 @@
|
||||
/* Application shell — global (unscoped) layout breakpoints */
|
||||
|
||||
.app-shell {
|
||||
height: 100dvh;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background: var(--color-shell-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-layout {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.app-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-main__content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
padding-inline: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.page-transition {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Mobile: full-width native app (< 768px) ── */
|
||||
.app-shell--with-nav {
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.app-shell--with-nav .app-frame {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* ── Tablet + Desktop: sidebar + header shell (>= 768px) ── */
|
||||
@media (min-width: 768px) {
|
||||
.app-shell--with-nav {
|
||||
background: var(--color-page-background);
|
||||
}
|
||||
|
||||
.app-shell--with-nav .app-frame {
|
||||
background: var(--color-page-background);
|
||||
}
|
||||
|
||||
.app-shell--with-nav .app-layout {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* One continuous divider under sidebar brand + top header */
|
||||
.app-shell--with-nav .app-layout::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: var(--header-height);
|
||||
inset-inline: 0;
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
z-index: 30;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scroll lives on app-main__content. Children must not shrink+clip
|
||||
* (flex + overflow:hidden), or short viewports hide the bottom of pages.
|
||||
*/
|
||||
.app-shell--with-nav .app-main__content {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.app-shell--with-nav .app-content,
|
||||
.app-shell--with-nav .page-transition {
|
||||
flex: 1 0 auto;
|
||||
min-height: min-content;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Let route roots grow with content so the shell scroll area can work */
|
||||
.app-shell--with-nav .page-transition > * {
|
||||
flex: 1 0 auto;
|
||||
min-height: min-content;
|
||||
height: auto;
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Guest pages (login, register, checkout) — all breakpoints ── */
|
||||
.app-shell--no-nav {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
background: var(--color-page-background);
|
||||
}
|
||||
|
||||
.app-shell--no-nav .app-layout {
|
||||
max-width: var(--form-max-width);
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: calc(100dvh - 32px);
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-shell--no-nav .app-frame {
|
||||
max-width: var(--form-max-width);
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: calc(100dvh - 32px);
|
||||
min-height: 0;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-frame);
|
||||
background: var(--color-surface);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.app-shell--no-nav .app-main,
|
||||
.app-shell--no-nav .app-main__content,
|
||||
.app-shell--no-nav .app-content,
|
||||
.app-shell--no-nav .page-transition {
|
||||
flex: 1 0 auto;
|
||||
min-height: min-content;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.app-shell--no-nav .app-content {
|
||||
padding-inline: var(--page-padding);
|
||||
}
|
||||
|
||||
.app-shell--no-nav .page {
|
||||
background: transparent;
|
||||
overflow: visible;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.app-shell--no-nav.app-shell--wide .app-layout,
|
||||
.app-shell--no-nav.app-shell--wide .app-frame {
|
||||
max-width: min(var(--content-max-width), calc(100vw - 32px));
|
||||
}
|
||||
|
||||
.app-shell--no-nav.app-shell--wide .app-frame {
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.app-shell--no-nav {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.app-shell--no-nav .app-layout,
|
||||
.app-shell--no-nav .app-frame {
|
||||
max-height: calc(100dvh - 48px);
|
||||
}
|
||||
|
||||
.app-shell--no-nav.app-shell--wide .app-layout,
|
||||
.app-shell--no-nav.app-shell--wide .app-frame {
|
||||
max-width: min(var(--content-max-width), calc(100vw - 48px));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/* Desktop page composition — >= 768px shell, >= 1200px full desktop */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-page {
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: auto;
|
||||
width: 100%;
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
padding: 20px var(--page-padding) 28px;
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.desktop-page__head {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.desktop-page__title {
|
||||
margin: 0 0 6px;
|
||||
font-size: 1.375rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.desktop-page__subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.desktop-two-col {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.desktop-two-col__main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.desktop-summary-panel {
|
||||
position: sticky;
|
||||
top: 16px;
|
||||
padding: 20px;
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.desktop-summary-panel__title {
|
||||
margin: 0 0 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.desktop-summary-panel__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.desktop-summary-panel__row span:first-child {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.desktop-summary-panel__row strong {
|
||||
color: var(--color-text);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.desktop-summary-panel__action {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.desktop-table-wrap {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-card);
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.desktop-table-scroll {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overscroll-behavior-x: contain;
|
||||
}
|
||||
|
||||
.desktop-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.875rem;
|
||||
min-width: 560px;
|
||||
}
|
||||
|
||||
.desktop-table th {
|
||||
padding: 12px 16px;
|
||||
text-align: start;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-bg);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.desktop-table td {
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
color: var(--color-text);
|
||||
vertical-align: middle;
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.desktop-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.desktop-table tbody tr:hover td {
|
||||
background: var(--color-elevated);
|
||||
}
|
||||
|
||||
.desktop-grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.desktop-grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.desktop-grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.desktop-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.desktop-toolbar__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.desktop-btn-compact {
|
||||
width: auto !important;
|
||||
min-width: 120px;
|
||||
padding-inline: 20px !important;
|
||||
}
|
||||
|
||||
.desktop-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.desktop-form-grid__full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.desktop-checkout-shell {
|
||||
width: 100%;
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
padding: 20px var(--page-padding) 28px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.desktop-settlement-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(280px, 380px));
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
max-width: 820px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.desktop-company-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(280px, 400px));
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
max-width: 900px;
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-page {
|
||||
padding: 24px var(--page-padding) 32px;
|
||||
}
|
||||
|
||||
.desktop-checkout-shell {
|
||||
padding: 24px var(--page-padding) 32px;
|
||||
}
|
||||
|
||||
.desktop-page__head {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.desktop-two-col:has(> .desktop-summary-panel) {
|
||||
grid-template-columns: minmax(0, 1fr) var(--summary-panel-width, 320px);
|
||||
}
|
||||
|
||||
.desktop-grid-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.desktop-grid-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.desktop-grid-3 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,613 @@
|
||||
/* App shell page layouts — 768px and above */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:root {
|
||||
--page-padding: var(--page-padding-tablet);
|
||||
--nav-height: 0px;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 20px var(--page-padding-tablet) 28px;
|
||||
background: transparent;
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
min-height: auto;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.page__scroll {
|
||||
overflow: visible;
|
||||
flex: none;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.page__scroll--with-nav {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* Shared page headings */
|
||||
.page-head {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-head__title {
|
||||
margin: 0 0 4px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-head__subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* Orders dashboard */
|
||||
.orders-page__desktop-head {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.orders-page__desktop-title {
|
||||
margin: 0 0 6px;
|
||||
font-size: 1.375rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-page__desktop-subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.orders-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.orders-stat-card {
|
||||
padding: 16px 18px 14px;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-sm);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.orders-stat-card__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.orders-stat-card__label {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.orders-stat-card__label--total,
|
||||
.orders-stat-card__label--review {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-stat-card__label--active {
|
||||
color: #ea580c;
|
||||
}
|
||||
|
||||
.orders-stat-card__label--done {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.orders-stat-card__value {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
line-height: 1.15;
|
||||
margin: 0 0 12px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.orders-stat-card__link {
|
||||
margin-top: auto;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--color-primary);
|
||||
font-family: inherit;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.orders-stat-card__link:hover {
|
||||
color: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.orders-stat-card__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.orders-stat-card__icon--total {
|
||||
background: var(--color-primary-soft);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.orders-stat-card__icon--review {
|
||||
background: var(--color-primary-soft);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.orders-stat-card__icon--active {
|
||||
background: var(--color-warning-light);
|
||||
color: #ea580c;
|
||||
}
|
||||
|
||||
.orders-stat-card__icon--done {
|
||||
background: var(--color-success-soft);
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.orders-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.orders-toolbar__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.orders-toolbar__filter-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 40px;
|
||||
padding: 0 18px;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-toolbar__filter-btn:hover {
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.orders-toolbar__pills {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.orders-filter-pill {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 999px;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-muted);
|
||||
font-family: inherit;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition:
|
||||
background 0.15s,
|
||||
color 0.15s,
|
||||
border-color 0.15s;
|
||||
}
|
||||
|
||||
.orders-filter-pill:hover {
|
||||
border-color: #cbd5e1;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-filter-pill--active {
|
||||
background: var(--color-primary-soft);
|
||||
border-color: #c7d7ff;
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.orders-table-wrap {
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-card);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.orders-table-scroll {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.875rem;
|
||||
min-width: 720px;
|
||||
}
|
||||
|
||||
.orders-table th {
|
||||
padding: 14px 16px;
|
||||
text-align: start;
|
||||
font-weight: 600;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-bg);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-table td {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
color: var(--color-text);
|
||||
vertical-align: middle;
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.orders-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.orders-table tbody tr:hover td {
|
||||
background: var(--color-elevated);
|
||||
}
|
||||
|
||||
.orders-table__number {
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-table__amount {
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-table__date {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8125rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-table__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.orders-table__action {
|
||||
padding: 7px 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-primary);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-table__action:hover {
|
||||
background: var(--color-primary-soft);
|
||||
border-color: #c7d7ff;
|
||||
}
|
||||
|
||||
.orders-table__menu {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.orders-table__menu:hover {
|
||||
background: var(--color-elevated);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 14px 16px;
|
||||
border-top: 1px solid var(--color-border);
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.orders-pagination__summary {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.orders-pagination__controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.orders-pagination__arrow {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-pagination__arrow:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.orders-pagination__arrow:not(:disabled):hover {
|
||||
border-color: var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.orders-pagination__arrow-icon--prev {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.orders-pagination__arrow-icon--next {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.orders-pagination__ellipsis {
|
||||
min-width: 24px;
|
||||
text-align: center;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.orders-pagination__page {
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
padding: 0 6px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.orders-pagination__page:hover:not(.orders-pagination__page--active) {
|
||||
border-color: var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.orders-pagination__page--active {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Product page desktop layout */
|
||||
.product-page__layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 300px;
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.product-page__main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.product-page__sidebar {
|
||||
position: sticky;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.cart-summary-panel {
|
||||
padding: 20px;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.cart-summary-panel__title {
|
||||
margin: 0 0 16px;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.cart-summary-panel__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.cart-summary-panel__row span:first-child {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.cart-summary-panel__row strong {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.cart-summary-panel__btn {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.product-page__scroll {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.product-page .sticky-footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.product-list {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
/* Cart desktop */
|
||||
.cart-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
padding: 20px var(--page-padding-tablet) 28px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.cart-page__desktop-title {
|
||||
margin: 0 0 16px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-page__body {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(280px, 320px);
|
||||
gap: 20px 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.cart-page__company {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
/* Order detail desktop */
|
||||
.order-detail-page {
|
||||
max-width: none;
|
||||
margin-inline: 0;
|
||||
padding: 24px var(--page-padding) 32px;
|
||||
background: transparent;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.order-detail-back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 12px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--color-primary);
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Company select desktop */
|
||||
.company-select-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
padding: 24px var(--page-padding-desktop);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Catalog desktop */
|
||||
.catalog-page {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.catalog-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
/* Profile desktop */
|
||||
.profile-page {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.profile-hero {
|
||||
border-radius: var(--radius-md);
|
||||
margin-inline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
:root {
|
||||
--page-padding: var(--page-padding-desktop);
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 24px var(--page-padding-desktop) 32px;
|
||||
}
|
||||
|
||||
.orders-stats {
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.orders-page__desktop-head {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.orders-toolbar {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.catalog-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.product-list {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum).woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Light.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_UltraLight.woff2') format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Medium.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Medium.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IRANSans';
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Black.woff2') format('woff2');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
:root {
|
||||
/* Brand — sampled from mockups/11-my-profile + FAB/CTA screens */
|
||||
--color-primary: #0a353c;
|
||||
--color-primary-hover: #072a2f;
|
||||
--color-primary-soft: #e8f4f1;
|
||||
--color-primary-dark: #062428;
|
||||
--color-primary-light: #e8f4f1;
|
||||
--color-primary-rgb: 10, 53, 60;
|
||||
--color-accent-navy: #1b223c;
|
||||
--color-accent-navy-rgb: 27, 34, 60;
|
||||
--color-success: #1b8a5a;
|
||||
--color-success-light: #eaf8f1;
|
||||
--color-success-soft: #eaf8f1;
|
||||
--color-warning: #e8a317;
|
||||
--color-warning-light: #fff6e5;
|
||||
--color-danger: #dc3545;
|
||||
--color-danger-light: #fee2e2;
|
||||
--color-purple: #7c3aed;
|
||||
--color-purple-light: #ede9fe;
|
||||
--color-info: #3b6fa0;
|
||||
--color-info-light: #eef3f7;
|
||||
--color-bg: #f6f8f7;
|
||||
--color-page-background: #f6f8f7;
|
||||
--color-shell-bg: #eef1f0;
|
||||
--color-surface: #ffffff;
|
||||
--color-border: #e5e9e8;
|
||||
--color-text: #121212;
|
||||
--color-text-primary: #121212;
|
||||
--color-text-muted: #6b7280;
|
||||
--color-text-secondary: #6b7280;
|
||||
--color-tab-inactive-bg: #f1f5f9;
|
||||
--color-tab-inactive-text: #64748b;
|
||||
--color-summary-bg: #f1f5f9;
|
||||
--color-elevated: #ffffff;
|
||||
--color-brand-warm: #f3ece3;
|
||||
--color-brand-warm-text: #1a202c;
|
||||
--color-brand-warm-muted: #718096;
|
||||
--color-level-gold: #c9a227;
|
||||
--color-level-gold-soft: #f7efd6;
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 12px;
|
||||
--radius-lg: 16px;
|
||||
--shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04);
|
||||
--shadow-md: 0 4px 16px rgba(16, 24, 40, 0.06);
|
||||
--shadow-card: 0 1px 2px rgba(16, 24, 40, 0.04), 0 4px 16px rgba(16, 24, 40, 0.04);
|
||||
--shadow-frame: 0 8px 32px rgba(15, 23, 42, 0.1);
|
||||
--nav-height: 64px;
|
||||
--page-padding: 16px;
|
||||
--page-padding-tablet: 20px;
|
||||
--page-padding-desktop: 28px;
|
||||
--page-gap: 12px;
|
||||
--content-max-width: 1360px;
|
||||
--form-max-width: 520px;
|
||||
--auth-form-max-width: 440px;
|
||||
--summary-panel-width: 320px;
|
||||
--sidebar-width: 240px;
|
||||
--sidebar-width-compact: 72px;
|
||||
--header-height: 70px;
|
||||
--app-shell-breakpoint: 768px;
|
||||
--font-family: 'IRANSans', 'Tahoma', sans-serif;
|
||||
--btn-height: 48px;
|
||||
--desktop-breakpoint: 1200px;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
--color-primary: #5eb8ad;
|
||||
--color-primary-hover: #7ad0c5;
|
||||
--color-primary-soft: #14353a;
|
||||
--color-primary-dark: #7ad0c5;
|
||||
--color-primary-light: #14353a;
|
||||
--color-primary-rgb: 94, 184, 173;
|
||||
--color-accent-navy: #9bb0d0;
|
||||
--color-accent-navy-rgb: 155, 176, 208;
|
||||
--color-success: #3dd68c;
|
||||
--color-success-light: #123528;
|
||||
--color-success-soft: #123528;
|
||||
--color-warning: #f5c14a;
|
||||
--color-warning-light: #3a2f14;
|
||||
--color-danger: #f47979;
|
||||
--color-danger-light: #3f1d22;
|
||||
--color-purple: #b39afa;
|
||||
--color-purple-light: #2a2144;
|
||||
--color-info: #7b9cff;
|
||||
--color-info-light: #1b2740;
|
||||
--color-bg: #0b0f14;
|
||||
--color-page-background: #0b0f14;
|
||||
--color-shell-bg: #080b10;
|
||||
--color-surface: #121821;
|
||||
--color-elevated: #1a2230;
|
||||
--color-border: #2a3444;
|
||||
--color-text: #eef2f8;
|
||||
--color-text-primary: #eef2f8;
|
||||
--color-text-muted: #9aa8bc;
|
||||
--color-text-secondary: #9aa8bc;
|
||||
--color-tab-inactive-bg: #1a2230;
|
||||
--color-tab-inactive-text: #9aa8bc;
|
||||
--color-summary-bg: #1a2230;
|
||||
--color-brand-warm: #2a241c;
|
||||
--color-brand-warm-text: #f3ebe0;
|
||||
--color-brand-warm-muted: #b9a88d;
|
||||
--color-level-gold: #e0c35a;
|
||||
--color-level-gold-soft: #3a3420;
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
|
||||
--shadow-md: 0 8px 24px rgba(0, 0, 0, 0.45);
|
||||
--shadow-card: 0 1px 2px rgba(0, 0, 0, 0.35), 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||
--shadow-frame: 0 12px 40px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-family);
|
||||
background: var(--color-shell-bg);
|
||||
color: var(--color-text);
|
||||
line-height: 1.5;
|
||||
direction: rtl;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100dvh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
input[type='number']::-webkit-inner-spin-button,
|
||||
input[type='number']::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.page {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page__scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.page__scroll--with-nav {
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
margin: 0 0 4px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--color-elevated);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
padding: 16px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.auth-page .card {
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
.card + .card {
|
||||
margin-top: var(--page-gap);
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 14px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background: var(--color-primary-light);
|
||||
color: var(--color-primary);
|
||||
border: 1px solid #cbd5e1;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background: var(--color-warning-light);
|
||||
color: #9a3412;
|
||||
border: 1px solid #fed7aa;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: var(--color-success-light);
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background: var(--color-danger-light);
|
||||
color: #991b1b;
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.form-hint {
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-muted);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sticky-footer {
|
||||
position: fixed;
|
||||
bottom: calc(var(--nav-height) + 12px);
|
||||
inset-inline: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
z-index: 50;
|
||||
padding-inline: var(--page-padding);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sticky-footer-inner {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.no-nav .page {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.no-nav .sticky-footer {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(15, 23, 42, 0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.dialog-overlay .dialog {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* Responsive visibility */
|
||||
.desktop-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-hidden {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.desktop-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-only,
|
||||
.mobile-block {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mobile-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.desktop-hidden {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.desktop-only-flex {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.desktop-only-grid {
|
||||
display: grid !important;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.page__scroll--with-nav {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Page route transitions */
|
||||
.page-fade-enter-active,
|
||||
.page-fade-leave-active,
|
||||
.page-forward-enter-active,
|
||||
.page-forward-leave-active,
|
||||
.page-back-enter-active,
|
||||
.page-back-leave-active {
|
||||
transition:
|
||||
opacity 0.22s ease,
|
||||
transform 0.22s ease;
|
||||
}
|
||||
|
||||
.page-fade-enter-from,
|
||||
.page-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.page-forward-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-18px);
|
||||
}
|
||||
|
||||
.page-forward-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(12px);
|
||||
}
|
||||
|
||||
.page-back-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(18px);
|
||||
}
|
||||
|
||||
.page-back-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-12px);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.page-fade-enter-active,
|
||||
.page-fade-leave-active,
|
||||
.page-forward-enter-active,
|
||||
.page-forward-leave-active,
|
||||
.page-back-enter-active,
|
||||
.page-back-leave-active {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/* Responsive breakpoints:
|
||||
Mobile: < 768px
|
||||
Tablet: 768px – 1199px
|
||||
Desktop: >= 1200px
|
||||
Large desktop: >= 1440px
|
||||
*/
|
||||
|
||||
@media (min-width: 768px) {
|
||||
:root {
|
||||
--page-padding: var(--page-padding-tablet);
|
||||
--nav-height: 0px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100dvh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cbd5e1 transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.sticky-footer {
|
||||
bottom: 0;
|
||||
max-width: min(var(--content-max-width), calc(100% - 2 * var(--page-padding)));
|
||||
}
|
||||
|
||||
.no-nav .sticky-footer {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* Auth pages */
|
||||
.auth-page__scroll {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-block: 48px;
|
||||
}
|
||||
|
||||
.auth-header,
|
||||
.auth-page .card,
|
||||
.auth-footer {
|
||||
width: 100%;
|
||||
max-width: var(--form-max-width);
|
||||
}
|
||||
|
||||
/* Company selection */
|
||||
.company-select-page__list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.company-brand-card {
|
||||
min-height: 220px;
|
||||
}
|
||||
|
||||
/* Catalog & product grids */
|
||||
.catalog-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--page-gap);
|
||||
}
|
||||
|
||||
.product-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--page-gap);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.product-page__scroll {
|
||||
padding-bottom: 88px;
|
||||
}
|
||||
|
||||
/* Settlement & check mode */
|
||||
.settlement-options,
|
||||
.mode-options {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
max-width: 720px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* Company page container */
|
||||
.company-select-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
padding-inline: var(--page-padding);
|
||||
}
|
||||
|
||||
.company-select-page__header {
|
||||
max-width: 560px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* Catalog & orders page containers */
|
||||
.catalog-page .page__scroll,
|
||||
.orders-page__scroll,
|
||||
.product-page .product-page__scroll {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Cart two-column layout */
|
||||
.cart-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
padding-inline: var(--page-padding);
|
||||
}
|
||||
|
||||
.cart-page__body {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(260px, 300px);
|
||||
grid-template-rows: auto 1fr;
|
||||
gap: 16px 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.cart-page__company {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 0.9375rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cart-page__scroll {
|
||||
grid-column: 1;
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.cart-page__footer {
|
||||
grid-column: 2;
|
||||
grid-row: 1 / -1;
|
||||
position: sticky;
|
||||
top: 16px;
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
border-top: none;
|
||||
box-shadow: var(--shadow-md);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.cart-table__head {
|
||||
position: static;
|
||||
}
|
||||
|
||||
/* Check list */
|
||||
.check-list-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
padding-inline: var(--page-padding);
|
||||
}
|
||||
|
||||
.check-list-page__scroll {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.summary-cards {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.checks-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.rass-panel {
|
||||
max-width: 480px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* Profile */
|
||||
.profile-page__scroll {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.profile-menu {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.profile-menu__item {
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-surface);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* Order detail & tracking */
|
||||
.order-detail-page__body {
|
||||
max-width: none;
|
||||
margin-inline: 0;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.order-detail-page__footer {
|
||||
max-width: none;
|
||||
margin-inline: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Checkout forms */
|
||||
.checkout-page__scroll,
|
||||
.cash-page__scroll,
|
||||
.settlement-page__scroll,
|
||||
.check-mode-page__scroll {
|
||||
max-width: var(--form-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Cash settlement desktop */
|
||||
.cash-page {
|
||||
max-width: var(--content-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cash-page__footer {
|
||||
max-width: var(--form-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
border-top: none;
|
||||
box-shadow: none;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.accounts-panel {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.bank-card + .bank-card {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.cash-page__submit {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.order-info-card {
|
||||
max-width: 520px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* Profile edit */
|
||||
.profile-edit-page .page__scroll {
|
||||
max-width: var(--form-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Success page */
|
||||
.success-page__scroll {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: var(--form-max-width);
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Dialogs */
|
||||
.dialog-overlay .dialog,
|
||||
.dialog-overlay .card.dialog {
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
:root {
|
||||
--page-padding: var(--page-padding-desktop);
|
||||
}
|
||||
|
||||
.catalog-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.checks-list {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.product-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1920px) {
|
||||
:root {
|
||||
--content-max-width: 1120px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue'
|
||||
import icons from '@/components/BasicPacks/tools/icons/icons.json'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
icon: string
|
||||
color?: string | null
|
||||
size?: string | number
|
||||
strokeWidth?: string | number
|
||||
}>(),
|
||||
{
|
||||
color: null,
|
||||
size: 24,
|
||||
strokeWidth: 1.5,
|
||||
},
|
||||
)
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const attrs = useAttrs()
|
||||
|
||||
const svgHtml = computed(() => {
|
||||
const raw = (icons as Record<string, string>)[props.icon]
|
||||
if (!raw) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.warn(`[BasicIcon] missing icon: ${props.icon}`)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const size = String(props.size)
|
||||
return raw
|
||||
.replace(/\swidth="[^"]*"/, ` width="${size}"`)
|
||||
.replace(/\sheight="[^"]*"/, ` height="${size}"`)
|
||||
.replace(/stroke="#[^"]*"/g, 'stroke="currentColor"')
|
||||
})
|
||||
|
||||
const style = computed(() => ({
|
||||
color: props.color || undefined,
|
||||
width: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
lineHeight: 0,
|
||||
flexShrink: 0,
|
||||
}))
|
||||
const ariaHidden = computed(() => {
|
||||
const value = attrs['aria-hidden']
|
||||
if (value === undefined || value === null) return true
|
||||
return value as boolean | 'true' | 'false'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="basic-icon"
|
||||
v-bind="attrs"
|
||||
:style="style"
|
||||
:aria-hidden="ariaHidden"
|
||||
v-html="svgHtml"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.basic-icon :deep(svg) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.basic-icon {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.basic-icon :deep(svg path) {
|
||||
stroke: currentColor;
|
||||
stroke-width: v-bind('String(props.strokeWidth)');
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"vuesax-linear:add": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M6 12H18\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 18V6\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:arrow-down": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M19.9201 8.94995L13.4001 15.47C12.6301 16.24 11.3701 16.24 10.6001 15.47L4.08008 8.94995\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:arrow-left-1": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M15 19.9201L8.47997 13.4001C7.70997 12.6301 7.70997 11.3701 8.47997 10.6001L15 4.08008\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:arrow-right-1": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.91003 19.9201L15.43 13.4001C16.2 12.6301 16.2 11.3701 15.43 10.6001L8.91003 4.08008\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:bag-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M7.5 7.67001V6.70001C7.5 4.45001 9.31 2.24001 11.56 2.03001C14.24 1.77001 16.5 3.88001 16.5 6.51001V7.89001\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.99999 22H15C19.02 22 19.74 20.39 19.95 18.43L20.7 12.43C20.97 9.99 20.27 8 16 8H7.99999C3.72999 8 3.02999 9.99 3.29999 12.43L4.04999 18.43C4.25999 20.39 4.97999 22 8.99999 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.4955 12H15.5045\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.49451 12H8.50349\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:bag-cross": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M13.39 17.36L10.64 14.61\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M13.36 14.64L10.61 17.39\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.81 2L5.19 5.63\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.19 2L18.81 5.63\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 7.84998C2 5.99998 2.99 5.84998 4.22 5.84998H19.78C21.01 5.84998 22 5.99998 22 7.84998C22 9.99998 21.01 9.84998 19.78 9.84998H4.22C2.99 9.84998 2 9.99998 2 7.84998Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n<path d=\"M3.5 10L4.91 18.64C5.23 20.58 6 22 8.86 22H14.89C18 22 18.46 20.64 18.82 18.76L20.5 10\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:box-1": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3.17004 7.43994L12 12.5499L20.77 7.46994\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 21.61V12.54\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.93001 2.48004L4.59001 5.44004C3.38001 6.11004 2.39001 7.79004 2.39001 9.17004V14.82C2.39001 16.2 3.38001 17.88 4.59001 18.55L9.93001 21.52C11.07 22.15 12.94 22.15 14.08 21.52L19.42 18.55C20.63 17.88 21.62 16.2 21.62 14.82V9.17004C21.62 7.79004 20.63 6.11004 19.42 5.44004L14.08 2.47004C12.93 1.84004 11.07 1.84004 9.93001 2.48004Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:box-remove": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3.17004 7.43994L12 12.5499L20.77 7.46991\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 21.6099V12.5399\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21.61 9.17V14.83C21.61 14.88 21.61 14.92 21.6 14.97C20.9 14.36 20 14 19 14C18.06 14 17.19 14.33 16.5 14.88C15.58 15.61 15 16.74 15 18C15 18.75 15.21 19.46 15.58 20.06C15.67 20.22 15.78 20.37 15.9 20.51L14.07 21.52C12.93 22.16 11.07 22.16 9.92999 21.52L4.59 18.56C3.38 17.89 2.39001 16.21 2.39001 14.83V9.17C2.39001 7.79 3.38 6.11002 4.59 5.44002L9.92999 2.48C11.07 1.84 12.93 1.84 14.07 2.48L19.41 5.44002C20.62 6.11002 21.61 7.79 21.61 9.17Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M23 18C23 18.75 22.79 19.46 22.42 20.06C22.21 20.42 21.94 20.74 21.63 21C20.93 21.63 20.01 22 19 22C17.54 22 16.27 21.22 15.58 20.06C15.21 19.46 15 18.75 15 18C15 16.74 15.58 15.61 16.5 14.88C17.19 14.33 18.06 14 19 14C21.21 14 23 15.79 23 18Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20.07 19.0399L17.95 16.9299\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20.05 16.96L17.93 19.0699\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:box-search": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3.17004 7.43994L12 12.5499L20.77 7.46991\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 21.6099V12.5399\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21.61 12.83V9.17C21.61 7.79 20.62 6.11002 19.41 5.44002L14.07 2.48C12.93 1.84 11.07 1.84 9.92999 2.48L4.59 5.44002C3.38 6.11002 2.39001 7.79 2.39001 9.17V14.83C2.39001 16.21 3.38 17.89 4.59 18.56L9.92999 21.52C10.5 21.84 11.25 22 12 22C12.75 22 13.5 21.84 14.07 21.52\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M19.2 21.4C20.9673 21.4 22.4 19.9673 22.4 18.2C22.4 16.4327 20.9673 15 19.2 15C17.4327 15 16 16.4327 16 18.2C16 19.9673 17.4327 21.4 19.2 21.4Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M23 22L22 21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:building": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12.5 22.0001H4.07997C2.91997 22.0001 1.96997 21.0701 1.96997 19.9301V5.09011C1.96997 2.47011 3.91997 1.2801 6.30997 2.4501L10.75 4.63011C11.71 5.10011 12.5 6.3501 12.5 7.4101V22.0001Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21.97 15.0602V18.8402C21.97 21.0002 20.97 22.0002 18.81 22.0002H12.5V10.4202L12.97 10.5202L17.47 11.5302L19.5 11.9802C20.82 12.2702 21.9 12.9502 21.96 14.8702C21.97 14.9302 21.97 14.9902 21.97 15.0602Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.5 9H8.97\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.5 13H8.97\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17.47 11.53V14.75C17.47 15.99 16.46 17 15.22 17C13.98 17 12.97 15.99 12.97 14.75V10.52L17.47 11.53Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21.96 14.87C21.9 16.05 20.92 17 19.72 17C18.48 17 17.47 15.99 17.47 14.75V11.53L19.5 11.98C20.82 12.27 21.9 12.95 21.96 14.87Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:buildings": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M13 22H5C3 22 2 21 2 19V11C2 9 3 8 5 8H10V19C10 21 11 22 13 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.11 4C10.03 4.3 10 4.63 10 5V8H5V6C5 4.9 5.9 4 7 4H10.11Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M14 8V13\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18 8V13\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 17H15C14.45 17 14 17.45 14 18V22H18V18C18 17.45 17.55 17 17 17Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6 13V17\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10 19V5C10 3 11 2 13 2H19C21 2 22 3 22 5V19C22 21 21 22 19 22H13C11 22 10 21 10 19Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:calendar": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8 2V5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 2V5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M3.5 9.08997H20.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21 8.5V17C21 20 19.5 22 16 22H8C4.5 22 3 20 3 17V8.5C3 5.5 4.5 3.5 8 3.5H16C19.5 3.5 21 5.5 21 8.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.6947 13.7H15.7037\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.6947 16.7H15.7037\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.9955 13.7H12.0045\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.9955 16.7H12.0045\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.29431 13.7H8.30329\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.29431 16.7H8.30329\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:call": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M21.97 18.33C21.97 18.69 21.89 19.06 21.72 19.42C21.55 19.78 21.33 20.12 21.04 20.44C20.55 20.98 20.01 21.37 19.4 21.62C18.8 21.87 18.15 22 17.45 22C16.43 22 15.34 21.76 14.19 21.27C13.04 20.78 11.89 20.12 10.75 19.29C9.6 18.45 8.51 17.52 7.47 16.49C6.44 15.45 5.51 14.36 4.68 13.22C3.86 12.08 3.2 10.94 2.72 9.81C2.24 8.67 2 7.58 2 6.54C2 5.86 2.12 5.21 2.36 4.61C2.6 4 2.98 3.44 3.51 2.94C4.15 2.31 4.85 2 5.59 2C5.87 2 6.15 2.06 6.4 2.18C6.66 2.3 6.89 2.48 7.07 2.74L9.39 6.01C9.57 6.26 9.7 6.49 9.79 6.71C9.88 6.92 9.93 7.13 9.93 7.32C9.93 7.56 9.86 7.8 9.72 8.03C9.59 8.26 9.4 8.5 9.16 8.74L8.4 9.53C8.29 9.64 8.24 9.77 8.24 9.93C8.24 10.01 8.25 10.08 8.27 10.16C8.3 10.24 8.33 10.3 8.35 10.36C8.53 10.69 8.84 11.12 9.28 11.64C9.73 12.16 10.21 12.69 10.73 13.22C11.27 13.75 11.79 14.24 12.32 14.69C12.84 15.13 13.27 15.43 13.61 15.61C13.66 15.63 13.72 15.66 13.79 15.69C13.87 15.72 13.95 15.73 14.04 15.73C14.21 15.73 14.34 15.67 14.45 15.56L15.21 14.81C15.46 14.56 15.7 14.37 15.93 14.25C16.16 14.11 16.39 14.04 16.64 14.04C16.83 14.04 17.03 14.08 17.25 14.17C17.47 14.26 17.7 14.39 17.95 14.56L21.26 16.91C21.52 17.09 21.7 17.3 21.81 17.55C21.91 17.8 21.97 18.05 21.97 18.33Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\"/>\n</svg>\n",
|
||||
"vuesax-linear:card": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M2 8.50488H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6 16.5049H8\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.5 16.5049H14.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6.44 3.50488H17.55C21.11 3.50488 22 4.38488 22 7.89488V16.1049C22 19.6149 21.11 20.4949 17.56 20.4949H6.44C2.89 20.5049 2 19.6249 2 16.1149V7.89488C2 4.38488 2.89 3.50488 6.44 3.50488Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:card-receive": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M2 8.5H14.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6 16.5H8\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.5 16.5H14.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 14.03V16.11C22 19.62 21.11 20.5 17.56 20.5H6.44C2.89 20.5 2 19.62 2 16.11V7.89C2 4.38 2.89 3.5 6.44 3.5H14.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20 3.5V9.5L22 7.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20 9.5L18 7.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:category": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5 10H7C9 10 10 9 10 7V5C10 3 9 2 7 2H5C3 2 2 3 2 5V7C2 9 3 10 5 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 10H19C21 10 22 9 22 7V5C22 3 21 2 19 2H17C15 2 14 3 14 5V7C14 9 15 10 17 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 22H19C21 22 22 21 22 19V17C22 15 21 14 19 14H17C15 14 14 15 14 17V19C14 21 15 22 17 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5 22H7C9 22 10 21 10 19V17C10 15 9 14 7 14H5C3 14 2 15 2 17V19C2 21 3 22 5 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:chart-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M9 22H15C20 22 22 20 22 15V9C22 4 20 2 15 2H9C4 2 2 4 2 9V15C2 20 4 22 9 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.5 18.5C16.6 18.5 17.5 17.6 17.5 16.5V7.5C17.5 6.4 16.6 5.5 15.5 5.5C14.4 5.5 13.5 6.4 13.5 7.5V16.5C13.5 17.6 14.39 18.5 15.5 18.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 18.5C9.6 18.5 10.5 17.6 10.5 16.5V13C10.5 11.9 9.6 11 8.5 11C7.4 11 6.5 11.9 6.5 13V16.5C6.5 17.6 7.39 18.5 8.5 18.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:clipboard-close": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M14 16.16L10.04 12.2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M13.96 12.24L10 16.2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10 6H14C16 6 16 5 16 4C16 2 15 2 14 2H10C9 2 8 2 8 4C8 6 9 6 10 6Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 4.02002C19.33 4.20002 21 5.43002 21 10V16C21 20 20 22 15 22H9C4 22 3 20 3 16V10C3 5.44002 4.67 4.20002 8 4.02002\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:clock": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 9.66003V12.45L13.4 13.85\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.5 12C5.5 8.41 8.41 5.5 12 5.5C15.59 5.5 18.5 8.41 18.5 12C18.5 14.08 17.52 15.94 16 17.13H15.99C14.89 17.99 13.51 18.5 12 18.5C10.51 18.5 9.14 18 8.04 17.15H8.03C6.49 15.96 5.5 14.1 5.5 12Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.03003 17.15H8.04003C9.14003 18 10.51 18.5 12 18.5C13.51 18.5 14.89 17.99 15.99 17.13H16L15.49 19.6C15 21.5 13.9 22 12.55 22H11.46C10.11 22 9.00003 21.5 8.52003 19.59L8.03003 17.15Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.03003 6.85H8.04003C9.14003 6 10.51 5.5 12 5.5C13.51 5.5 14.89 6.01 15.99 6.87H16L15.49 4.4C15 2.5 13.9 2 12.55 2H11.46C10.11 2 9.00003 2.5 8.52003 4.41L8.03003 6.85Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:close-circle": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.16998 14.83L14.83 9.17004\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M14.83 14.83L9.16998 9.17004\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:cpu": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M9.6 20H14.4C18.4 20 20 18.4 20 14.4V9.6C20 5.6 18.4 4 14.4 4H9.6C5.6 4 4 5.6 4 9.6V14.4C4 18.4 5.6 20 9.6 20Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.5 17H13.5C16 17 17 16 17 13.5V10.5C17 8 16 7 13.5 7H10.5C8 7 7 8 7 10.5V13.5C7 16 8 17 10.5 17Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.01001 4V2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 4V2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 4V2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20 8H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20 12H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20 16H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 20V22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12.01 20V22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.01001 20V22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 8H4\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 12H4\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 16H4\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:diamonds": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M16.29 2.15002H7.69995C5.99995 2.15002 5.24995 3.00002 4.78995 4.04002L2.22995 9.80002C1.76995 10.84 2.01995 12.39 2.78995 13.23L9.64995 20.77C10.95 22.19 13.07 22.19 14.36 20.77L21.21 13.22C21.98 12.37 22.23 10.83 21.76 9.79002L19.2 4.03002C18.74 3.00002 17.99 2.15002 16.29 2.15002Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M3.5 8H20.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:document-text": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M21 7V17C21 20 19.5 22 16 22H8C4.5 22 3 20 3 17V7C3 4 4.5 2 8 2H16C19.5 2 21 4 21 7Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M14.5 4.5V6.5C14.5 7.6 15.4 8.5 16.5 8.5H18.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8 13H12\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8 17H16\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:edit-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M13.26 3.59997L5.04997 12.29C4.73997 12.62 4.43997 13.27 4.37997 13.72L4.00997 16.96C3.87997 18.13 4.71997 18.93 5.87997 18.73L9.09997 18.18C9.54997 18.1 10.18 17.77 10.49 17.43L18.7 8.73997C20.12 7.23997 20.76 5.52997 18.55 3.43997C16.35 1.36997 14.68 2.09997 13.26 3.59997Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.89 5.05005C12.32 7.81005 14.56 9.92005 17.34 10.2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M3 22H21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:element-3": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M22 8.52V3.98C22 2.57 21.36 2 19.77 2H15.73C14.14 2 13.5 2.57 13.5 3.98V8.51C13.5 9.93 14.14 10.49 15.73 10.49H19.77C21.36 10.5 22 9.93 22 8.52Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 19.77V15.73C22 14.14 21.36 13.5 19.77 13.5H15.73C14.14 13.5 13.5 14.14 13.5 15.73V19.77C13.5 21.36 14.14 22 15.73 22H19.77C21.36 22 22 21.36 22 19.77Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.5 8.52V3.98C10.5 2.57 9.86 2 8.27 2H4.23C2.64 2 2 2.57 2 3.98V8.51C2 9.93 2.64 10.49 4.23 10.49H8.27C9.86 10.5 10.5 9.93 10.5 8.52Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.5 19.77V15.73C10.5 14.14 9.86 13.5 8.27 13.5H4.23C2.64 13.5 2 14.14 2 15.73V19.77C2 21.36 2.64 22 4.23 22H8.27C9.86 22 10.5 21.36 10.5 19.77Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:eye": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M15.58 12C15.58 13.98 13.98 15.58 12 15.58C10.02 15.58 8.42004 13.98 8.42004 12C8.42004 10.02 10.02 8.42004 12 8.42004C13.98 8.42004 15.58 10.02 15.58 12Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 20.27C15.53 20.27 18.82 18.19 21.11 14.59C22.01 13.18 22.01 10.81 21.11 9.39997C18.82 5.79997 15.53 3.71997 12 3.71997C8.46997 3.71997 5.17997 5.79997 2.88997 9.39997C1.98997 10.81 1.98997 13.18 2.88997 14.59C5.17997 18.19 8.46997 20.27 12 20.27Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:eye-slash": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M14.53 9.47004L9.47004 14.53C8.82004 13.88 8.42004 12.99 8.42004 12C8.42004 10.02 10.02 8.42004 12 8.42004C12.99 8.42004 13.88 8.82004 14.53 9.47004Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17.82 5.76998C16.07 4.44998 14.07 3.72998 12 3.72998C8.46997 3.72998 5.17997 5.80998 2.88997 9.40998C1.98997 10.82 1.98997 13.19 2.88997 14.6C3.67997 15.84 4.59997 16.91 5.59997 17.77\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.42004 19.5301C9.56004 20.0101 10.77 20.2701 12 20.2701C15.53 20.2701 18.82 18.1901 21.11 14.5901C22.01 13.1801 22.01 10.8101 21.11 9.40005C20.78 8.88005 20.42 8.39005 20.05 7.93005\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.5099 12.7C15.2499 14.11 14.0999 15.26 12.6899 15.52\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.47 14.53L2 22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 2L14.53 9.47\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:filter": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5.40002 2.09998H18.6C19.7 2.09998 20.6 2.99998 20.6 4.09998V6.29998C20.6 7.09998 20.1 8.09998 19.6 8.59998L15.3 12.4C14.7 12.9 14.3 13.9 14.3 14.7V19C14.3 19.6 13.9 20.4 13.4 20.7L12 21.6C10.7 22.4 8.90002 21.5 8.90002 19.9V14.6C8.90002 13.9 8.50002 13 8.10002 12.5L4.30002 8.49998C3.80002 7.99998 3.40002 7.09998 3.40002 6.49998V4.19998C3.40002 2.99998 4.30002 2.09998 5.40002 2.09998Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.93 2.09998L6 9.99998\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:flash": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M9.31993 13.28H12.4099V20.48C12.4099 21.54 13.7299 22.04 14.4299 21.24L21.9999 12.64C22.6599 11.89 22.1299 10.72 21.1299 10.72H18.0399V3.51997C18.0399 2.45997 16.7199 1.95997 16.0199 2.75997L8.44994 11.36C7.79994 12.11 8.32993 13.28 9.31993 13.28Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 4H1.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7.5 20H1.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M4.5 12H1.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:headphone": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5.46005 18.49V15.57C5.46005 14.6 6.22005 13.73 7.30005 13.73C8.27005 13.73 9.14005 14.49 9.14005 15.57V18.38C9.14005 20.33 7.52005 21.9501 5.57005 21.9501C3.62005 21.9501 2.00005 20.32 2.00005 18.38V12.22C1.89005 6.60005 6.33005 2.05005 11.95 2.05005C17.57 2.05005 22 6.60005 22 12.11V18.2701C22 20.2201 20.38 21.84 18.43 21.84C16.48 21.84 14.86 20.2201 14.86 18.2701V15.46C14.86 14.49 15.62 13.62 16.7 13.62C17.67 13.62 18.54 14.38 18.54 15.46V18.49\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:home": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 18V15\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.07 2.81997L3.14002 8.36997C2.36002 8.98997 1.86002 10.3 2.03002 11.28L3.36002 19.24C3.60002 20.66 4.96002 21.81 6.40002 21.81H17.6C19.03 21.81 20.4 20.65 20.64 19.24L21.97 11.28C22.13 10.3 21.63 8.98997 20.86 8.36997L13.93 2.82997C12.86 1.96997 11.13 1.96997 10.07 2.81997Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:info-circle": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 8V13\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.9945 16H12.0035\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:lamp-on": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.30011 18.0399V16.8799C6.00011 15.4899 4.11011 12.7799 4.11011 9.89993C4.11011 4.94993 8.66011 1.06993 13.8001 2.18993C16.0601 2.68993 18.0401 4.18993 19.0701 6.25993C21.1601 10.4599 18.9601 14.9199 15.7301 16.8699V18.0299C15.7301 18.3199 15.8401 18.9899 14.7701 18.9899H9.26011C8.16011 18.9999 8.30011 18.5699 8.30011 18.0399Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 22C10.79 21.35 13.21 21.35 15.5 22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:location": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 13.4299C13.7231 13.4299 15.12 12.0331 15.12 10.3099C15.12 8.58681 13.7231 7.18994 12 7.18994C10.2769 7.18994 8.88 8.58681 8.88 10.3099C8.88 12.0331 10.2769 13.4299 12 13.4299Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n<path d=\"M3.62001 8.49C5.59001 -0.169998 18.42 -0.159997 20.38 8.5C21.53 13.58 18.37 17.88 15.6 20.54C13.59 22.48 10.41 22.48 8.39001 20.54C5.63001 17.88 2.47001 13.57 3.62001 8.49Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n</svg>\n",
|
||||
"vuesax-linear:lock": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M6 10V8C6 4.69 7 2 12 2C17 2 18 4.69 18 8V10\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 22H7C3 22 2 21 2 17V15C2 11 3 10 7 10H17C21 10 22 11 22 15V17C22 21 21 22 17 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.9965 16H16.0054\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.9955 16H12.0045\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7.99451 16H8.00349\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:logout": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.90002 7.55999C9.21002 3.95999 11.06 2.48999 15.11 2.48999H15.24C19.71 2.48999 21.5 4.27999 21.5 8.74999V15.27C21.5 19.74 19.71 21.53 15.24 21.53H15.11C11.09 21.53 9.24002 20.08 8.91002 16.54\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15 12H3.62\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.85 8.6499L2.5 11.9999L5.85 15.3499\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:menu": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M3 7H21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n<path d=\"M3 12H21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n<path d=\"M3 17H21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:message": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.5 19H8C4 19 2 18 2 13V8C2 4 4 2 8 2H16C20 2 22 4 22 8V13C22 17 20 19 16 19H15.5C15.19 19 14.89 19.15 14.7 19.4L13.2 21.4C12.54 22.28 11.46 22.28 10.8 21.4L9.3 19.4C9.14 19.18 8.77 19 8.5 19Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.9965 11H16.0054\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11.9955 11H12.0045\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7.99451 11H8.00349\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:mobile": "<svg width=\"18\" height=\"22\" viewBox=\"0 0 18 22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M17 6V16C17 20 16 21 12 21H6C2 21 1 20 1 16V6C1 2 2 1 6 1H12C16 1 17 2 17 6Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11 4.5H7\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.99995 18.1C9.85599 18.1 10.55 17.406 10.55 16.55C10.55 15.694 9.85599 15 8.99995 15C8.14391 15 7.44995 15.694 7.44995 16.55C7.44995 17.406 8.14391 18.1 8.99995 18.1Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:money-4": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M17 20.5H7C4 20.5 2 19 2 15.5V8.5C2 5 4 3.5 7 3.5H17C20 3.5 22 5 22 8.5V15.5C22 19 20 20.5 17 20.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 6H7C5.62 6 4.5 7.12 4.5 8.5V10\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.5 6H17C18.38 6 19.5 7.12 19.5 8.5V10\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 18H7C5.62 18 4.5 16.88 4.5 15.5V14\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.5 18H17C18.38 18 19.5 16.88 19.5 15.5V14\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:monitor": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M6.44 2H17.55C21.11 2 22 2.89 22 6.44V12.77C22 16.33 21.11 17.21 17.56 17.21H6.44C2.89 17.22 2 16.33 2 12.78V6.44C2 2.89 2.89 2 6.44 2Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 17.22V22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 13H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7.5 22H16.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:moon": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M2.03009 12.42C2.39009 17.57 6.76009 21.76 11.9901 21.99C15.6801 22.15 18.9801 20.43 20.9601 17.72C21.7801 16.61 21.3401 15.87 19.9701 16.12C19.3001 16.24 18.6101 16.29 17.8901 16.26C13.0001 16.06 9.00009 11.97 8.98009 7.13996C8.97009 5.83996 9.24009 4.60996 9.73009 3.48996C10.2701 2.24996 9.62009 1.65996 8.37009 2.18996C4.41009 3.85996 1.70009 7.84996 2.03009 12.42Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:more": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5 10C3.9 10 3 10.9 3 12C3 13.1 3.9 14 5 14C6.1 14 7 13.1 7 12C7 10.9 6.1 10 5 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n<path d=\"M19 10C17.9 10 17 10.9 17 12C17 13.1 17.9 14 19 14C20.1 14 21 13.1 21 12C21 10.9 20.1 10 19 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n<path d=\"M12 10C10.9 10 10 10.9 10 12C10 13.1 10.9 14 12 14C13.1 14 14 13.1 14 12C14 10.9 13.1 10 12 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\"/>\n</svg>\n",
|
||||
"vuesax-linear:note-remove": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M7 14H12\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7 5.95996L3.25 2.20996\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6.96002 2.25L3.21002 6\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7 10H15\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10 2H16C19.33 2.18 21 3.41 21 7.99V16\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M3 9.01001V15.98C3 19.99 4 22 9 22H12C12.17 22 14.84 22 15 22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21 16L15 22V19C15 17 16 16 18 16H21Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:notification": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12.02 2.90991C8.70997 2.90991 6.01997 5.59991 6.01997 8.90991V11.7999C6.01997 12.4099 5.75997 13.3399 5.44997 13.8599L4.29997 15.7699C3.58997 16.9499 4.07997 18.2599 5.37997 18.6999C9.68997 20.1399 14.34 20.1399 18.65 18.6999C19.86 18.2999 20.39 16.8699 19.73 15.7699L18.58 13.8599C18.28 13.3399 18.02 12.4099 18.02 11.7999V8.90991C18.02 5.60991 15.32 2.90991 12.02 2.90991Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\"/>\n<path d=\"M13.87 3.19994C13.56 3.10994 13.24 3.03994 12.91 2.99994C11.95 2.87994 11.03 2.94994 10.17 3.19994C10.46 2.45994 11.18 1.93994 12.02 1.93994C12.86 1.93994 13.58 2.45994 13.87 3.19994Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15.02 19.0601C15.02 20.7101 13.67 22.0601 12.02 22.0601C11.2 22.0601 10.44 21.7201 9.90002 21.1801C9.36002 20.6401 9.02002 19.8801 9.02002 19.0601\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\"/>\n</svg>\n",
|
||||
"vuesax-linear:pen-add": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M21.19 8.0399L18.01 4.85991C16.81 3.65991 15.16 3.71993 14.35 5.00993L12.58 7.80992L18.25 13.4799L21.05 11.7099C22.26 10.9399 22.33 9.1699 21.19 8.0399Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.25 13.47L18.49 17.59C18.72 19.89 17.92 20.69 15.74 20.95L7.02 21.98C5.18 22.19 3.86 20.87 4.08 19.04L5.06 10.76\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12.58 7.80994L10.83 7.69995\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.28 20.7799L8.46001 17.5898\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M11 6.5C11 6.91 10.94 7.32001 10.83 7.70001C10.72 8.10001 10.56 8.47001 10.35 8.82001C10.11 9.22001 9.81001 9.58 9.46001 9.88C8.67001 10.58 7.64 11 6.5 11C5.99 11 5.51 10.92 5.06 10.76C4.04 10.42 3.18999 9.72001 2.64999 8.82001C2.23999 8.14001 2 7.34 2 6.5C2 5.08 2.65 3.80999 3.69 2.98999C4.46 2.36999 5.44 2 6.5 2C8.99 2 11 4.01 11 6.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6.52 8.18005V4.82007\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.16 6.5H4.8\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:people": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M18 7.16C17.94 7.15 17.87 7.15 17.81 7.16C16.43 7.11 15.33 5.98 15.33 4.58C15.33 3.15 16.48 2 17.91 2C19.34 2 20.49 3.16 20.49 4.58C20.48 5.98 19.38 7.11 18 7.16Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16.9699 14.44C18.3399 14.67 19.8499 14.43 20.9099 13.72C22.3199 12.78 22.3199 11.24 20.9099 10.3C19.8399 9.59004 18.3099 9.35003 16.9399 9.59003\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.96998 7.16C6.02998 7.15 6.09998 7.15 6.15998 7.16C7.53998 7.11 8.63998 5.98 8.63998 4.58C8.63998 3.15 7.48998 2 6.05998 2C4.62998 2 3.47998 3.16 3.47998 4.58C3.48998 5.98 4.58998 7.11 5.96998 7.16Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6.99994 14.44C5.62994 14.67 4.11994 14.43 3.05994 13.72C1.64994 12.78 1.64994 11.24 3.05994 10.3C4.12994 9.59004 5.65994 9.35003 7.02994 9.59003\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 14.63C11.94 14.62 11.87 14.62 11.81 14.63C10.43 14.58 9.32996 13.45 9.32996 12.05C9.32996 10.62 10.48 9.46997 11.91 9.46997C13.34 9.46997 14.49 10.63 14.49 12.05C14.48 13.45 13.38 14.59 12 14.63Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.08997 17.78C7.67997 18.72 7.67997 20.26 9.08997 21.2C10.69 22.27 13.31 22.27 14.91 21.2C16.32 20.26 16.32 18.72 14.91 17.78C13.32 16.72 10.69 16.72 9.08997 17.78Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:personalcard": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M17 21H7C3 21 2 20 2 16V8C2 4 3 3 7 3H17C21 3 22 4 22 8V16C22 20 21 21 17 21Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M14 8H19\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M15 12H19\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 16H19\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.49994 11.2899C9.49958 11.2899 10.3099 10.4796 10.3099 9.47992C10.3099 8.48029 9.49958 7.66992 8.49994 7.66992C7.50031 7.66992 6.68994 8.48029 6.68994 9.47992C6.68994 10.4796 7.50031 11.2899 8.49994 11.2899Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 16.33C11.86 14.88 10.71 13.74 9.26 13.61C8.76 13.56 8.25 13.56 7.74 13.61C6.29 13.75 5.14 14.88 5 16.33\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:printer": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M7.25 7H16.75V5C16.75 3 16 2 13.75 2H10.25C8 2 7.25 3 7.25 5V7Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 15V19C16 21 15 22 13 22H11C9 22 8 21 8 19V15H16Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21 10V15C21 17 20 18 18 18H16V15H8V18H6C4 18 3 17 3 15V10C3 8 4 7 6 7H18C20 7 21 8 21 10Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 15H15.79H7\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7 11H10\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:profile-2user": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M9.16006 10.87C9.06006 10.86 8.94006 10.86 8.83006 10.87C6.45006 10.79 4.56006 8.84 4.56006 6.44C4.56006 3.99 6.54006 2 9.00006 2C11.4501 2 13.4401 3.99 13.4401 6.44C13.4301 8.84 11.5401 10.79 9.16006 10.87Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16.41 4C18.35 4 19.91 5.57 19.91 7.5C19.91 9.39 18.41 10.93 16.54 11C16.46 10.99 16.37 10.99 16.28 11\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M4.15997 14.56C1.73997 16.18 1.73997 18.82 4.15997 20.43C6.90997 22.27 11.42 22.27 14.17 20.43C16.59 18.81 16.59 16.17 14.17 14.56C11.43 12.73 6.91997 12.73 4.15997 14.56Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.3401 20C19.0601 19.85 19.7401 19.56 20.3001 19.13C21.8601 17.96 21.8601 16.03 20.3001 14.86C19.7501 14.44 19.0801 14.16 18.3701 14\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:profile-circle": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12.12 12.78C12.05 12.77 11.96 12.77 11.88 12.78C10.12 12.72 8.71997 11.28 8.71997 9.50998C8.71997 7.69998 10.18 6.22998 12 6.22998C13.81 6.22998 15.28 7.69998 15.28 9.50998C15.27 11.28 13.88 12.72 12.12 12.78Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.74 19.3801C16.96 21.0101 14.6 22.0001 12 22.0001C9.40001 22.0001 7.04001 21.0101 5.26001 19.3801C5.36001 18.4401 5.96001 17.5201 7.03001 16.8001C9.77001 14.9801 14.25 14.9801 16.97 16.8001C18.04 17.5201 18.64 18.4401 18.74 19.3801Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:receipt-search": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M20.5 11.3V7.04001C20.5 3.01001 19.56 2 15.78 2H8.22C4.44 2 3.5 3.01001 3.5 7.04001V18.3C3.5 20.96 4.96001 21.59 6.73001 19.69L6.73999 19.68C7.55999 18.81 8.80999 18.88 9.51999 19.83L10.53 21.18\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.2 21.4C19.9673 21.4 21.4 19.9673 21.4 18.2C21.4 16.4327 19.9673 15 18.2 15C16.4327 15 15 16.4327 15 18.2C15 19.9673 16.4327 21.4 18.2 21.4Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 22L21 21\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8 7H16\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9 11H15\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:search-normal": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M11 20C15.9706 20 20 15.9706 20 11C20 6.02944 15.9706 2 11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.9299 20.6898C19.4599 22.2898 20.6699 22.4498 21.5999 21.0498C22.4499 19.7698 21.8899 18.7198 20.3499 18.7198C19.2099 18.7098 18.5699 19.5998 18.9299 20.6898Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:search-status": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M14 5H20\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M14 8H17\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21 11.5C21 16.75 16.75 21 11.5 21C6.25 21 2 16.75 2 11.5C2 6.25 6.25 2 11.5 2\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 22L20 20\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:setting-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M2 12.8799V11.1199C2 10.0799 2.85 9.21994 3.9 9.21994C5.71 9.21994 6.45 7.93994 5.54 6.36994C5.02 5.46994 5.33 4.29994 6.24 3.77994L7.97 2.78994C8.76 2.31994 9.78 2.59994 10.25 3.38994L10.36 3.57994C11.26 5.14994 12.74 5.14994 13.65 3.57994L13.76 3.38994C14.23 2.59994 15.25 2.31994 16.04 2.78994L17.77 3.77994C18.68 4.29994 18.99 5.46994 18.47 6.36994C17.56 7.93994 18.3 9.21994 20.11 9.21994C21.15 9.21994 22.01 10.0699 22.01 11.1199V12.8799C22.01 13.9199 21.16 14.7799 20.11 14.7799C18.3 14.7799 17.56 16.0599 18.47 17.6299C18.99 18.5399 18.68 19.6999 17.77 20.2199L16.04 21.2099C15.25 21.6799 14.23 21.3999 13.76 20.6099L13.65 20.4199C12.75 18.8499 11.27 18.8499 10.36 20.4199L10.25 20.6099C9.78 21.3999 8.76 21.6799 7.97 21.2099L6.24 20.2199C5.33 19.6999 5.02 18.5299 5.54 17.6299C6.45 16.0599 5.71 14.7799 3.9 14.7799C2.85 14.7799 2 13.9199 2 12.8799Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:shopping-bag": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.39999 6.5H15.6C19 6.5 19.34 8.09 19.57 10.03L20.47 17.53C20.76 19.99 20 22 16.5 22H7.50999C3.99999 22 3.23999 19.99 3.53999 17.53L4.44 10.03C4.66 8.09 4.99999 6.5 8.39999 6.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8 8V4.5C8 3 9 2 10.5 2H13.5C15 2 16 3 16 4.5V8\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20.41 17.03H8\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:sms": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M17 20.5H7C4 20.5 2 19 2 15.5V8.5C2 5 4 3.5 7 3.5H17C20 3.5 22 5 22 8.5V15.5C22 19 20 20.5 17 20.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17 9L13.87 11.5C12.84 12.32 11.15 12.32 10.12 11.5L7 9\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:sun-1": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 18.5C15.5899 18.5 18.5 15.5899 18.5 12C18.5 8.41015 15.5899 5.5 12 5.5C8.41015 5.5 5.5 8.41015 5.5 12C5.5 15.5899 8.41015 18.5 12 18.5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M19.14 19.14L19.01 19.01M19.01 4.99L19.14 4.86L19.01 4.99ZM4.86 19.14L4.99 19.01L4.86 19.14ZM12 2.08V2V2.08ZM12 22V21.92V22ZM2.08 12H2H2.08ZM22 12H21.92H22ZM4.99 4.99L4.86 4.86L4.99 4.99Z\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:tick-circle": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M7.75 12L10.58 14.83L16.25 9.17004\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:timer-1": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M20.75 13.25C20.75 18.08 16.83 22 12 22C7.17 22 3.25 18.08 3.25 13.25C3.25 8.42 7.17 4.5 12 4.5C16.83 4.5 20.75 8.42 20.75 13.25Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 8V13\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9 2H15\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:trash": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M21 5.97998C17.67 5.64998 14.32 5.47998 10.98 5.47998C9 5.47998 7.02 5.57998 5.04 5.77998L3 5.97998\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8.5 4.97L8.72 3.66C8.88 2.71 9 2 10.69 2H13.31C15 2 15.13 2.75 15.28 3.67L15.5 4.97\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M18.85 9.14001L18.2 19.21C18.09 20.78 18 22 15.21 22H8.79002C6.00002 22 5.91002 20.78 5.80002 19.21L5.15002 9.14001\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.33 16.5H13.66\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.5 12.5H14.5\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:truck-time": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M15 2V12C15 13.1 14.1 14 13 14H2V7.62C2.73 8.49 3.85003 9.03 5.09003 9C6.10003 8.98 7.01 8.59 7.69 7.94C8 7.68 8.26002 7.34999 8.46002 6.98999C8.82002 6.37999 9.02 5.65997 9 4.90997C8.97 3.73997 8.45001 2.71 7.64001 2H15Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 14V17C22 18.66 20.66 20 19 20H18C18 18.9 17.1 18 16 18C14.9 18 14 18.9 14 20H10C10 18.9 9.1 18 8 18C6.9 18 6 18.9 6 20H5C3.34 20 2 18.66 2 17V14H13C14.1 14 15 13.1 15 12V5H16.84C17.56 5 18.22 5.39001 18.58 6.01001L20.29 9H19C18.45 9 18 9.45 18 10V13C18 13.55 18.45 14 19 14H22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M8 22C9.10457 22 10 21.1046 10 20C10 18.8954 9.10457 18 8 18C6.89543 18 6 18.8954 6 20C6 21.1046 6.89543 22 8 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16 22C17.1046 22 18 21.1046 18 20C18 18.8954 17.1046 18 16 18C14.8954 18 14 18.8954 14 20C14 21.1046 14.8954 22 16 22Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 12V14H19C18.45 14 18 13.55 18 13V10C18 9.45 18.45 9 19 9H20.29L22 12Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9 5C9 6.2 8.47001 7.27 7.64001 8C6.93001 8.62 6.01 9 5 9C2.79 9 1 7.21 1 5C1 3.74 1.58 2.61 2.5 1.88C3.19 1.33 4.06 1 5 1C7.21 1 9 2.79 9 5Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.25 3.75V5.25L4 6\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-miterlimit=\"10\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:verify": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M8.38 12L10.79 14.42L15.62 9.57996\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M10.75 2.44995C11.44 1.85995 12.57 1.85995 13.27 2.44995L14.85 3.80995C15.15 4.06995 15.71 4.27995 16.11 4.27995H17.81C18.87 4.27995 19.74 5.14995 19.74 6.20995V7.90995C19.74 8.29995 19.95 8.86995 20.21 9.16995L21.57 10.7499C22.16 11.4399 22.16 12.5699 21.57 13.2699L20.21 14.8499C19.95 15.1499 19.74 15.7099 19.74 16.1099V17.8099C19.74 18.8699 18.87 19.7399 17.81 19.7399H16.11C15.72 19.7399 15.15 19.9499 14.85 20.2099L13.27 21.5699C12.58 22.1599 11.45 22.1599 10.75 21.5699L9.17 20.2099C8.87 19.9499 8.31 19.7399 7.91 19.7399H6.18C5.12 19.7399 4.25 18.8699 4.25 17.8099V16.0999C4.25 15.7099 4.04 15.1499 3.79 14.8499L2.44 13.2599C1.86 12.5699 1.86 11.4499 2.44 10.7599L3.79 9.16995C4.04 8.86995 4.25 8.30995 4.25 7.91995V6.19995C4.25 5.13995 5.12 4.26995 6.18 4.26995H7.91C8.3 4.26995 8.87 4.05995 9.17 3.79995L10.75 2.44995Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:wallet": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M22 12V17C22 20 20 22 17 22H7C4 22 2 20 2 17V12C2 9.28 3.64 7.38 6.19 7.06C6.45 7.02 6.72 7 7 7H17C17.26 7 17.51 7.00999 17.75 7.04999C20.33 7.34999 22 9.26 22 12Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M17.7514 7.05C17.5114 7.01 17.2614 7.00001 17.0014 7.00001H7.00141C6.72141 7.00001 6.45141 7.02001 6.19141 7.06001C6.33141 6.78001 6.53141 6.52001 6.77141 6.28001L10.0214 3.02C11.3914 1.66 13.6114 1.66 14.9814 3.02L16.7314 4.79002C17.3714 5.42002 17.7114 6.22 17.7514 7.05Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M22 12.5H19C17.9 12.5 17 13.4 17 14.5C17 15.6 17.9 16.5 19 16.5H22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-linear:warning-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 7.75V13\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M21.08 8.58003V15.42C21.08 16.54 20.48 17.58 19.51 18.15L13.57 21.58C12.6 22.14 11.4 22.14 10.42 21.58L4.47998 18.15C3.50998 17.59 2.90997 16.55 2.90997 15.42V8.58003C2.90997 7.46003 3.50998 6.41999 4.47998 5.84999L10.42 2.42C11.39 1.86 12.59 1.86 13.57 2.42L19.51 5.84999C20.48 6.41999 21.08 7.45003 21.08 8.58003Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 16.2V16.2999\" stroke=\"#292D32\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:notification"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:flash"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
color?: string
|
||||
filled?: boolean
|
||||
}>(),
|
||||
{ size: 18, color: '#9AA3AF', filled: false },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg
|
||||
:width="size"
|
||||
:height="size"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M6.75 3.25h10.5c.97 0 1.75.78 1.75 1.75v15.2c0 .67-.73 1.08-1.3.73L12 17.02 6.3 20.93c-.57.35-1.3-.06-1.3-.73V5c0-.97.78-1.75 1.75-1.75Z"
|
||||
:stroke="color"
|
||||
:fill="filled ? color : 'none'"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:buildings"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:bag-2"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:money-4"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:card"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:category"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:card-receive"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:tick-circle"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:arrow-right-1"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:arrow-left-1"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:clipboard-close"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:diamonds"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:edit-2"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(defineProps<{ size?: number }>(), { size: 72 })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg
|
||||
class="icon-logo"
|
||||
:width="size"
|
||||
:height="size"
|
||||
viewBox="0 0 72 72"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<rect x="14" y="14" width="28" height="28" rx="4" transform="rotate(12 28 28)" />
|
||||
<rect x="30" y="30" width="28" height="28" rx="4" transform="rotate(-12 44 44)" />
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon-logo {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:pen-add"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:filter"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:headphone"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import IconBookmark from '@/components/icons/IconBookmark.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
color?: string
|
||||
filled?: boolean
|
||||
}>(),
|
||||
{ size: 18, color: '#9AA3AF', filled: false },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IconBookmark v-bind="props" />
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:home"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:timer-1"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:personalcard"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:element-3"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:lamp-on"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:lock"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:sms"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:location"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
}>(),
|
||||
{ size: 44 },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg
|
||||
class="icon-medal"
|
||||
:width="size"
|
||||
:height="size"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M18 28.5L14 44l10-5 10 5-4-15.5" fill="#C0C7D1" />
|
||||
<path d="M18 28.5L14 44l10-5V28.5H18Z" fill="#A8B0BC" />
|
||||
<circle cx="24" cy="18" r="14" fill="#D8DEE6" />
|
||||
<circle cx="24" cy="18" r="11" fill="#F3F5F8" stroke="#B8C0CB" stroke-width="1.5" />
|
||||
<path
|
||||
d="M24 10.5l2.2 4.5 5 .7-3.6 3.5.9 5L24 21.8 19.5 24l.9-5-3.6-3.5 5-.7L24 10.5Z"
|
||||
fill="#8B95A5"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:more"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:document-text"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(defineProps<{ size?: number }>(), { size: 72 })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg
|
||||
class="icon-logo"
|
||||
:width="size"
|
||||
:height="size"
|
||||
viewBox="0 0 72 72"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<text
|
||||
x="36"
|
||||
y="50"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="middle"
|
||||
fill="currentColor"
|
||||
style="font-family: IRANSans, Tahoma, sans-serif; font-size: 48px; font-weight: 700"
|
||||
>
|
||||
پ
|
||||
</text>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon-logo {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:call"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:add"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:profile-circle"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:clock"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:search-normal"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:setting-2"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:shopping-bag"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:tick-circle"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:trash"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
color?: string | null
|
||||
}>(),
|
||||
{ size: 24, strokeWidth: 1.5, color: null },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:verify"
|
||||
:size="size"
|
||||
:stroke-width="strokeWidth"
|
||||
:color="color"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultLayout from '@/layouts/DefaultLayout.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultLayout>
|
||||
<slot />
|
||||
</DefaultLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,170 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useCartStore } from '@/stores/cart'
|
||||
import { MAIN_NAV_ITEMS, isNavItemActive } from '@/utils/navigation'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const cartStore = useCartStore()
|
||||
|
||||
const cartCount = computed(() => cartStore.itemCount)
|
||||
|
||||
function navigate(path: string, event: Event) {
|
||||
const target = event.currentTarget
|
||||
if (target instanceof HTMLElement) target.blur()
|
||||
|
||||
// «ثبت سفارش»: سبد خالی → انتخاب شرکت؛ در غیر این صورت سبد خرید
|
||||
if (path === '/cart' && cartStore.itemCount === 0) {
|
||||
router.push('/companies')
|
||||
return
|
||||
}
|
||||
router.push(path)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="bottom-nav" aria-label="ناوبری اصلی">
|
||||
<button
|
||||
v-for="item in MAIN_NAV_ITEMS"
|
||||
:key="item.name"
|
||||
type="button"
|
||||
class="nav-item"
|
||||
:class="{
|
||||
active: isNavItemActive(item.name, item.path, route.path),
|
||||
'nav-item--fab': item.name === 'order-fab',
|
||||
}"
|
||||
:aria-current="isNavItemActive(item.name, item.path, route.path) ? 'page' : undefined"
|
||||
:aria-label="item.label"
|
||||
@click="navigate(item.path, $event)"
|
||||
>
|
||||
<span class="nav-icon" :class="{ 'nav-icon--fab': item.name === 'order-fab' }">
|
||||
<component
|
||||
:is="item.icon"
|
||||
:size="item.name === 'order-fab' ? 26 : 22"
|
||||
:stroke-width="item.name === 'order-fab' ? 1.8 : 1.5"
|
||||
:color="item.name === 'order-fab' ? '#ffffff' : undefined"
|
||||
/>
|
||||
<span
|
||||
v-if="item.name === 'order-fab' && cartCount > 0"
|
||||
class="nav-badge"
|
||||
>{{ cartCount }}</span>
|
||||
</span>
|
||||
<span v-if="item.name !== 'order-fab'" class="nav-label">{{ item.label }}</span>
|
||||
<span v-else class="nav-label nav-label--fab">{{ item.label }}</span>
|
||||
</button>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.bottom-nav {
|
||||
flex-shrink: 0;
|
||||
min-height: var(--nav-height);
|
||||
background: var(--color-surface);
|
||||
border-top: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: flex-end;
|
||||
z-index: 100;
|
||||
padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0));
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.bottom-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 4px 2px 2px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-muted);
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.nav-item:focus,
|
||||
.nav-item:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
color: var(--color-primary);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-item.active .nav-label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.nav-item--fab {
|
||||
justify-content: flex-end;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.nav-item--fab.active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex-shrink: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.nav-icon--fab {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
margin-top: -28px;
|
||||
border-radius: 999px;
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
box-shadow: 0 6px 16px rgba(var(--color-primary-rgb), 0.35);
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-label--fab {
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
|
||||
.nav-badge {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
inset-inline-end: -2px;
|
||||
background: var(--color-danger);
|
||||
color: #fff;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 4px;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,141 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
currentStep: 1 | 2 | 3 | 4
|
||||
}>()
|
||||
|
||||
const steps = [
|
||||
{ num: 1, label: 'سبد خرید' },
|
||||
{ num: 2, label: 'پیشسفارش' },
|
||||
{ num: 3, label: 'صدور فاکتور' },
|
||||
{ num: 4, label: 'تسویه' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="checkout-stepper" aria-label="مراحل تسویه">
|
||||
<template v-for="(step, index) in steps" :key="step.num">
|
||||
<div
|
||||
class="checkout-stepper__item"
|
||||
:class="{
|
||||
'checkout-stepper__item--done': step.num < currentStep,
|
||||
'checkout-stepper__item--active': step.num === currentStep,
|
||||
}"
|
||||
>
|
||||
<span class="checkout-stepper__dot">
|
||||
<span v-if="step.num < currentStep" class="checkout-stepper__check">✓</span>
|
||||
<template v-else>{{ step.num }}</template>
|
||||
</span>
|
||||
<span class="checkout-stepper__label">{{ step.label }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="index < steps.length - 1"
|
||||
class="checkout-stepper__bridge"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span
|
||||
class="checkout-stepper__bridge-line"
|
||||
:class="{ 'checkout-stepper__bridge-line--done': index < currentStep }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.checkout-stepper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: flex-start;
|
||||
direction: rtl;
|
||||
gap: 0;
|
||||
width: 100%;
|
||||
padding: 22px 28px 20px;
|
||||
margin-bottom: 24px;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.checkout-stepper__item {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 88px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.checkout-stepper__bridge {
|
||||
flex: 1 1 0;
|
||||
min-width: 20px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.checkout-stepper__bridge-line {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #e2e8f0;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.checkout-stepper__bridge-line--done {
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
.checkout-stepper__dot {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #e2e8f0;
|
||||
background: var(--color-surface);
|
||||
color: #94a3b8;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkout-stepper__item--done .checkout-stepper__dot {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.checkout-stepper__item--active .checkout-stepper__dot {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.checkout-stepper__check {
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.checkout-stepper__label {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
color: #94a3b8;
|
||||
line-height: 1.35;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.checkout-stepper__item--active .checkout-stepper__label {
|
||||
color: var(--color-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.checkout-stepper__item--done .checkout-stepper__label {
|
||||
color: var(--color-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,267 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useCartStore } from '@/stores/cart'
|
||||
import { useNotificationStore } from '@/stores/notification'
|
||||
import IconBell from '@/components/icons/IconBell.vue'
|
||||
import IconChevronLeft from '@/components/icons/IconChevronLeft.vue'
|
||||
import AuthThemeToggle from '@/components/ui/AuthThemeToggle.vue'
|
||||
import UserAvatar from '@/components/ui/UserAvatar.vue'
|
||||
import { toPersianDigits } from '@/utils/format'
|
||||
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const cartStore = useCartStore()
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
const showUserMenu = ref(false)
|
||||
|
||||
const unreadLabel = computed(() =>
|
||||
toPersianDigits(
|
||||
notificationStore.unreadCount > 9 ? '9+' : String(notificationStore.unreadCount),
|
||||
),
|
||||
)
|
||||
|
||||
const initials = computed(() => {
|
||||
const first = authStore.user?.firstName?.[0] ?? ''
|
||||
const last = authStore.user?.lastName?.[0] ?? ''
|
||||
return `${first}${last}` || '؟'
|
||||
})
|
||||
|
||||
const companyLabel = computed(
|
||||
() => cartStore.companyNamesLabel || cartStore.activeCart?.companyName || '',
|
||||
)
|
||||
|
||||
function toggleUserMenu() {
|
||||
showUserMenu.value = !showUserMenu.value
|
||||
}
|
||||
|
||||
function goProfile() {
|
||||
showUserMenu.value = false
|
||||
router.push('/profile')
|
||||
}
|
||||
|
||||
function logout() {
|
||||
showUserMenu.value = false
|
||||
authStore.logout()
|
||||
router.replace('/login')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="desktop-header">
|
||||
<div class="desktop-header__spacer" aria-hidden="true" />
|
||||
|
||||
<div class="desktop-header__actions">
|
||||
<span v-if="companyLabel" class="desktop-header__company">{{ companyLabel }}</span>
|
||||
|
||||
<AuthThemeToggle variant="inline" />
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="desktop-header__icon-btn"
|
||||
aria-label="اعلانها"
|
||||
@click="router.push('/profile/notifications')"
|
||||
>
|
||||
<IconBell :size="20" />
|
||||
<span
|
||||
v-if="notificationStore.hasUnread"
|
||||
class="desktop-header__notif-badge"
|
||||
:aria-label="`${notificationStore.unreadCount} اعلان خواندهنشده`"
|
||||
>
|
||||
{{ unreadLabel }}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div class="desktop-header__user-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="desktop-header__user"
|
||||
:aria-expanded="showUserMenu"
|
||||
@click="toggleUserMenu"
|
||||
>
|
||||
<UserAvatar
|
||||
class="desktop-header__avatar"
|
||||
:src="authStore.user?.avatarUrl"
|
||||
:initials="initials"
|
||||
:size="32"
|
||||
/>
|
||||
<span class="desktop-header__user-name">{{ authStore.fullName }}</span>
|
||||
<IconChevronLeft :size="16" class="desktop-header__chevron" />
|
||||
</button>
|
||||
|
||||
<div v-if="showUserMenu" class="desktop-header__menu">
|
||||
<button type="button" @click="goProfile">پروفایل</button>
|
||||
<button type="button" class="desktop-header__menu-logout" @click="logout">خروج</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.desktop-header {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
height: var(--header-height);
|
||||
min-height: var(--header-height);
|
||||
max-height: var(--header-height);
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 0 28px;
|
||||
background: var(--color-surface);
|
||||
/* Border drawn by shared shell rule so it aligns with the sidebar brand */
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-header {
|
||||
display: flex;
|
||||
padding: 0 var(--page-padding);
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-header {
|
||||
padding: 0 var(--page-padding);
|
||||
gap: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-header__spacer {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.desktop-header__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-shrink: 0;
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
.desktop-header__company {
|
||||
display: none;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted);
|
||||
padding-inline-end: 8px;
|
||||
border-inline-end: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.desktop-header__company {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-header__icon-btn {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-muted);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.desktop-header__notif-badge {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
inset-inline-end: 4px;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
padding: 0 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9px;
|
||||
background: var(--color-danger);
|
||||
color: var(--color-on-primary, #fff);
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
border: 2px solid var(--color-surface);
|
||||
}
|
||||
|
||||
.desktop-header__user-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.desktop-header__user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 12px 6px 8px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.desktop-header__avatar {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-surface);
|
||||
}
|
||||
|
||||
.desktop-header__user-name {
|
||||
display: none;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-header__user-name {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-header__chevron {
|
||||
color: var(--color-text-muted);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.desktop-header__menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 6px);
|
||||
inset-inline-end: 0;
|
||||
min-width: 160px;
|
||||
padding: 6px;
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-md);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.desktop-header__menu button {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
background: none;
|
||||
text-align: start;
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.desktop-header__menu button:hover {
|
||||
background: var(--color-elevated);
|
||||
}
|
||||
|
||||
.desktop-header__menu-logout {
|
||||
color: var(--color-danger) !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,286 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useCartStore } from '@/stores/cart'
|
||||
import { useOrderStore } from '@/stores/order'
|
||||
import {
|
||||
DESKTOP_NAV_ITEMS,
|
||||
isNavItemActive,
|
||||
resolveNavPath,
|
||||
} from '@/utils/navigation'
|
||||
import IconHeadset from '@/components/icons/IconHeadset.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const cartStore = useCartStore()
|
||||
const orderStore = useOrderStore()
|
||||
|
||||
const cartCount = computed(() => cartStore.itemCount)
|
||||
const draftCheckCount = computed(() => orderStore.draftChecks.length)
|
||||
const activeCompanyId = computed(
|
||||
() => cartStore.selectedCompanyId || cartStore.activeCart?.companyId || null,
|
||||
)
|
||||
|
||||
function navigate(item: (typeof DESKTOP_NAV_ITEMS)[number]) {
|
||||
router.push(resolveNavPath(item, activeCompanyId.value))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<aside class="desktop-sidebar" aria-label="ناوبری اصلی">
|
||||
<div class="desktop-sidebar__brand">
|
||||
<span class="desktop-sidebar__logo-mark" aria-hidden="true">پ</span>
|
||||
<strong class="desktop-sidebar__title">پارس بافت</strong>
|
||||
</div>
|
||||
|
||||
<nav class="desktop-sidebar__nav">
|
||||
<button
|
||||
v-for="item in DESKTOP_NAV_ITEMS"
|
||||
:key="item.name"
|
||||
type="button"
|
||||
class="desktop-sidebar__item"
|
||||
:class="{ active: isNavItemActive(item.name, item.path, route.path) }"
|
||||
:aria-current="isNavItemActive(item.name, item.path, route.path) ? 'page' : undefined"
|
||||
:aria-label="item.label"
|
||||
:title="item.label"
|
||||
@click="navigate(item)"
|
||||
>
|
||||
<span class="desktop-sidebar__icon">
|
||||
<component :is="item.icon" :size="20" />
|
||||
</span>
|
||||
<span class="desktop-sidebar__label">{{ item.label }}</span>
|
||||
<span v-if="item.name === 'cart' && cartCount > 0" class="desktop-sidebar__badge">
|
||||
{{ cartCount }}
|
||||
</span>
|
||||
<span v-if="item.name === 'checks' && draftCheckCount > 0" class="desktop-sidebar__badge">
|
||||
{{ draftCheckCount }}
|
||||
</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="desktop-sidebar__support">
|
||||
<span class="desktop-sidebar__support-icon" aria-hidden="true">
|
||||
<IconHeadset :size="22" />
|
||||
</span>
|
||||
<strong class="desktop-sidebar__support-title">پشتیبانی و راهنما</strong>
|
||||
<p class="desktop-sidebar__support-text">
|
||||
در صورت نیاز به راهنمایی یا گزارش مشکل با تیم پشتیبانی تماس بگیرید.
|
||||
</p>
|
||||
<a href="tel:02112345678" class="desktop-sidebar__support-btn">تماس با پشتیبانی</a>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.desktop-sidebar {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
width: var(--sidebar-width);
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
background: var(--color-surface);
|
||||
border-inline-start: 1px solid var(--color-border);
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.desktop-sidebar {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-sidebar__brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
height: var(--header-height);
|
||||
min-height: var(--header-height);
|
||||
max-height: var(--header-height);
|
||||
box-sizing: border-box;
|
||||
padding: 0 20px;
|
||||
/* Border drawn by shared shell rule so it aligns with the top header */
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-sidebar__brand {
|
||||
padding: 0 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-sidebar__logo-mark {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-primary);
|
||||
color: var(--color-surface);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.desktop-sidebar__title {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.desktop-sidebar__nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
flex: 1;
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-sidebar__nav {
|
||||
padding: 16px 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-sidebar__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
padding: 11px 12px;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-secondary);
|
||||
text-align: start;
|
||||
transition:
|
||||
background 0.15s,
|
||||
color 0.15s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-sidebar__item {
|
||||
padding: 11px 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-sidebar__item:hover {
|
||||
background: var(--color-elevated);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.desktop-sidebar__item:focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.desktop-sidebar__item.active {
|
||||
background: var(--color-primary-soft);
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.desktop-sidebar__item.active .desktop-sidebar__icon {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.desktop-sidebar__icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
flex-shrink: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.desktop-sidebar__label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.desktop-sidebar__badge {
|
||||
margin-inline-start: auto;
|
||||
background: var(--color-danger);
|
||||
color: var(--color-surface);
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.desktop-sidebar__support {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin: auto 12px 20px;
|
||||
padding: 14px;
|
||||
background: var(--color-primary-soft);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.desktop-sidebar__support {
|
||||
margin: auto 16px 24px;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-sidebar__support-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-surface);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.desktop-sidebar__support-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.desktop-sidebar__support-text {
|
||||
margin: 0;
|
||||
font-size: 0.6875rem;
|
||||
line-height: 1.5;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.desktop-sidebar__support-btn {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
padding: 10px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-primary);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.desktop-sidebar__support-btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,169 @@
|
||||
<script setup lang="ts">
|
||||
import IconChevronBack from '@/components/icons/IconChevronBack.vue'
|
||||
import AuthThemeToggle from '@/components/ui/AuthThemeToggle.vue'
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
subtitle?: string
|
||||
showBack?: boolean
|
||||
centered?: boolean
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
back: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="centered">
|
||||
<header class="page-nav">
|
||||
<button
|
||||
v-if="showBack"
|
||||
type="button"
|
||||
class="nav-btn"
|
||||
aria-label="بازگشت"
|
||||
@click="$emit('back')"
|
||||
>
|
||||
<IconChevronBack :size="20" />
|
||||
</button>
|
||||
<span v-else class="nav-btn" />
|
||||
<h1 class="page-nav__title">{{ title }}</h1>
|
||||
<div class="page-nav__trailing">
|
||||
<slot name="trailing" />
|
||||
<AuthThemeToggle variant="inline" class="mobile-only" />
|
||||
</div>
|
||||
</header>
|
||||
<p v-if="subtitle" class="page-nav__subtitle">{{ subtitle }}</p>
|
||||
</template>
|
||||
|
||||
<header v-else class="page-header">
|
||||
<button
|
||||
v-if="showBack"
|
||||
type="button"
|
||||
class="back-btn"
|
||||
aria-label="بازگشت"
|
||||
@click="$emit('back')"
|
||||
>
|
||||
<IconChevronBack :size="20" />
|
||||
</button>
|
||||
<div class="header-text">
|
||||
<h1 class="page-title">{{ title }}</h1>
|
||||
<p v-if="subtitle" class="page-subtitle">{{ subtitle }}</p>
|
||||
</div>
|
||||
<div class="page-header__trailing">
|
||||
<slot name="trailing" />
|
||||
<AuthThemeToggle variant="inline" class="mobile-only" />
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.page-nav {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr auto;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
padding-inline: var(--page-padding);
|
||||
padding-top: 8px;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-nav__title {
|
||||
margin: 0;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-nav__subtitle {
|
||||
margin: 0 0 16px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.page-nav__trailing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
padding-inline: var(--page-padding);
|
||||
padding-top: 8px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-header__trailing {
|
||||
margin-inline-start: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
flex-shrink: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text);
|
||||
transition:
|
||||
border-color 0.15s,
|
||||
background 0.15s;
|
||||
}
|
||||
|
||||
.back-btn:hover {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-summary-bg);
|
||||
}
|
||||
|
||||
.header-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
margin: 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
margin: 4px 0 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
<script setup lang="ts">
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import type { StatusHeroConfig } from '@/utils/orderTracking'
|
||||
|
||||
defineProps<{
|
||||
config: StatusHeroConfig
|
||||
}>()
|
||||
|
||||
const icons = {
|
||||
waiting: 'vuesax-linear:timer-1',
|
||||
success: 'vuesax-linear:tick-circle',
|
||||
info: 'vuesax-linear:info-circle',
|
||||
none: 'vuesax-linear:info-circle',
|
||||
} as const
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="config.variant !== 'none'" class="status-hero" :class="`status-hero--${config.variant}`">
|
||||
<div class="status-hero__icon" aria-hidden="true">
|
||||
<BasicIcon :icon="icons[config.variant]" :size="28" :stroke-width="1.5" />
|
||||
</div>
|
||||
<div class="status-hero__copy">
|
||||
<h2 class="status-hero__title">{{ config.title }}</h2>
|
||||
<p v-if="config.description" class="status-hero__desc">{{ config.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.status-hero {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 8px 12px 20px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.status-hero__icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 14px;
|
||||
color: var(--color-primary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-hero--waiting .status-hero__icon {
|
||||
background: var(--color-primary-soft);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.status-hero--success .status-hero__icon {
|
||||
background: var(--color-primary-soft);
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.status-hero--info .status-hero__icon {
|
||||
background: var(--color-primary-light);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.status-hero__copy {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.status-hero__title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.status-hero--success .status-hero__title {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.status-hero__desc {
|
||||
margin: 0;
|
||||
max-width: 320px;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.status-hero {
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
text-align: start;
|
||||
padding: 0;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.status-hero__icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-hero__title {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.status-hero__desc {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { Order } from '@/types'
|
||||
import { formatCurrency, formatNumber, toPersianDigits } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
order: Order
|
||||
}>()
|
||||
|
||||
const checksTotal = computed(() =>
|
||||
props.order.checks?.reduce((sum, check) => sum + check.amount, 0) ?? 0,
|
||||
)
|
||||
|
||||
function settlementLabel(type: 'cash' | 'check' | null) {
|
||||
if (!type) return 'در انتظار انتخاب مشتری'
|
||||
return type === 'cash' ? 'تسویه نقدی' : 'تسویه چکی'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tracking-summary">
|
||||
<div class="tracking-summary__row">
|
||||
<span>مبلغ فاکتور</span>
|
||||
<strong>
|
||||
{{ order.finalAmount ? formatNumber(order.finalAmount) : 'در انتظار قیمتگذاری' }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="tracking-summary__row">
|
||||
<span>نوع تسویه</span>
|
||||
<strong>{{ settlementLabel(order.settlementType) }}</strong>
|
||||
</div>
|
||||
|
||||
<template v-if="order.settlementType === 'check' && order.checks?.length">
|
||||
<div class="tracking-summary__row">
|
||||
<span>تعداد چکها</span>
|
||||
<strong>{{ toPersianDigits(String(order.checks.length)) }} فقره</strong>
|
||||
</div>
|
||||
<div class="tracking-summary__row">
|
||||
<span>مجموع مبلغ چکها</span>
|
||||
<strong>{{ formatCurrency(checksTotal) }}</strong>
|
||||
</div>
|
||||
<div v-if="order.checkRassDays != null" class="tracking-summary__row">
|
||||
<span>رأس چک (تقریبی)</span>
|
||||
<strong>{{ toPersianDigits(String(order.checkRassDays)) }} روز</strong>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="order.settlementType === 'cash' && order.cashReceipt">
|
||||
<div class="tracking-summary__row">
|
||||
<span>مبلغ واریزی</span>
|
||||
<strong>{{ formatCurrency(order.cashReceipt.amount) }}</strong>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tracking-summary {
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
background: var(--color-elevated);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.tracking-summary__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 0;
|
||||
font-size: 0.875rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.tracking-summary__row:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.tracking-summary__row span {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.tracking-summary__row strong {
|
||||
color: var(--color-text);
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,175 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { Order, OrderStatus } from '@/types'
|
||||
import {
|
||||
getOrderTrackingSteps,
|
||||
getStepTimestamp,
|
||||
getTrackingStepIndex,
|
||||
} from '@/utils/orderTracking'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
order: Order
|
||||
}>()
|
||||
|
||||
const steps = computed(() => getOrderTrackingSteps(props.order))
|
||||
const currentIndex = computed(() => getTrackingStepIndex(props.order.status))
|
||||
|
||||
function stepState(index: number): 'done' | 'current' | 'pending' {
|
||||
if (index < currentIndex.value) return 'done'
|
||||
if (index === currentIndex.value) return 'current'
|
||||
return 'pending'
|
||||
}
|
||||
|
||||
function timestampFor(step: OrderStatus) {
|
||||
const raw = getStepTimestamp(props.order, step)
|
||||
return raw ? formatDateTime(raw) : null
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tracking-timeline">
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.status"
|
||||
class="tracking-timeline__item"
|
||||
:class="`tracking-timeline__item--${stepState(index)}`"
|
||||
>
|
||||
<div class="tracking-timeline__marker-wrap">
|
||||
<div class="tracking-timeline__line" aria-hidden="true" />
|
||||
<div class="tracking-timeline__marker">
|
||||
<span v-if="stepState(index) === 'done'" class="tracking-timeline__check">✓</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="tracking-timeline__content"
|
||||
:class="{ 'tracking-timeline__content--current': stepState(index) === 'current' }"
|
||||
>
|
||||
<strong class="tracking-timeline__label">{{ step.label }}</strong>
|
||||
<span v-if="timestampFor(step.status)" class="tracking-timeline__time">
|
||||
{{ timestampFor(step.status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tracking-timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tracking-timeline__item {
|
||||
display: grid;
|
||||
grid-template-columns: 28px minmax(0, 1fr);
|
||||
column-gap: 12px;
|
||||
align-items: start;
|
||||
/* Same vertical rhythm for every step so the connector stays continuous */
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.tracking-timeline__marker-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-self: stretch;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.tracking-timeline__line {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 2px;
|
||||
transform: translateX(-50%);
|
||||
background: var(--color-border);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.tracking-timeline__item:last-child .tracking-timeline__line {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tracking-timeline__item--done .tracking-timeline__line {
|
||||
background: var(--color-success);
|
||||
}
|
||||
|
||||
.tracking-timeline__item--current .tracking-timeline__line {
|
||||
background: color-mix(in srgb, var(--color-primary) 35%, var(--color-border));
|
||||
}
|
||||
|
||||
.tracking-timeline__marker {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
margin-top: 2px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-border);
|
||||
border: 2px solid var(--color-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tracking-timeline__item--done .tracking-timeline__marker {
|
||||
background: var(--color-success);
|
||||
border-color: var(--color-success);
|
||||
}
|
||||
|
||||
.tracking-timeline__item--current .tracking-timeline__marker {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 28%, transparent);
|
||||
}
|
||||
|
||||
.tracking-timeline__item--pending .tracking-timeline__marker {
|
||||
background: var(--color-elevated);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
.tracking-timeline__check {
|
||||
color: var(--color-surface);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tracking-timeline__content {
|
||||
min-width: 0;
|
||||
padding: 2px 0 14px;
|
||||
}
|
||||
|
||||
.tracking-timeline__content--current {
|
||||
padding: 10px 14px 12px;
|
||||
border-radius: 12px;
|
||||
background: var(--color-primary-soft);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.tracking-timeline__label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.45;
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.tracking-timeline__item--done .tracking-timeline__label,
|
||||
.tracking-timeline__item--current .tracking-timeline__label {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.tracking-timeline__time {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,75 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
/** floating = auth pages; inline = header / toolbar */
|
||||
variant?: 'floating' | 'inline'
|
||||
}>(),
|
||||
{ variant: 'floating' },
|
||||
)
|
||||
|
||||
const themeStore = useThemeStore()
|
||||
const { isDark } = storeToRefs(themeStore)
|
||||
|
||||
const themeIcon = computed(() =>
|
||||
isDark.value ? 'vuesax-linear:sun-1' : 'vuesax-linear:moon',
|
||||
)
|
||||
const themeLabel = computed(() =>
|
||||
isDark.value ? 'تغییر به تم روشن' : 'تغییر به تم تاریک',
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="auth-theme-toggle"
|
||||
:class="variant === 'inline' ? 'auth-theme-toggle--inline' : 'auth-theme-toggle--floating'"
|
||||
:aria-label="themeLabel"
|
||||
:title="themeLabel"
|
||||
@click="themeStore.toggleLightDark()"
|
||||
>
|
||||
<BasicIcon :icon="themeIcon" :size="18" :stroke-width="1.5" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.auth-theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.auth-theme-toggle--floating {
|
||||
position: fixed;
|
||||
top: calc(12px + env(safe-area-inset-top, 0px));
|
||||
inset-inline-end: 16px;
|
||||
z-index: 100;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.auth-theme-toggle--inline {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
flex-shrink: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.auth-theme-toggle:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
variant?: 'warning' | 'success' | 'info' | 'purple' | 'danger' | 'neutral'
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="badge" :class="`badge-${variant ?? 'neutral'}`">
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: var(--color-warning-light);
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: var(--color-success-light);
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background: var(--color-info-light);
|
||||
color: var(--color-info);
|
||||
}
|
||||
|
||||
.badge-purple {
|
||||
background: var(--color-purple-light);
|
||||
color: var(--color-purple);
|
||||
}
|
||||
|
||||
.badge-danger {
|
||||
background: var(--color-danger-light);
|
||||
color: var(--color-danger);
|
||||
}
|
||||
|
||||
.badge-neutral {
|
||||
background: var(--color-summary-bg);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'danger' | 'ghost'
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
block?: boolean
|
||||
disabled?: boolean
|
||||
loading?: boolean
|
||||
type?: 'button' | 'submit'
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
:type="type ?? 'button'"
|
||||
class="btn"
|
||||
:class="[`btn-${variant ?? 'primary'}`, `btn-${size ?? 'md'}`, { 'btn-block': block }]"
|
||||
:disabled="disabled || loading"
|
||||
>
|
||||
<span v-if="loading" class="btn-spinner" />
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.15s,
|
||||
opacity 0.15s;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
min-height: 36px;
|
||||
padding: 0 14px;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.btn-md {
|
||||
min-height: var(--btn-height);
|
||||
padding: 0 24px;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
min-height: 52px;
|
||||
padding: 0 28px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-surface);
|
||||
}
|
||||
|
||||
.btn-primary:not(:disabled):hover {
|
||||
background: var(--color-primary-dark);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: var(--color-primary-light);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--color-primary);
|
||||
border: 1.5px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: var(--color-danger);
|
||||
color: var(--color-surface);
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.btn-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string | number
|
||||
label?: string
|
||||
type?: string
|
||||
placeholder?: string
|
||||
hint?: string
|
||||
error?: string
|
||||
disabled?: boolean
|
||||
min?: number
|
||||
max?: number
|
||||
step?: number
|
||||
maxlength?: number | string
|
||||
inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'
|
||||
autocomplete?: string
|
||||
dir?: string
|
||||
align?: 'start' | 'center' | 'end'
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
blur: [event: FocusEvent]
|
||||
}>()
|
||||
|
||||
const isNumericField = computed(() => {
|
||||
const type = props.type ?? 'text'
|
||||
return (
|
||||
type === 'number' ||
|
||||
type === 'tel' ||
|
||||
props.inputmode === 'numeric' ||
|
||||
props.inputmode === 'decimal' ||
|
||||
props.inputmode === 'tel' ||
|
||||
props.dir === 'ltr'
|
||||
)
|
||||
})
|
||||
|
||||
/** Numbers default to right; OTP/login can still force center via `align`. */
|
||||
const resolvedAlign = computed(() => props.align ?? (isNumericField.value ? 'end' : 'start'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-group">
|
||||
<label v-if="label" class="form-label">{{ label }}</label>
|
||||
<input
|
||||
class="input"
|
||||
:class="[`input--align-${resolvedAlign}`, { 'input-error': error }]"
|
||||
:type="type ?? 'text'"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:min="min"
|
||||
:max="max"
|
||||
:step="step"
|
||||
:maxlength="maxlength"
|
||||
:inputmode="inputmode"
|
||||
:autocomplete="autocomplete"
|
||||
:dir="dir"
|
||||
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
||||
@blur="$emit('blur', $event)"
|
||||
/>
|
||||
<p v-if="error" class="input-error-text">{{ error }}</p>
|
||||
<p v-else-if="hint" class="form-hint">{{ hint }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.input {
|
||||
width: 100%;
|
||||
height: var(--btn-height);
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.9375rem;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.input--align-start {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.input--align-center {
|
||||
text-align: center;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.input--align-end {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: var(--color-danger);
|
||||
}
|
||||
|
||||
.input-error-text {
|
||||
color: var(--color-danger);
|
||||
font-size: 0.8125rem;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { formatMeterage } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
current: number
|
||||
max: number
|
||||
}>()
|
||||
|
||||
const remaining = computed(() => Math.max(0, props.max - props.current))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="capacity-summary">
|
||||
<div class="capacity-summary__row">
|
||||
<span class="capacity-summary__label">جمع متراژ</span>
|
||||
<span class="capacity-summary__value">{{ formatMeterage(current) }}</span>
|
||||
</div>
|
||||
<div class="capacity-summary__row">
|
||||
<span class="capacity-summary__label">حداکثر مجاز</span>
|
||||
<span class="capacity-summary__value">{{ formatMeterage(max) }}</span>
|
||||
</div>
|
||||
<div class="capacity-summary__row">
|
||||
<span class="capacity-summary__label">باقیمانده</span>
|
||||
<span class="capacity-summary__value capacity-summary__value--accent">
|
||||
{{ formatMeterage(remaining) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.capacity-summary {
|
||||
background: var(--color-summary-bg);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 14px 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.capacity-summary__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6px 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.capacity-summary__row:not(:last-child) {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.capacity-summary__label {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.capacity-summary__value {
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.capacity-summary__value--accent {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,124 @@
|
||||
<script setup lang="ts">
|
||||
import { formatMeterage, toPersianDigits } from '@/utils/format'
|
||||
import IconCart from '@/components/icons/IconCart.vue'
|
||||
|
||||
defineProps<{
|
||||
totalMeterage: number
|
||||
itemCount?: number
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
click: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="cart-meterage-footer"
|
||||
aria-label="مشاهده سبد خرید"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<span class="cart-meterage-footer__info">
|
||||
<span class="cart-meterage-footer__label">کل متراژ</span>
|
||||
<span class="cart-meterage-footer__value">{{ formatMeterage(totalMeterage) }}</span>
|
||||
</span>
|
||||
|
||||
<span class="cart-meterage-footer__action">
|
||||
<span class="cart-meterage-footer__action-text">مشاهده سبد</span>
|
||||
<span class="cart-meterage-footer__icon-wrap">
|
||||
<IconCart :size="20" />
|
||||
<span v-if="itemCount" class="cart-meterage-footer__badge">
|
||||
{{ toPersianDigits(String(itemCount)) }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cart-meterage-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
min-height: 56px;
|
||||
padding: 12px 16px;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
box-shadow: var(--shadow-md);
|
||||
cursor: pointer;
|
||||
text-align: start;
|
||||
transition:
|
||||
transform 0.15s ease,
|
||||
filter 0.15s ease;
|
||||
}
|
||||
|
||||
.cart-meterage-footer:hover {
|
||||
filter: brightness(1.05);
|
||||
}
|
||||
|
||||
.cart-meterage-footer:active {
|
||||
transform: scale(0.99);
|
||||
}
|
||||
|
||||
.cart-meterage-footer__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__label {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__value {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__action-text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__icon-wrap {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cart-meterage-footer__badge {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
inset-inline-start: -4px;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
padding: 0 4px;
|
||||
border-radius: 999px;
|
||||
background: var(--color-danger);
|
||||
color: #fff;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import BaseButton from '@/components/ui/BaseButton.vue'
|
||||
import { resolveConfirm, useConfirmState } from '@/composables/useConfirm'
|
||||
|
||||
const state = useConfirmState()
|
||||
|
||||
function cancel() {
|
||||
resolveConfirm(false)
|
||||
}
|
||||
|
||||
function confirmAction() {
|
||||
resolveConfirm(true)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="state.open"
|
||||
class="dialog-overlay confirm-dialog-overlay"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
:aria-labelledby="'confirm-dialog-title'"
|
||||
@click.self="cancel"
|
||||
>
|
||||
<div class="dialog card confirm-dialog">
|
||||
<h3 id="confirm-dialog-title" class="confirm-dialog__title">{{ state.title }}</h3>
|
||||
<p class="confirm-dialog__message">{{ state.message }}</p>
|
||||
<div class="dialog-actions confirm-dialog__actions">
|
||||
<BaseButton variant="outline" @click="cancel">{{ state.cancelLabel }}</BaseButton>
|
||||
<BaseButton :variant="state.tone === 'danger' ? 'danger' : 'primary'" @click="confirmAction">
|
||||
{{ state.confirmLabel }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.confirm-dialog {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.confirm-dialog__title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.confirm-dialog__message {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.confirm-dialog__actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.confirm-dialog__actions {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { extractNumericString, formatNumber } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
hint?: string
|
||||
error?: string
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
const displayValue = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(value) => {
|
||||
const numeric = extractNumericString(value ?? '')
|
||||
displayValue.value = numeric ? formatNumber(Number(numeric)) : ''
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function onInput(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
const numeric = extractNumericString(input.value)
|
||||
displayValue.value = numeric ? formatNumber(Number(numeric)) : ''
|
||||
emit('update:modelValue', numeric)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-group">
|
||||
<label v-if="label" class="form-label">{{ label }}</label>
|
||||
<input
|
||||
class="input"
|
||||
:class="{ 'input-error': error }"
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
dir="ltr"
|
||||
:value="displayValue"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
@input="onInput"
|
||||
/>
|
||||
<p v-if="error" class="input-error-text">{{ error }}</p>
|
||||
<p v-else-if="hint" class="form-hint">{{ hint }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.input {
|
||||
width: 100%;
|
||||
height: var(--btn-height);
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.9375rem;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
transition: border-color 0.15s;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: var(--color-danger);
|
||||
}
|
||||
|
||||
.input-error-text {
|
||||
color: var(--color-danger);
|
||||
font-size: 0.8125rem;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,315 @@
|
||||
<script setup lang="ts">
|
||||
import { useTimeoutFn, onKeyStroke } from '@vueuse/core'
|
||||
import { ref, watch } from 'vue'
|
||||
import BaseButton from '@/components/ui/BaseButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useThemeStore, type ThemePreference } from '@/stores/theme'
|
||||
|
||||
const open = defineModel<boolean>({ default: false })
|
||||
|
||||
const theme = useThemeStore()
|
||||
const saved = ref(false)
|
||||
|
||||
const { start: hideSaved } = useTimeoutFn(() => {
|
||||
saved.value = false
|
||||
}, 2000)
|
||||
|
||||
const themeOptions: {
|
||||
value: ThemePreference
|
||||
label: string
|
||||
description: string
|
||||
icon: string
|
||||
}[] = [
|
||||
{
|
||||
value: 'light',
|
||||
label: 'روشن',
|
||||
description: 'پسزمینه روشن و کنتراست بالا',
|
||||
icon: 'vuesax-linear:sun-1',
|
||||
},
|
||||
{
|
||||
value: 'dark',
|
||||
label: 'تاریک',
|
||||
description: 'مناسب استفاده در شب',
|
||||
icon: 'vuesax-linear:moon',
|
||||
},
|
||||
{
|
||||
value: 'system',
|
||||
label: 'سیستم',
|
||||
description: 'همتراز با تنظیمات دستگاه',
|
||||
icon: 'vuesax-linear:mobile',
|
||||
},
|
||||
]
|
||||
|
||||
function close() {
|
||||
open.value = false
|
||||
}
|
||||
|
||||
function save() {
|
||||
saved.value = true
|
||||
hideSaved()
|
||||
window.setTimeout(() => {
|
||||
close()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
onKeyStroke('Escape', () => {
|
||||
if (open.value) close()
|
||||
})
|
||||
|
||||
watch(open, (isOpen) => {
|
||||
if (!isOpen) saved.value = false
|
||||
document.body.style.overflow = isOpen ? 'hidden' : ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<Transition name="display-sheet">
|
||||
<div
|
||||
v-if="open"
|
||||
class="display-overlay"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="display-settings-title"
|
||||
@click.self="close"
|
||||
>
|
||||
<div class="display-sheet">
|
||||
<div class="display-sheet__handle" aria-hidden="true" />
|
||||
<header class="display-sheet__head">
|
||||
<h2 id="display-settings-title">تنظیمات نمایش</h2>
|
||||
<button type="button" class="display-sheet__close" aria-label="بستن" @click="close">
|
||||
×
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<fieldset class="display-fieldset">
|
||||
<legend class="display-fieldset__legend">حالت نمایش</legend>
|
||||
<div class="display-grid" role="radiogroup" aria-label="حالت نمایش">
|
||||
<button
|
||||
v-for="option in themeOptions"
|
||||
:key="option.value"
|
||||
type="button"
|
||||
class="theme-card"
|
||||
:class="{ 'theme-card--active': theme.preference === option.value }"
|
||||
role="radio"
|
||||
:aria-checked="theme.preference === option.value"
|
||||
@click="theme.preference = option.value"
|
||||
>
|
||||
<span class="theme-card__icon" aria-hidden="true">
|
||||
<BasicIcon :icon="option.icon" :size="24" :stroke-width="1.5" />
|
||||
</span>
|
||||
<span class="theme-card__body">
|
||||
<strong class="theme-card__label">{{ option.label }}</strong>
|
||||
<span class="theme-card__desc">{{ option.description }}</span>
|
||||
</span>
|
||||
<span class="theme-card__check" aria-hidden="true">
|
||||
<BasicIcon
|
||||
v-if="theme.preference === option.value"
|
||||
icon="vuesax-linear:tick-circle"
|
||||
:size="20"
|
||||
:stroke-width="1.75"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<BaseButton block @click="save">ذخیره تنظیمات</BaseButton>
|
||||
<p v-if="saved" class="display-saved">تنظیمات نمایش ذخیره شد ✓</p>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.display-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 200;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.display-sheet {
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
max-height: min(88dvh, 640px);
|
||||
overflow-y: auto;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
border-radius: 20px 20px 0 0;
|
||||
padding: 10px 16px calc(16px + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: var(--shadow-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.display-sheet__handle {
|
||||
width: 40px;
|
||||
height: 4px;
|
||||
border-radius: 999px;
|
||||
background: var(--color-border);
|
||||
margin: 4px auto 0;
|
||||
}
|
||||
|
||||
.display-sheet__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.display-sheet__head h2 {
|
||||
margin: 0;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.display-sheet__close {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
font-size: 1.4rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.display-fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.display-fieldset__legend {
|
||||
margin: 0 0 10px;
|
||||
padding: 0;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.display-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
display: grid;
|
||||
grid-template-columns: 44px 1fr 24px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 14px;
|
||||
background: var(--color-elevated);
|
||||
color: var(--color-text);
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-card--active {
|
||||
border-color: var(--color-primary);
|
||||
background: var(--color-primary-soft);
|
||||
box-shadow: 0 0 0 1px var(--color-primary);
|
||||
}
|
||||
|
||||
.theme-card__icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.theme-card--active .theme-card__icon {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.theme-card__body {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.theme-card__label {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.theme-card__desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.theme-card--active .theme-card__label {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.theme-card__check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.display-saved {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.display-sheet-enter-active,
|
||||
.display-sheet-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.display-sheet-enter-active .display-sheet,
|
||||
.display-sheet-leave-active .display-sheet {
|
||||
transition: transform 0.22s ease;
|
||||
}
|
||||
|
||||
.display-sheet-enter-from,
|
||||
.display-sheet-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.display-sheet-enter-from .display-sheet,
|
||||
.display-sheet-leave-to .display-sheet {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.display-overlay {
|
||||
align-items: center;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.display-sheet {
|
||||
border-radius: 16px;
|
||||
max-height: min(80dvh, 560px);
|
||||
padding: 20px 20px 24px;
|
||||
}
|
||||
|
||||
.display-sheet__handle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
message?: string
|
||||
title?: string
|
||||
/** Context for default icon + copy */
|
||||
variant?: 'default' | 'products' | 'catalogs' | 'orders' | 'cart' | 'checks' | 'search'
|
||||
icon?: string
|
||||
iconSize?: number
|
||||
}>(),
|
||||
{
|
||||
message: undefined,
|
||||
title: undefined,
|
||||
variant: 'default',
|
||||
icon: undefined,
|
||||
iconSize: 72,
|
||||
},
|
||||
)
|
||||
|
||||
const variantIcons: Record<string, string> = {
|
||||
default: 'vuesax-linear:clipboard-close',
|
||||
products: 'vuesax-linear:box-remove',
|
||||
catalogs: 'vuesax-linear:category',
|
||||
orders: 'vuesax-linear:document-text',
|
||||
cart: 'vuesax-linear:bag-cross',
|
||||
checks: 'vuesax-linear:card-receive',
|
||||
search: 'vuesax-linear:search-status',
|
||||
}
|
||||
|
||||
const variantTitles: Record<string, string> = {
|
||||
default: '',
|
||||
products: 'محصولی یافت نشد',
|
||||
catalogs: 'کالیتهای یافت نشد',
|
||||
orders: 'سفارشی یافت نشد',
|
||||
cart: 'سبد خرید خالی است',
|
||||
checks: 'چکی ثبت نشده است',
|
||||
search: 'نتیجهای یافت نشد',
|
||||
}
|
||||
|
||||
const resolvedIcon = computed(
|
||||
() => props.icon ?? variantIcons[props.variant] ?? 'vuesax-linear:clipboard-close',
|
||||
)
|
||||
const resolvedTitle = computed(() => props.title ?? variantTitles[props.variant] ?? '')
|
||||
const resolvedMessage = computed(() => props.message ?? '')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="empty-state">
|
||||
<div class="empty-state__icon" aria-hidden="true">
|
||||
<slot name="icon">
|
||||
<BasicIcon :icon="resolvedIcon" :size="iconSize" :stroke-width="1.25" />
|
||||
</slot>
|
||||
</div>
|
||||
<h2 v-if="resolvedTitle || $slots.title" class="empty-state__title">
|
||||
<slot name="title">{{ resolvedTitle }}</slot>
|
||||
</h2>
|
||||
<p v-if="resolvedMessage || $slots.message" class="empty-state__message">
|
||||
<slot name="message">{{ resolvedMessage }}</slot>
|
||||
</p>
|
||||
<div v-if="$slots.default" class="empty-state__action">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 48px 24px;
|
||||
min-height: 280px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-state__icon {
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text-muted);
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.empty-state__title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.empty-state__message {
|
||||
margin: 0 0 24px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.5;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
.empty-state__message:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.empty-state__action {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
modelValue: string
|
||||
tabs: { id: string; label: string }[]
|
||||
equal?: boolean
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="filter-tabs" :class="{ 'filter-tabs--equal': equal }" role="tablist">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
type="button"
|
||||
role="tab"
|
||||
class="filter-tab"
|
||||
:class="{ active: modelValue === tab.id }"
|
||||
:aria-selected="modelValue === tab.id"
|
||||
@click="$emit('update:modelValue', tab.id)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.filter-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 2px;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.filter-tabs--equal {
|
||||
gap: 6px;
|
||||
overflow: visible;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.filter-tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
flex-shrink: 0;
|
||||
height: 36px;
|
||||
padding: 0 18px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
background: var(--color-tab-inactive-bg);
|
||||
color: var(--color-tab-inactive-text);
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.15s,
|
||||
color 0.15s,
|
||||
border-color 0.15s;
|
||||
}
|
||||
|
||||
.filter-tabs--equal .filter-tab {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 38px;
|
||||
padding: 0 6px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.filter-tab.active {
|
||||
background: var(--color-primary);
|
||||
border-color: var(--color-primary);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.filter-tabs--equal .filter-tab.active {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.filter-tab:not(.active):hover {
|
||||
border-color: var(--color-border);
|
||||
color: var(--color-text);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
message?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="message" class="form-error-banner" role="alert">
|
||||
{{ message }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.form-error-banner {
|
||||
padding: 12px 14px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-danger-light);
|
||||
border: 1px solid color-mix(in srgb, var(--color-danger) 40%, transparent);
|
||||
color: var(--color-danger);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { formatMeterage } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
current: number
|
||||
max: number
|
||||
}>()
|
||||
|
||||
const remaining = computed(() => Math.max(0, props.max - props.current))
|
||||
const percentage = computed(() => Math.min(100, (props.current / props.max) * 100))
|
||||
const isNearFull = computed(() => percentage.value >= 80)
|
||||
const isFull = computed(() => props.current >= props.max)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="meterage-bar" :class="{ near: isNearFull, full: isFull }">
|
||||
<div class="meterage-info">
|
||||
<span
|
||||
>متراژ سبد: <strong>{{ formatMeterage(current) }}</strong></span
|
||||
>
|
||||
<span
|
||||
>باقیمانده: <strong>{{ formatMeterage(remaining) }}</strong></span
|
||||
>
|
||||
</div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" :style="{ width: `${percentage}%` }" />
|
||||
</div>
|
||||
<p class="meterage-max text-sm text-muted">حداکثر مجاز: {{ formatMeterage(max) }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.meterage-bar {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.meterage-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.progress-track {
|
||||
height: 8px;
|
||||
background: #e2e8f0;
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--color-primary);
|
||||
border-radius: 999px;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
.meterage-bar.near .progress-fill {
|
||||
background: var(--color-warning);
|
||||
}
|
||||
|
||||
.meterage-bar.full .progress-fill {
|
||||
background: var(--color-danger);
|
||||
}
|
||||
|
||||
.meterage-max {
|
||||
margin: 6px 0 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,235 @@
|
||||
<script setup lang="ts">
|
||||
import SkeletonBlock from '@/components/ui/SkeletonBlock.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
/** list | cards | grid | detail | profile | home | form */
|
||||
variant?: 'list' | 'cards' | 'grid' | 'detail' | 'profile' | 'home' | 'form'
|
||||
rows?: number
|
||||
}>(),
|
||||
{
|
||||
variant: 'list',
|
||||
rows: 4,
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-skeleton" role="status" aria-live="polite" aria-busy="true" aria-label="در حال بارگذاری">
|
||||
<!-- Home -->
|
||||
<template v-if="variant === 'home'">
|
||||
<div class="page-skeleton__banner">
|
||||
<SkeletonBlock height="148px" radius="16px" />
|
||||
</div>
|
||||
<div class="page-skeleton__quick">
|
||||
<div v-for="n in 4" :key="`q-${n}`" class="page-skeleton__quick-item">
|
||||
<SkeletonBlock circle width="48px" height="48px" />
|
||||
<SkeletonBlock width="64%" height="10px" />
|
||||
</div>
|
||||
</div>
|
||||
<SkeletonBlock width="40%" height="16px" />
|
||||
<div class="page-skeleton__grid">
|
||||
<div v-for="n in 4" :key="`g-${n}`" class="page-skeleton__card">
|
||||
<SkeletonBlock height="110px" radius="12px" />
|
||||
<SkeletonBlock width="80%" height="12px" />
|
||||
<SkeletonBlock width="50%" height="10px" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Profile -->
|
||||
<template v-else-if="variant === 'profile'">
|
||||
<div class="page-skeleton__profile-hero">
|
||||
<SkeletonBlock circle width="72px" height="72px" />
|
||||
<SkeletonBlock width="45%" height="18px" />
|
||||
<SkeletonBlock width="30%" height="12px" />
|
||||
</div>
|
||||
<div class="page-skeleton__panel">
|
||||
<div v-for="n in 4" :key="`s-${n}`" class="page-skeleton__stat">
|
||||
<SkeletonBlock width="50%" height="10px" />
|
||||
<SkeletonBlock width="70%" height="18px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-skeleton__list">
|
||||
<div v-for="n in 5" :key="`m-${n}`" class="page-skeleton__row">
|
||||
<SkeletonBlock circle width="36px" height="36px" />
|
||||
<div class="page-skeleton__row-text">
|
||||
<SkeletonBlock width="55%" height="12px" />
|
||||
<SkeletonBlock width="35%" height="10px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Detail -->
|
||||
<template v-else-if="variant === 'detail'">
|
||||
<SkeletonBlock height="220px" radius="0" />
|
||||
<div class="page-skeleton__detail-body">
|
||||
<SkeletonBlock width="70%" height="20px" />
|
||||
<SkeletonBlock width="40%" height="12px" />
|
||||
<SkeletonBlock height="72px" radius="12px" />
|
||||
<SkeletonBlock width="100%" height="12px" />
|
||||
<SkeletonBlock width="92%" height="12px" />
|
||||
<SkeletonBlock width="85%" height="12px" />
|
||||
<SkeletonBlock height="48px" radius="12px" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Product / category grid -->
|
||||
<template v-else-if="variant === 'grid' || variant === 'cards'">
|
||||
<SkeletonBlock width="55%" height="16px" />
|
||||
<div class="page-skeleton__chips">
|
||||
<SkeletonBlock v-for="n in 4" :key="`c-${n}`" width="72px" height="32px" radius="999px" />
|
||||
</div>
|
||||
<div class="page-skeleton__grid">
|
||||
<div v-for="n in rows" :key="`card-${n}`" class="page-skeleton__card">
|
||||
<SkeletonBlock height="120px" radius="12px" />
|
||||
<SkeletonBlock width="85%" height="12px" />
|
||||
<SkeletonBlock width="55%" height="10px" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Form -->
|
||||
<template v-else-if="variant === 'form'">
|
||||
<div class="page-skeleton__form">
|
||||
<div v-for="n in rows" :key="`f-${n}`" class="page-skeleton__field">
|
||||
<SkeletonBlock width="30%" height="10px" />
|
||||
<SkeletonBlock height="44px" radius="10px" />
|
||||
</div>
|
||||
<SkeletonBlock height="48px" radius="12px" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Default list -->
|
||||
<template v-else>
|
||||
<div class="page-skeleton__list">
|
||||
<div v-for="n in rows" :key="`r-${n}`" class="page-skeleton__row page-skeleton__row--card">
|
||||
<SkeletonBlock circle width="40px" height="40px" />
|
||||
<div class="page-skeleton__row-text">
|
||||
<SkeletonBlock width="62%" height="13px" />
|
||||
<SkeletonBlock width="42%" height="10px" />
|
||||
<SkeletonBlock width="28%" height="10px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.page-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 4px 0 24px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page-skeleton__banner,
|
||||
.page-skeleton__panel,
|
||||
.page-skeleton__detail-body,
|
||||
.page-skeleton__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.page-skeleton__quick {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.page-skeleton__quick-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.page-skeleton__card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__profile-hero {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 20px 0 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__panel {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
background: var(--color-elevated);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.page-skeleton__stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.page-skeleton__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.page-skeleton__row--card {
|
||||
padding: 12px;
|
||||
background: var(--color-elevated);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.page-skeleton__row-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-skeleton__detail-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-skeleton__field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.page-skeleton__grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,336 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import {
|
||||
JALALI_MONTH_NAMES,
|
||||
JALALI_WEEKDAY_NAMES,
|
||||
buildCalendarDays,
|
||||
formatJalaliLabel,
|
||||
isoToJalali,
|
||||
jalaliToISO,
|
||||
todayJalali,
|
||||
} from '@/utils/jalali'
|
||||
import { toPersianDigits } from '@/utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
hint?: string
|
||||
error?: string
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
const rootRef = ref<HTMLElement | null>(null)
|
||||
const isOpen = ref(false)
|
||||
const viewYear = ref(todayJalali().jy)
|
||||
const viewMonth = ref(todayJalali().jm)
|
||||
|
||||
const selectedJalali = computed(() => isoToJalali(props.modelValue ?? ''))
|
||||
|
||||
const displayValue = computed(() => {
|
||||
if (!selectedJalali.value) return ''
|
||||
const { jy, jm, jd } = selectedJalali.value
|
||||
return formatJalaliLabel(jy, jm, jd)
|
||||
})
|
||||
|
||||
const calendarDays = computed(() => buildCalendarDays(viewYear.value, viewMonth.value))
|
||||
|
||||
const monthLabel = computed(
|
||||
() => `${JALALI_MONTH_NAMES[viewMonth.value - 1]} ${toPersianDigits(String(viewYear.value))}`,
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(value) => {
|
||||
const jalali = isoToJalali(value ?? '')
|
||||
if (jalali) {
|
||||
viewYear.value = jalali.jy
|
||||
viewMonth.value = jalali.jm
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function toggleCalendar() {
|
||||
if (props.disabled) return
|
||||
isOpen.value = !isOpen.value
|
||||
}
|
||||
|
||||
function closeCalendar() {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
function selectDay(day: number) {
|
||||
emit('update:modelValue', jalaliToISO(viewYear.value, viewMonth.value, day))
|
||||
closeCalendar()
|
||||
}
|
||||
|
||||
function changeMonth(delta: number) {
|
||||
let month = viewMonth.value + delta
|
||||
let year = viewYear.value
|
||||
|
||||
if (month > 12) {
|
||||
month = 1
|
||||
year += 1
|
||||
} else if (month < 1) {
|
||||
month = 12
|
||||
year -= 1
|
||||
}
|
||||
|
||||
viewMonth.value = month
|
||||
viewYear.value = year
|
||||
}
|
||||
|
||||
function selectToday() {
|
||||
const today = todayJalali()
|
||||
viewYear.value = today.jy
|
||||
viewMonth.value = today.jm
|
||||
emit('update:modelValue', jalaliToISO(today.jy, today.jm, today.jd))
|
||||
closeCalendar()
|
||||
}
|
||||
|
||||
function isSelected(day: number) {
|
||||
if (!selectedJalali.value) return false
|
||||
const { jy, jm, jd } = selectedJalali.value
|
||||
return jy === viewYear.value && jm === viewMonth.value && jd === day
|
||||
}
|
||||
|
||||
function isToday(day: number) {
|
||||
const today = todayJalali()
|
||||
return today.jy === viewYear.value && today.jm === viewMonth.value && today.jd === day
|
||||
}
|
||||
|
||||
function onDocumentClick(event: MouseEvent) {
|
||||
if (!rootRef.value?.contains(event.target as Node)) {
|
||||
closeCalendar()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', onDocumentClick)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', onDocumentClick)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="rootRef" class="form-group persian-date-input">
|
||||
<label v-if="label" class="form-label">{{ label }}</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="input persian-date-input__trigger"
|
||||
:class="{ 'input-error': error, 'is-open': isOpen }"
|
||||
:disabled="disabled"
|
||||
@click.stop="toggleCalendar"
|
||||
>
|
||||
<span :class="{ 'persian-date-input__placeholder': !displayValue }">
|
||||
{{ displayValue || placeholder || 'انتخاب تاریخ' }}
|
||||
</span>
|
||||
<span class="persian-date-input__icon" aria-hidden="true">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
|
||||
<rect x="3" y="5" width="18" height="16" rx="2" stroke="currentColor" stroke-width="1.5" />
|
||||
<path d="M8 3v4M16 3v4M3 10h18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div v-if="isOpen" class="persian-date-input__panel" @click.stop>
|
||||
<div class="persian-date-input__header">
|
||||
<button type="button" class="persian-date-input__nav" @click="changeMonth(-1)">‹</button>
|
||||
<strong class="persian-date-input__month">{{ monthLabel }}</strong>
|
||||
<button type="button" class="persian-date-input__nav" @click="changeMonth(1)">›</button>
|
||||
</div>
|
||||
|
||||
<div class="persian-date-input__weekdays">
|
||||
<span v-for="weekday in JALALI_WEEKDAY_NAMES" :key="weekday">{{ weekday }}</span>
|
||||
</div>
|
||||
|
||||
<div class="persian-date-input__grid">
|
||||
<template v-for="(day, index) in calendarDays" :key="index">
|
||||
<span v-if="day === null" class="persian-date-input__cell persian-date-input__cell--empty" />
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="persian-date-input__cell"
|
||||
:class="{
|
||||
'persian-date-input__cell--selected': isSelected(day),
|
||||
'persian-date-input__cell--today': isToday(day),
|
||||
}"
|
||||
@click="selectDay(day)"
|
||||
>
|
||||
{{ toPersianDigits(String(day)) }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<button type="button" class="persian-date-input__today" @click="selectToday">امروز</button>
|
||||
</div>
|
||||
|
||||
<p v-if="error" class="input-error-text">{{ error }}</p>
|
||||
<p v-else-if="hint" class="form-hint">{{ hint }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.persian-date-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
height: var(--btn-height);
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.9375rem;
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.persian-date-input__trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.persian-date-input__trigger:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.persian-date-input__trigger.is-open,
|
||||
.persian-date-input__trigger:focus-visible {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.persian-date-input__trigger:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.persian-date-input__placeholder {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.persian-date-input__icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: var(--color-danger);
|
||||
}
|
||||
|
||||
.input-error-text {
|
||||
color: var(--color-danger);
|
||||
font-size: 0.8125rem;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
|
||||
.persian-date-input__panel {
|
||||
position: absolute;
|
||||
top: calc(100% + 6px);
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 120;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.persian-date-input__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.persian-date-input__month {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.persian-date-input__nav {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-elevated);
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.persian-date-input__weekdays,
|
||||
.persian-date-input__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.persian-date-input__weekdays {
|
||||
margin-bottom: 6px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.persian-date-input__cell {
|
||||
height: 34px;
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
font-size: 0.8125rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.persian-date-input__cell--empty {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.persian-date-input__cell--today {
|
||||
border: 1px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.persian-date-input__cell--selected {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-on-primary, #fff);
|
||||
}
|
||||
|
||||
.persian-date-input__today {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-elevated);
|
||||
color: var(--color-primary);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.15s,
|
||||
border-color 0.15s;
|
||||
}
|
||||
|
||||
.persian-date-input__today:hover {
|
||||
background: var(--color-primary-soft);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
modelValue?: string
|
||||
placeholder?: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search-field">
|
||||
<input
|
||||
class="search-field__input"
|
||||
type="search"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.search-field__input {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
font-family: inherit;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.5;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.search-field__input::placeholder {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.search-field__input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
width?: string
|
||||
height?: string
|
||||
radius?: string
|
||||
circle?: boolean
|
||||
}>(),
|
||||
{
|
||||
width: '100%',
|
||||
height: '14px',
|
||||
radius: '8px',
|
||||
circle: false,
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="sk"
|
||||
:class="{ 'sk--circle': circle }"
|
||||
:style="{
|
||||
width,
|
||||
height,
|
||||
borderRadius: circle ? '50%' : radius,
|
||||
}"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.sk {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
color-mix(in srgb, var(--color-border) 55%, var(--color-surface)) 0%,
|
||||
color-mix(in srgb, var(--color-border) 85%, var(--color-elevated, var(--color-surface))) 45%,
|
||||
color-mix(in srgb, var(--color-border) 55%, var(--color-surface)) 100%
|
||||
);
|
||||
background-size: 220% 100%;
|
||||
animation: sk-shimmer 1.35s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.sk--circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@keyframes sk-shimmer {
|
||||
0% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.sk {
|
||||
animation: none;
|
||||
background: var(--color-border);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BaseBadge from './BaseBadge.vue'
|
||||
import { ORDER_STATUS_LABELS, STATUS_BADGE_VARIANT } from '@/utils/constants'
|
||||
import type { OrderStatus } from '@/types'
|
||||
|
||||
const props = defineProps<{
|
||||
status: OrderStatus
|
||||
}>()
|
||||
|
||||
const label = computed(() => ORDER_STATUS_LABELS[props.status] ?? props.status)
|
||||
const variant = computed(() => STATUS_BADGE_VARIANT[props.status] ?? 'neutral')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseBadge :variant="variant">{{ label }}</BaseBadge>
|
||||
</template>
|
||||
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
src?: string | null
|
||||
initials: string
|
||||
size?: number
|
||||
}>(),
|
||||
{ size: 72 },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="user-avatar"
|
||||
:style="{ width: `${size}px`, height: `${size}px`, fontSize: `${Math.round(size * 0.38)}px` }"
|
||||
>
|
||||
<img v-if="src" class="user-avatar__img" :src="src" alt="" />
|
||||
<span v-else>{{ initials }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-avatar {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
overflow: hidden;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
color: inherit;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-avatar__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user