feat: add gold day calculator and polish desktop UI

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-20 21:35:18 +03:30
co-authored by Cursor
parent d2737a4998
commit 444178df05
15 changed files with 574 additions and 93 deletions
+3 -8
View File
@@ -98,6 +98,8 @@
>
<AppCreditLink variant="float" />
</div>
<GoldDayCalculatorModal />
</div>
</template>
@@ -121,6 +123,7 @@ import { useApplyDesktopLayoutClass, useDesktopBreakpoint } from '@/layouts/comp
import AppCreditLink from '@/components/AppCreditLink.vue'
import { usePwaInstall } from '@/composables/usePwaInstall'
import PwaInstallGuideModal from '@/components/pwa/PwaInstallGuideModal.vue'
import GoldDayCalculatorModal from '@/components/GoldDayCalculatorModal.vue'
import { useUserStore } from '@/store/userStore'
import { useSettingsStore } from '@/store/settingsStore'
import { connectChatIfExists, disconnectChat, isSettingFlagOn, unreadSupportCount, useChatService } from '@/utils/chat'
@@ -464,12 +467,4 @@ watch(latestIncomingNotification, (payload) => {
transform: scale(0.94);
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.12);
}
/* در دسکتاپ، دکمه پشتیبانی کنار سایدبار و پایین صفحه قرار می‌گیرد (مانند khaneghi_user) */
html.app-layout--desktop {
#support-button {
bottom: 12px;
right: calc(var(--app-desktop-sidebar-width, 260px) + 20px);
}
}
</style>
+7 -3
View File
@@ -2,7 +2,7 @@
<div>
<a-modal
v-model:visible="localValue"
:title="props.title"
:title="slots.title ? undefined : props.title"
centered
@ok="emits('ok')"
@cancel="emits('close')"
@@ -14,6 +14,9 @@
:closable="props.closable"
:wrapClassName="props.wrapClassName"
>
<template v-if="slots.title" #title>
<slot name="title" />
</template>
<template v-if="props.customFooter" #footer> <slot name="footer" /></template>
<a-spin :spinning="props.loading">
<div class="overflow-y-auto py-2 px-1 relative max-h-[83vh]" id="body">
@@ -25,8 +28,7 @@
</template>
<script setup lang="ts">
//define emit
import { computed } from 'vue'
import { computed, useSlots } from 'vue'
const emits = defineEmits(['ok', 'close', 'update:visible'])
@@ -53,6 +55,8 @@ const props = withDefaults(defineProps<Prop>(), {
closable: true
})
const slots = useSlots()
const localValue = computed({
get() {
return props.visible
+307
View File
@@ -0,0 +1,307 @@
<template>
<BasicModal
v-model:visible="visible"
width="400px"
destroy-on-close
custom-footer
wrap-class-name="gold-day-calc-modal"
>
<template #title>
<div class="gold-day-calc-modal__title">
<BasicIcon icon="vuesax-linear:chart-2" size="20" class="gold-day-calc-modal__title-icon" />
<span>محاسبه‌گر طلای شما</span>
</div>
</template>
<div class="gold-day-calc" dir="rtl">
<BasicInput
v-model:value="weight"
title="وزن طلا (گرم)"
type="tel"
place-holder="مثلاً ۱۰.۵"
inputmode="decimal"
/>
<BasicInput
:value="unitPriceInput"
title="قیمت روز طلا"
type="tel"
disabled
addon-before="ریال"
place-holder="قیمت صفحه اصلی"
/>
<BasicInput
v-model:value="feePercent"
title="اجرت ساخت (%)"
type="tel"
place-holder="مثلاً ۷"
inputmode="decimal"
/>
<BasicInput
v-model:value="taxPercent"
title="سود و مالیات (%)"
type="tel"
place-holder="مثلاً ۹"
inputmode="decimal"
/>
<div class="gold-day-calc__result rounded-xl border border-solid border-gray-200 bg-gray-50 p-3">
<div class="text-xs text-gray-500 mb-1">کل نهایی</div>
<div class="gold-day-calc__total text-lg font-bold text-primary">
<span class="gold-day-calc__num">{{ formattedTotal }}</span>
<span class="text-sm font-medium text-gray-600">ریال</span>
</div>
<div class="mt-2 flex flex-col gap-1 text-xs text-gray-600">
<div class="flex justify-between gap-2">
<span>هزینه طلا</span>
<span class="gold-day-calc__num">{{ formatRial(breakdown.goldCost) }}</span>
</div>
<div class="flex justify-between gap-2">
<span>اجرت</span>
<span class="gold-day-calc__num">{{ formatRial(breakdown.feeCost) }}</span>
</div>
<div class="flex justify-between gap-2">
<span>سود و مالیات</span>
<span class="gold-day-calc__num">{{ formatRial(breakdown.taxCost) }}</span>
</div>
</div>
</div>
</div>
<template #footer>
<BasicButton type="primary" class="!w-full" size="middle" @click="recalculate">
محاسبه مجدد
</BasicButton>
</template>
</BasicModal>
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { goldDayCalculatorVisible } from '@/composables/useGoldDayCalculator'
import {
getLastPrices,
getTradeBuyPrice,
lastPrice,
startLastPricePolling,
stopLastPricePolling,
} from '@/utils/price'
import { getPriceDisplayState, NO_QUOTE_MESSAGE } from '@/utils/storeHours'
import { usePriceWithoutType } from '@/utils/usePrice'
import { persianToEnglishDigits } from '@/utils/persianDigits'
const visible = goldDayCalculatorVisible
const weight = ref<string | number>('')
const feePercent = ref<string | number>('')
const taxPercent = ref<string | number>('')
const tick = ref(0)
function parseNum(raw: string | number | undefined): number {
const s = persianToEnglishDigits(String(raw ?? ''))
.replace(/,/g, '')
.replace(/[^\d.]/g, '')
const n = Number.parseFloat(s)
return Number.isFinite(n) ? n : 0
}
const liveUnitPrice = computed(() => {
void tick.value
if (getPriceDisplayState() !== 'open') return 0
return getTradeBuyPrice(lastPrice.value) || 0
})
const unitPriceInput = computed(() => {
void tick.value
const state = getPriceDisplayState()
if (state === 'closed') return 'فروشگاه بسته است'
if (state === 'no_quote') return NO_QUOTE_MESSAGE
const p = liveUnitPrice.value
return p > 0 ? usePriceWithoutType(p) : ''
})
const breakdown = computed(() => {
void tick.value
const w = parseNum(weight.value)
const fee = parseNum(feePercent.value)
const tax = parseNum(taxPercent.value)
const unit = liveUnitPrice.value
const goldCost = w * unit
const feeCost = goldCost * (fee / 100)
const taxCost = (goldCost + feeCost) * (tax / 100)
const total = goldCost + feeCost + taxCost
return { goldCost, feeCost, taxCost, total }
})
const formattedTotal = computed(() => formatRial(breakdown.value.total))
function formatRial(n: number) {
if (!Number.isFinite(n) || n <= 0) return '۰'
return usePriceWithoutType(Math.round(n))
}
function recalculate() {
tick.value += 1
void getLastPrices()
}
watch(visible, async (open) => {
if (open) {
startLastPricePolling()
await getLastPrices()
tick.value += 1
} else {
stopLastPricePolling()
}
})
</script>
<style scoped>
.gold-day-calc {
display: flex;
flex-direction: column;
gap: 0.75rem;
direction: rtl;
text-align: right;
}
/* فقط متن لیبل RTL — گروه اینپوت LTR بماند تا addon ریال نشکند */
.gold-day-calc :deep(.ant-input-group) {
direction: ltr;
display: table;
width: 100%;
}
.gold-day-calc :deep(.ant-input-group > .ant-input) {
direction: ltr;
text-align: left;
}
.gold-day-calc :deep(.ant-input:not(.ant-input-group *)) {
text-align: right;
}
.gold-day-calc__result {
direction: rtl;
text-align: right;
}
.gold-day-calc__total {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: flex-start;
gap: 0.35rem;
}
.gold-day-calc__num {
direction: ltr;
unicode-bidi: isolate;
display: inline-block;
}
</style>
<style lang="less">
.gold-day-calc-modal {
.ant-modal-content {
direction: rtl;
display: flex;
flex-direction: column;
max-height: min(88dvh, 640px);
overflow: hidden;
}
.ant-modal-header {
flex-shrink: 0;
direction: rtl;
text-align: right;
/* ضربدر فیزیکی چپ — پدینگ راست کم تا عنوان نزدیک لبه راست بماند */
padding-left: 2.75rem;
padding-right: 1rem;
}
.ant-modal-title {
text-align: right;
width: 100%;
}
.gold-day-calc-modal__title {
display: inline-flex;
align-items: center;
justify-content: flex-start;
gap: 0.5rem;
direction: rtl;
width: 100%;
}
.gold-day-calc-modal__title-icon {
flex-shrink: 0;
color: var(--App-secondary-color, #c9a062);
}
/* ضربدر سمت چپ — عنوان سمت راست */
.ant-modal-close {
inset-inline-start: 0 !important;
inset-inline-end: auto !important;
right: auto !important;
left: 0 !important;
}
.ant-modal-body {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
padding-bottom: 0.25rem;
max-height: none;
}
#body {
max-height: min(48dvh, 360px) !important;
overflow-y: auto !important;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
.ant-modal-footer {
flex-shrink: 0;
margin-top: 0;
padding-top: 0.75rem;
border-top: 1px solid rgba(148, 163, 184, 0.25);
}
}
@media screen and (max-width: 767.98px) {
.gold-day-calc-modal {
.ant-modal {
max-width: calc(100vw - 1.5rem);
margin: 0 auto;
}
.ant-modal-content {
max-height: min(86dvh, 100%);
}
/* بین هدر و دکمه — ارتفاع کمتر تا اسکرول بخورد */
#body {
max-height: min(42dvh, 280px) !important;
}
.ant-modal-body {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
}
}
@media screen and (max-width: 400px) {
.gold-day-calc-modal #body {
max-height: min(38dvh, 240px) !important;
}
}
</style>
+12
View File
@@ -0,0 +1,12 @@
import { ref } from 'vue'
/** باز/بسته بودن مدال محاسبه‌گر طلا — مشترک بین منوی کاربر و همبرگر */
export const goldDayCalculatorVisible = ref(false)
export function openGoldDayCalculator() {
goldDayCalculatorVisible.value = true
}
export function closeGoldDayCalculator() {
goldDayCalculatorVisible.value = false
}
@@ -111,13 +111,17 @@ html.app-layout--desktop {
}
.dhome-topbar {
position: sticky;
top: 0;
z-index: 30;
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
margin-bottom: 28px;
padding-bottom: 24px;
margin: -4px 0 20px;
padding: 12px 0 20px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
background: #f6f7f9;
&__eyebrow {
font-size: 12px;
+65 -13
View File
@@ -1,7 +1,9 @@
import { computed, onMounted, onUnmounted, ref } from 'vue'
const DRAG_THRESHOLD = 6
const POSITION_VERSION = 1
/** v2: دسکتاپ از کنار سایدبار تا انتهای viewport (نه ستون ۴۲۶px) */
const POSITION_VERSION = 2
const MOBILE_CONTENT_MAX = 426
type FabPosition = { x: number; y: number }
@@ -11,6 +13,11 @@ type SavedFabOffset = {
dy: number
}
type HorizontalBounds = {
offsetX: number
contentWidth: number
}
type DraggableFloatingOptions = {
width?: number
height?: number
@@ -40,6 +47,46 @@ function readBottomChromeHeight(): number {
return measured > 0 ? measured : nav
}
function isDesktopLayout(): boolean {
const el = document.documentElement
return (
el.classList.contains('app-layout--desktop')
|| el.getAttribute('data-layout') === 'desktop'
)
}
function readCssLengthPx(varName: string): number | null {
const raw = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()
if (!raw) return null
if (raw.endsWith('px')) {
const n = parseFloat(raw)
return Number.isNaN(n) ? null : n
}
if (raw.endsWith('rem')) {
const rem = parseFloat(raw)
const root = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16
return Number.isNaN(rem) ? null : rem * root
}
const n = parseFloat(raw)
return Number.isNaN(n) ? null : n
}
/** سایدبار دسکتاپ معمولاً سمت راست (RTL) است. */
function readDesktopSidebarWidthPx(): number {
if (document.documentElement.classList.contains('app-layout--desktop-no-sidebar')) {
return 0
}
return (
readCssLengthPx('--app-desktop-sidebar-width')
?? readCssLengthPx('--app-sidebar-width')
?? 260
)
}
export function useDraggableFloatingButton(
storageKey: string,
options: DraggableFloatingOptions = {}
@@ -66,22 +113,28 @@ export function useDraggableFloatingButton(
touchAction: 'none'
}))
function getViewportWidth() {
return Math.min(window.innerWidth, 426)
}
function getHorizontalOffset() {
function getHorizontalBounds(): HorizontalBounds {
const vw = window.innerWidth
const contentWidth = getViewportWidth()
return Math.max(0, (vw - contentWidth) / 2)
if (isDesktopLayout()) {
const sidebar = readDesktopSidebarWidthPx()
return {
offsetX: 0,
contentWidth: Math.max(width, vw - sidebar)
}
}
const contentWidth = Math.min(vw, MOBILE_CONTENT_MAX)
return {
offsetX: Math.max(0, (vw - contentWidth) / 2),
contentWidth
}
}
function getDefaultPosition(): FabPosition {
const vh = window.innerHeight
const offsetX = getHorizontalOffset()
const contentWidth = getViewportWidth()
const bottomChrome = readBottomChromeHeight()
const { offsetX, contentWidth } = getHorizontalBounds()
const bottomChrome = isDesktopLayout() ? 0 : readBottomChromeHeight()
return {
x: offsetX + contentWidth - width - defaultRightOffset,
@@ -100,8 +153,7 @@ export function useDraggableFloatingButton(
function clampToViewport() {
const vh = window.innerHeight
const offsetX = getHorizontalOffset()
const contentWidth = getViewportWidth()
const { offsetX, contentWidth } = getHorizontalBounds()
const minX = offsetX
const maxX = offsetX + contentWidth - width
@@ -34,13 +34,17 @@
}
.dgold-topbar {
position: sticky;
top: 0;
z-index: 30;
display: flex;
align-items: flex-start;
gap: 16px;
max-width: 720px;
margin: 0 auto 24px;
padding-bottom: 24px;
margin: -4px auto 20px;
padding: 12px 0 20px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
background: #f6f7f9;
&__back {
display: inline-flex;
@@ -53,13 +53,17 @@
/* Topbar */
.dhome-topbar {
position: sticky;
top: 0;
z-index: 30;
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
margin-bottom: 28px;
padding-bottom: 24px;
margin: -4px 0 20px;
padding: 12px 0 20px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
background: #f6f7f9;
&__eyebrow {
font-size: 12px;
@@ -1,5 +1,5 @@
<template>
<a-form ref="formRef" :model="userFormState" class="!mt-5" name="basic" @finish="ok">
<a-form ref="formRef" :model="userFormState" class="user-profile-form !mt-5" name="basic" dir="rtl" @finish="ok">
<a-form-item :rules="[isValidPersian()]" label="نام" name="fname">
<BasicInput v-model:value="userFormState.fname" />
</a-form-item>
@@ -39,3 +39,20 @@ withDefaults(defineProps<{ showSubmit?: boolean }>(), { showSubmit: false })
const { userFormState, formRef, isValidPersian, requireNationalCode, ok } = useUserPageContext()
</script>
<style scoped>
.user-profile-form {
direction: rtl;
text-align: right;
}
:deep(.ant-form-item-label) {
text-align: right;
}
:deep(.ant-input),
:deep(.ant-input-affix-wrapper) {
direction: rtl;
text-align: right;
}
</style>
@@ -17,6 +17,7 @@ import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeatu
import { useSettingsStore } from '@/store/settingsStore'
import { useSupportMessenger } from '@/composables/useSupportMessenger'
import { isUserSupportChatEnabled, unreadSupportCount } from '@/utils/chat'
import { openGoldDayCalculator } from '@/composables/useGoldDayCalculator'
export interface UserMenuAction {
id: string
@@ -104,6 +105,13 @@ export function useUserPage() {
onClick: () => { editPasswordVisible.value = true },
visible: true,
},
{
id: 'goldDayCalculator',
label: 'قیمت روز طلا',
icon: 'vuesax-linear:chart-2',
onClick: () => openGoldDayCalculator(),
visible: true,
},
{
id: 'notify',
label: 'هشدار قیمت',
+12 -12
View File
@@ -31,11 +31,11 @@
</div>
<div class="duser-profile__field">
<span class="duser-profile__label">شماره تلفن همراه</span>
<span class="duser-profile__value">{{ userStore.userInfo?.mobile }}</span>
<span class="duser-profile__value duser-profile__value--ltr">{{ userStore.userInfo?.mobile }}</span>
</div>
<div v-if="userStore.userInfo?.referral_id" class="duser-profile__field">
<span class="duser-profile__label">کد معرف</span>
<span class="duser-profile__value">{{ userStore.userInfo?.referral_id }}</span>
<span class="duser-profile__value duser-profile__value--ltr">{{ userStore.userInfo?.referral_id }}</span>
</div>
</div>
@@ -83,17 +83,17 @@
<span class="duser-actions__label">{{ action.label }}</span>
<BasicIcon class="duser-actions__chevron" icon="vuesax-linear:arrow-left" size="16" />
</button>
<button
type="button"
class="duser-actions__item duser-actions__item--logout"
@click="requestLogout"
>
<span class="duser-actions__icon duser-actions__icon--logout">
<BasicIcon icon="vuesax-linear:logout" size="18" />
</span>
<span class="duser-actions__label duser-actions__label--logout">خروج</span>
</button>
</div>
<button
type="button"
class="duser-actions__item duser-actions__item--logout"
@click="requestLogout"
>
<span class="duser-actions__icon duser-actions__icon--logout">
<BasicIcon icon="vuesax-linear:logout" size="18" />
</span>
<span class="duser-actions__label duser-actions__label--logout">خروج</span>
</button>
</section>
</div>
</div>
@@ -4,22 +4,30 @@
min-height: 100%;
background: #f6f7f9;
color: #111827;
direction: rtl;
text-align: right;
}
.duser__container {
max-width: 960px;
width: 100%;
max-width: 1280px;
margin: 0 auto;
padding: 28px 36px 40px;
padding: 28px 28px 40px;
box-sizing: border-box;
}
.duser-topbar {
position: sticky;
top: 0;
z-index: 30;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 28px;
padding-bottom: 24px;
margin: -4px 0 20px;
padding: 12px 0 20px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
background: #f6f7f9;
&__back {
display: inline-flex;
@@ -62,8 +70,9 @@
}
.duser-grid {
/* تنظیمات و خدمات عریض‌تر از کارت پروفایل */
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(280px, 340px);
grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.4fr);
gap: 20px;
align-items: start;
}
@@ -71,8 +80,9 @@
.duser-surface {
background: #ffffff;
border-radius: 14px;
padding: 24px;
padding: 22px 20px;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
min-width: 0;
}
.duser-profile {
@@ -110,24 +120,32 @@
color: #6b7280;
margin: 0;
direction: ltr;
unicode-bidi: isolate;
text-align: right;
}
&__fields {
display: flex;
flex-direction: column;
gap: 14px;
flex-direction: row;
flex-wrap: nowrap;
gap: 10px;
margin-bottom: 20px;
direction: rtl;
}
&__field {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex: 1 1 0;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 6px;
min-width: 0;
padding: 12px 14px;
border-radius: 10px;
background: #f9fafb;
direction: rtl;
text-align: right;
}
&__label {
@@ -137,11 +155,18 @@
}
&__value {
width: 100%;
font-size: 14px;
font-weight: 600;
color: #111827;
direction: ltr;
text-align: left;
direction: rtl;
text-align: right;
&--ltr {
direction: ltr;
unicode-bidi: isolate;
text-align: right;
}
}
&__referral-actions {
@@ -187,6 +212,9 @@
}
.duser-actions {
direction: rtl;
text-align: right;
&__title {
font-size: 13px;
font-weight: 600;
@@ -195,20 +223,28 @@
}
&__list {
display: flex;
flex-direction: column;
gap: 8px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
direction: rtl;
@media screen and (min-width: 1100px) {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
&__item {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
gap: 10px;
width: 100%;
padding: 12px 14px;
min-width: 0;
padding: 14px 14px;
border: 1px solid #f3f4f6;
border-radius: 10px;
background: #fff;
direction: rtl;
text-align: right;
cursor: pointer;
font-family: inherit;
@@ -220,7 +256,8 @@
}
&--logout {
margin-top: 8px;
grid-column: 1 / -1;
margin-top: 4px;
border-color: rgba(239, 68, 68, 0.25);
&:hover {
+14 -1
View File
@@ -70,13 +70,25 @@
icon=""
iconSize="18"
size="large"
@click="editPasswordVisible = true"
@click="editPasswordVisible = true"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:lock" class="absolute right-8" />
<div>تغییر رمز عبور</div>
</div>
</BasicButton>
<BasicButton
class="mt-2 w-full"
icon=""
iconSize="18"
size="large"
@click="openGoldDayCalculator"
>
<div class="flex">
<BasicIcon icon="vuesax-linear:chart-2" class="absolute right-8" />
<div>قیمت روز طلا</div>
</div>
</BasicButton>
<!-- <BasicButton
class="w-full mt-2"
size="large"
@@ -204,6 +216,7 @@ import { useSettingsStore } from '@/store/settingsStore'
import { useUserStore } from '@/store/userStore'
import { useUserPageContext } from '../composables/useUserPage'
import MobilePageHeader from '@/layouts/components/MobilePageHeader.vue'
import { openGoldDayCalculator } from '@/composables/useGoldDayCalculator'
const userStore = useUserStore()
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
@@ -1,38 +1,41 @@
<template>
<div class="dwallet">
<div class="dwallet__container">
<DesktopPageTopbar
eyebrow="مالی"
title="کیف پول"
subtitle="واریز و برداشت وجه از کیف پول خود"
/>
<div class="dwallet-sticky-header">
<DesktopPageTopbar
eyebrow="مالی"
title="کیف پول"
subtitle="واریز و برداشت وجه از کیف پول خود"
:sticky="false"
/>
<div class="dwallet-toolbar">
<div class="dwallet-toggle">
<button
type="button"
class="dwallet-toggle__btn"
:class="{ 'dwallet-toggle__btn--active': isDeposit }"
@click="setIsDeposit(true)"
>
واریز
</button>
<button
type="button"
class="dwallet-toggle__btn"
:class="{ 'dwallet-toggle__btn--active': !isDeposit }"
@click="setIsDeposit(false)"
>
برداشت
</button>
</div>
<div class="dwallet-toolbar">
<div class="dwallet-toggle">
<button
type="button"
class="dwallet-toggle__btn"
:class="{ 'dwallet-toggle__btn--active': isDeposit }"
@click="setIsDeposit(true)"
>
واریز
</button>
<button
type="button"
class="dwallet-toggle__btn"
:class="{ 'dwallet-toggle__btn--active': !isDeposit }"
@click="setIsDeposit(false)"
>
برداشت
</button>
</div>
<div class="dwallet-balance-pill">
<span class="dwallet-balance-pill__label">موجودی کیف پول</span>
<span class="dwallet-balance-pill__value number-ltr">
{{ usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0) }}
<span>ریال</span>
</span>
<div class="dwallet-balance-pill">
<span class="dwallet-balance-pill__label">موجودی کیف پول</span>
<span class="dwallet-balance-pill__value number-ltr">
{{ usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0) }}
<span>ریال</span>
</span>
</div>
</div>
</div>
@@ -12,6 +12,21 @@
padding: 28px 36px 40px;
}
.dwallet-sticky-header {
position: sticky;
top: 0;
z-index: 30;
margin: -4px 0 20px;
padding-top: 4px;
background: #f6f7f9;
.dpage-topbar {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: none;
}
}
.dwallet-topbar {
margin-bottom: 24px;
padding-bottom: 24px;
@@ -49,6 +64,12 @@
margin-bottom: 24px;
}
.dwallet-sticky-header .dwallet-toolbar {
margin-bottom: 0;
padding-bottom: 16px;
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.dwallet-toggle {
display: inline-flex;
gap: 4px;