You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

104 lines
1.9 KiB

// composables/useCartUI.ts
import { useMediaQuery } from '@vueuse/core'
/**
* Cart UI composable
*
* Manages cart sidebar/sheet UI state and responsive behavior
*
* Features:
* - Sidebar/sheet open/close state
* - Responsive detection (mobile vs desktop)
* - Body scroll lock when cart is open
* - Global state (shared across all components)
*
* Usage:
* const { isOpen, isMobile, open, close, toggle } = useCartUI()
*/
// Global cart UI state (shared across all components)
const isOpen = ref(false)
export function useCartUI() {
// Responsive breakpoint: mobile = width < 1024px (lg breakpoint)
const isMobile = useMediaQuery('(max-width: 1023px)')
/**
* Open cart sidebar/sheet
*/
function open() {
isOpen.value = true
lockBodyScroll()
}
/**
* Close cart sidebar/sheet
*/
function close() {
isOpen.value = false
unlockBodyScroll()
}
/**
* Toggle cart sidebar/sheet
*/
function toggle() {
if (isOpen.value) {
close()
} else {
open()
}
}
/**
* Lock body scroll (prevent scrolling when cart is open)
*/
function lockBodyScroll() {
if (import.meta.client) {
document.body.style.overflow = 'hidden'
}
}
/**
* Unlock body scroll
*/
function unlockBodyScroll() {
if (import.meta.client) {
document.body.style.overflow = ''
}
}
/**
* Clean up: Ensure body scroll is unlocked when component unmounts
*/
onUnmounted(() => {
unlockBodyScroll()
})
/**
* Watch for route changes: Close cart when navigating
*/
if (import.meta.client) {
const route = useRoute()
watch(
() => route.path,
() => {
if (isOpen.value) {
close()
}
}
)
}
return {
// State
isOpen: readonly(isOpen),
isMobile: readonly(isMobile),
// Methods
open,
close,
toggle,
}
}