diff react_games/src/Games.tsx @ 37:fb9bcd3145cb

[ReactGames] Few games I made using react just to practice few things.
author MrJuneJune <me@mrjunejune.com>
date Mon, 01 Dec 2025 20:22:47 -0800
parents
children 49b611c808e7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/react_games/src/Games.tsx	Mon Dec 01 20:22:47 2025 -0800
@@ -0,0 +1,147 @@
+import ReactDOM from 'react-dom/client';
+import React, { CSSProperties, lazy, LazyExoticComponent, Suspense, useEffect, useState } from "react";
+
+const LazyTicTacToe   = lazy(() => import("./Tictactoe/main.tsx").then(m => ({ default: m.TicTacToe })));
+const LazyConnectFour = lazy(() => import("./Connectfour/main.tsx").then(m => ({ default: m.ConnectFour })));
+const LazyMemoryGame  = lazy(() => import("./CardMatchiing/main.tsx").then(m => ({ default: m.MemoryGame })));
+const LazyLightsOut  = lazy(() => import("./LightsOut/main.tsx").then(m => ({ default: m.LightsOut })));
+const LazyWordle  = lazy(() => import("./Wordle/main.tsx").then(m => ({ default: m.Wordle })));
+const LazyMinesweeper  = lazy(() => import("./Minesweeper/main.tsx").then(m => ({ default: m.Minesweeper })));
+
+
+
+const wrapperStyle: CSSProperties = {
+  display: 'flex',
+  justifyContent: 'center',
+  alignItems: 'center',
+  minHeight: '100vh',
+  fontFamily: 'system-ui, sans-serif',
+};
+
+const menuStyle: CSSProperties = {
+  listStyle: 'none',
+  padding: 0,
+  margin: '2rem auto',
+  width: 280,
+  display: 'flex',
+  flexDirection: 'column',
+  gap: '1rem',
+  cursor: 'pointer',
+};
+
+const menuItemStyle: CSSProperties = {
+  padding: '0.75rem 1rem',
+  borderRadius: 8,
+  background: '#f3f4f6',
+  textAlign: 'center',
+  transition: 'background 120ms',
+};
+
+type ComponentLabels = 
+  | "tictactoe"
+  | "connectfour"
+  | "memorygame"
+  | "lightsout"
+  | "wordle"
+  | "minesweeper"
+
+interface ComponentData {
+  LazyComponent: LazyExoticComponent<() => React.ReactNode>;
+  title: string;
+}
+
+const gameMap: (Record<ComponentLabels, ComponentData>) = {
+  tictactoe: {
+    LazyComponent: LazyTicTacToe,
+    title: "TicTacToe",
+  },
+  connectfour: {
+    LazyComponent: LazyConnectFour,
+    title: "Connect Four",
+  },
+  memorygame: {
+    LazyComponent: LazyMemoryGame,
+    title: "Memory Game",
+  },
+  lightsout: {
+    LazyComponent: LazyLightsOut,
+    title: "Lights out",
+  },
+  wordle: {
+    LazyComponent: LazyWordle,
+    title: "Wordle",
+  },
+  minesweeper: {
+    LazyComponent: LazyMinesweeper,
+    title: "Minesweeper",
+  },
+}
+
+type GameKey = ComponentLabels | null;
+
+const BASE = "/games";
+const Games = () => {
+  const getKey = (p: string): GameKey => {
+    const m = p.match(/^\/games\/?([^/]+)?/i);
+    const k = (m?.[1] || '').toLowerCase() as GameKey;
+    return k && k in gameMap ? k : null;
+  };
+  
+  const [game, setGame] = useState<GameKey>(() => getKey(location.pathname));
+  
+  useEffect(() => {
+    const onPop = () => setGame(getKey(location.pathname));
+    addEventListener('popstate', onPop);
+    return () => removeEventListener('popstate', onPop);
+  }, []);
+  
+  useEffect(() => {
+    history.pushState(null, '', game ? `${BASE}/${game}` : BASE);
+  }, [game]);
+
+  const selected = game ? gameMap[game] : null;
+
+  return (
+    <main style={wrapperStyle}>
+      <section>
+        <h1 style={{ textAlign: "center" }}>MAI React Playground</h1>
+
+        {selected?.LazyComponent ? (
+          <Suspense fallback={<div>loading...</div>}>
+            <div style={
+              { 
+                display: "flex", 
+                flexDirection: "column", 
+                justifyContent: "center", 
+                alignItems: "center",
+                gap: 10,
+              }}> 
+              <selected.LazyComponent />
+            </div>
+          </Suspense>
+        ) : (
+          <ul style={menuStyle}>
+            {Object.entries(gameMap).map(([key, value]) => (
+              <li key={key} style={menuItemStyle} onClick={() => setGame(key as GameKey)}>
+                {value.title}
+              </li>
+            ))}
+          </ul>
+        )}
+
+        {game && (
+          <button style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "cetner", margin: "1.5rem auto 0" }} onClick={() => setGame(null)}>
+            Back to menu
+          </button>
+        )}
+
+      </section>
+    </main>
+  );
+};
+
+export {
+  Games,
+}
+
+ReactDOM.createRoot(document.getElementById('root')!).render(<Games />);