diff --git a/packages/www/src/components/Modal.tsx b/packages/www/src/components/Modal.tsx new file mode 100644 index 00000000..5886bbe4 --- /dev/null +++ b/packages/www/src/components/Modal.tsx @@ -0,0 +1,80 @@ +import { Component, JSX, Show, createSignal } from "solid-js"; +import { Portal } from "solid-js/web"; +import { styled } from "@macaron-css/solid"; +import { theme } from "@nestri/www/ui/theme"; + +const ModalContainer = styled("div", { + base: { + width: "100%", + maxWidth: 370, + maxHeight: "75vh", + height: "auto", + borderRadius: 12, + borderWidth: 1, + borderStyle: "solid", + borderColor: theme.color.gray.d400, + backgroundColor: theme.color.gray.d200, + boxShadow: theme.color.boxShadow, + backdropFilter: "blur(20px)", + padding: "20px 25px" + } +}) + +export interface ModalProps { + isOpen?: boolean; + onClose?: ((value: boolean) => void) | (() => void); + children: JSX.Element; + mountPoint?: HTMLElement; + containerClass?: string; + overlayClass?: string; +} + +export function createModalController() { + const [isOpen, setIsOpen] = createSignal(false); + + return { + isOpen, + open: () => setIsOpen(true), + close: () => setIsOpen(false), + toggle: () => setIsOpen(!isOpen()), + }; +} + +export const Modal: Component = (props) => { + const mountPoint = props.mountPoint || document.getElementById("styled") || document.body; + const isOpen = () => props.isOpen ?? false; + + const defaultOverlayStyle = ` + position: fixed; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0.5); + z-index: 50; + `; + + return ( + + +
{ + if (e.target === e.currentTarget && props.onClose) { + if (props.onClose.length > 0) { + (props.onClose as (value: boolean) => void)(false); + } else { + (props.onClose as () => void)(); + } + } + }} + > + + {props.children} + +
+
+
+ ); +}; diff --git a/packages/www/src/pages/play.tsx b/packages/www/src/pages/play.tsx index 6df0e5ca..91ba5102 100644 --- a/packages/www/src/pages/play.tsx +++ b/packages/www/src/pages/play.tsx @@ -8,6 +8,7 @@ import { Keyboard, Mouse, WebRTCStream } from "@nestri/input"; import { Container, FullScreen } from "@nestri/www/ui/layout"; import { styled } from "@macaron-css/solid"; import { lightClass, theme, darkClass } from "@nestri/www/ui/theme"; +import { Modal, createModalController } from "../components/Modal"; const Canvas = styled("canvas", { base: { @@ -19,22 +20,7 @@ const Canvas = styled("canvas", { } }); -const ModalContainer = styled("div", { - base: { - width: "100%", - maxWidth: 370, - maxHeight: "75vh", - height: "auto", - borderRadius: 12, - borderWidth: 1, - borderStyle: "solid", - borderColor: theme.color.gray.d400, - backgroundColor: theme.color.gray.d200, - boxShadow: theme.color.boxShadow, - backdropFilter: "blur(20px)", - padding: "20px 25px" - } -}) + const Button = styled("button", { base: { @@ -72,6 +58,7 @@ export function PlayComponent() { let nestriMouse: Mouse, nestriKeyboard: Keyboard; const { Modal, openModal } = createModal(); + const { WelcomeModal, openWelcomeModal } = createWelcomeModal(); const initializeInputDevices = () => { const canvasElement = canvas(); @@ -149,14 +136,17 @@ export function PlayComponent() { if (document.pointerLockElement === canvasElement) { initializeInputDevices(); } else { - - if (!showBannerModal) { + console.log("Pointer lock lost Show Banner Modal:", showBannerModal()); + if (!showBannerModal()) { + console.log("Pointer lock lost, showing banner"); const playing = sessionStorage.getItem("showedBanner"); setShowBannerModal(!playing || playing !== "true"); - if(!playing) { + openWelcomeModal(); + + if (playing) { + setShowButtonModal(true); openModal(); } - } @@ -202,11 +192,27 @@ export function PlayComponent() { setupPointerLockListener(); video = document.createElement("video"); video.style.visibility = "hidden"; - webrtc = new WebRTCStream("http://192.168.1.200:8088", id, async (mediaStream) => { + webrtc = new WebRTCStream("https://relay.dathorse.com", id, async (mediaStream) => { if (video && mediaStream) { video.srcObject = mediaStream; setHasStream(true); setShowOffline(false); + + const playing = sessionStorage.getItem("showedBanner") + console.log("Playing:", playing); + if (!playing || playing != "true") { + console.log("Showing banner: ", showBannerModal()); + if (!showBannerModal()) { + setShowBannerModal(false) + openWelcomeModal(); + } + } else { + if (!showButtonModal()) { + setShowButtonModal(true) + openModal(); + } + } + await handleVideoInput(); } else if (mediaStream === null) { console.log("MediaStream is null, Room is offline"); @@ -229,20 +235,27 @@ export function PlayComponent() { }); return ( - {showOffline() ? ( -
- Offline -
- ) : ( - - )} + {showOffline() ? ( +
+ Offline +
+ ) : ( + + )} + + -
+ setShow={setShowButtonModal} + closeOnBackdropClick={false} + handleVideoInput={handleVideoInput} + lockPlay={lockPlay} /> + ); } @@ -254,109 +267,60 @@ interface ModalProps { lockPlay?: () => Promise; } +type GameModalProps = ModalProps & { + handleVideoInput?: () => Promise; + lockPlay?: () => Promise; + setShow?: (show: boolean) => void; +} + function createWelcomeModal() { - const [open, setOpen] = createSignal(false); + const controller = createModalController(); return { - openWelcomeModal() { - setOpen(true); - }, - WelcomeModal(props: ModalProps) { + openWelcomeModal: controller.open, + WelcomeModal(props: GameModalProps) { return ( - - -
- -
- Happy that you use Nestri! - -
-
-
-
-
+ +
+ Happy that you use Nestri! + +
+
); }, }; } function createModal() { - const [open, setOpen] = createSignal(false); + const controller = createModalController(); return { - openModal() { - setOpen(true); - }, - Modal(props: ModalProps) { + openModal: controller.open, + Modal(props: GameModalProps) { return ( - - -
- -
- - -
-
-
-
-
+ +
+ + +
+
); }, }; -} - -function Modal(props: ModalProps) { - return ( - - - e.stopPropagation()} // Prevent closing when clicking inside modal - > -
-
- - -
-
-
- ); } \ No newline at end of file