Split desktop and mobile layouts with shared page data so APIs fetch once per context.

Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-14 10:08:46 +03:30
co-authored by Cursor
parent 4404b4cb92
commit a5e458ed25
234 changed files with 18425 additions and 5503 deletions
+14 -1
View File
@@ -114,7 +114,7 @@ export function getProjectLoginTaglineLines() {
}
return [
'بورس مس مرجع هوشمند معاملات',
'مرجع هوشمند معاملات',
' و سرمایه‌گذاری در صنعت مس',
]
}
@@ -123,6 +123,18 @@ export function getProjectSplashBackground() {
return isBoursecuProject() ? BOURSECU_BRAND_NAV : '#ffffff'
}
/** Reset splash-time inline backgrounds so mobile overscroll shows white again. */
export function resetAppSurfaceBackground() {
const background = '#ffffff'
document.documentElement.style.backgroundColor = background
document.body.style.backgroundColor = background
const metaTheme = document.querySelector('meta[name="theme-color"]')
if (metaTheme) {
metaTheme.setAttribute('content', background)
}
}
export function getProjectFontFamily() {
return getConfigApp('name') === 'boursecu' ? "'dana', sans-serif" : "'iran-sans', sans-serif"
}
@@ -142,6 +154,7 @@ export function applyProjectTheme() {
}
document.documentElement.classList.add('project-boursecu')
document.documentElement.style.setProperty('--App-brand-nav', BOURSECU_BRAND_NAV)
document.documentElement.style.setProperty('--App-brand-red', BOURSECU_BRAND_RED)
document.documentElement.style.setProperty('--App-brand-red-50', '#f8ecec')
document.documentElement.style.setProperty('--App-brand-red-100', '#f0d8d8')
+29
View File
@@ -0,0 +1,29 @@
const PERSIAN_DIGITS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'] as const
export function toPersianDigits(value: string | number | null | undefined): string {
if (value === null || value === undefined) return ''
return String(value).replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)] ?? digit)
}
export function toEnglishDigits(value: string): string {
return value.replace(/[۰-۹]/g, (digit) => {
const index = PERSIAN_DIGITS.indexOf(digit as (typeof PERSIAN_DIGITS)[number])
return index >= 0 ? String(index) : digit
})
}
export function formatFixed(value: string | number | null | undefined, decimals = 2): string {
const num = Number(value)
if (!Number.isFinite(num)) return toPersianDigits(String(value ?? ''))
return toPersianDigits(num.toFixed(decimals))
}
export function formatPercent(
value: number,
decimals = 2,
options: { showSign?: boolean; suffix?: string } = {},
): string {
const { showSign = false, suffix = '%' } = options
const prefix = showSign && value > 0 ? '+' : value < 0 ? '-' : showSign ? '+' : ''
return `${prefix}${formatFixed(Math.abs(value), decimals)}${suffix}`
}
+1
View File
@@ -1,3 +1,4 @@
import { toPersianDigits } from '@/utils/persianDigits'
import type { Product } from '@/models/products'
import type { UserWalletLine } from '@/models/wallet'
import type { ProductFile } from '@/utils/file'
+26 -2
View File
@@ -2,13 +2,37 @@ import type { Product } from '@/models/products'
import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
import { isMetalCommodityGroup, isMeltedProductUsingAppPrice, isMeltedTradeGroup } from '@/utils/productCategories'
function applyPriceOffsetPercent(basePrice: number, offsetPercent?: number | null) {
export function resolvePriceOffsetRatio(offsetPercent?: number | null) {
const offset = Number(offsetPercent ?? 0)
if (!offset) {
return 0
}
// 5 => 5% ، 0.05 => 5% (اعشاری)
if (Math.abs(offset) > 0 && Math.abs(offset) < 1) {
return offset
}
return offset / 100
}
export function applyPriceOffsetPercent(basePrice: number, offsetPercent?: number | null) {
const ratio = resolvePriceOffsetRatio(offsetPercent)
if (!ratio) {
return basePrice
}
return Math.round(basePrice * (1 + offset / 100))
return Math.round(basePrice * (1 + ratio))
}
/** boursecu chart: قیمت + (قیمت × offset) */
export function applyChartPriceOffset(basePrice: number, offsetPercent?: number | null) {
const ratio = resolvePriceOffsetRatio(offsetPercent)
if (!ratio) {
return basePrice
}
return Math.round(basePrice + basePrice * ratio)
}
/** قیمت خرید نمایشی محصول (همان مقداری که در لیست و اکشن‌شیت نشان داده می‌شود) */