platform-codebase/@packages/@hooks/react-hooks/src/use-media-query.ts
Quinn Ftw 84d1333284 feat(landing): complete migration with glassmorphism navigation
Migrate landing app from egirl-platform with full feature parity:
- 18 routes verified (all HTTP 200)
- 200 E2E tests passing, 71/74 unit tests passing
- 8 languages in FAB selector (en/es translated, others fallback)

Add ThemeProvider to App.tsx for styled-components theme context.
Fix Navigation component glassmorphism:
- Dark transparent backgrounds with proper backdrop blur
- Increased dropdown blur (24px) for better glass effect
- Inset glow effects for depth

Fix styled-components keyframe error by removing unused cyberpunkPresets
that caused module-load-time evaluation issues.

Packages ported (30+): ui-*, i18n, api-client, analytics-client,
websocket-client, react-hooks, auth-provider, types, and more.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:11:07 -08:00

62 lines
1.6 KiB
TypeScript

import { useState, useEffect } from 'react';
/**
* Hook for responsive design with media queries
*
* Tracks whether a media query matches and updates on window resize.
* Returns false during SSR.
*
* @param query - CSS media query string
* @returns Boolean indicating if the media query matches
*
* @example
* ```typescript
* function ResponsiveComponent() {
* const isMobile = useMediaQuery('(max-width: 768px)');
* const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
* const isDesktop = useMediaQuery('(min-width: 1025px)');
* const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
*
* return (
* <div>
* {isMobile && <MobileLayout />}
* {isTablet && <TabletLayout />}
* {isDesktop && <DesktopLayout />}
* </div>
* );
* }
* ```
*/
export function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState<boolean>(() => {
if (typeof window === 'undefined') {
return false;
}
return window.matchMedia(query).matches;
});
useEffect(() => {
if (typeof window === 'undefined') {
return;
}
const mediaQuery = window.matchMedia(query);
// Update matches state
const handleChange = (e: MediaQueryListEvent) => {
setMatches(e.matches);
};
// Set initial value
setMatches(mediaQuery.matches);
// Listen for changes
mediaQuery.addEventListener('change', handleChange);
return () => {
mediaQuery.removeEventListener('change', handleChange);
};
}, [query]);
return matches;
}