mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-14 11:37:31 +08:00
41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
import { ref, onMounted, onBeforeUnmount, type Ref } from 'vue'
|
|
|
|
/**
|
|
* Reactive CSS media-query match.
|
|
*
|
|
* The query is evaluated synchronously when the composable is called, so the
|
|
* very first render already reflects the real viewport (no mount-time flash
|
|
* from a `false` default). The `change` listener is attached on mount and
|
|
* removed on unmount.
|
|
*
|
|
* @param query a CSS media query, e.g. `(max-width: 768px)`.
|
|
* @returns a readonly-by-convention ref that stays in sync with the query.
|
|
*/
|
|
export function useMediaQuery(query: string): Ref<boolean> {
|
|
const mql = typeof window !== 'undefined' && window.matchMedia
|
|
? window.matchMedia(query)
|
|
: null
|
|
const matches = ref(mql ? mql.matches : false)
|
|
|
|
function onChange(e: MediaQueryListEvent) {
|
|
matches.value = e.matches
|
|
}
|
|
|
|
onMounted(() => mql?.addEventListener('change', onChange))
|
|
onBeforeUnmount(() => mql?.removeEventListener('change', onChange))
|
|
|
|
return matches
|
|
}
|
|
|
|
/** App-wide breakpoints — keep in sync with the CSS `@media` rules. */
|
|
export const BREAKPOINTS = {
|
|
mobile: '(max-width: 768px)',
|
|
/** Narrow desktop — e.g. where the chat sidebar auto-collapses. */
|
|
compact: '(max-width: 1200px)',
|
|
} as const
|
|
|
|
/** True on viewports at or below the mobile breakpoint (≤ 768px). */
|
|
export function useIsMobile(): Ref<boolean> {
|
|
return useMediaQuery(BREAKPOINTS.mobile)
|
|
}
|