Improve boursecu UX: banners, support FAB, wallet deposit guide, fund/physical layouts, nav, and sidebar credit.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+108
-119
@@ -1,4 +1,19 @@
|
||||
<template>
|
||||
<!-- Splash outside .desktopConfig so the 426px mobile frame cannot clip it -->
|
||||
<div
|
||||
v-if="showSplash"
|
||||
class="app-splash-screen flex justify-center"
|
||||
:style="{ backgroundColor: getProjectSplashBackground() }"
|
||||
>
|
||||
<div class="self-center splash_appear_fade_in">
|
||||
<img
|
||||
:src="getProjectSplashLogo(config?.config?.avatar)"
|
||||
class="w-[min(72vw,280px)] h-auto object-contain"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="desktopConfig w-full right-0 left-0">
|
||||
<div v-if="popVisible" class="top-0 bottom-0 wrap-fix bg-primary z-100 opacity-60">
|
||||
<div class="absolute right-0 left-0 bottom-10vh flex flex-col items-center">
|
||||
@@ -10,17 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<AConfigProvider :theme="antTheme ?? undefined" direction="rtl">
|
||||
<div v-if="showSplash" class="app-splash-screen flex justify-center" :style="{ backgroundColor: getProjectSplashBackground() }">
|
||||
<div class="self-center splash_appear_fade_in">
|
||||
<img
|
||||
:src="getProjectSplashLogo(config?.config?.avatar)"
|
||||
class="w-[min(72vw,280px)] h-auto object-contain"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="app-main">
|
||||
<div v-if="!showSplash" class="app-main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</router-view>
|
||||
@@ -29,8 +34,12 @@
|
||||
<div
|
||||
v-if="showSupportButton && !showSplash"
|
||||
id="support-button"
|
||||
class="draggable-support-button"
|
||||
:class="{ 'is-dragging': supportDragging }"
|
||||
ref="supportButtonEl"
|
||||
class="fixed z-[5100] cursor-grab select-none rounded-full"
|
||||
:class="{
|
||||
'cursor-grabbing': supportDragging,
|
||||
'z-[var(--app-z-support-fab-open,5615)]': supportPickerOpen,
|
||||
}"
|
||||
:style="supportButtonStyle"
|
||||
title="پشتیبانی"
|
||||
@pointerdown="onSupportPointerDown"
|
||||
@@ -38,9 +47,20 @@
|
||||
@pointerup="handleSupportPointerUp"
|
||||
@pointercancel="onSupportPointerCancel"
|
||||
>
|
||||
<div class="support-button-inner" :style="{ '--support-accent': supportAccentColor }">
|
||||
<BasicIcon :icon="supportIcon" size="18" class="support-button-icon" />
|
||||
<span class="support-button-label">پشتیبانی</span>
|
||||
<div
|
||||
class="inline-flex items-center gap-2 rounded-full bg-white border border-solid border-gray-200 shadow-[0_6px_20px_rgba(15,23,42,0.14)] px-3.5 py-[9px] text-slate-800 text-[13px] font-600 leading-none transition-all duration-200"
|
||||
:class="{
|
||||
'shadow-[0_10px_28px_rgba(15,23,42,0.22)]': supportDragging,
|
||||
'scale-[0.94] shadow-[0_4px_14px_rgba(15,23,42,0.12)]': supportPickerOpen && !supportDragging,
|
||||
}"
|
||||
>
|
||||
<BasicIcon
|
||||
:icon="supportIcon"
|
||||
size="18"
|
||||
:color="supportAccentColor"
|
||||
class="shrink-0"
|
||||
/>
|
||||
<span class="whitespace-nowrap">پشتیبانی</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,6 +77,13 @@
|
||||
<AppCreditLink variant="float" />
|
||||
</div>
|
||||
|
||||
<SupportMessengerPicker
|
||||
v-model:open="supportPickerOpen"
|
||||
:entries="supportMessengerEntries"
|
||||
:anchor-el="pickerAnchorEl"
|
||||
@select="openMessengerEntry"
|
||||
/>
|
||||
|
||||
<VersionUpdateModal />
|
||||
</template>
|
||||
|
||||
@@ -68,13 +95,11 @@ import {getProjectFontFamily, getProjectSplashBackground, getProjectSplashLogo,
|
||||
import {ConfigProvider as AConfigProvider} from 'ant-design-vue'
|
||||
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
|
||||
import { useApplyDesktopLayoutClass, useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import {
|
||||
buildSupportMessengerUrl,
|
||||
loadSupportMessengerFromSettings,
|
||||
supportMessengerSettings,
|
||||
} from '@/utils/supportMessenger'
|
||||
import { useSupportMessenger } from '@/composables/useSupportMessenger'
|
||||
import { loadSupportMessengerFromSettings } from '@/utils/supportMessenger'
|
||||
import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
|
||||
import AppCreditLink from '@/components/AppCreditLink.vue'
|
||||
import SupportMessengerPicker from '@/components/SupportMessengerPicker.vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { recoverMobileViewportAfterAuth } from '@/layouts/composables/useMobileScrollReset'
|
||||
|
||||
@@ -95,47 +120,25 @@ const config = useConfigStore()
|
||||
const showSplash = ref(true)
|
||||
const popVisible = ref(false)
|
||||
|
||||
const supportLink = computed(() => {
|
||||
return buildSupportMessengerUrl(
|
||||
supportMessengerSettings.value.messenger,
|
||||
supportMessengerSettings.value.messengerId
|
||||
)
|
||||
})
|
||||
const {
|
||||
supportPickerOpen,
|
||||
supportPickerAnchor,
|
||||
supportMessengerEntries,
|
||||
messengerMeta,
|
||||
hasMessengerLink: showSupportButton,
|
||||
openMessengerEntry,
|
||||
openSupportMessenger,
|
||||
} = useSupportMessenger()
|
||||
|
||||
const showSupportButton = computed(() => !!supportLink.value)
|
||||
const supportButtonEl = ref<HTMLElement | null>(null)
|
||||
const pickerAnchorEl = computed(() => supportPickerAnchor.value ?? supportButtonEl.value)
|
||||
|
||||
const supportIcon = computed(() => {
|
||||
const messenger = (supportMessengerSettings.value.messenger ?? '').toLowerCase()
|
||||
switch (messenger) {
|
||||
case 'whatsapp':
|
||||
return 'vuesax-linear:whatsapp'
|
||||
case 'telegram':
|
||||
return 'vuesax-linear:send-2'
|
||||
case 'bale':
|
||||
return 'vuesax-linear:messages-2'
|
||||
default:
|
||||
return 'vuesax-linear:messages-2'
|
||||
}
|
||||
})
|
||||
const supportIcon = computed(() => messengerMeta.value.icon)
|
||||
|
||||
const supportAccentColor = computed(() => {
|
||||
const messenger = (supportMessengerSettings.value.messenger ?? '').toLowerCase()
|
||||
switch (messenger) {
|
||||
case 'whatsapp':
|
||||
return '#22c55e'
|
||||
case 'telegram':
|
||||
return '#0ea5e9'
|
||||
case 'bale':
|
||||
return '#16a34a'
|
||||
case 'rubika':
|
||||
return '#7c3aed'
|
||||
case 'eitaa':
|
||||
return '#f59e0b'
|
||||
case 'soroush':
|
||||
return '#2563eb'
|
||||
default:
|
||||
return config.config?.color || '#334155'
|
||||
}
|
||||
const accent = messengerMeta.value.accent
|
||||
if (accent !== '#334155') return accent
|
||||
return config.config?.color || accent
|
||||
})
|
||||
|
||||
const {
|
||||
@@ -153,14 +156,14 @@ const {
|
||||
})
|
||||
|
||||
function openSupportLink() {
|
||||
if (!supportLink.value) return
|
||||
window.open(supportLink.value, '_blank', 'noopener,noreferrer')
|
||||
void openSupportMessenger(supportButtonEl.value)
|
||||
}
|
||||
|
||||
function handleSupportPointerUp(event: PointerEvent) {
|
||||
if (supportPointerUp(event)) {
|
||||
openSupportLink()
|
||||
}
|
||||
const clicked = supportPointerUp(event)
|
||||
if (!clicked) return
|
||||
event.stopPropagation()
|
||||
openSupportLink()
|
||||
}
|
||||
|
||||
const antTheme = computed(() => {
|
||||
@@ -196,11 +199,19 @@ onMounted(async () => {
|
||||
}, 2000)
|
||||
})
|
||||
|
||||
watch(showSplash, (visible) => {
|
||||
if (!visible) {
|
||||
watch(
|
||||
showSplash,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
const splashBg = getProjectSplashBackground()
|
||||
document.documentElement.style.backgroundColor = splashBg
|
||||
document.body.style.backgroundColor = splashBg
|
||||
return
|
||||
}
|
||||
resetAppSurfaceBackground()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
() => route.name,
|
||||
@@ -236,6 +247,8 @@ watch(
|
||||
--app-z-dialog: 5300;
|
||||
/* زیر لایه دراپداون اینت (99999) تا تقویم/سلکت داخل مدال روی آن باز شود */
|
||||
--app-z-modal: 5500;
|
||||
--app-z-support-picker: 5600;
|
||||
--app-z-support-fab-open: 5615;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
@@ -310,15 +323,30 @@ watch(
|
||||
}
|
||||
|
||||
&--sidebar {
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding: 4px;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 4px 4px;
|
||||
color: #9ca3af;
|
||||
font-size: 10px;
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
.app-credit-link__text {
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.app-credit-link__logo {
|
||||
height: 15px;
|
||||
opacity: 0.85;
|
||||
max-width: 68px;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,11 +368,15 @@ watch(
|
||||
|
||||
html.project-boursecu {
|
||||
.app-credit-link--sidebar {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
color: rgba(255, 255, 255, 0.55);
|
||||
|
||||
.app-credit-link__logo {
|
||||
filter: brightness(1.15);
|
||||
opacity: 0.75;
|
||||
filter: brightness(1.2);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,50 +394,7 @@ html.project-boursecu {
|
||||
}
|
||||
|
||||
#support-button {
|
||||
position: fixed;
|
||||
z-index: 5100;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
border-radius: 9999px;
|
||||
|
||||
&.is-dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.support-button-inner {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 9px 14px 9px 12px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
||||
border-radius: 9999px;
|
||||
box-shadow: 0 6px 20px rgba(15, 23, 42, 0.14);
|
||||
color: #1e293b;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
direction: rtl;
|
||||
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
||||
|
||||
.support-button-icon {
|
||||
color: var(--support-accent, #334155);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.support-button-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
#support-button:not(.is-dragging):hover .support-button-inner {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
|
||||
#support-button.is-dragging .support-button-inner {
|
||||
box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22);
|
||||
/* جای draggable از fabStyle میآید */
|
||||
}
|
||||
|
||||
@media screen and (min-width: 426px) and (max-width: 767.98px) {
|
||||
|
||||
Reference in New Issue
Block a user