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:
@@ -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'
|
||||
Reference in New Issue
Block a user