diff --git a/components.d.ts b/components.d.ts
index ef35dfd..ecd8d5f 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -14,6 +14,7 @@ declare module 'vue' {
AInput: typeof import('ant-design-vue/es')['Input']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AModal: typeof import('ant-design-vue/es')['Modal']
+ AppCreditLink: typeof import('./src/components/AppCreditLink.vue')['default']
ARadio: typeof import('ant-design-vue/es')['Radio']
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
@@ -69,6 +70,5 @@ declare module 'vue' {
TransactionSkeleton: typeof import('./src/components/TransactionSkeleton.vue')['default']
VanActionSheet: typeof import('vant/es')['ActionSheet']
VanDialog: typeof import('vant/es')['Dialog']
- VanField: typeof import('vant/es')['Field']
}
}
diff --git a/src/App.vue b/src/App.vue
index 87971a4..c2c9247 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -27,10 +27,13 @@
@@ -90,20 +93,16 @@
+
@@ -118,19 +117,28 @@ import img_bottomGradiant from '@/views/login/assets/img/gr_bottom_white.svg'
import {DotLottieVue} from '@lottiefiles/dotlottie-vue'
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import {useConfigStore} from "@/store/configStore";
-import {getProjectFontFamily, getProjectLoginLogo, getProjectSplashBackground, getProjectBrandRed, hasCustomLoginLogoLayout, isBoursecuProject, resetAppSurfaceBackground} from "@/utils/config";
+import {getProjectFontFamily, getProjectSplashBackground, getProjectSplashLogo, getProjectBrandRed, hasCustomLoginLogoLayout, isBoursecuProject, resetAppSurfaceBackground} from "@/utils/config";
import {ConfigProvider as AConfigProvider} from 'ant-design-vue'
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
-import { useApplyDesktopLayoutClass } from '@/layouts/composables/useAppLayout'
+import { useApplyDesktopLayoutClass, useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
import {
buildSupportMessengerUrl,
loadSupportMessengerFromSettings,
supportMessengerSettings,
} from '@/utils/supportMessenger'
-import {useDraggableFloatingButton} from '@/utils/useDraggableFloatingButton'
+import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
+import AppCreditLink from '@/components/AppCreditLink.vue'
+import { useRoute } from 'vue-router'
useApplyDesktopLayoutClass()
+const isDesktop = useDesktopBreakpoint()
+const route = useRoute()
+const showDesktopFloatingCredit = computed(() => {
+ if (!isDesktop.value) return false
+ return route.name === 'login' || !!route.meta.hideMenu
+})
+
const {offlineReady, needRefresh, updateServiceWorker} = useRegisterSW()
const config = useConfigStore()
const splashIndicator = computed(() => h(LoadingOutlined, {
@@ -310,16 +318,106 @@ function update() {
bottom: 0;
left: 0;
right: 0;
+ z-index: 1000000;
+ box-sizing: content-box;
+}
+
+.app-credit-footer--mobile {
width: 100%;
max-width: 426px;
margin-left: auto;
margin-right: auto;
- z-index: 1000000;
min-height: var(--app-credit-bar-inner);
padding-bottom: var(--app-safe-bottom);
- box-sizing: content-box;
background: #fff;
box-shadow: 0 -2px 4px -2px #0000001a;
+ display: flex;
+ justify-content: center;
+ font-size: 9px;
+}
+
+.app-credit-footer--desktop-float {
+ left: auto;
+ right: 20px;
+ bottom: 16px;
+ width: auto;
+}
+
+.app-credit-link {
+ display: inline-flex;
+ align-items: center;
+ text-decoration: none;
+ color: inherit;
+ transition: opacity 0.15s ease;
+
+ &:hover {
+ opacity: 0.85;
+ }
+
+ &__text {
+ font-weight: 500;
+ white-space: nowrap;
+ }
+
+ &__logo {
+ width: auto;
+ object-fit: contain;
+ }
+
+ &--mobile {
+ gap: 4px;
+ padding: 4px 0;
+ color: inherit;
+
+ .app-credit-link__logo {
+ height: 12px;
+ }
+ }
+
+ &--sidebar {
+ flex-direction: column;
+ gap: 6px;
+ padding: 4px;
+ color: #9ca3af;
+ font-size: 10px;
+
+ .app-credit-link__logo {
+ height: 15px;
+ opacity: 0.85;
+ }
+ }
+
+ &--float {
+ gap: 6px;
+ padding: 7px 14px;
+ font-size: 10px;
+ color: #6b7280;
+ background: #fff;
+ border-radius: 999px;
+ border: 1px solid rgba(15, 23, 42, 0.08);
+ box-shadow: 0 2px 10px rgba(15, 23, 42, 0.06);
+
+ .app-credit-link__logo {
+ height: 13px;
+ }
+ }
+}
+
+html.project-boursecu {
+ .app-credit-link--sidebar {
+ color: rgba(255, 255, 255, 0.5);
+
+ .app-credit-link__logo {
+ filter: brightness(1.15);
+ opacity: 0.75;
+ }
+ }
+
+ .app-credit-link--float {
+ background: var(--App-brand-nav, #133050);
+ border-color: rgba(255, 255, 255, 0.1);
+ color: rgba(255, 255, 255, 0.65);
+ }
}
.updateButton .van-dialog__confirm .van-button__text {
diff --git a/src/assets/img/boursemes-login.png b/src/assets/img/boursemes-login.png
new file mode 100644
index 0000000..d19c776
Binary files /dev/null and b/src/assets/img/boursemes-login.png differ
diff --git a/src/assets/img/boursemes-splash.png b/src/assets/img/boursemes-splash.png
new file mode 100644
index 0000000..1ec4e91
Binary files /dev/null and b/src/assets/img/boursemes-splash.png differ
diff --git a/src/components/AppCreditLink.vue b/src/components/AppCreditLink.vue
new file mode 100644
index 0000000..7bfcc89
--- /dev/null
+++ b/src/components/AppCreditLink.vue
@@ -0,0 +1,21 @@
+
+
+ توسعه و طراحی توسط
+
+
+
+
+
diff --git a/src/composables/useProductsCatalog.ts b/src/composables/useProductsCatalog.ts
index bdb24ce..eff8aa1 100644
--- a/src/composables/useProductsCatalog.ts
+++ b/src/composables/useProductsCatalog.ts
@@ -1,13 +1,18 @@
+import { ref } from 'vue'
import { getProducts } from '@/api/products'
import type { Product } from '@/models/products'
/** Shared product catalog — dedupes getProducts() across wallet assets and chart offset. */
-let catalogCache: Product[] | null = null
+const catalogProducts = ref([])
let catalogPromise: Promise | null = null
+export function getProductsCatalogRef() {
+ return catalogProducts
+}
+
export function getProductsCatalog(force = false): Promise {
- if (!force && catalogCache) {
- return Promise.resolve(catalogCache)
+ if (!force && catalogProducts.value.length > 0) {
+ return Promise.resolve(catalogProducts.value)
}
if (!force && catalogPromise) {
@@ -16,8 +21,8 @@ export function getProductsCatalog(force = false): Promise {
catalogPromise = getProducts()
.then((products) => {
- catalogCache = products ?? []
- return catalogCache
+ catalogProducts.value = products ?? []
+ return catalogProducts.value
})
.finally(() => {
catalogPromise = null
@@ -27,6 +32,6 @@ export function getProductsCatalog(force = false): Promise {
}
export function clearProductsCatalog() {
- catalogCache = null
+ catalogProducts.value = []
catalogPromise = null
}
diff --git a/src/layouts/desktop/DesktopSidebar.vue b/src/layouts/desktop/DesktopSidebar.vue
index 1f79045..caf48a5 100644
--- a/src/layouts/desktop/DesktopSidebar.vue
+++ b/src/layouts/desktop/DesktopSidebar.vue
@@ -34,20 +34,25 @@
@click="navigateTo(item.routeName)"
/>
+
+
+
+
diff --git a/src/views/base/home/components/CurrentPrice.vue b/src/views/base/home/components/CurrentPrice.vue
index a9c6ac2..3ff433c 100644
--- a/src/views/base/home/components/CurrentPrice.vue
+++ b/src/views/base/home/components/CurrentPrice.vue
@@ -20,7 +20,7 @@
ریال
diff --git a/src/views/base/home/components/PriceStats.vue b/src/views/base/home/components/PriceStats.vue
index 2862caa..be49183 100644
--- a/src/views/base/home/components/PriceStats.vue
+++ b/src/views/base/home/components/PriceStats.vue
@@ -2,7 +2,7 @@
@@ -33,31 +33,28 @@
diff --git a/src/views/base/home/desktop/components/DesktopLivePrice.vue b/src/views/base/home/desktop/components/DesktopLivePrice.vue
index a69174f..09939f0 100644
--- a/src/views/base/home/desktop/components/DesktopLivePrice.vue
+++ b/src/views/base/home/desktop/components/DesktopLivePrice.vue
@@ -13,7 +13,7 @@
ریال
diff --git a/src/views/base/home/desktop/components/DesktopPriceOverview.vue b/src/views/base/home/desktop/components/DesktopPriceOverview.vue
index 8a2468c..13de215 100644
--- a/src/views/base/home/desktop/components/DesktopPriceOverview.vue
+++ b/src/views/base/home/desktop/components/DesktopPriceOverview.vue
@@ -1,13 +1,7 @@
@@ -17,7 +11,7 @@ const statsLayout = computed(() => (toValue(ctx.isBoursecuHomeLayout) ? 'boursec
-
+
diff --git a/src/views/base/home/layouts/HomeLayoutRenderer.vue b/src/views/base/home/layouts/HomeLayoutRenderer.vue
index d695353..f4cd6b4 100644
--- a/src/views/base/home/layouts/HomeLayoutRenderer.vue
+++ b/src/views/base/home/layouts/HomeLayoutRenderer.vue
@@ -52,5 +52,5 @@ function resolveSectionComponent(sectionId: HomeSectionId) {
-
+
diff --git a/src/views/base/home/layouts/sections/PriceStatsSection.vue b/src/views/base/home/layouts/sections/PriceStatsSection.vue
index 5d17187..a6a1aeb 100644
--- a/src/views/base/home/layouts/sections/PriceStatsSection.vue
+++ b/src/views/base/home/layouts/sections/PriceStatsSection.vue
@@ -1,21 +1,7 @@
-
+
diff --git a/src/views/login/desktop/components/DesktopAuthShell.vue b/src/views/login/desktop/components/DesktopAuthShell.vue
index 123185d..13955a9 100644
--- a/src/views/login/desktop/components/DesktopAuthShell.vue
+++ b/src/views/login/desktop/components/DesktopAuthShell.vue
@@ -37,8 +37,8 @@ import pkg from '../../../../../package.json'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { useConfigStore } from '@/store/configStore'
import {
- getProjectLoginLogo,
getProjectLoginTaglineLines,
+ getProjectSplashLogo,
hasCustomLoginLogoLayout,
isBoursecuProject,
} from '@/utils/config'
@@ -48,7 +48,7 @@ const isBoursecu = isBoursecuProject()
const hasCustomLayout = hasCustomLoginLogoLayout()
const version = pkg.version
-const logo = computed(() => getProjectLoginLogo(config.config?.avatar))
+const logo = computed(() => getProjectSplashLogo(config.config?.avatar))
const taglineLines = computed(() => getProjectLoginTaglineLines())
const tagline = computed(() => {
diff --git a/src/views/login/desktop/styles/desktop-auth.less b/src/views/login/desktop/styles/desktop-auth.less
index 5bfbcb6..1e06014 100644
--- a/src/views/login/desktop/styles/desktop-auth.less
+++ b/src/views/login/desktop/styles/desktop-auth.less
@@ -27,9 +27,9 @@
&--boursecu {
.dauth-brand__logo {
- max-width: 300px;
- max-height: 110px;
- width: 100%;
+ max-width: 280px;
+ max-height: 280px;
+ width: min(100%, 280px);
object-fit: contain;
}
}