|
1 | | -<!DOCTYPE html> |
2 | | -<html lang="en"> |
| 1 | +<!doctype html> |
| 2 | +<html lang="hi"> |
3 | 3 | <head>
|
4 | | -<meta charset="UTF-8"> |
5 | | -<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
6 | | -<title>My Game Collection</title> |
7 | | -<style> |
8 | | - body { |
9 | | - font-family: Arial, sans-serif; |
10 | | - background: #111; |
11 | | - color: #fff; |
12 | | - margin: 0; |
13 | | - padding: 0; |
14 | | - text-align: center; |
| 4 | + <meta charset="utf-8" /> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> |
| 6 | + <title>My HTML Games — Play</title> |
| 7 | + <style> |
| 8 | + :root{ |
| 9 | + --bg:#071022; --card:#0b1220; --muted:#9aa5b1; --accent:#06b6d4; |
15 | 10 | }
|
16 | | - h1 { |
17 | | - margin-top: 20px; |
18 | | - } |
19 | | - .game-list { |
20 | | - display: flex; |
21 | | - flex-wrap: wrap; |
22 | | - justify-content: center; |
23 | | - margin-top: 20px; |
24 | | - gap: 15px; |
25 | | - } |
26 | | - .game-card { |
27 | | - background: #222; |
28 | | - padding: 15px; |
29 | | - border-radius: 8px; |
30 | | - width: 200px; |
31 | | - cursor: pointer; |
32 | | - transition: 0.3s; |
33 | | - } |
34 | | - .game-card:hover { |
35 | | - background: #444; |
36 | | - } |
37 | | - iframe { |
38 | | - width: 100%; |
39 | | - height: 80vh; |
40 | | - border: none; |
41 | | - margin-top: 20px; |
42 | | - } |
43 | | - button { |
44 | | - background: #ff5722; |
45 | | - border: none; |
46 | | - padding: 10px 20px; |
47 | | - color: white; |
48 | | - cursor: pointer; |
49 | | - margin-top: 10px; |
| 11 | + *{box-sizing:border-box} |
| 12 | + body{margin:0;font-family:system-ui,Segoe UI,Roboto,"Noto Sans",Arial;background:linear-gradient(180deg,#071024,#04121a);color:#e6eef3;min-height:100vh;} |
| 13 | + header{padding:14px 18px;display:flex;align-items:center;gap:12px;background:rgba(255,255,255,0.02)} |
| 14 | + header h1{margin:0;font-size:18px} |
| 15 | + .wrap{display:grid;grid-template-columns:320px 1fr;gap:16px;padding:16px;height:calc(100vh - 68px);} |
| 16 | + .sidebar{background:var(--card);border-radius:10px;padding:12px;overflow:auto} |
| 17 | + .game-list{display:flex;flex-direction:column;gap:8px} |
| 18 | + .game-item{display:flex;gap:10px;align-items:center;padding:8px;border-radius:8px;cursor:pointer;transition:all .12s;background:transparent} |
| 19 | + .game-item:hover{transform:translateY(-2px);background:rgba(255,255,255,0.02)} |
| 20 | + .game-item.active{outline:2px solid rgba(6,182,212,0.12);background:linear-gradient(90deg, rgba(6,182,212,0.03), transparent)} |
| 21 | + .gi-thumb{width:52px;height:40px;border-radius:6px;background:linear-gradient(135deg,#08324a,#04202b);display:flex;align-items:center;justify-content:center;font-weight:700;color:var(--muted);font-size:12px} |
| 22 | + .gi-info{flex:1} |
| 23 | + .gi-title{font-size:14px;margin:0} |
| 24 | + .gi-sub{font-size:12px;color:var(--muted);margin:0} |
| 25 | + |
| 26 | + .main{background:var(--card);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:10px;overflow:hidden} |
| 27 | + .controls{display:flex;gap:8px;align-items:center;justify-content:space-between} |
| 28 | + .btn{background:transparent;border:1px solid rgba(255,255,255,0.04);padding:8px 12px;border-radius:8px;color:inherit;cursor:pointer} |
| 29 | + .iframe-wrap{flex:1;position:relative;border-radius:8px;overflow:hidden;background:#000;min-height:300px} |
| 30 | + iframe{width:100%;height:100%;border:0;display:block} |
| 31 | + |
| 32 | + .note{font-size:12px;color:var(--muted)} |
| 33 | + |
| 34 | + @media (max-width:880px){ |
| 35 | + .wrap{grid-template-columns:1fr; padding:10px; height:calc(100vh - 68px)} |
| 36 | + .sidebar{order:2;height:220px} |
| 37 | + .main{order:1;min-height:60vh} |
50 | 38 | }
|
51 | | -</style> |
| 39 | +</style> |
52 | 40 | </head>
|
53 | 41 | <body>
|
| 42 | + <header> |
| 43 | + <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36'%3E%3Crect rx='8' width='36' height='36' fill='%2306b6d4'/%3E%3Ctext x='50%25' y='55%25' font-family='Arial' font-size='14' text-anchor='middle' fill='%230b1220'%3EGG%3C/text%3E%3C/svg%3E" alt="logo" style="width:36px;height:36px;border-radius:8px"> |
| 44 | + <div style="flex:1"> |
| 45 | + <h1 style="margin:0">HTML Games Collection</h1> |
| 46 | + <div class="note">30 games — click to play. Mobile touch friendly.</div> |
| 47 | + </div> |
| 48 | + <div style="display:flex;gap:8px;align-items:center"> |
| 49 | + <button class="btn" id="openNewTab">Open in new tab</button> |
| 50 | + <button class="btn" id="fullscreenBtn">Fullscreen</button> |
| 51 | + </div> |
| 52 | + </header> |
| 53 | + |
| 54 | + <div class="wrap"> |
| 55 | + <aside class="sidebar"> |
| 56 | + <div style="font-size:13px;color:var(--muted);margin-bottom:8px">Games list</div> |
| 57 | + <div class="game-list" id="gameList"></div> |
| 58 | + <div class="note" style="margin-top:10px">अगर iframe कोई game load न करे → "Open in new tab" दबाएं।</div> |
| 59 | + </aside> |
| 60 | + |
| 61 | + <main class="main"> |
| 62 | + <div class="controls"> |
| 63 | + <div><strong id="currentTitle">Select a game to play →</strong></div> |
| 64 | + <div class="note" id="statusNote"></div> |
| 65 | + </div> |
| 66 | + |
| 67 | + <div class="iframe-wrap" id="frameWrap"> |
| 68 | + <iframe id="gameFrame" src="" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock"></iframe> |
| 69 | + </div> |
| 70 | + |
| 71 | + <div style="display:flex;justify-content:space-between;align-items:center"> |
| 72 | + <div class="note">Tip: Mobile users — use landscape for best experience.</div> |
| 73 | + <div class="note">Built for demo • MIT</div> |
| 74 | + </div> |
| 75 | + </main> |
| 76 | + </div> |
| 77 | + |
| 78 | + <script> |
| 79 | + /* ========== Edit these if folder names differ in your repo ========== */ |
| 80 | + const games = [ |
| 81 | + {id:1, title:"01 - Candy Crush", path:"01-Candy-Crush-Game"}, |
| 82 | + {id:2, title:"02 - Archery", path:"02-Archery-Game"}, |
| 83 | + {id:3, title:"03 - Speed Typing", path:"03-Speed-Typing-Game"}, |
| 84 | + {id:4, title:"04 - Breakout", path:"04-Breakout-Game"}, |
| 85 | + {id:5, title:"05 - Minesweeper", path:"05-Minesweeper-Game"}, |
| 86 | + {id:6, title:"06 - Tower Blocks", path:"06-Tower-Blocks"}, |
| 87 | + {id:7, title:"07 - Ping Pong", path:"07-Ping-Pong-Game"}, |
| 88 | + {id:8, title:"08 - Tetris", path:"08-Tetris-Game"}, |
| 89 | + {id:9, title:"09 - Tilting Maze", path:"09-Tilting-Maze-Game"}, |
| 90 | + {id:10, title:"10 - Memory Card", path:"10-Memory-Card-Game"}, |
| 91 | + {id:11, title:"11 - Rock Paper Scissors", path:"11-Rock-Paper-Scissors"}, |
| 92 | + {id:12, title:"12 - Type Number Guessing", path:"12-Type-Number-Guessing-Game"}, |
| 93 | + {id:13, title:"13 - Tic Tac Toe", path:"13-Tic-Tac-Toe"}, |
| 94 | + {id:14, title:"14 - Snake", path:"14-Snake-Game"}, |
| 95 | + {id:15, title:"15 - Connect Four", path:"15-Connect-Four-Game"}, |
| 96 | + {id:16, title:"16 - Insect Catch", path:"16-Insect-Catch-Game"}, |
| 97 | + {id:17, title:"17 - Typing Game", path:"17-Typing-Game"}, |
| 98 | + {id:18, title:"18 - Hangman", path:"18-Hangman-Game"}, |
| 99 | + {id:19, title:"19 - Flappy Bird", path:"19-Flappy-Bird-Game"}, |
| 100 | + {id:20, title:"20 - Crossy Road", path:"20-Crossy-Road-Game"}, |
| 101 | + {id:21, title:"21 - 2048", path:"21-2048-Game"}, |
| 102 | + {id:22, title:"22 - Dice Roll", path:"22-Dice-Roll-Simulator"}, |
| 103 | + {id:23, title:"23 - Shape Clicker", path:"23-Shape-Clicker-Game"}, |
| 104 | + {id:24, title:"24 - Typing Game #2", path:"24-Typing-Game"}, |
| 105 | + {id:25, title:"25 - Speak Number Guessing", path:"25-Speak-Number-Guessing-Game"}, |
| 106 | + {id:26, title:"26 - Fruit Slicer", path:"26-Fruit-Slicer-Game"}, |
| 107 | + {id:27, title:"27 - Quiz Game", path:"27-Quiz-Game"}, |
| 108 | + {id:28, title:"28 - Emoji Catcher", path:"28-Emoji-Catcher-Game"}, |
| 109 | + {id:29, title:"29 - Whack-A-Mole", path:"29-Whack-A-Mole-Game"}, |
| 110 | + {id:30, title:"30 - Simon Says", path:"30-Simon-Says-Game"} |
| 111 | + ]; |
| 112 | + |
| 113 | + const listEl = document.getElementById('gameList'); |
| 114 | + const frame = document.getElementById('gameFrame'); |
| 115 | + const titleEl = document.getElementById('currentTitle'); |
| 116 | + const statusNote = document.getElementById('statusNote'); |
| 117 | + const frameWrap = document.getElementById('frameWrap'); |
| 118 | + |
| 119 | + // Create list entries |
| 120 | + games.forEach(g => { |
| 121 | + const div = document.createElement('div'); |
| 122 | + div.className = 'game-item'; |
| 123 | + div.dataset.path = g.path; |
| 124 | + |
| 125 | + const thumb = document.createElement('div'); |
| 126 | + thumb.className = 'gi-thumb'; |
| 127 | + thumb.innerText = String(g.id).padStart(2,'0'); |
| 128 | + |
| 129 | + const info = document.createElement('div'); |
| 130 | + info.className = 'gi-info'; |
| 131 | + const t = document.createElement('p'); t.className='gi-title'; t.innerText = g.title; |
| 132 | + const s = document.createElement('p'); s.className='gi-sub'; s.innerText = g.path; |
| 133 | + info.appendChild(t); info.appendChild(s); |
| 134 | + |
| 135 | + div.appendChild(thumb); div.appendChild(info); |
| 136 | + |
| 137 | + div.addEventListener('click', () => { |
| 138 | + document.querySelectorAll('.game-item').forEach(el=>el.classList.remove('active')); |
| 139 | + div.classList.add('active'); |
| 140 | + loadGame(g); |
| 141 | + }); |
| 142 | + |
| 143 | + listEl.appendChild(div); |
| 144 | + }); |
| 145 | + |
| 146 | + // Load selected game into iframe (relative path within repo) |
| 147 | + function loadGame(g){ |
| 148 | + const url = './' + g.path + '/'; |
| 149 | + titleEl.innerText = 'Playing: ' + g.title; |
| 150 | + statusNote.innerText = ''; |
| 151 | + frame.src = url; |
| 152 | + frame.dataset.current = url; |
| 153 | + |
| 154 | + // Add small timeout to detect 404 or blocked embed (if fails to load) |
| 155 | + let loaded = false; |
| 156 | + function onLoad(){ loaded = true; statusNote.innerText = ''; frame.removeEventListener('load', onLoad); } |
| 157 | + frame.addEventListener('load', onLoad); |
| 158 | + setTimeout(()=> { |
| 159 | + if(!loaded){ |
| 160 | + statusNote.innerText = 'अगर लोड नहीं हुआ, तो "Open in new tab" दबाकर जांचें (CORS/GitHub Pages hosting)।'; |
| 161 | + } |
| 162 | + }, 1500); |
| 163 | + } |
| 164 | + |
| 165 | + // Default: load first game |
| 166 | + if(games.length) { |
| 167 | + // mark first active |
| 168 | + const first = document.querySelector('.game-item'); |
| 169 | + if(first) first.classList.add('active'); |
| 170 | + loadGame(games[0]); |
| 171 | + } |
| 172 | + |
| 173 | + // Open current in new tab |
| 174 | + document.getElementById('openNewTab').addEventListener('click', function(){ |
| 175 | + const url = frame.dataset.current || frame.src; |
| 176 | + if(!url) return alert('कोई गेम चुना नहीं गया है।'); |
| 177 | + // For GitHub Pages, open absolute URL |
| 178 | + let abs = url; |
| 179 | + // If running from GitHub Pages domain, convert to absolute |
| 180 | + if(location.hostname.endsWith('github.io')){ |
| 181 | + // repo assumed to be at /<repo>/ |
| 182 | + // Keep relative path which works as absolute on pages |
| 183 | + abs = new URL(url, location.href).href; |
| 184 | + } |
| 185 | + window.open(abs, '_blank'); |
| 186 | + }); |
| 187 | + |
| 188 | + // Fullscreen toggle for iframe container |
| 189 | + document.getElementById('fullscreenBtn').addEventListener('click', function(){ |
| 190 | + const el = frameWrap; |
| 191 | + if(el.requestFullscreen) el.requestFullscreen(); |
| 192 | + else if(el.webkitRequestFullscreen) el.webkitRequestFullscreen(); |
| 193 | + else alert('Fullscreen समर्थित नहीं है आपके ब्राउज़र में।'); |
| 194 | + }); |
| 195 | + |
| 196 | + // Touch improvements: prevent page scroll when touching iframe area |
| 197 | + frameWrap.addEventListener('touchstart', function(e){ e.preventDefault(); }, {passive:false}); |
54 | 198 |
|
55 | | -<h1>🎮 My Game Collection</h1> |
56 | | -<div class="game-list"> |
57 | | - <div class="game-card" onclick="loadGame('snake/index.html')">🐍 Snake Game</div> |
58 | | - <div class="game-card" onclick="loadGame('tetris/index.html')">🧱 Tetris</div> |
59 | | - <div class="game-card" onclick="loadGame('flappy-bird/index.html')">🐦 Flappy Bird</div> |
60 | | - <div class="game-card" onclick="loadGame('tic-tac-toe/index.html')">❌⭕ Tic Tac Toe</div> |
61 | | -</div> |
62 | | - |
63 | | -<div id="gameArea" style="display:none;"> |
64 | | - <iframe id="gameFrame"></iframe> |
65 | | - <br> |
66 | | - <button onclick="closeGame()">⬅ Back to Menu</button> |
67 | | -</div> |
68 | | - |
69 | | -<script> |
70 | | -function loadGame(path) { |
71 | | - document.querySelector('.game-list').style.display = 'none'; |
72 | | - document.getElementById('gameArea').style.display = 'block'; |
73 | | - document.getElementById('gameFrame').src = path; |
74 | | -} |
75 | | -function closeGame() { |
76 | | - document.querySelector('.game-list').style.display = 'flex'; |
77 | | - document.getElementById('gameArea').style.display = 'none'; |
78 | | - document.getElementById('gameFrame').src = ''; |
79 | | -} |
80 | | -</script> |
| 199 | + // Optional: convert touch events to mouse events for games that listen to mouse |
| 200 | + (function(){ |
| 201 | + var selectors = ['iframe']; |
| 202 | + var elements = selectors.map(s => document.querySelector(s)).filter(Boolean); |
| 203 | + if(elements.length === 0) return; |
| 204 | + // We cannot inject events inside iframe due to cross-origin; but most games inside repo are same-origin on GitHub Pages, so they will receive pointer events. |
| 205 | + // If some games still don't react to touch, user can open in new tab. |
| 206 | + })(); |
81 | 207 |
|
| 208 | + </script> |
82 | 209 | </body>
|
83 | 210 | </html>
|
0 commit comments