diff --git a/game/game.js b/game/game.js index 0d879b0..a50a894 100644 --- a/game/game.js +++ b/game/game.js @@ -47,13 +47,19 @@ const ELEMENTS = { A: document.createElement('a'), } +let KEY_LISTENER_OFF = false + function addMenuToDom(gameId) { const previewImageUrl = Game.getImageUrl(gameId) function row (...elements) { const row = ELEMENTS.TR.cloneNode(true) for (let el of elements) { const td = ELEMENTS.TD.cloneNode(true) - td.appendChild(el) + if (typeof el === 'string') { + td.appendChild(document.createTextNode(el)) + } else { + td.appendChild(el) + } row.appendChild(td) } return row @@ -103,6 +109,52 @@ function addMenuToDom(gameId) { nameChangeEl ) + const kbd = function(txt) { + const el = document.createElement('kbd') + el.appendChild(document.createTextNode(txt)) + return el + } + + const h = function(...els) { + const el = ELEMENTS.DIV.cloneNode(true) + for (const other of els) { + if (typeof other === 'string') { + el.appendChild(document.createTextNode(other)) + } else { + el.appendChild(other) + } + } + return el + } + + const helpEl = ELEMENTS.TABLE.cloneNode(true) + helpEl.classList.add('help') + helpEl.appendChild(row('âŦ†ī¸ Move up:', h(kbd('W'), '/', kbd('↑'), '/đŸ–ąī¸'))) + helpEl.appendChild(row('âŦ‡ī¸ Move down:', h(kbd('S'), '/', kbd('↓'), '/đŸ–ąī¸'))) + helpEl.appendChild(row('âŦ…ī¸ Move left:', h(kbd('A'), '/', kbd('←'), '/đŸ–ąī¸'))) + helpEl.appendChild(row('âžĄī¸ Move right:', h(kbd('D'), '/', kbd('→'), '/đŸ–ąī¸'))) + helpEl.appendChild(row('', h('Move faster by holding ', kbd('Shift')))) + helpEl.appendChild(row('🔍+ Zoom in:', h(kbd('E'), '/đŸ–ąī¸-Wheel'))) + helpEl.appendChild(row('🔍- Zoom out:', h(kbd('Q'), '/đŸ–ąī¸-Wheel'))) + helpEl.appendChild(row('đŸ–ŧī¸ Toggle preview:', h(kbd('Space')))) + helpEl.addEventListener('click', (e) => { + e.stopPropagation() + }) + + const toggle = (el, disableHotkeys = true) => { + el.classList.toggle('closed') + if (disableHotkeys) { + KEY_LISTENER_OFF = !el.classList.contains('closed') + } + } + + const helpOverlay = ELEMENTS.DIV.cloneNode(true) + helpOverlay.classList.add('overlay', 'transparent', 'closed') + helpOverlay.appendChild(helpEl) + helpOverlay.addEventListener('click', () => { + toggle(helpOverlay) + }) + const settingsEl = ELEMENTS.TABLE.cloneNode(true) settingsEl.classList.add('settings') settingsEl.appendChild(bgColorPickerRow) @@ -116,7 +168,7 @@ function addMenuToDom(gameId) { settingsOverlay.classList.add('overlay', 'transparent', 'closed') settingsOverlay.appendChild(settingsEl) settingsOverlay.addEventListener('click', () => { - settingsOverlay.classList.toggle('closed') + toggle(settingsOverlay) }) const previewEl = ELEMENTS.DIV.cloneNode(true) @@ -137,12 +189,15 @@ function addMenuToDom(gameId) { togglePreview() }) - const settingsOpenerEl = ELEMENTS.DIV.cloneNode(true) - settingsOpenerEl.classList.add('opener') - settingsOpenerEl.appendChild(document.createTextNode('đŸ› ī¸ Settings')) - settingsOpenerEl.addEventListener('click', () => { - settingsOverlay.classList.toggle('closed') - }) + const opener = (txt, overlay, disableHotkeys = true) => { + const el = ELEMENTS.DIV.cloneNode(true) + el.classList.add('opener') + el.appendChild(document.createTextNode(txt)) + el.addEventListener('click', () => { + toggle(overlay, disableHotkeys) + }) + return el + } const homeEl = ELEMENTS.A.cloneNode(true) homeEl.classList.add('opener') @@ -150,18 +205,16 @@ function addMenuToDom(gameId) { homeEl.target = '_blank' homeEl.href = '/' - const previewOpenerEl = ELEMENTS.DIV.cloneNode(true) - previewOpenerEl.classList.add('opener') - previewOpenerEl.appendChild(document.createTextNode('đŸ–ŧī¸ Preview')) - previewOpenerEl.addEventListener('click', () => { - previewOverlay.classList.toggle('closed') - }) + const settingsOpenerEl = opener('đŸ› ī¸ Settings', settingsOverlay) + const previewOpenerEl = opener('đŸ–ŧī¸ Preview', previewOverlay, false) + const helpOpenerEl = opener('â„šī¸ Help', helpOverlay) const tabsEl = ELEMENTS.DIV.cloneNode(true) tabsEl.classList.add('tabs') tabsEl.appendChild(homeEl) tabsEl.appendChild(previewOpenerEl) tabsEl.appendChild(settingsOpenerEl) + tabsEl.appendChild(helpOpenerEl) const menuEl = ELEMENTS.DIV.cloneNode(true) menuEl.classList.add('menu') @@ -250,6 +303,7 @@ function addMenuToDom(gameId) { document.body.appendChild(settingsOverlay) document.body.appendChild(previewOverlay) + document.body.appendChild(helpOverlay) document.body.appendChild(timerEl) document.body.appendChild(menuEl) document.body.appendChild(scoresEl) @@ -296,6 +350,9 @@ export default class EventAdapter { canvas.addEventListener('wheel', this._wheel.bind(this)) window.addEventListener('keydown', (ev) => { + if (KEY_LISTENER_OFF) { + return + } if (ev.key === 'Shift') { this.SHIFT = true } else if (ev.key === 'ArrowUp' || ev.key === 'w' || ev.key === 'W') { @@ -313,6 +370,9 @@ export default class EventAdapter { } }) window.addEventListener('keyup', (ev) => { + if (KEY_LISTENER_OFF) { + return + } if (ev.key === 'Shift') { this.SHIFT = false } else if (ev.key === 'ArrowUp' || ev.key === 'w' || ev.key === 'W') { @@ -534,6 +594,9 @@ async function main() { } window.addEventListener('keypress', (ev) => { + if (KEY_LISTENER_OFF) { + return + } if (ev.key === ' ') { togglePreview() } @@ -846,7 +909,6 @@ async function main() { // Names ctx.fillStyle = 'white' - ctx.font = '10px sans-serif' ctx.textAlign = 'center' for (let [txt, x, y] of texts) { ctx.fillText(txt, x, y) diff --git a/game/style.css b/game/style.css index ed4b1f2..7dfee68 100644 --- a/game/style.css +++ b/game/style.css @@ -13,7 +13,13 @@ body { background: #2b2b2b; color: var(--main-color); height: 100%; - font-family: sans-serif; +} +* { + font-family: monospace; + font-size: 15px; +} +h1, h2, h3, h4 { + font-size: 20px; } a { color: var(--link-color); text-decoration: none; } @@ -72,6 +78,18 @@ a:hover { color: var(--link-hover-color); } background: transparent; } +.help { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%,-50%); + background: var(--bg-color); + padding: 5px; + border: solid 1px black; + box-shadow: 0 0 10px 0 rgba(0,0,0,.7); + z-index: 1; +} + .settings { position: absolute; left: 50%; @@ -135,7 +153,6 @@ input:focus { } .btn { - font: 15px sans-serif; display: inline-block; background: var(--input-bg-color); color: var(--link-color); @@ -214,3 +231,17 @@ input:focus { background-repeat: no-repeat; background-color: #222; } + +kbd { + background-color: #eee; + border-radius: 3px; + border: 1px solid #b4b4b4; + box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 2px 0 0 rgba(255, 255, 255, .7) inset; + color: #333; + display: inline-block; + font-size: .85em; + font-weight: 700; + line-height: 1; + padding: 2px 4px; + white-space: nowrap; + }