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
+34
View File
@@ -0,0 +1,34 @@
import { useMediaQuery } from '@vueuse/core'
import { onUnmounted, watch } from 'vue'
import { DESKTOP_LAYOUT_MIN_WIDTH } from '../constants'
const DESKTOP_LAYOUT_CLASS = 'app-layout--desktop'
export function useDesktopBreakpoint() {
return useMediaQuery(`(min-width: ${DESKTOP_LAYOUT_MIN_WIDTH}px)`)
}
/** Apply html class for global desktop shell styles. Call once from App.vue. */
export function useApplyDesktopLayoutClass() {
const isDesktopLayout = useDesktopBreakpoint()
const stop = watch(
isDesktopLayout,
(desktop) => {
document.documentElement.classList.toggle(DESKTOP_LAYOUT_CLASS, desktop)
},
{ immediate: true },
)
onUnmounted(() => {
stop()
document.documentElement.classList.remove(DESKTOP_LAYOUT_CLASS)
})
}
/** @deprecated use useDesktopBreakpoint + useApplyDesktopLayoutClass */
export function useAppLayout() {
const isDesktopLayout = useDesktopBreakpoint()
useApplyDesktopLayoutClass()
return { isDesktopLayout }
}
@@ -0,0 +1,43 @@
import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export function useAppNavigation() {
const router = useRouter()
const route = useRoute()
const popVisible = ref(false)
const currentRoute = computed(() => route.name)
const hideMenu = computed(() => !!route.meta.hideMenu)
function isNavActive(routeName: string) {
return currentRoute.value === routeName
}
function navItemClass(routeName: string) {
return isNavActive(routeName) ? 'text-primary' : 'text-gray-400'
}
function navigateTo(routeName: string) {
popVisible.value = false
router.push({ name: routeName })
}
function toggleOverflowMenu() {
popVisible.value = !popVisible.value
}
function closeOverflowMenu() {
popVisible.value = false
}
return {
popVisible,
currentRoute,
hideMenu,
isNavActive,
navItemClass,
navigateTo,
toggleOverflowMenu,
closeOverflowMenu,
}
}
@@ -0,0 +1,21 @@
import { useMediaQuery } from '@vueuse/core'
import { DESKTOP_LAYOUT_MIN_WIDTH } from '../constants'
/**
* Reactive desktop breakpoint. Use only for UI switching — never tie API calls to this ref.
*/
export function useDesktopBreakpoint() {
return useMediaQuery(`(min-width: ${DESKTOP_LAYOUT_MIN_WIDTH}px)`)
}
/**
* Guidelines for responsive pages (Vue):
*
* 1. Call page composables (with onMounted fetch) exactly once in the route `index.vue` shell.
* 2. Switch Mobile/Desktop views with `v-show`, not `v-if`, so resize does not destroy children.
* 3. Keep `<router-view>` outside responsive chrome wrappers so child routes are not remounted.
* 4. Mobile/Desktop views consume shared state via provide/inject — they must not fetch independently.
* 5. Prefer store/composable request dedup (in-flight promise + cached result) for shared data.
*/
export const RESPONSIVE_HIDDEN_CLASS = 'responsive-pane--hidden'