fix: Colors

This commit is contained in:
Wanjohi
2025-03-03 23:36:18 +03:00
parent c994dc112c
commit 1e78238593
4 changed files with 311 additions and 270 deletions

View File

@@ -14,6 +14,7 @@ import { AuthProvider, useAuth } from './providers/auth';
import { Navigate, Route, Router } from "@solidjs/router"; import { Navigate, Route, Router } from "@solidjs/router";
import { globalStyle, macaron$ } from "@macaron-css/core"; import { globalStyle, macaron$ } from "@macaron-css/core";
import { Component, createSignal, Match, onCleanup, Switch } from 'solid-js'; import { Component, createSignal, Match, onCleanup, Switch } from 'solid-js';
import TestComponent from './pages/test';
const Root = styled("div", { const Root = styled("div", {
base: { base: {
@@ -87,12 +88,14 @@ export const App: Component = () => {
<Route <Route
path="*" path="*"
component={(props) => ( component={(props) => (
<AuthProvider> // <AuthProvider>
{props.children} // {props.children}
</AuthProvider> props.children
// </AuthProvider>
)} )}
> >
<Route path="play/:id" component={PlayComponent} /> <Route path="play/:id" component={PlayComponent} />
<Route path="test" component={TestComponent} />
<Route <Route
path="/" path="/"
component={() => { component={() => {

View File

@@ -8,7 +8,7 @@ import { render } from "solid-js/web";
import "modern-normalize/modern-normalize.css"; import "modern-normalize/modern-normalize.css";
import { App } from "./App"; import { App } from "./App";
import { StorageProvider } from "./providers/account"; import { StorageProvider } from "./providers/account";
import { ToastProvider, Toaster } from "solid-notifications"; // import { ToastProvider, Toaster } from "solid-notifications";
const root = document.getElementById("root"); const root = document.getElementById("root");
@@ -20,12 +20,12 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
render( render(
() => ( () => (
<ToastProvider> // <ToastProvider>
<Toaster /> // <Toaster />
<StorageProvider> <StorageProvider>
<App /> <App />
</StorageProvider> </StorageProvider>
</ToastProvider> // </ToastProvider>
), ),
root! root!
); );

View File

@@ -1,11 +1,11 @@
import { Text } from "@nestri/www/ui/text"; import { Text } from "@nestri/www/ui/text";
import { createSignal, createEffect, onCleanup, onMount, Show} from "solid-js"; import { createSignal, createEffect, onCleanup, onMount, Show } from "solid-js";
import { Portal } from "solid-js/web"; import { Portal } from "solid-js/web";
import { useParams } from "@solidjs/router"; import { useParams } from "@solidjs/router";
import { Keyboard, Mouse, WebRTCStream } from "@nestri/input"; import { Keyboard, Mouse, WebRTCStream } from "@nestri/input";
import { Container, FullScreen } from "@nestri/www/ui/layout"; import { Container, FullScreen } from "@nestri/www/ui/layout";
import { styled } from "@macaron-css/solid"; import { styled } from "@macaron-css/solid";
import { theme } from "../ui/theme"; import { lightClass, theme, darkClass } from "@nestri/www/ui/theme";
const Canvas = styled("canvas", { const Canvas = styled("canvas", {
base: { base: {
@@ -14,289 +14,309 @@ const Canvas = styled("canvas", {
height: "100%", height: "100%",
objectFit: "contain", objectFit: "contain",
maxHeight: "100vh", maxHeight: "100vh",
}}); }
});
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.pink.d400,
backgroundColor: theme.color.red.d300,
// boxShadow: theme.color.boxShadow,
// backdropFilter: "blur(20px)",
padding: "20px 25px"
}
})
const ModalContainer = styled("div", {
base: {
width: "100%",
maxWidth: 370,
maxHeight: "75vh",
borderRadius: 12,
borderWidth: 1,
borderStyle: "solid",
borderColor: theme.color.gray.d400,
backgroundColor: theme.color.pink.d400,
boxShadow: theme.color.boxShadow,
backdropFilter: "blur(20px)",
padding: "20px 25px"
}
})
export function PlayComponent() { export function PlayComponent() {
const params = useParams(); const params = useParams();
const id = params.id; const id = params.id;
const [showBannerModal, setShowBannerModal] = createSignal(false);
const [showButtonModal, setShowButtonModal] = createSignal(false);
const [gamepadConnected, setGamepadConnected] = createSignal(false);
const [buttonPressed, setButtonPressed] = createSignal(null);
const [leftStickX, setLeftStickX] = createSignal(0);
const [leftStickY, setLeftStickY] = createSignal(0);
const [hasStream, setHasStream] = createSignal(false);
const [nestriLock, setNestriLock] = createSignal(false);
const [showOffline, setShowOffline] = createSignal(false);
const [canvas, setCanvas] = createSignal<HTMLCanvasElement | undefined>(undefined);
let video: HTMLVideoElement;
let webrtc: WebRTCStream;
let nestriMouse: Mouse , nestriKeyboard: Keyboard;
const initializeInputDevices = () => {
const canvasElement = canvas();
if (!canvasElement || !webrtc) return;
try {
nestriMouse = new Mouse({ canvas: canvasElement, webrtc });
nestriKeyboard = new Keyboard({ canvas: canvasElement, webrtc });
console.log("Input devices initialized successfully");
} catch (error) {
console.error("Failed to initialize input devices:", error);
}
};
/*const initializeGamepad = () => {
console.log("Initializing gamepad...");
const updateGamepadState = () => {
const gamepads = navigator.getGamepads();
const gamepad = gamepads[0];
if (gamepad) {
setButtonPressed(gamepad.buttons.findIndex(btn => btn.pressed) !== -1 ? "Button pressed" : null);
setLeftStickX(Number(gamepad.axes[0].toFixed(2)));
setLeftStickY(Number(gamepad.axes[1].toFixed(2)));
}
requestAnimationFrame(updateGamepadState);
};
window.addEventListener("gamepadconnected", () => {
setGamepadConnected(true);
console.log("Gamepad connected!");
updateGamepadState();
});
window.addEventListener("gamepaddisconnected", () => {
setGamepadConnected(false);
console.log("Gamepad disconnected!");
});
};*/
const lockPlay = async () => {
const canvasElement = canvas();
if (!canvasElement || !hasStream()) return;
try {
await canvasElement.requestPointerLock();
await canvasElement.requestFullscreen();
//initializeGamepad();
if (document.fullscreenElement !== null) {
if ('keyboard' in navigator && 'lock' in (navigator.keyboard as any)) {
const keys = [
"AltLeft", "AltRight", "Tab", "Escape",
"ContextMenu", "MetaLeft", "MetaRight"
];
try { const [showBannerModal, setShowBannerModal] = createSignal(false);
await (navigator.keyboard as any).lock(keys); const [showButtonModal, setShowButtonModal] = createSignal(false);
setNestriLock(true); const [gamepadConnected, setGamepadConnected] = createSignal(false);
console.log("Keyboard lock acquired"); const [buttonPressed, setButtonPressed] = createSignal(null);
} catch (e) { const [leftStickX, setLeftStickX] = createSignal(0);
console.warn("Keyboard lock failed:", e); const [leftStickY, setLeftStickY] = createSignal(0);
setNestriLock(false); const [hasStream, setHasStream] = createSignal(false);
} const [nestriLock, setNestriLock] = createSignal(false);
} const [showOffline, setShowOffline] = createSignal(false);
}
const [canvas, setCanvas] = createSignal<HTMLCanvasElement | undefined>(undefined);
} catch (error) { let video: HTMLVideoElement;
console.error("Error during lock sequence:", error); let webrtc: WebRTCStream;
} let nestriMouse: Mouse, nestriKeyboard: Keyboard;
};
const initializeInputDevices = () => {
const setupPointerLockListener = () => { const canvasElement = canvas();
document.addEventListener("pointerlockchange", () => { if (!canvasElement || !webrtc) return;
const canvasElement = canvas(); try {
if (!canvasElement) return; nestriMouse = new Mouse({ canvas: canvasElement, webrtc });
if (document.pointerLockElement === canvasElement) { nestriKeyboard = new Keyboard({ canvas: canvasElement, webrtc });
initializeInputDevices(); console.log("Input devices initialized successfully");
} else { } catch (error) {
console.error("Failed to initialize input devices:", error);
if (!showBannerModal) { }
const playing = sessionStorage.getItem("showedBanner"); };
setShowBannerModal(!playing || playing !== "true");
setShowButtonModal(playing === "false"); /*const initializeGamepad = () => {
console.log("Initializing gamepad...");
const updateGamepadState = () => {
const gamepads = navigator.getGamepads();
const gamepad = gamepads[0];
if (gamepad) {
setButtonPressed(gamepad.buttons.findIndex(btn => btn.pressed) !== -1 ? "Button pressed" : null);
setLeftStickX(Number(gamepad.axes[0].toFixed(2)));
setLeftStickY(Number(gamepad.axes[1].toFixed(2)));
}
requestAnimationFrame(updateGamepadState);
};
window.addEventListener("gamepadconnected", () => {
setGamepadConnected(true);
console.log("Gamepad connected!");
updateGamepadState();
});
window.addEventListener("gamepaddisconnected", () => {
setGamepadConnected(false);
console.log("Gamepad disconnected!");
});
};*/
const lockPlay = async () => {
const canvasElement = canvas();
if (!canvasElement || !hasStream()) return;
try {
await canvasElement.requestPointerLock();
await canvasElement.requestFullscreen();
//initializeGamepad();
if (document.fullscreenElement !== null) {
if ('keyboard' in navigator && 'lock' in (navigator.keyboard as any)) {
const keys = [
"AltLeft", "AltRight", "Tab", "Escape",
"ContextMenu", "MetaLeft", "MetaRight"
];
try {
await (navigator.keyboard as any).lock(keys);
setNestriLock(true);
console.log("Keyboard lock acquired");
} catch (e) {
console.warn("Keyboard lock failed:", e);
setNestriLock(false);
} }
nestriKeyboard?.dispose();
nestriMouse?.dispose();
} }
}); }
};
const handleVideoInput = async () => { } catch (error) {
const canvasElement = canvas(); console.error("Error during lock sequence:", error);
if (!video || !canvasElement) return; }
};
try {
const setupPointerLockListener = () => {
await video.play(); document.addEventListener("pointerlockchange", () => {
if (canvasElement && video) {
canvasElement.width = video.videoWidth;
canvasElement.height = video.videoHeight;
const ctx = canvasElement.getContext("2d");
const renderer = () => {
if (ctx && hasStream() && video) {
ctx.drawImage(video, 0, 0);
video.requestVideoFrameCallback(renderer);
}
};
video.requestVideoFrameCallback(renderer);
}
} catch (error) {
console.error("Error playing video:", error);
}
};
onMount(() => {
const canvasElement = canvas(); const canvasElement = canvas();
if(!canvasElement) return; if (!canvasElement) return;
if (document.pointerLockElement === canvasElement) {
initializeInputDevices();
} else {
setupPointerLockListener(); if (!showBannerModal) {
video = document.createElement("video"); const playing = sessionStorage.getItem("showedBanner");
video.style.visibility = "hidden"; setShowBannerModal(!playing || playing !== "true");
webrtc = new WebRTCStream("http://192.168.1.200:8088", id, async (mediaStream) => { setShowButtonModal(playing === "false");
if (video && mediaStream) {
video.srcObject = mediaStream;
setHasStream(true);
setShowOffline(false);
await handleVideoInput();
} else if (mediaStream === null) {
console.log("MediaStream is null, Room is offline");
setShowOffline(true);
setHasStream(false);
const ctx = canvasElement.getContext("2d");
if (ctx) ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
} else if (video && video.srcObject !== null) {
setHasStream(true);
setShowOffline(true);
await handleVideoInput();
} }
});
});
onCleanup(() => {
nestriKeyboard?.dispose();
nestriMouse?.dispose();
});
const { Modal, openModal } = createModal();
return (
<>
nestriKeyboard?.dispose();
nestriMouse?.dispose();
}
});
};
const handleVideoInput = async () => {
const canvasElement = canvas();
if (!video || !canvasElement) return;
try {
await video.play();
if (canvasElement && video) {
canvasElement.width = video.videoWidth;
canvasElement.height = video.videoHeight;
const ctx = canvasElement.getContext("2d");
const renderer = () => {
if (ctx && hasStream() && video) {
ctx.drawImage(video, 0, 0);
video.requestVideoFrameCallback(renderer);
}
};
video.requestVideoFrameCallback(renderer);
}
} catch (error) {
console.error("Error playing video:", error);
}
};
onMount(() => {
const canvasElement = canvas();
if (!canvasElement) return;
setupPointerLockListener();
video = document.createElement("video");
video.style.visibility = "hidden";
webrtc = new WebRTCStream("http://192.168.1.200:8088", id, async (mediaStream) => {
if (video && mediaStream) {
video.srcObject = mediaStream;
setHasStream(true);
setShowOffline(false);
await handleVideoInput();
} else if (mediaStream === null) {
console.log("MediaStream is null, Room is offline");
setShowOffline(true);
setHasStream(false);
const ctx = canvasElement.getContext("2d");
if (ctx) ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
} else if (video && video.srcObject !== null) {
setHasStream(true);
setShowOffline(true);
await handleVideoInput();
}
});
});
onCleanup(() => {
nestriKeyboard?.dispose();
nestriMouse?.dispose();
});
const { Modal, openModal } = createModal();
return (
<>
<button type="button" onClick={openModal}> <button type="button" onClick={openModal}>
open modal open modal
</button> </button>
<Modal /> <Modal />
</> </>
/*<FullScreen> /*<FullScreen>
{showOffline() ? ( {showOffline() ? (
<div class="w-screen h-screen flex justify-center items-center"> <div class="w-screen h-screen flex justify-center items-center">
<span class="text-2xl font-semibold flex items-center gap-2">Offline</span> <span class="text-2xl font-semibold flex items-center gap-2">Offline</span>
<button onClick={() =>setShowButtonModal(true)}>Show Modal</button> <button onClick={() =>setShowButtonModal(true)}>Show Modal</button>
</div> </div>
) : ( ) : (
<Canvas ref={setCanvas} onClick={lockPlay}/> <Canvas ref={setCanvas} onClick={lockPlay}/>
)} )}
<Modal show={showButtonModal} <Modal show={showButtonModal}
setShow={setShowButtonModal} setShow={setShowButtonModal}
closeOnBackdropClick={false} closeOnBackdropClick={false}
handleVideoInput={handleVideoInput} handleVideoInput={handleVideoInput}
lockPlay={lockPlay} /> lockPlay={lockPlay} />
</FullScreen>*/ </FullScreen>*/
); );
} }
interface ModalProps { interface ModalProps {
show: () => boolean; show: () => boolean;
setShow: (value: boolean) => void; setShow: (value: boolean) => void;
closeOnBackdropClick?: boolean; closeOnBackdropClick?: boolean;
handleVideoInput?: () => Promise<void>; handleVideoInput?: () => Promise<void>;
lockPlay?: () => Promise<void>; lockPlay?: () => Promise<void>;
} }
function createModal() { function createModal() {
const [open, setOpen] = createSignal(false); const [open, setOpen] = createSignal(false);
const [theme, setTheme] = createSignal<string>(
return { window.matchMedia("(prefers-color-scheme: dark)").matches
openModal() { ? "dark"
setOpen(true); : "light",
}, );
Modal() {
return ( const darkMode = window.matchMedia("(prefers-color-scheme: dark)");
<Portal> const setColorScheme = (e: MediaQueryListEvent) => {
<Show when={open()}> setTheme(e.matches ? "dark" : "light");
<div };
style={` darkMode.addEventListener("change", setColorScheme);
onCleanup(() => {
darkMode.removeEventListener("change", setColorScheme);
});
return {
openModal() {
setOpen(true);
},
Modal() {
return (
<Portal>
<Show when={open()}>
<div
class={theme() === "light" ? lightClass : darkClass} id="styled"
style={`
position: absolute; position: absolute;
inset: 0; inset: 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
`} `}
> >
<ModalContainer> <ModalContainer>
Hello from modal <br /> Hello from modal <br />
<button onClick={() => setOpen(false)}>close modal</button> <button onClick={() => setOpen(false)}>close modal</button>
</ModalContainer> </ModalContainer>
</div>
</Show>
</Portal>
);
},
};
}
function Modal(props: ModalProps) {
return (
<ModalContainer
onClick={(e) => e.stopPropagation()} // Prevent closing when clicking inside modal
>
<div class="size-full flex flex-col">
<div class="flex flex-col gap-3">
<button
class="transition-all duration-200 focus:ring-2 focus:ring-gray-300 focus:dark:ring-gray-700 outline-none w-full hover:bg-gray-300 hover:dark:bg-gray-700 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 items-center justify-center font-medium font-title rounded-lg flex py-3 px-4"
onClick={async () => {
props.setShow(false);
sessionStorage.setItem("showedBanner", "true");
await props.handleVideoInput?.();
await props.lockPlay?.();
}}
>
Continue Playing
</button>
<button
class="transition-all duration-200 focus:ring-2 focus:ring-gray-300 focus:dark:ring-gray-700 outline-none w-full hover:bg-gray-300 hover:dark:bg-gray-700 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 items-center justify-center font-medium font-title rounded-lg flex py-3 px-4"
>
Shutdown Nestri
</button>
</div>
</div> </div>
</ModalContainer> </Show>
); </Portal>
} );
},
};
}
function Modal(props: ModalProps) {
return (
<ModalContainer
onClick={(e) => e.stopPropagation()} // Prevent closing when clicking inside modal
>
<div class="size-full flex flex-col">
<div class="flex flex-col gap-3">
<button
class="transition-all duration-200 focus:ring-2 focus:ring-gray-300 focus:dark:ring-gray-700 outline-none w-full hover:bg-gray-300 hover:dark:bg-gray-700 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 items-center justify-center font-medium font-title rounded-lg flex py-3 px-4"
onClick={async () => {
props.setShow(false);
sessionStorage.setItem("showedBanner", "true");
await props.handleVideoInput?.();
await props.lockPlay?.();
}}
>
Continue Playing
</button>
<button
class="transition-all duration-200 focus:ring-2 focus:ring-gray-300 focus:dark:ring-gray-700 outline-none w-full hover:bg-gray-300 hover:dark:bg-gray-700 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 items-center justify-center font-medium font-title rounded-lg flex py-3 px-4"
>
Shutdown Nestri
</button>
</div>
</div>
</ModalContainer>
);
}

View File

@@ -0,0 +1,18 @@
import { styled } from "@macaron-css/solid";
import { theme } from "../ui/theme";
const Testing = styled("div", {
base: {
height: "100%",
width: "100%",
position: "fixed",
backgroundColor: theme.color.blue.d600
}
})
export default function TestComponent() {
return (
<Testing />
)
}