Compare commits
2
Commits
mian-test2
...
main-test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04dad5cce0 | ||
|
|
f797f5616c |
+23
-9
@@ -1,21 +1,30 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="desktopConfig w-full right-0 left-0">
|
||||
<transition mode="out-in" name="fade">
|
||||
<AConfigProvider
|
||||
v-if="!showSplash"
|
||||
:theme="{
|
||||
token: {
|
||||
colorPrimary: colors.primary,
|
||||
colorLink: colors.primary,
|
||||
colorLinkActive: colors.primary,
|
||||
colorLinkHover: colors['primary-rgba']
|
||||
colorPrimary: primaryColor,
|
||||
colorLink: primaryColor,
|
||||
colorLinkActive: primaryColor,
|
||||
colorLinkHover: primaryColor
|
||||
}
|
||||
}"
|
||||
direction="rtl"
|
||||
>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition :name="route.meta.transition || 'fade'">
|
||||
<component :is="Component" :key="route.fullPath" class="app-main" />
|
||||
<!--
|
||||
Key only the top-level matched route (e.g. main vs login), not fullPath.
|
||||
Using fullPath remounted the whole AppLayoutShell (sidebar/bottom nav)
|
||||
on every page change and reloaded the menu logo each time.
|
||||
-->
|
||||
<component
|
||||
:is="Component"
|
||||
:key="route.matched[0]?.name ?? route.name"
|
||||
class="app-main"
|
||||
/>
|
||||
</transition>
|
||||
</router-view>
|
||||
</AConfigProvider>
|
||||
@@ -71,6 +80,7 @@
|
||||
import { colors } from './themeConfig'
|
||||
import pkg from '../package.json'
|
||||
import { getDisplayAppVersion } from '@/config/config-cache'
|
||||
import { getAppPrimaryColor } from '@/config/brand-theme'
|
||||
import { computed, defineAsyncComponent, h, onMounted, ref } from 'vue'
|
||||
import img_topGradiant from '@/views/login/assets/img/gr_top_white.svg'
|
||||
import img_pattern from '@/views/login/assets/img/pattern.svg'
|
||||
@@ -84,8 +94,11 @@ import {
|
||||
import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
|
||||
import { useApplyDesktopLayoutClass } from '@/layouts/composables/useAppLayout'
|
||||
|
||||
import { getAppLogoFullUrl } from '@/config/brand-assets'
|
||||
|
||||
import img_bottomGradiant from '@/views/login/assets/img/gr_bottom_white.svg'
|
||||
import logoFull from '@/assets/img/logo_full_.png'
|
||||
|
||||
const logoFull = getAppLogoFullUrl()
|
||||
|
||||
const VersionUpdateModal = defineAsyncComponent(
|
||||
() => import('@/modules/version/VersionUpdateModal.vue')
|
||||
@@ -99,6 +112,7 @@ const indicator = h(LoadingOutlined, {
|
||||
})
|
||||
const displayVersion = getDisplayAppVersion(pkg.version)
|
||||
const showSplash = ref(true)
|
||||
const primaryColor = getAppPrimaryColor(colors.primary || '#000000')
|
||||
|
||||
useApplyDesktopLayoutClass()
|
||||
|
||||
@@ -141,7 +155,7 @@ const supportAccentColor = computed(() => {
|
||||
case 'soroush':
|
||||
return '#2563eb'
|
||||
default:
|
||||
return colors.primary || '#334155'
|
||||
return primaryColor || '#334155'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -181,7 +195,7 @@ onMounted(async () => {
|
||||
|
||||
<style lang="less">
|
||||
.updateButton .van-dialog__confirm .van-button__text {
|
||||
color: @primary-color !important;
|
||||
color: var(--app-primary-color, #a72b77) !important;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
+60
-8
@@ -14,6 +14,44 @@ import {
|
||||
setHasFingerPrint
|
||||
} from '@/app/authBoot'
|
||||
import { recoverMobileViewportAfterAuth } from '@/layouts/composables/useMobileScrollReset'
|
||||
import {
|
||||
getDefaultLandingRoute,
|
||||
hasAbshodeTrading,
|
||||
hasHomePage,
|
||||
hasProductShop,
|
||||
} from '@/config/project-profile'
|
||||
|
||||
const GUEST_PUBLIC_ROUTES = ['login', '404', 'about', 'cart'] as const
|
||||
|
||||
function getGuestPublicRoutes(): string[] {
|
||||
const routes: string[] = [...GUEST_PUBLIC_ROUTES]
|
||||
if (hasProductShop()) {
|
||||
routes.push('buyProduct', 'productDetail')
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
function enforceProjectRouteAccess(
|
||||
to: RouteLocationNormalized,
|
||||
next: NavigationGuardNext
|
||||
): boolean {
|
||||
if (!hasHomePage() && to.name === 'home') {
|
||||
next({ name: getDefaultLandingRoute() })
|
||||
return true
|
||||
}
|
||||
|
||||
if (!hasAbshodeTrading() && to.name === 'gold') {
|
||||
next({ name: getDefaultLandingRoute() })
|
||||
return true
|
||||
}
|
||||
|
||||
if (!hasProductShop() && (to.name === 'buyProduct' || to.name === 'productDetail')) {
|
||||
next({ name: getDefaultLandingRoute() })
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function setupRouterGuards() {
|
||||
const userStore = useUserStore()
|
||||
@@ -43,7 +81,7 @@ export function setupRouterGuards() {
|
||||
}
|
||||
|
||||
function goToLogin(to: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||
if (to.name === 'buyProduct' || to.name === 'productDetail' || to.name === 'about' || to.name === 'cart') {
|
||||
if (getGuestPublicRoutes().includes(to.name as string)) {
|
||||
return next()
|
||||
}
|
||||
if (to.name !== 'login') {
|
||||
@@ -52,9 +90,10 @@ export function setupRouterGuards() {
|
||||
return next()
|
||||
}
|
||||
|
||||
function goToHome(to: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||
if (to.name !== 'buyProduct') {
|
||||
return next({ name: 'buyProduct' })
|
||||
function goToLanding(to: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||
const landing = getDefaultLandingRoute()
|
||||
if (to.name !== landing) {
|
||||
return next({ name: landing })
|
||||
}
|
||||
return next()
|
||||
}
|
||||
@@ -64,6 +103,10 @@ export function setupRouterGuards() {
|
||||
clearFingerTimeout()
|
||||
setFingerTimeOut(to)
|
||||
|
||||
if (enforceProjectRouteAccess(to, next)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isFirst) {
|
||||
isFirst = false
|
||||
|
||||
@@ -83,12 +126,15 @@ export function setupRouterGuards() {
|
||||
}
|
||||
} else {
|
||||
if (to.name == 'login') {
|
||||
goToHome(to, next)
|
||||
return goToLanding(to, next)
|
||||
}
|
||||
if (enforceProjectRouteAccess(to, next)) {
|
||||
return
|
||||
}
|
||||
return next()
|
||||
}
|
||||
} else {
|
||||
if (['login', '404', 'buyProduct', 'productDetail', 'about', 'cart'].includes(to.name as string)) {
|
||||
if (getGuestPublicRoutes().includes(to.name as string)) {
|
||||
return next()
|
||||
}
|
||||
goToLogin(to, next)
|
||||
@@ -97,18 +143,24 @@ export function setupRouterGuards() {
|
||||
if (getFingerPosition()) {
|
||||
if (getToken()) {
|
||||
if (to.name === 'login') {
|
||||
return next({ name: from.name || 'buyProduct' })
|
||||
return next({ name: (from.name as string) || getDefaultLandingRoute() })
|
||||
}
|
||||
if (enforceProjectRouteAccess(to, next)) {
|
||||
return
|
||||
}
|
||||
return next()
|
||||
}
|
||||
|
||||
if (['login', '404', 'buyProduct', 'productDetail', 'about', 'cart'].includes(to.name as string)) {
|
||||
if (getGuestPublicRoutes().includes(to.name as string)) {
|
||||
return next()
|
||||
}
|
||||
return next({ name: 'login' })
|
||||
}
|
||||
|
||||
if (getToken() && !getHasFingerPrint()) {
|
||||
if (enforceProjectRouteAccess(to, next)) {
|
||||
return
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
goToLogin(to, next)
|
||||
|
||||
@@ -61,6 +61,12 @@ body {
|
||||
|
||||
:root {
|
||||
color-scheme: only light;
|
||||
--app-primary-color: #a72b77;
|
||||
--app-secondary-color: #a72b77;
|
||||
--app-tertiary-color: #e0be7f;
|
||||
--app-background-color: #ffffff;
|
||||
--app-primary-dark: #711d4d;
|
||||
--app-primary-light: #c45f9a;
|
||||
--app-safe-top: env(safe-area-inset-top, 0px);
|
||||
--app-safe-bottom: env(safe-area-inset-bottom, 0px);
|
||||
--app-credit-bar-inner: 0px;
|
||||
@@ -164,7 +170,7 @@ body {
|
||||
background-color: #fff;
|
||||
//display: none;
|
||||
outline: none;
|
||||
border: 1px solid #a72b77 !important;
|
||||
border: 1px solid var(--app-primary-color, #a72b77) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,24 +368,49 @@ body {
|
||||
}
|
||||
.ant-radio-group-solid
|
||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{
|
||||
color: #a72b77 !important;
|
||||
color: var(--app-primary-color, #a72b77) !important;
|
||||
}
|
||||
.ant-input-group-addon{
|
||||
background-color: #a72b77 !important;
|
||||
color: #e0be7f !important;
|
||||
background-color: var(--app-primary-color, #a72b77) !important;
|
||||
color: var(--app-tertiary-color, #e0be7f) !important;
|
||||
}
|
||||
.ant-slider-track{
|
||||
background-color: #a72b77 !important;
|
||||
background-color: var(--app-primary-color, #a72b77) !important;
|
||||
|
||||
}
|
||||
.ant-radio-checked .ant-radio-inner,.ant-radio-group-solid .ant-radio-button-wrapper-checked {
|
||||
border-color: var(--app-primary-color)!important;
|
||||
background-color: var(--app-primary-color)!important
|
||||
}
|
||||
|
||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover:before {
|
||||
background-color: var(--app-primary-color)!important
|
||||
}
|
||||
|
||||
.ant-slider-handle {
|
||||
background-color: #a72b77 !important;
|
||||
|
||||
background-color: var(--app-primary-color, #a72b77) !important;
|
||||
border-color: var(--app-tertiary-color, #e0be7f) !important;
|
||||
}
|
||||
.ant-btn-primary{
|
||||
background-color: var(--app-primary-color, #a72b77) !important;
|
||||
color: var(--app-tertiary-color, #ffffff) !important;
|
||||
border-color: var(--app-primary-color, #a72b77) !important;;
|
||||
}
|
||||
|
||||
.ant-drawer-body{
|
||||
padding: 0px !important;
|
||||
}
|
||||
.ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{
|
||||
color: white !important;
|
||||
}
|
||||
.ant-spin{
|
||||
color: var(--app-tertiary-color, #000000) !important;
|
||||
}
|
||||
.ant-spin-dot-item{
|
||||
background-color: var(--app-tertiary-color, #a72b77) !important;
|
||||
|
||||
}
|
||||
.ant-btn:hover{
|
||||
color: var(--app-primary-color, #a72b77) !important;
|
||||
border-color: var(--app-primary-color, #a72b77) !important;;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@prefixCls: 'noname';
|
||||
|
||||
/* مقادیر ثابت برای Ant Design Less (fade و توابع رنگ). تم واقعی در runtime با --app-primary-color ست میشود. */
|
||||
@primary-color: #a72b77;
|
||||
@secondary-color: #a72b77;
|
||||
@App-primary-color: #a72b77;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<AButton :disabled="props.disabledB" :type="props.type" :size="props.size" :class="[prefixCls, _class]" :loading="props.loading">
|
||||
<!-- py-1 px-2-->
|
||||
<div
|
||||
class="flex items-center gap-1 justify-center flex-row-reverse gap-2 py-1 px-2"
|
||||
class="flex items-center gap-1 justify-center flex-row-reverse gap-2 px-2"
|
||||
:class="[{ 'flex-row-reverse': suffixIcon }]"
|
||||
>
|
||||
<slot v-if="$slots.default"></slot>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import icons from '@/components/BasicPacks/tools/icons/icons.json'
|
||||
import {usePrefix} from "@/utils/usePrefix";
|
||||
import {computed, onMounted, ref, withDefaults, defineProps} from "vue";
|
||||
import { getAppPrimaryColor } from '@/config/brand-theme'
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
@@ -28,6 +29,11 @@ const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLDivElement>()
|
||||
tempIcon.value = icons[`${props.icon}`] as string
|
||||
const color = computed(() => {
|
||||
if (!props.color) return props.color
|
||||
const raw = String(props.color).trim()
|
||||
if (raw.includes('--app-primary-color') || raw === 'primary') {
|
||||
return getAppPrimaryColor()
|
||||
}
|
||||
return props.color
|
||||
})
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import {usePrefix} from "@/utils/usePrefix";
|
||||
import {computed} from "vue";
|
||||
import {usePrice} from "@/components/BasicPacks/BasicPriceInput/src/utils/usePrice";
|
||||
import {persianToEnglishDigits, shouldNormalizeInputDigits} from '@/utils/persianDigits';
|
||||
import { getAppPrimaryColor } from '@/config/brand-theme'
|
||||
|
||||
//Props
|
||||
interface Prop {
|
||||
@@ -55,12 +56,22 @@ interface Prop {
|
||||
placeHolder?: String
|
||||
}
|
||||
|
||||
const addonBgColor = computed(() => props.addonBgColor)
|
||||
const addonTextColor = computed(() => props.addonTextColor)
|
||||
function resolveCssColor(value?: String | string | null) {
|
||||
if (!value) return value
|
||||
const raw = String(value).trim()
|
||||
if (raw.includes('--app-primary-color') || raw === 'primary') {
|
||||
return getAppPrimaryColor()
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
isPassword: false
|
||||
})
|
||||
|
||||
const addonBgColorResolved = computed(() => resolveCssColor(props.addonBgColor) || getAppPrimaryColor())
|
||||
const addonTextColorResolved = computed(() => resolveCssColor(props.addonTextColor) || 'white')
|
||||
|
||||
const emits = defineEmits(['update:value', 'onchange'])
|
||||
|
||||
const localValue = computed({
|
||||
@@ -118,8 +129,8 @@ const {prefixCls} = usePrefix('input')
|
||||
}
|
||||
|
||||
.ant-input-group-addon {
|
||||
background-color: v-bind(addonBgColor);
|
||||
color: v-bind(addonTextColor);
|
||||
background-color: v-bind(addonBgColorResolved);
|
||||
color: v-bind(addonTextColorResolved);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div>
|
||||
{{ props.title }}
|
||||
@@ -105,7 +105,7 @@ const handleChange = (e: any) => {
|
||||
//padding: 5px;
|
||||
/* .ant-select {
|
||||
.ant-select-selector {
|
||||
border-color: @primary-color;
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { getConfig } from '@/config/app-config'
|
||||
import { getAppIconUrl, resolveConfigAssetUrl } from '@/config/brand-assets'
|
||||
import { applyBrandTheme } from '@/config/brand-theme'
|
||||
import { isPwaManifestReady } from '@/modules/pwa/manifest'
|
||||
|
||||
export function applyAppConfig() {
|
||||
applyBrandTheme()
|
||||
|
||||
if (isPwaManifestReady()) return
|
||||
|
||||
setTitle()
|
||||
@@ -13,10 +17,6 @@ function setTitle() {
|
||||
document.title = getConfig('name_fa', 'در حال بارگذاری...')
|
||||
}
|
||||
|
||||
function getLogoUrl() {
|
||||
return getConfig<string>('avatar') || '/favicon.png'
|
||||
}
|
||||
|
||||
function setFavicon() {
|
||||
let faviconLink =
|
||||
document.querySelector<HTMLLinkElement>("link[rel='icon']") ||
|
||||
@@ -28,14 +28,14 @@ function setFavicon() {
|
||||
document.head.appendChild(faviconLink)
|
||||
}
|
||||
|
||||
const logoUrl = getLogoUrl()
|
||||
const logoUrl = getAppIconUrl()
|
||||
|
||||
faviconLink.type = 'image/png'
|
||||
faviconLink.href = logoUrl.startsWith('http') ? logoUrl : resolveRemoteLogo(logoUrl)
|
||||
faviconLink.href = logoUrl
|
||||
}
|
||||
|
||||
function setAppleTouchIconFallback() {
|
||||
const logoUrl = getLogoUrl()
|
||||
const logoUrl = getAppIconUrl()
|
||||
|
||||
if (!logoUrl) return
|
||||
|
||||
@@ -57,7 +57,7 @@ function setAppleTouchIconFallback() {
|
||||
document.head.appendChild(link)
|
||||
}
|
||||
|
||||
link.href = logoUrl.startsWith('http') ? logoUrl : resolveRemoteLogo(logoUrl)
|
||||
link.href = logoUrl
|
||||
})
|
||||
|
||||
let appleTitle = document.querySelector<HTMLMetaElement>("meta[name='apple-mobile-web-app-title']")
|
||||
@@ -71,13 +71,4 @@ function setAppleTouchIconFallback() {
|
||||
appleTitle.content = getConfig('name_fa', 'اپ مشتری')
|
||||
}
|
||||
|
||||
function resolveRemoteLogo(path: string) {
|
||||
if (/^(https?:\/\/|data:|blob:)/i.test(path)) return path
|
||||
|
||||
const lastSuccess = localStorage.getItem('CONFIG_Success_URL')
|
||||
const base = lastSuccess
|
||||
? lastSuccess.replace(/\/get_user\/?$/i, '').replace(/\/+$/, '')
|
||||
: 'https://nerkh.gold'
|
||||
|
||||
return `${base}/${path.replace(/^\/+/, '')}`
|
||||
}
|
||||
export { resolveConfigAssetUrl }
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { getConfig } from '@/config/app-config'
|
||||
|
||||
const CONFIG_SUCCESS_URL_KEY = 'CONFIG_Success_URL'
|
||||
|
||||
const DEFAULT_ICON = '/favicon.png'
|
||||
const DEFAULT_LOGO = '/logo.png'
|
||||
const DEFAULT_LOGO_FULL = '/logo_full_.png'
|
||||
|
||||
export function resolveConfigAssetUrl(path?: string | null): string {
|
||||
if (!path) return ''
|
||||
|
||||
if (/^(https?:\/\/|data:|blob:)/i.test(path)) return path
|
||||
|
||||
const lastSuccess = localStorage.getItem(CONFIG_SUCCESS_URL_KEY)
|
||||
const base = lastSuccess
|
||||
? lastSuccess.replace(/\/get_user\/?$/i, '').replace(/\/+$/, '')
|
||||
: 'https://nerkh.gold'
|
||||
|
||||
return `${base}/${path.replace(/^\/+/, '')}`
|
||||
}
|
||||
|
||||
function pickConfigAsset(...keys: string[]): string {
|
||||
for (const key of keys) {
|
||||
const value = getConfig<string>(key)
|
||||
if (value) return resolveConfigAssetUrl(value)
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
/** آیکون کوچک اپ — معمولاً فیلد avatar در get_user */
|
||||
export function getAppIconUrl(fallback = DEFAULT_ICON): string {
|
||||
return pickConfigAsset('avatar', 'icon') || fallback
|
||||
}
|
||||
|
||||
/** لوگوی فشرده — برای هدر و FAB */
|
||||
export function getAppLogoUrl(fallback = DEFAULT_LOGO): string {
|
||||
return pickConfigAsset('logo', 'avatar') || fallback
|
||||
}
|
||||
|
||||
/** لوگوی کامل — برای اسپلش، لاگین و سایدبار */
|
||||
export function getAppLogoFullUrl(fallback = DEFAULT_LOGO_FULL): string {
|
||||
return pickConfigAsset('logo_full', 'logo', 'avatar') || fallback
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { getConfig } from '@/config/app-config'
|
||||
import { colors } from '@/themeConfig'
|
||||
|
||||
export const DEFAULT_PRIMARY_COLOR = '#a72b77'
|
||||
export const DEFAULT_SECONDARY_COLOR = '#a72b77'
|
||||
export const DEFAULT_TERTIARY_COLOR = '#e0be7f'
|
||||
export const DEFAULT_BACKGROUND_COLOR = '#ffffff'
|
||||
|
||||
function normalizeHex(value: unknown): string | null {
|
||||
if (typeof value !== 'string') return null
|
||||
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed) return null
|
||||
|
||||
const withHash = trimmed.startsWith('#') ? trimmed : `#${trimmed}`
|
||||
|
||||
if (!/^#[0-9a-fA-F]{6}$/.test(withHash) && !/^#[0-9a-fA-F]{3}$/.test(withHash)) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (withHash.length === 4) {
|
||||
const [, r, g, b] = withHash
|
||||
return `#${r}${r}${g}${g}${b}${b}`.toLowerCase()
|
||||
}
|
||||
|
||||
return withHash.toLowerCase()
|
||||
}
|
||||
|
||||
function lightenHex(hex: string, amount = 0.22): string {
|
||||
const normalized = normalizeHex(hex)
|
||||
if (!normalized) return hex
|
||||
|
||||
const num = parseInt(normalized.slice(1), 16)
|
||||
const r = (num >> 16) & 255
|
||||
const g = (num >> 8) & 255
|
||||
const b = num & 255
|
||||
|
||||
const mix = (channel: number) => Math.round(channel + (255 - channel) * amount)
|
||||
|
||||
return `#${[mix(r), mix(g), mix(b)]
|
||||
.map((channel) => channel.toString(16).padStart(2, '0'))
|
||||
.join('')}`
|
||||
}
|
||||
|
||||
function darkenHex(hex: string, amount = 0.22): string {
|
||||
const normalized = normalizeHex(hex)
|
||||
if (!normalized) return hex
|
||||
|
||||
const num = parseInt(normalized.slice(1), 16)
|
||||
const r = Math.round(((num >> 16) & 255) * (1 - amount))
|
||||
const g = Math.round(((num >> 8) & 255) * (1 - amount))
|
||||
const b = Math.round((num & 255) * (1 - amount))
|
||||
|
||||
return `#${[r, g, b].map((channel) => channel.toString(16).padStart(2, '0')).join('')}`
|
||||
}
|
||||
|
||||
export function getAppPrimaryColor(fallback = DEFAULT_PRIMARY_COLOR): string {
|
||||
return (
|
||||
normalizeHex(getConfig('color')) ||
|
||||
normalizeHex(getConfig('primary_color')) ||
|
||||
normalizeHex(getConfig('primary')) ||
|
||||
fallback
|
||||
)
|
||||
}
|
||||
|
||||
export function getAppSecondaryColor(fallback = DEFAULT_SECONDARY_COLOR): string {
|
||||
return (
|
||||
normalizeHex(getConfig('secondary_color')) ||
|
||||
normalizeHex(getConfig('secondary')) ||
|
||||
getAppPrimaryColor(fallback)
|
||||
)
|
||||
}
|
||||
|
||||
export function getAppTertiaryColor(fallback = DEFAULT_TERTIARY_COLOR): string {
|
||||
return (
|
||||
normalizeHex(getConfig('tertiary_color')) ||
|
||||
normalizeHex(getConfig('tertiary')) ||
|
||||
fallback
|
||||
)
|
||||
}
|
||||
|
||||
export function getAppBackgroundColor(fallback = DEFAULT_BACKGROUND_COLOR): string {
|
||||
return (
|
||||
normalizeHex(getConfig('background_color')) ||
|
||||
normalizeHex(getConfig('background')) ||
|
||||
fallback
|
||||
)
|
||||
}
|
||||
|
||||
export function getAppPrimaryDark(fallback = '#711d4d'): string {
|
||||
return darkenHex(getAppPrimaryColor(), 0.22) || fallback
|
||||
}
|
||||
|
||||
export function getAppPrimaryLight(fallback = '#c45f9a'): string {
|
||||
return lightenHex(getAppPrimaryColor(), 0.22) || fallback
|
||||
}
|
||||
|
||||
function setCssVar(name: string, value: string) {
|
||||
document.documentElement.style.setProperty(name, value)
|
||||
}
|
||||
|
||||
export function applyBrandTheme() {
|
||||
const primary = getAppPrimaryColor()
|
||||
const secondary = getAppSecondaryColor()
|
||||
const tertiary = getAppTertiaryColor()
|
||||
const background = getAppBackgroundColor()
|
||||
const primaryDark = getAppPrimaryDark()
|
||||
const primaryLight = getAppPrimaryLight()
|
||||
|
||||
setCssVar('--app-primary-color', primary)
|
||||
setCssVar('--app-secondary-color', secondary)
|
||||
setCssVar('--app-tertiary-color', tertiary)
|
||||
setCssVar('--app-background-color', background)
|
||||
setCssVar('--app-primary-dark', primaryDark)
|
||||
setCssVar('--app-primary-light', primaryLight)
|
||||
|
||||
colors.primary = primary
|
||||
colors['primary-rgba'] = primary
|
||||
colors.secondary = secondary
|
||||
colors['secondary-rgba'] = secondary
|
||||
colors.tertiary = tertiary
|
||||
colors['tertiary-rgba'] = tertiary
|
||||
|
||||
const themeMeta = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]')
|
||||
if (themeMeta) {
|
||||
themeMeta.content = primary
|
||||
} else {
|
||||
const meta = document.createElement('meta')
|
||||
meta.name = 'theme-color'
|
||||
meta.content = primary
|
||||
document.head.appendChild(meta)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { getConfig } from '@/config/app-config'
|
||||
|
||||
export type ProjectProfileId = 'ghatre' | 'kashkool' | 'boursecu' | 'default'
|
||||
|
||||
export interface ProjectFeatures {
|
||||
id: ProjectProfileId
|
||||
hasHomePage: boolean
|
||||
hasAbshodeTrading: boolean
|
||||
hasProductShop: boolean
|
||||
landingRoute: 'home' | 'buyProduct'
|
||||
}
|
||||
|
||||
const PROFILE_FEATURES: Record<ProjectProfileId, ProjectFeatures> = {
|
||||
ghatre: {
|
||||
id: 'ghatre',
|
||||
hasHomePage: false,
|
||||
hasAbshodeTrading: false,
|
||||
hasProductShop: true,
|
||||
landingRoute: 'buyProduct',
|
||||
},
|
||||
kashkool: {
|
||||
id: 'kashkool',
|
||||
hasHomePage: true,
|
||||
hasAbshodeTrading: true,
|
||||
hasProductShop: true,
|
||||
landingRoute: 'home',
|
||||
},
|
||||
boursecu: {
|
||||
id: 'boursecu',
|
||||
hasHomePage: true,
|
||||
hasAbshodeTrading: true,
|
||||
hasProductShop: true,
|
||||
landingRoute: 'home',
|
||||
},
|
||||
default: {
|
||||
id: 'default',
|
||||
hasHomePage: true,
|
||||
hasAbshodeTrading: true,
|
||||
hasProductShop: true,
|
||||
landingRoute: 'home',
|
||||
},
|
||||
}
|
||||
|
||||
function normalizeSlug(value: unknown): string {
|
||||
return String(value ?? '').toLowerCase().trim()
|
||||
}
|
||||
|
||||
function matchesAny(haystack: string, needles: string[]): boolean {
|
||||
return needles.some((needle) => haystack.includes(needle))
|
||||
}
|
||||
|
||||
export function resolveProjectProfileId(): ProjectProfileId {
|
||||
const name = normalizeSlug(getConfig('name'))
|
||||
const nameFa = String(getConfig('name_fa') ?? '')
|
||||
const mode = normalizeSlug(getConfig('mode'))
|
||||
|
||||
if (
|
||||
matchesAny(name, ['ghatre', 'ghatreh', 'qatre']) ||
|
||||
nameFa.includes('قطره')
|
||||
) {
|
||||
return 'ghatre'
|
||||
}
|
||||
|
||||
if (
|
||||
matchesAny(name, ['boursecu', 'bourse', 'bours']) ||
|
||||
nameFa.includes('بورس')
|
||||
) {
|
||||
return 'boursecu'
|
||||
}
|
||||
|
||||
if (
|
||||
matchesAny(name, ['kashkool', 'kashkol', 'kashkoolgold']) ||
|
||||
nameFa.includes('کشکول')
|
||||
) {
|
||||
return 'kashkool'
|
||||
}
|
||||
|
||||
if (matchesAny(mode, ['ghatre', 'ghatreh', 'qatre'])) return 'ghatre'
|
||||
if (matchesAny(mode, ['boursecu', 'bourse'])) return 'boursecu'
|
||||
if (matchesAny(mode, ['kashkool', 'kashkol'])) return 'kashkool'
|
||||
|
||||
return 'default'
|
||||
}
|
||||
|
||||
export function getProjectProfile(): ProjectFeatures {
|
||||
return PROFILE_FEATURES[resolveProjectProfileId()]
|
||||
}
|
||||
|
||||
export function getProjectProfileId(): ProjectProfileId {
|
||||
return resolveProjectProfileId()
|
||||
}
|
||||
|
||||
export function getProjectDisplayName(fallback = 'اپ مشتری'): string {
|
||||
return getConfig('name_fa') || getConfig('name') || fallback
|
||||
}
|
||||
|
||||
export function getDefaultLandingRoute(): 'home' | 'buyProduct' {
|
||||
return getProjectProfile().landingRoute
|
||||
}
|
||||
|
||||
export function hasHomePage(): boolean {
|
||||
return getProjectProfile().hasHomePage
|
||||
}
|
||||
|
||||
export function hasAbshodeTrading(): boolean {
|
||||
return getProjectProfile().hasAbshodeTrading
|
||||
}
|
||||
|
||||
export function hasProductShop(): boolean {
|
||||
return getProjectProfile().hasProductShop
|
||||
}
|
||||
|
||||
export function isGhatreProject(): boolean {
|
||||
return resolveProjectProfileId() === 'ghatre'
|
||||
}
|
||||
|
||||
export function isKashkoolProject(): boolean {
|
||||
return resolveProjectProfileId() === 'kashkool'
|
||||
}
|
||||
|
||||
export function isBoursecuProject(): boolean {
|
||||
return resolveProjectProfileId() === 'boursecu'
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { AppNavItem } from '../types'
|
||||
import {
|
||||
hasAbshodeTrading,
|
||||
hasHomePage,
|
||||
hasProductShop,
|
||||
isKashkoolProject,
|
||||
} from '@/config/project-profile'
|
||||
|
||||
/** تبهای پایین موبایل — کاربر لاگینشده */
|
||||
/** تبهای پایین موبایل — کاربر لاگینشده (کشکول و مشابه) */
|
||||
export const AUTH_PRIMARY_NAV: AppNavItem[] = [
|
||||
{ id: 'home', routeName: 'home', label: 'صفحه اصلی', icon: 'vuesax-linear:home' },
|
||||
{ id: 'transactions', routeName: 'transactions', label: 'گزارش', icon: 'vuesax-linear:receipt-item' },
|
||||
@@ -8,6 +14,14 @@ export const AUTH_PRIMARY_NAV: AppNavItem[] = [
|
||||
{ id: 'cart', routeName: 'cart', label: 'سبد خرید', icon: 'vuesax-linear:shopping-cart' },
|
||||
]
|
||||
|
||||
/** تبهای پایین موبایل — قطره (بدون صفحه اصلی) */
|
||||
export const GHATRE_AUTH_PRIMARY_NAV: AppNavItem[] = [
|
||||
{ id: 'buyProduct', routeName: 'buyProduct', label: 'فروشگاه', icon: 'vuesax-linear:coin' },
|
||||
{ id: 'transactions', routeName: 'transactions', label: 'گزارش', icon: 'vuesax-linear:receipt-item' },
|
||||
{ id: 'wallet', routeName: 'wallet', label: 'کیف پول', icon: 'vuesax-linear:wallet-1' },
|
||||
{ id: 'cart', routeName: 'cart', label: 'سبد خرید', icon: 'vuesax-linear:shopping-cart' },
|
||||
]
|
||||
|
||||
/** تبهای پایین موبایل — مهمان */
|
||||
export const GUEST_PRIMARY_NAV: AppNavItem[] = [
|
||||
{ id: 'buyProduct', routeName: 'buyProduct', label: 'فروشگاه', icon: 'vuesax-linear:coin' },
|
||||
@@ -30,10 +44,55 @@ export const AUTH_SECONDARY_NAV: AppNavItem[] = [
|
||||
{ id: 'rules', routeName: 'rules', label: 'قوانین و مقررات', icon: 'vuesax-linear:task' },
|
||||
]
|
||||
|
||||
/** منوی تمامصفحه کشکول — فقط این آیتمها */
|
||||
export const KASHKOOL_OVERFLOW_NAV: AppNavItem[] = [
|
||||
{ id: 'user', routeName: 'user', label: 'حساب کاربری', icon: 'vuesax-linear:user' },
|
||||
{ id: 'physicalReceive', routeName: 'physicalReceive', label: 'دریافت طلای فیزیکی', icon: 'vuesax-linear:direct-inbox' },
|
||||
{ id: 'notifyTrigger', routeName: 'notifyTrigger', label: 'هشدار قیمت', icon: 'vuesax-linear:bill' },
|
||||
{ id: 'buyProduct', routeName: 'buyProduct', label: 'خرید محصول', icon: 'vuesax-linear:coin' },
|
||||
{ id: 'giftCard', routeName: 'giftCard', label: 'ثبت کارت هدیه', icon: 'vuesax-linear:gift' },
|
||||
{ id: 'rules', routeName: 'rules', label: 'قوانین و مقررات', icon: 'vuesax-linear:task' },
|
||||
]
|
||||
|
||||
function filterSecondaryNavItems(items: AppNavItem[]): AppNavItem[] {
|
||||
return items.filter((item) => {
|
||||
if (item.routeName === 'buyProduct' && !hasProductShop()) return false
|
||||
if (item.routeName === 'notifyTrigger' && !hasAbshodeTrading()) return false
|
||||
if (item.routeName === 'earnMoney' && !hasAbshodeTrading()) return false
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
export function getPrimaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
||||
return isAuthenticated ? AUTH_PRIMARY_NAV : GUEST_PRIMARY_NAV
|
||||
if (!isAuthenticated) {
|
||||
return GUEST_PRIMARY_NAV.filter(
|
||||
(item) => item.routeName !== 'buyProduct' || hasProductShop()
|
||||
)
|
||||
}
|
||||
|
||||
if (!hasHomePage()) {
|
||||
return GHATRE_AUTH_PRIMARY_NAV
|
||||
}
|
||||
|
||||
return AUTH_PRIMARY_NAV
|
||||
}
|
||||
|
||||
export function getSecondaryNavItems(isAuthenticated: boolean): AppNavItem[] {
|
||||
return isAuthenticated ? AUTH_SECONDARY_NAV : []
|
||||
if (!isAuthenticated) return []
|
||||
if (isKashkoolProject()) return KASHKOOL_OVERFLOW_NAV
|
||||
return filterSecondaryNavItems(AUTH_SECONDARY_NAV)
|
||||
}
|
||||
|
||||
export function getOverflowMenuItems(isAuthenticated: boolean): AppNavItem[] {
|
||||
if (!isAuthenticated) {
|
||||
return AUTH_SECONDARY_NAV.filter((item) =>
|
||||
['about', 'rules'].includes(item.routeName)
|
||||
)
|
||||
}
|
||||
|
||||
if (isKashkoolProject()) {
|
||||
return KASHKOOL_OVERFLOW_NAV
|
||||
}
|
||||
|
||||
return filterSecondaryNavItems(AUTH_SECONDARY_NAV)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ defineEmits<{
|
||||
height: 18px;
|
||||
padding: 0 4px;
|
||||
border-radius: 999px;
|
||||
background: #a72b77;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<aside class="desktop-sidebar">
|
||||
<div class="desktop-sidebar__brand">
|
||||
<img :src="navLogo" alt="کشکول گلد" class="desktop-sidebar__logo" />
|
||||
<img :src="navLogo" :alt="projectName" class="desktop-sidebar__logo" />
|
||||
</div>
|
||||
|
||||
<nav class="desktop-sidebar__section" aria-label="منوی اصلی">
|
||||
@@ -39,16 +39,18 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import logoFull from '@/assets/img/logo_full_.png'
|
||||
import { isToken } from '@/utils'
|
||||
import { useCartStore } from '@/store/cartStore'
|
||||
import { getPrimaryNavItems, getSecondaryNavItems } from '../config/navigation'
|
||||
import { useAppNavigation } from '../composables/useAppNavigation'
|
||||
import { getProjectDisplayName } from '@/config/project-profile'
|
||||
import { getAppLogoFullUrl } from '@/config/brand-assets'
|
||||
import DesktopNavItem from './DesktopNavItem.vue'
|
||||
|
||||
const cartStore = useCartStore()
|
||||
const authenticated = computed(() => isToken())
|
||||
const navLogo = logoFull
|
||||
const navLogo = getAppLogoFullUrl()
|
||||
const projectName = getProjectDisplayName('کشکول گلد')
|
||||
const primaryItems = computed(() => getPrimaryNavItems(authenticated.value))
|
||||
const secondaryItems = computed(() => getSecondaryNavItems(authenticated.value))
|
||||
const cartCount = computed(() => cartStore.itemCount || 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.desktop-app-layout {
|
||||
.desktop-app-layout {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100vh;
|
||||
@@ -110,15 +110,15 @@
|
||||
|
||||
&:hover {
|
||||
background: rgba(167, 43, 119, 0.06);
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: rgba(167, 43, 119, 0.1);
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
|
||||
.desktop-nav-item__icon {
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Shared desktop layouts for inner pages */
|
||||
/* Shared desktop layouts for inner pages */
|
||||
|
||||
.dinner {
|
||||
min-height: 100%;
|
||||
@@ -85,7 +85,7 @@
|
||||
&__price {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
&__total {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
.dproduct-info__price {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
.dproduct-info__desc {
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
<div class="main_in">
|
||||
<div class="text-white circle_in">
|
||||
<div class="circle_into" @click="$emit('toggle-overflow')">
|
||||
<img class="p-2" :src="navLogo" alt="" />
|
||||
<img
|
||||
class="p-2"
|
||||
:class="{ 'nav-logo--white': isKashkool }"
|
||||
:src="navLogo"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,8 +50,9 @@ import { computed } from 'vue'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { isToken } from '@/utils'
|
||||
import { useCartStore } from '@/store/cartStore'
|
||||
import { getAppIconUrl } from '@/config/brand-assets'
|
||||
import { isKashkoolProject } from '@/config/project-profile'
|
||||
import { getPrimaryNavItems } from '../config/navigation'
|
||||
import logo from '@/assets/img/logo.png'
|
||||
|
||||
defineProps<{
|
||||
navItemClass: (routeName: string) => string
|
||||
@@ -58,7 +64,8 @@ defineEmits<{
|
||||
}>()
|
||||
|
||||
const cartStore = useCartStore()
|
||||
const navLogo = logo
|
||||
const navLogo = getAppIconUrl()
|
||||
const isKashkool = isKashkoolProject()
|
||||
const cartCount = computed(() => cartStore.itemCount || 0)
|
||||
|
||||
const primaryItems = computed(() => getPrimaryNavItems(isToken()))
|
||||
@@ -80,4 +87,8 @@ const rightTabs = computed(() => primaryItems.value.slice(2))
|
||||
.tab__icon :deep(.ant-badge) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.nav-logo--white {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,85 +17,15 @@
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<BasicButton
|
||||
v-for="item in menuItems"
|
||||
:key="item.id"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('user')"
|
||||
@click="go(item.routeName)"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:user" size="16" class="absolute right-2" />
|
||||
<div>حساب کاربری</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="authenticated"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('physicalReceive')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:direct-inbox" size="16" class="absolute right-2" />
|
||||
<div>دریافت طلای فیزیکی</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="authenticated"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('notifyTrigger')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:bill" size="16" class="absolute right-2" />
|
||||
<div>هشدار قیمت</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="authenticated"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('buyProduct')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:coin" size="16" class="absolute right-2" />
|
||||
<div>خرید محصول</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<!-- <BasicButton-->
|
||||
<!-- v-if="authenticated"-->
|
||||
<!-- icon-size="16"-->
|
||||
<!-- class="!font-bold w-15rem"-->
|
||||
<!-- @click="go('list')"-->
|
||||
<!-- >-->
|
||||
<!-- <div class="flex gap-2 items-center">-->
|
||||
<!-- <BasicIcon icon="vuesax-linear:receipt-item" size="16" class="absolute right-2" />-->
|
||||
<!-- <div>لیست دریافتی ها</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </BasicButton>-->
|
||||
<BasicButton
|
||||
v-if="authenticated"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('giftCard')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:gift" size="16" class="absolute right-2" />
|
||||
<div>ثبت کارت هدیه</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton icon-size="16" class="!font-bold w-15rem" @click="go('about')">
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:info-circle" size="16" class="absolute right-2" />
|
||||
<div>درباره ما</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="authenticated"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('rules')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:task" size="16" class="absolute right-2" />
|
||||
<div>قوانین و مقررات</div>
|
||||
<BasicIcon :icon="item.icon" size="16" class="absolute right-2" />
|
||||
<div>{{ item.label }}</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
@@ -109,6 +39,7 @@ import { computed } from 'vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { isToken } from '@/utils'
|
||||
import { getOverflowMenuItems } from '../config/navigation'
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
@@ -119,7 +50,7 @@ const emit = defineEmits<{
|
||||
navigate: [routeName: string]
|
||||
}>()
|
||||
|
||||
const authenticated = computed(() => isToken())
|
||||
const menuItems = computed(() => getOverflowMenuItems(isToken()))
|
||||
|
||||
function go(routeName: string) {
|
||||
emit('navigate', routeName)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.bottom-appbar {
|
||||
.bottom-appbar {
|
||||
z-index: var(--app-z-nav, 5000);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
&.text-primary .tab__icon,
|
||||
&.text-primary .tab__icon .ant-badge {
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
&.text-gray-400 .tab__icon,
|
||||
@@ -68,11 +68,11 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #a72b77;
|
||||
background-color: var(--app-primary-color, #a72b77);
|
||||
|
||||
.circle_into {
|
||||
overflow: hidden;
|
||||
background-color: @primary-color;
|
||||
background-color: var(--app-primary-color, #a72b77);
|
||||
border-radius: 50%;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Shared mobile page chrome (inner pages — not home .app-header) */
|
||||
/* Shared mobile page chrome (inner pages — not home .app-header) */
|
||||
|
||||
:root {
|
||||
--mpage-header-bar: 2.75rem;
|
||||
@@ -31,7 +31,7 @@
|
||||
padding: 0.75rem;
|
||||
padding-top: calc(0.75rem + var(--app-safe-top, env(safe-area-inset-top, 0px)));
|
||||
background: #fff;
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
@@ -67,7 +67,7 @@
|
||||
z-index: 1999;
|
||||
padding: 0.75rem;
|
||||
background: #fff;
|
||||
color: @primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import {createRouter, createWebHistory} from 'vue-router'
|
||||
import { getDefaultLandingRoute } from '@/config/project-profile'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
@@ -17,7 +18,7 @@ const router = createRouter({
|
||||
{
|
||||
path: `/`,
|
||||
name: 'main',
|
||||
redirect: {name: 'buyProduct'},
|
||||
redirect: () => ({ name: getDefaultLandingRoute() }),
|
||||
component: () => import('../views/base/index.vue'),
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -6,3 +6,31 @@ export function getConfigApp(key: string) {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export {
|
||||
getProjectDisplayName,
|
||||
getDefaultLandingRoute,
|
||||
hasHomePage,
|
||||
hasAbshodeTrading,
|
||||
hasProductShop,
|
||||
isGhatreProject,
|
||||
isKashkoolProject,
|
||||
isBoursecuProject,
|
||||
getProjectProfile,
|
||||
getProjectProfileId,
|
||||
} from '@/config/project-profile'
|
||||
|
||||
export {
|
||||
getAppIconUrl,
|
||||
getAppLogoUrl,
|
||||
getAppLogoFullUrl,
|
||||
resolveConfigAssetUrl,
|
||||
} from '@/config/brand-assets'
|
||||
|
||||
export {
|
||||
getAppPrimaryColor,
|
||||
getAppSecondaryColor,
|
||||
getAppTertiaryColor,
|
||||
getAppBackgroundColor,
|
||||
applyBrandTheme,
|
||||
} from '@/config/brand-theme'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop about page */
|
||||
/* Premium desktop about page */
|
||||
|
||||
.dabout {
|
||||
min-height: 100%;
|
||||
@@ -95,7 +95,7 @@
|
||||
height: 56px;
|
||||
border-radius: 14px;
|
||||
background: rgba(9, 61, 81, 0.08);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
border: 1px solid rgba(9, 61, 81, 0.15);
|
||||
border-radius: 12px;
|
||||
background: rgba(9, 61, 81, 0.03);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
&__divider {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="dinner cart-page">
|
||||
<div class="dinner__container">
|
||||
<DesktopPageTopbar title="سبد خرید" show-back>
|
||||
@@ -174,7 +174,7 @@ const {
|
||||
.dcart-summary__discount-link {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
font-size: 13px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="dinner earn-money-page">
|
||||
<div class="dinner__container">
|
||||
<DesktopPageTopbar title="کسب درآمد" show-back />
|
||||
@@ -94,7 +94,7 @@ const { data, userStore, isTransaction, setIsTransaction, copyCode, shareCode }
|
||||
|
||||
&--active {
|
||||
background: #fff;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-white w-full py-3 px-3 text-primary font-bold drop-shadow flex">
|
||||
<div @click="router.back()">
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="mr-2">کسب درآمد</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="p-3 border-solid border-1 rounded-[8px] border-[#a72b77]">
|
||||
<div class="p-3 border-solid border-1 rounded-[8px] border-primary">
|
||||
<div class="flex items-center">
|
||||
<div class="bg-[#DBEAFE] h-10 w-10 rounded-100% flex justify-center items-center">
|
||||
<img :src="coin" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop fund page */
|
||||
/* Premium desktop fund page */
|
||||
|
||||
.dfund {
|
||||
min-height: 100%;
|
||||
@@ -73,7 +73,7 @@
|
||||
overflow: hidden;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 24px;
|
||||
background: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
|
||||
&--bazretala {
|
||||
@@ -339,7 +339,7 @@
|
||||
.dfund-info__balance-value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
.dfund-info__balance-unit {
|
||||
@@ -495,8 +495,8 @@
|
||||
cursor: pointer;
|
||||
|
||||
&--active {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop gift card page */
|
||||
/* Premium desktop gift card page */
|
||||
|
||||
.dgift {
|
||||
min-height: 100%;
|
||||
@@ -47,7 +47,7 @@
|
||||
height: 56px;
|
||||
border-radius: 14px;
|
||||
background: rgba(167, 43, 119, 0.08);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
}
|
||||
|
||||
.basic-icon {
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="h-35rem overflow-y-auto px-5">
|
||||
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
|
||||
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
|
||||
@@ -51,14 +51,14 @@
|
||||
<bg_main/>
|
||||
<div class="z-100 relative">
|
||||
<a-form-item>
|
||||
<BasicInput v-model:value="form.goldCash" addon-before="ریال" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldCash" addon-before="ریال" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="ارزش کل"
|
||||
size="large"
|
||||
type="price" @onchange="calculateGold" />
|
||||
</a-form-item>
|
||||
<a-form-item :rules="[justNumber()]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="گرم" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="گرم" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="مقدار طلا"
|
||||
size="large" type="text" inputmode="decimal" @onchange="calculateCash" />
|
||||
@@ -647,7 +647,7 @@ async function ok() {
|
||||
|
||||
<style lang="less">
|
||||
.completeButtonStyle .van-dialog__confirm .van-button__content {
|
||||
background-color: #a72b77;
|
||||
background-color: var(--app-primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<template>
|
||||
<div v-if="props.ProductItem.wallet" class="bg-gradient-to-l from-primary rounded-lg p-px to-transparent ">
|
||||
<div class="flex flex-col gap-7 rounded-lg p-4 w-56 bg-white ">
|
||||
<div class="flex justify-between items-center font-medium text-sm">
|
||||
<div class="text-primary">موجودی {{ props.ProductItem.title }}</div>
|
||||
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:grammerly"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:coin"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:keyboard"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='آبشده'" stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else stroke-width="1" size="50" color="#a72b77" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:grammerly"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:coin"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:keyboard"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='آبشده'" stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else stroke-width="1" size="50" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
</div>
|
||||
<div class="flex justify-between px-2 items-center ">
|
||||
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="26" color="#a72b77" class="rotate-310" icon="vuesax-linear:grammerly"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="26" color="#a72b77" class="rotate-310" icon="vuesax-linear:coin"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="26" color="#a72b77" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="26" color="#a72b77" class="rotate-310" icon="vuesax-linear:keyboard"/>
|
||||
<BasicIcon v-else stroke-width="1" size="26" color="#a72b77" class="rotate-310" icon="vuesax-linear:slider-vertical"/> <div class="flex justify-between gap-2 items-center">
|
||||
<BasicIcon v-if="props.ProductItem.group_type=='گوی'" stroke-width="1" size="26" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:grammerly"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='سکه'" stroke-width="1" size="26" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:coin"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='شمش'" stroke-width="1" size="26" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:slider-vertical"/>
|
||||
<BasicIcon v-else-if="props.ProductItem.group_type=='مکعب'" stroke-width="1" size="26" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:keyboard"/>
|
||||
<BasicIcon v-else stroke-width="1" size="26" color="var(--app-primary-color)" class="rotate-310" icon="vuesax-linear:slider-vertical"/> <div class="flex justify-between gap-2 items-center">
|
||||
<span v-if="props.ProductItem.group_type=='آبشده'" class="font-bold text-secondary">{{userWallet.walletInfo?.gold??0}}</span>
|
||||
<span v-else class="font-bold text-secondary">{{props?.ProductItem.wallet?.gold??0}}</span>
|
||||
<span class="text-gray-400">{{props?.ProductItem?.unit}}</span>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<template v-else-if="userStore.userInfo">
|
||||
<section class="dhome-hero-row">
|
||||
<div class="dhome-surface dhome-hero-price">
|
||||
<span class="dhome-label">قیمت خرید از کشکول گلد</span>
|
||||
<span class="dhome-label">قیمت خرید از {{ projectName }}</span>
|
||||
<div class="dhome-hero-price__value-row">
|
||||
<span
|
||||
v-if="percentPriceChanged() !== 0"
|
||||
@@ -174,11 +174,15 @@ import DesktopHomeTopbar from '@/views/base/home/components/DesktopHomeTopbar.vu
|
||||
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
||||
import bannerImg from '@/assets/img/banner/2.png'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { getProjectDisplayName, hasAbshodeTrading } from '@/config/project-profile'
|
||||
import { getAppPrimaryColor } from '@/config/brand-theme'
|
||||
|
||||
const emit = defineEmits<{ logout: []; openBalance: [] }>()
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||
const projectName = getProjectDisplayName('کشکول گلد')
|
||||
const primaryColor = getAppPrimaryColor()
|
||||
|
||||
const goldVal = ref<number | undefined>()
|
||||
const selection = ref<'DAILY' | 'WEEKLY' | 'MONTHLY'>('DAILY')
|
||||
@@ -189,7 +193,7 @@ const priceChartOptions = ref({
|
||||
dataLabels: { enabled: false },
|
||||
yaxis: { show: false },
|
||||
xaxis: { type: 'datetime', labels: { show: false }, axisBorder: { show: false } },
|
||||
colors: ['#a72b77'],
|
||||
colors: [primaryColor],
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: { shadeIntensity: 1, opacityFrom: 0.7, opacityTo: 0.9, stops: [0, 100] },
|
||||
@@ -220,13 +224,30 @@ const totalRialDisplay = computed(() =>
|
||||
resolveAssetsRialValue(assetsSummary.value, getTradeBuyPrice(price.value) || Number(goldVal.value ?? 0))
|
||||
)
|
||||
|
||||
const mainActions = [
|
||||
{ name: 'buySell', icon: 'vuesax-linear:money-receive', label: 'خرید و فروش', handler: () => router.push({ name: 'gold' }) },
|
||||
{ name: 'deposit', icon: 'vuesax-linear:card-add', label: 'واریز نقدی', handler: () => router.push({ name: 'wallet', query: { state: 'deposit' } }) },
|
||||
{ name: 'balance', icon: 'vuesax-linear:receipt-item', label: 'موجودی', handler: () => emitBalance() },
|
||||
{ name: 'fund', icon: 'vuesax-linear:archive-1', label: 'دارایی ها', handler: () => router.push({ name: 'fund' }) },
|
||||
{ name: 'earn', icon: 'vuesax-linear:dollar-circle', label: 'کسب درآمد', handler: () => router.push({ name: 'earnMoney' }) },
|
||||
]
|
||||
const mainActions = computed(() => {
|
||||
const actions = [
|
||||
{ name: 'deposit', icon: 'vuesax-linear:card-add', label: 'واریز نقدی', handler: () => router.push({ name: 'wallet', query: { state: 'deposit' } }) },
|
||||
{ name: 'balance', icon: 'vuesax-linear:receipt-item', label: 'موجودی', handler: () => emitBalance() },
|
||||
{ name: 'fund', icon: 'vuesax-linear:archive-1', label: 'دارایی ها', handler: () => router.push({ name: 'fund' }) },
|
||||
]
|
||||
|
||||
if (hasAbshodeTrading()) {
|
||||
actions.unshift({
|
||||
name: 'buySell',
|
||||
icon: 'vuesax-linear:money-receive',
|
||||
label: 'خرید و فروش',
|
||||
handler: () => router.push({ name: 'gold' }),
|
||||
})
|
||||
actions.push({
|
||||
name: 'earn',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
label: 'کسب درآمد',
|
||||
handler: () => router.push({ name: 'earnMoney' }),
|
||||
})
|
||||
}
|
||||
|
||||
return actions
|
||||
})
|
||||
|
||||
function emitBalance() {
|
||||
emit('openBalance')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop home — SaaS dashboard design tokens */
|
||||
/* Premium desktop home — SaaS dashboard design tokens */
|
||||
|
||||
.dhome {
|
||||
min-height: 100%;
|
||||
@@ -420,7 +420,7 @@
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
background: #f3f4f6;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
transition: background 0.15s ease;
|
||||
overflow: visible;
|
||||
@@ -498,7 +498,7 @@
|
||||
height: 40px;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
|
||||
&--active {
|
||||
background: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<div
|
||||
class="px-5 py-5 shadow-lg rounded-2xl text-white relative overflow-hidden shadow-lg"
|
||||
style=" background: linear-gradient(145deg, #a72b77 0%, #711d4d 40%, #a72b77 100%); "
|
||||
:style="{ background: `linear-gradient(145deg, ${primaryColor} 0%, ${primaryDark} 40%, ${primaryColor} 100%)` }"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-0 opacity-20"
|
||||
@@ -32,14 +32,19 @@
|
||||
|
||||
<div class="relative z-10">
|
||||
<div class="flex font-bold text-lg items-center gap-2 mb-3">
|
||||
<img src='@/assets/img/logo.png' alt='' class='h-8 drop-shadow-md' />
|
||||
<div class="tracking-wide">کشکول گلد </div>
|
||||
<img
|
||||
:src="appIconUrl"
|
||||
alt=""
|
||||
class="h-8 drop-shadow-md"
|
||||
:class="{ 'home-brand-logo--white': isKashkool }"
|
||||
/>
|
||||
<div class="tracking-wide">{{ projectName }}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-end mb-3">
|
||||
<div class="text-sm" />
|
||||
<div>
|
||||
<div class="text-xs opacity-75" style="justify-self: end;">شناسه شما در کشکول گلد</div>
|
||||
<div class="text-xs opacity-75" style="justify-self: end;">شناسه شما در {{ projectName }}</div>
|
||||
<div class="flex">
|
||||
<div v-if="userStore?.userInfo?.virtual_card_number" class="ml-2 " @click.stop="copyCode()">
|
||||
<BasicIcon
|
||||
@@ -84,7 +89,7 @@
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[42px] h-[42px] bg-primary flex items-center justify-center"
|
||||
style="border: solid 1px #a72b77"
|
||||
style="border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
|
||||
>
|
||||
<Icon class="text-tertiary" icon="vuesax-linear:money-send" />
|
||||
@@ -92,13 +97,14 @@
|
||||
<div class="text-primary">فروش</div>
|
||||
</div>-->
|
||||
<div
|
||||
v-if="showAbshodeTrading"
|
||||
class="text-center w-full flex-flex-col items-center home_appear_fade_in_up"
|
||||
style="text-align: -webkit-center"
|
||||
@click="router.push({ name: 'gold' })"
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||
style="border: solid 1px #a72b77"
|
||||
style="border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
|
||||
>
|
||||
<Icon class="text-white" icon="vuesax-linear:money-receive" />
|
||||
@@ -112,7 +118,7 @@
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||
style="border: solid 1px #a72b77"
|
||||
style="border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
|
||||
>
|
||||
<Icon class="text-white" icon="vuesax-linear:card-add" />
|
||||
@@ -126,7 +132,7 @@
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center "
|
||||
style="border: solid 1px #a72b77"
|
||||
style="border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
>
|
||||
<Icon class="text-white" icon="vuesax-linear:receipt-item" />
|
||||
</div>
|
||||
@@ -139,20 +145,21 @@
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||
style=" border: solid 1px #a72b77"
|
||||
style=" border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
>
|
||||
<Icon class="text-white font-bold" icon="vuesax-linear:archive-1" />
|
||||
</div>
|
||||
<div class="text-primary">دارایی ها</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showAbshodeTrading"
|
||||
class="text-center w-full flex-flex-col items-center home_appear_fade_in_down"
|
||||
style="text-align: -webkit-center"
|
||||
@click="router.push({ name: 'earnMoney' })"
|
||||
>
|
||||
<div
|
||||
class="rounded-full w-[50px] h-[50px] bg-primary flex items-center justify-center"
|
||||
style=" border: solid 1px #a72b77"
|
||||
style=" border: solid 1px var(--app-primary-color, #a72b77)"
|
||||
|
||||
>
|
||||
<Icon class="text-white font-bold" icon="vuesax-linear:dollar-circle" />
|
||||
@@ -254,7 +261,7 @@
|
||||
>
|
||||
|
||||
<div class="w-full items-center flex flex-col">
|
||||
<div class="text-gray-600">قیمت خرید از کشکول گلد</div>
|
||||
<div class="text-gray-600">قیمت خرید از {{ projectName }}</div>
|
||||
<div v-if="price" class="flex gap-1 mt-3 text-xs items-center">
|
||||
<!-- <div id="odometer" class="font-bold text-2xl odometer animated fadeIn">
|
||||
<!– {{ usePriceWithoutType(useCounterAnim(price.price_last) ?? 0) }}–>
|
||||
@@ -498,6 +505,9 @@ import type { PInventory, Product } from '@/models/products'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import { resolveAssetsRialValue } from '@/utils/productAssets'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { getProjectDisplayName, hasAbshodeTrading, isKashkoolProject } from '@/config/project-profile'
|
||||
import { getAppIconUrl } from '@/config/brand-assets'
|
||||
import { getAppPrimaryColor, getAppPrimaryDark } from '@/config/brand-theme'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
@@ -507,6 +517,12 @@ import AppHeader from '@/views/base/home/components/AppHeader.vue'
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const projectName = getProjectDisplayName('کشکول گلد')
|
||||
const showAbshodeTrading = hasAbshodeTrading()
|
||||
const isKashkool = isKashkoolProject()
|
||||
const appIconUrl = getAppIconUrl()
|
||||
const primaryColor = getAppPrimaryColor()
|
||||
const primaryDark = getAppPrimaryDark()
|
||||
const chartLoading = ref<boolean>(false)
|
||||
const openModal = ref<boolean>(false)
|
||||
const wholeBalanceVisible = ref<boolean>(false)
|
||||
@@ -717,7 +733,7 @@ const priceChartOptions = ref({
|
||||
show: false
|
||||
}
|
||||
},
|
||||
colors: ['#a72b77'],
|
||||
colors: [primaryColor],
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
@@ -978,4 +994,8 @@ apexchart {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.home-brand-logo--white {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="">
|
||||
<!-- <div class="bg-primary h-30 mt-[-3rem] z-100000000000"></div>-->
|
||||
<div class="fixed h-[60vh] bg-[#a72b77] w-screen">
|
||||
<div class="fixed h-[60vh] bg-primary w-screen">
|
||||
<div class="flex w-full justify-around mt-18">
|
||||
<div class="text-center">
|
||||
<div class="text-[#E5D7CE] text-xs ">موجودی کیف طلا</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="h-35rem overflow-y-auto">
|
||||
<!-- <div class="bg-primary h-30 mt-[-3rem] z-100000000000"></div>-->
|
||||
<div class="h-[60vh] bg-primary wrap-fix">
|
||||
@@ -620,7 +620,7 @@ const priceChartOptions = ref({
|
||||
show: false
|
||||
}
|
||||
},
|
||||
colors: ['#a72b77'],
|
||||
colors: ['var(--app-primary-color)'],
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex">
|
||||
<div class="bg-gray-100 m-2 rounded-lg w-18 h-18 flex justify-center p-1 shrink-0">
|
||||
@@ -25,7 +25,7 @@
|
||||
<BasicInput
|
||||
v-model:value="item.count"
|
||||
:addon-before="item.product.unit"
|
||||
addon-bg-color="#a72b77"
|
||||
addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="h-35rem overflow-y-auto">
|
||||
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
|
||||
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<a-form-item v-if="isBuy" name="goldValue"
|
||||
:rules="[justNumber2(props?.ProductItem?.price , form.method , props?.ProductItem?.amount, true)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
<a-form-item v-else name="goldValue"
|
||||
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum ,false)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
@@ -694,7 +694,7 @@ watch(form.value.goldValue, () => {
|
||||
background: blue;
|
||||
}*/
|
||||
.completeButtonStyle .van-dialog__confirm .van-button__content {
|
||||
background: #a72b77;
|
||||
background: var(--app-primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop price trigger page */
|
||||
/* Premium desktop price trigger page */
|
||||
|
||||
.dptr {
|
||||
min-height: 100%;
|
||||
@@ -87,8 +87,8 @@
|
||||
transition: border-color 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@
|
||||
margin-top: 4px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="h-35rem overflow-y-auto">
|
||||
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
|
||||
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
|
||||
@@ -61,14 +61,14 @@
|
||||
|
||||
<a-form-item v-if="isBuy" name="goldValue"
|
||||
:rules="[justNumber4(props?.ProductItem?.price , form.method , props?.ProductItem?.amount, true, form.gateway)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
</a-form-item>
|
||||
<a-form-item v-else name="goldValue"
|
||||
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum ,false)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
@@ -773,7 +773,7 @@ async function ok() {
|
||||
background: blue;
|
||||
}*/
|
||||
.completeButtonStyle .van-dialog__confirm .van-button__content {
|
||||
background: #a72b77;
|
||||
background: var(--app-primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="h-35rem overflow-y-auto">
|
||||
<div class=" !overflow-y-scroll bg-white py-3 text-primary font-bold flex justify-evenly">
|
||||
<!-- <div @click="isBuy = false" class="w-full text-center" :class="!isBuy?'text-primary':'text-gray-400'">خرید طلا</div>
|
||||
@@ -61,14 +61,14 @@
|
||||
|
||||
<a-form-item v-if="isBuy" name="goldValue"
|
||||
:rules="[justNumber2(props?.ProductItem?.price , form.method , props?.ProductItem?.amount, true, form.gateway)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
</a-form-item>
|
||||
<a-form-item v-else name="goldValue"
|
||||
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum ,false)]">
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#a72b77"
|
||||
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="تعداد"
|
||||
size="large" type="number" inputmode="number" @onchange="calculateCash" />
|
||||
@@ -749,7 +749,7 @@ async function ok() {
|
||||
background: blue;
|
||||
}*/
|
||||
.completeButtonStyle .van-dialog__confirm .van-button__content {
|
||||
background: #a72b77;
|
||||
background: var(--app-primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop rules page */
|
||||
/* Premium desktop rules page */
|
||||
|
||||
.drules {
|
||||
min-height: 100%;
|
||||
@@ -46,7 +46,7 @@
|
||||
height: 56px;
|
||||
border-radius: 14px;
|
||||
background: rgba(167, 43, 119, 0.08);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
border: 1px solid rgba(167, 43, 119, 0.15);
|
||||
border-radius: 12px;
|
||||
background: rgba(167, 43, 119, 0.03);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop transactions page */
|
||||
/* Premium desktop transactions page */
|
||||
|
||||
.dtxn {
|
||||
min-height: 100%;
|
||||
@@ -44,8 +44,8 @@
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop user account page */
|
||||
/* Premium desktop user account page */
|
||||
|
||||
.duser {
|
||||
min-height: 100%;
|
||||
@@ -93,7 +93,7 @@
|
||||
height: 64px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(135deg, #f0f4ff 0%, #e8eeff 100%);
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -174,8 +174,8 @@
|
||||
|
||||
&--primary {
|
||||
width: 100%;
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="dwallet">
|
||||
<div class="dwallet__container">
|
||||
<DesktopPageTopbar
|
||||
@@ -45,7 +45,7 @@
|
||||
<BasicInput
|
||||
v-model:value="form.value"
|
||||
addon-before="ریال"
|
||||
addon-bg-color="#a72b77"
|
||||
addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="مبلغ"
|
||||
size="large"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Premium desktop wallet page */
|
||||
/* Premium desktop wallet page */
|
||||
|
||||
.dwallet {
|
||||
min-height: 100%;
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
&--active {
|
||||
background: #fff;
|
||||
color: @App-primary-color;
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
}
|
||||
@@ -182,8 +182,8 @@
|
||||
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
@@ -255,13 +255,13 @@
|
||||
transition: border-color 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: @App-primary-color;
|
||||
color: @App-primary-color;
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: var(--app-primary-color, #a72b77);
|
||||
}
|
||||
|
||||
&--primary {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
background: var(--app-primary-color, #a72b77);
|
||||
border-color: var(--app-primary-color, #a72b77);
|
||||
color: #fff;
|
||||
padding: 10px 16px;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div>
|
||||
<div class="absolute inset-0 bg-cover bg-center opacity-60" :style="{ backgroundImage: `url(${img})` }"></div>
|
||||
<div class="mpage-header wrap-fix z-[1999]">کیف پول</div>
|
||||
@@ -38,7 +38,7 @@
|
||||
<BasicInput
|
||||
v-model:value="form.value"
|
||||
addon-before="ریال"
|
||||
addon-bg-color="#a72b77"
|
||||
addon-bg-color="var(--app-primary-color)"
|
||||
addon-text-color="white"
|
||||
place-holder="مبلغ"
|
||||
size="large"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="w-full flex flex-col">
|
||||
<img :src="logo" alt="" class="z-100 rounded-full aspect-square self-center w-42 " STYLE="margin-bottom: 60px">
|
||||
|
||||
@@ -151,9 +151,11 @@ import { loginCustomer, verifyToken } from '@/api/login'
|
||||
import router from '@/router'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import logo from '@/assets/img/logo_full_.png'
|
||||
import { getAppLogoFullUrl } from '@/config/brand-assets'
|
||||
import { fingerPosition, setTruth } from '@/main'
|
||||
|
||||
const logo = getAppLogoFullUrl()
|
||||
|
||||
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
|
||||
const enableSendAgainCode = ref<boolean>(false)
|
||||
|
||||
@@ -435,7 +437,7 @@ const getcode=()=>{
|
||||
</div>
|
||||
</BasicButton>
|
||||
<div class="flex gap-1 justify-center mt-5 text-xs" @click="$emit('register',true)">اگر حساب کاربری ندارید
|
||||
<div class="font-bold text-[#a72b77]">از این قسمت</div>
|
||||
<div class="font-bold text-primary">از این قسمت</div>
|
||||
ثبت نام کنید.
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
@@ -125,7 +125,9 @@ import registerDelayImage from '@/assets/img/registerDelay.svg'
|
||||
import DialogVantOneButton from '@/components/DialogVantOneButton.vue'
|
||||
import { registerCustomer } from '@/api/login'
|
||||
import router from '@/router'
|
||||
import logo from "@/assets/img/logo_full_.png";
|
||||
import { getAppLogoFullUrl } from '@/config/brand-assets'
|
||||
|
||||
const logo = getAppLogoFullUrl()
|
||||
|
||||
|
||||
// const stepTwoVerify = ref<boolean>(false)
|
||||
|
||||
+3
-3
@@ -11,9 +11,9 @@ export default defineConfig({
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
"primary": "#a72b77",
|
||||
"secondary": "#ffffff",
|
||||
"tertiary": "#e0be7f"
|
||||
"primary": "var(--app-primary-color, #a72b77)",
|
||||
"secondary": "var(--app-secondary-color, #ffffff)",
|
||||
"tertiary": "var(--app-tertiary-color, #e0be7f)"
|
||||
}
|
||||
},
|
||||
presets: [
|
||||
|
||||
Reference in New Issue
Block a user