diff --git a/src/element/flyout.tsx b/src/element/flyout.tsx new file mode 100644 index 0000000..1c390d7 --- /dev/null +++ b/src/element/flyout.tsx @@ -0,0 +1,40 @@ +import { CSSProperties, ReactNode } from "react"; +import { IconButton } from "./buttons"; +import { createPortal } from "react-dom"; +import classNames from "classnames"; + +export default function Flyout({ + show, + children, + onClose, + side, +}: { + show: boolean; + children: ReactNode; + onClose: () => void; + side: "left" | "right"; +}) { + const styles = { + "--flyout-w": "200px", + transition: "all 0.2s ease-in-out", + transform: + side === "right" + ? `translate(${show ? "0" : "var(--flyout-w)"},0)` + : `translate(${show ? "0" : "calc(-1 * var(--flyout-w))"},0)`, + } as CSSProperties; + + return createPortal( +
+
+ + {children} +
+
, + document.body, + ) as React.ReactNode; +} diff --git a/src/pages/layout/header.tsx b/src/pages/layout/header.tsx index 41581cf..3f5e8b7 100644 --- a/src/pages/layout/header.tsx +++ b/src/pages/layout/header.tsx @@ -142,7 +142,7 @@ export function HeaderNav() { {layoutState.leftNav && ( { layoutState.update(c => { c.leftNavExpand = !c.leftNavExpand; diff --git a/src/pages/layout/left-nav.tsx b/src/pages/layout/left-nav.tsx index 537f4b1..e31b1fc 100644 --- a/src/pages/layout/left-nav.tsx +++ b/src/pages/layout/left-nav.tsx @@ -1,41 +1,77 @@ import { useLayout } from "./context"; import { NavLinkIcon } from "./nav-icon"; import { FormattedMessage } from "react-intl"; +import { useMediaQuery } from "usehooks-ts"; +import Flyout from "@/element/flyout"; export function LeftNav() { const layout = useLayout(); + const isDesktop = useMediaQuery("(min-width: 1280px)"); + const expandLabels = !isDesktop || layout.leftNavExpand; + + function hideAfterMobileNav() { + if (isDesktop) return; + layout.update(c => { + c.leftNavExpand = false; + return { ...c }; + }); + } if (layout.leftNav === false) return; - return ( -
- - {layout.leftNavExpand && ( - - - - )} - - - {layout.leftNavExpand && ( - - - - )} - - - {layout.leftNavExpand && ( - - - - )} - - - {layout.leftNavExpand && ( - - - - )} - -
- ); + function navInner() { + return ( +
+ + {expandLabels && ( + + + + )} + + + {expandLabels && ( + + + + )} + + + {expandLabels && ( + + + + )} + + + {expandLabels && ( + + + + )} + +
+ ); + } + + if (isDesktop) { + return navInner(); + } else { + return ( + { + layout.update(c => { + c.leftNavExpand = !c.leftNavExpand; + return { ...c }; + }); + }}> + {navInner()} + + ); + } } diff --git a/src/pages/stream-page.tsx b/src/pages/stream-page.tsx index c23006c..68c7c1f 100644 --- a/src/pages/stream-page.tsx +++ b/src/pages/stream-page.tsx @@ -1,6 +1,6 @@ import { NostrLink, TaggedNostrEvent } from "@snort/system"; import { Helmet } from "react-helmet"; -import { Suspense, lazy, useEffect } from "react"; +import { Suspense, lazy } from "react"; import { useMediaQuery } from "usehooks-ts"; const LiveVideoPlayer = lazy(() => import("@/element/stream/live-video-player")); @@ -12,7 +12,6 @@ import { ContentWarningOverlay, useContentWarning } from "@/element/nsfw"; import { useCurrentStreamFeed } from "@/hooks/current-stream-feed"; import { StreamState } from "@/const"; import { StreamInfo } from "@/element/stream/stream-info"; -import { useLayout } from "./layout/context"; import { StreamContextProvider } from "@/element/stream/stream-state"; export function StreamPage({ link, evPreload }: { evPreload?: TaggedNostrEvent; link: NostrLink }) { @@ -33,25 +32,6 @@ export function StreamPage({ link, evPreload }: { evPreload?: TaggedNostrEvent; const goal = useZapGoal(goalTag); const isDesktop = useMediaQuery("(min-width: 1280px)"); const isGrownUp = useContentWarning(); - const layout = useLayout(); - - useEffect(() => { - if (layout.leftNav) { - layout.update(c => { - c.leftNav = false; - return { ...c }; - }); - } - }, [layout]); - - useEffect(() => { - return () => { - layout.update(c => { - c.leftNav = true; - return { ...c }; - }); - }; - }, []); if (contentWarning && !isGrownUp) { return ;