Added media query awareness.
This commit is contained in:
+13
-1
@@ -3,6 +3,7 @@ import styles from "./App.module.css";
|
|||||||
import ColorPicker from "./components/ColorPicker/ColorPicker";
|
import ColorPicker from "./components/ColorPicker/ColorPicker";
|
||||||
import ColorValues from "./components/ColorValues/ColorValues";
|
import ColorValues from "./components/ColorValues/ColorValues";
|
||||||
import { LeftMenu, RightMenu } from "./components/SideMenu";
|
import { LeftMenu, RightMenu } from "./components/SideMenu";
|
||||||
|
import { useMediaQuery } from "./providers/hooks";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
// Menu Button Components
|
// Menu Button Components
|
||||||
@@ -133,22 +134,29 @@ function MobileContent({
|
|||||||
}: MenuStateProps) {
|
}: MenuStateProps) {
|
||||||
const toggleRightMenu = () => setIsRightMenuOpen(!isRightMenuOpen);
|
const toggleRightMenu = () => setIsRightMenuOpen(!isRightMenuOpen);
|
||||||
const toggleLeftMenu = () => setIsLeftMenuOpen(!isLeftMenuOpen);
|
const toggleLeftMenu = () => setIsLeftMenuOpen(!isLeftMenuOpen);
|
||||||
|
const { isMobilePortrait, isMobileLandscape } = useMediaQuery();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className={styles.mobileContent}>
|
<main className={styles.mobileContent}>
|
||||||
|
{isMobilePortrait && (
|
||||||
<MobileTopNav
|
<MobileTopNav
|
||||||
onLeftMenuClick={toggleLeftMenu}
|
onLeftMenuClick={toggleLeftMenu}
|
||||||
onRightMenuClick={toggleRightMenu}
|
onRightMenuClick={toggleRightMenu}
|
||||||
isLeftMenuOpen={isLeftMenuOpen}
|
isLeftMenuOpen={isLeftMenuOpen}
|
||||||
isRightMenuOpen={isRightMenuOpen}
|
isRightMenuOpen={isRightMenuOpen}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isMobileLandscape && (
|
||||||
<MobileLeftNav onClick={toggleLeftMenu} isOpen={isLeftMenuOpen} />
|
<MobileLeftNav onClick={toggleLeftMenu} isOpen={isLeftMenuOpen} />
|
||||||
|
)}
|
||||||
|
|
||||||
<MobileFirstZone />
|
<MobileFirstZone />
|
||||||
<MobileSecondZone />
|
<MobileSecondZone />
|
||||||
|
|
||||||
|
{isMobileLandscape && (
|
||||||
<MobileRightNav onClick={toggleRightMenu} isOpen={isRightMenuOpen} />
|
<MobileRightNav onClick={toggleRightMenu} isOpen={isRightMenuOpen} />
|
||||||
|
)}
|
||||||
|
|
||||||
<LeftMenu
|
<LeftMenu
|
||||||
isOpen={isLeftMenuOpen}
|
isOpen={isLeftMenuOpen}
|
||||||
@@ -220,16 +228,20 @@ function DesktopContent() {
|
|||||||
function App() {
|
function App() {
|
||||||
const [isRightMenuOpen, setIsRightMenuOpen] = useState(false);
|
const [isRightMenuOpen, setIsRightMenuOpen] = useState(false);
|
||||||
const [isLeftMenuOpen, setIsLeftMenuOpen] = useState(false);
|
const [isLeftMenuOpen, setIsLeftMenuOpen] = useState(false);
|
||||||
|
const { isDesktop } = useMediaQuery();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.appWrapper} role="application">
|
<div className={styles.appWrapper} role="application">
|
||||||
|
{!isDesktop && (
|
||||||
<MobileContent
|
<MobileContent
|
||||||
isLeftMenuOpen={isLeftMenuOpen}
|
isLeftMenuOpen={isLeftMenuOpen}
|
||||||
setIsLeftMenuOpen={setIsLeftMenuOpen}
|
setIsLeftMenuOpen={setIsLeftMenuOpen}
|
||||||
isRightMenuOpen={isRightMenuOpen}
|
isRightMenuOpen={isRightMenuOpen}
|
||||||
setIsRightMenuOpen={setIsRightMenuOpen}
|
setIsRightMenuOpen={setIsRightMenuOpen}
|
||||||
/>
|
/>
|
||||||
<DesktopContent />
|
)}
|
||||||
|
|
||||||
|
{isDesktop && <DesktopContent />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ import { StrictMode } from "react";
|
|||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
|
import { MediaQueryProvider } from "./providers";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
<MediaQueryProvider>
|
||||||
<App />
|
<App />
|
||||||
|
</MediaQueryProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { createContext, useState, useEffect } from "react";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
enum ViewportMode {
|
||||||
|
DESKTOP = "desktop",
|
||||||
|
MOBILE_LANDSCAPE = "mobile-landscape",
|
||||||
|
MOBILE_PORTRAIT = "mobile-portrait",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MediaQueryContextType {
|
||||||
|
viewportMode: ViewportMode;
|
||||||
|
isDesktop: boolean;
|
||||||
|
isMobileLandscape: boolean;
|
||||||
|
isMobilePortrait: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaQueryContext = createContext<MediaQueryContextType | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
function MediaQueryProvider({ children }: { children: ReactNode }) {
|
||||||
|
const [viewportMode, setViewportMode] = useState<ViewportMode>(
|
||||||
|
ViewportMode.DESKTOP,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const desktopQuery = window.matchMedia(
|
||||||
|
"(min-width: 992px), (min-width: 568px) and (max-width: 991px) and (orientation: portrait)",
|
||||||
|
);
|
||||||
|
const mobileLandscapeQuery = window.matchMedia(
|
||||||
|
"(min-width: 568px) and (max-width: 991px) and (orientation: landscape)",
|
||||||
|
);
|
||||||
|
const mobilePortraitQuery = window.matchMedia("(max-width: 567px)");
|
||||||
|
|
||||||
|
const updateViewportMode = () => {
|
||||||
|
if (desktopQuery.matches) {
|
||||||
|
setViewportMode(ViewportMode.DESKTOP);
|
||||||
|
} else if (mobileLandscapeQuery.matches) {
|
||||||
|
setViewportMode(ViewportMode.MOBILE_LANDSCAPE);
|
||||||
|
} else if (mobilePortraitQuery.matches) {
|
||||||
|
setViewportMode(ViewportMode.MOBILE_PORTRAIT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateViewportMode();
|
||||||
|
|
||||||
|
desktopQuery.addEventListener("change", updateViewportMode);
|
||||||
|
mobileLandscapeQuery.addEventListener("change", updateViewportMode);
|
||||||
|
mobilePortraitQuery.addEventListener("change", updateViewportMode);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
desktopQuery.removeEventListener("change", updateViewportMode);
|
||||||
|
mobileLandscapeQuery.removeEventListener("change", updateViewportMode);
|
||||||
|
mobilePortraitQuery.removeEventListener("change", updateViewportMode);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const isDesktop = viewportMode === ViewportMode.DESKTOP;
|
||||||
|
const isMobileLandscape = viewportMode === ViewportMode.MOBILE_LANDSCAPE;
|
||||||
|
const isMobilePortrait = viewportMode === ViewportMode.MOBILE_PORTRAIT;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MediaQueryContext.Provider
|
||||||
|
value={{
|
||||||
|
viewportMode,
|
||||||
|
isDesktop,
|
||||||
|
isMobileLandscape,
|
||||||
|
isMobilePortrait,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</MediaQueryContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MediaQueryProvider;
|
||||||
|
export { MediaQueryContext };
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { useContext } from "react";
|
||||||
|
import { MediaQueryContext } from "./MediaQueryProvider";
|
||||||
|
|
||||||
|
function useMediaQuery() {
|
||||||
|
const context = useContext(MediaQueryContext);
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error("useMediaQuery must be used within a MediaQueryProvider");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useMediaQuery };
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import MediaQueryProvider from "./MediaQueryProvider";
|
||||||
|
|
||||||
|
export { MediaQueryProvider };
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user