Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x 25x 25x 25x 25x 7x 25x 25x 25x 14x 7x 7x 7x 7x 7x 7x 7x 7x 1x 1x 7x 7x 7x 7x 7x 7x 7x 25x 25x 25x 25x 1x 1x 1x 1x 1x 3x 3x 1x 1x 3x 3x 1x 1x 3x 3x | 'use client'
import { useEffect, useState } from 'react'
/**
* Hook to detect media query matches
* @param query - CSS media query string (e.g., '(min-width: 768px)')
* @returns boolean indicating if the query matches
*/
export function useMediaQuery(query: string): boolean {
// Initialize with false to avoid hydration mismatch
const [matches, setMatches] = useState(false)
const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
useEffect(() => {
if (!isClient) return
const mediaQuery = window.matchMedia(query)
// Set initial value
setMatches(mediaQuery.matches)
// Create event listener
const handler = (event: MediaQueryListEvent) => {
setMatches(event.matches)
}
// Modern browsers
mediaQuery.addEventListener('change', handler)
return () => {
mediaQuery.removeEventListener('change', handler)
}
}, [query, isClient])
return matches
}
/**
* Common breakpoint hooks
*/
export function useIsMobile(): boolean {
return useMediaQuery('(max-width: 767px)')
}
export function useIsTablet(): boolean {
return useMediaQuery('(min-width: 768px) and (max-width: 1023px)')
}
export function useIsDesktop(): boolean {
return useMediaQuery('(min-width: 1024px)')
}
|