From 0923ad56dde170bfc00cce129aa548378fc492ef Mon Sep 17 00:00:00 2001 From: Nathan DECHER Date: Mon, 6 Apr 2020 20:16:28 +0200 Subject: [PATCH] added config editor (closes #19) --- assets/metaConfig.json | 10 ++--- public/index.html | 7 +++- src/js/configEditor.js | 94 ++++++++++++++++++++++++++++++++++++++++++ src/js/main.js | 8 ++++ src/js/popup.js | 13 +++++- src/less/popup.less | 12 ++++-- src/less/snek.less | 24 +++++++++++ 7 files changed, 157 insertions(+), 11 deletions(-) create mode 100644 src/js/configEditor.js diff --git a/assets/metaConfig.json b/assets/metaConfig.json index 6f52aeb..0fc2082 100644 --- a/assets/metaConfig.json +++ b/assets/metaConfig.json @@ -3,6 +3,11 @@ "name": "Input settings" }, + "input.buffer": { + "name": "Enable input buffering", + "type": "boolean" + }, + "input.touchscreen": { "name": "Touchscreen settings" }, @@ -99,11 +104,6 @@ "type": "boolean" }, - "input.buffer": { - "name": "Enable input buffering", - "type": "boolean" - }, - "appearance": { "name": "Appearance" }, diff --git a/public/index.html b/public/index.html index 0e6ae3d..7205a65 100644 --- a/public/index.html +++ b/public/index.html @@ -12,9 +12,14 @@
- +

Snek

A "simple" Snake

+
diff --git a/src/js/configEditor.js b/src/js/configEditor.js new file mode 100644 index 0000000..0c2c577 --- /dev/null +++ b/src/js/configEditor.js @@ -0,0 +1,94 @@ +const config=require('config'); +const assets=require('assets'); +const Popup=require('popup'); + +let lastCEId=0; +class ConfigEditor extends Popup { + constructor() { + super("Config editor", [], {ok: "OK"}); + + const metaConfig=assets.get('metaConfig'); + + this.watchers=[]; + + for(let key in metaConfig) { + const level=Array.from(key).reduce((a, c) => a+c=='.', 0)+2; + const data=metaConfig[key]; + + if(!data.type) { + this.addHeading(data.name); + } else { + let span=document.createElement('span'); + let id='cfgInput-'+(lastCEId++)+'-'+key.replace(/\./g, '-'); + let label=span.appendChild(document.createElement('label')); + label.innerText=data.name; + label.title=key; + + let input; + if(data.type=='boolean') { + input=document.createElement('input'); + input.type='checkbox'; + input.checked=config.getB(key); + input.addEventListener('change', () => config.set(key, input.checked)); + } else if(data.type=='choice') { + input=document.createElement('select'); + data.bounds.choices.forEach(choice => { + let option=document.createElement('option'); + option.value=choice; + option.innerText=choice; + input.appendChild(option); + }); + input.value=config.getS(key); + input.addEventListener('change', () => config.set(key, input.value)); + } else if(data.type=='number') { + input=document.createElement('input'); + input.type='number'; + if(data.bounds) { + input.setAttribute('min', data.bounds.min); + input.setAttribute('max', data.bounds.max); + input.setAttribute('step', data.bounds.inc); + } + input.value=config.getN(key); + input.addEventListener('change', () => config.set(key, input.value)); + } + + input.setAttribute('id', id); + span.appendChild(input); + label.setAttribute('for', id); + this.addContent(span); + + if(data.excludes) { + const setEnabled=() => + input.disabled= + data.excludes + .some(key => config.getB(key)) + + setEnabled(); + data.excludes.forEach(key => { + let c=config.watchB(key, setEnabled); + this.watchers.push([key, c]); + }); + } + if(data.parent) { + input.disabled=!config.getB(data.parent); + let c=config.watchB(data.parent, (k, v) => input.disabled=!v); + this.watchers.push([data.parent, c]); + } + } + } + + this.large=true; + } + + discard() { + this.watchers.forEach(([k, c]) => config.unwatch(k, c)); + } +}; + +return module.exports={ + show: async () => { + let editor=new ConfigEditor(); + await editor.display(); + editor.discard(); + } +}; diff --git a/src/js/main.js b/src/js/main.js index 6576acd..5c392c1 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -4,6 +4,7 @@ const assets=require('assets'); const Popup=require('popup'); const SnekGame=require('snek'); + const configEditor=require('configEditor'); const input=require('input'); const levels=require('levels'); const config=require('config'); @@ -154,6 +155,13 @@ stopGame(); }; + // show config editor + settings=async () => { + stopGame(); + await configEditor.show(); + location.hash='menu'; + }; + // display the win popup handleWin=async snek => { // hide the HUD diff --git a/src/js/popup.js b/src/js/popup.js index 9934397..a8339eb 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -1,5 +1,7 @@ const objToDom=obj => { - if(obj[Popup.EM]) { + if(obj instanceof Node) { + return obj; + } else if(obj[Popup.EM]) { let em=document.createElement('em'); em.appendChild(document.createTextNode(obj[Popup.EM])); return em; @@ -27,10 +29,11 @@ const objToDom=obj => { } class Popup { - constructor(title, content=[], buttons={}) { + constructor(title, content=[], buttons={}, large=false) { this.title=title; this.content=content.map(objToDom); this.buttons={...buttons}; + this.large=large; } addContent(cnt) { @@ -45,12 +48,18 @@ class Popup { addStrong(cnt) { this.content.push(objToDom({[Popup.STRONG]: cnt})); } + addHeading(cnt, level=2) { + let hn=document.createElement('h'+level); + hn.innerText=cnt; + this.content.push(hn); + } async display(parent=document.body) { let outer=document.createElement('div'); outer.classList.add('popup'); let popup=outer.appendChild(document.createElement('div')); popup.classList.add('content'); + if(this.large) popup.classList.add('large'); let title=popup.appendChild(document.createElement('h1')); title.innerText=this.title; diff --git a/src/less/popup.less b/src/less/popup.less index a90452b..5eeb6da 100644 --- a/src/less/popup.less +++ b/src/less/popup.less @@ -29,15 +29,17 @@ transform: translate(-50%, -50%); box-sizing: border-box; - max-width: 50vw; - max-height: 50vh; - padding: 2rem; display: flex; flex-direction: column; font-size: 1.4rem; + &.large { + width: 80vw; + height: 80vh; + } + & > section { margin: 1rem; @@ -45,6 +47,7 @@ display: flex; flex-direction: column; align-items: center; + overflow-y: auto; & > * { margin: .5rem; @@ -82,6 +85,9 @@ flex: 1; } } + label { + margin-right: 1ex; + } button { display: inline; diff --git a/src/less/snek.less b/src/less/snek.less index 9c279bc..826b9d6 100644 --- a/src/less/snek.less +++ b/src/less/snek.less @@ -33,6 +33,7 @@ h1, h2, h3, h4, h5, h6 { a { text-decoration: inherit; + display: contents; } em { @@ -66,6 +67,20 @@ footer img { height: 4rem; } +header ul { + display: flex; + list-style-type: none; + + li { + margin-right: 1ex; + font-size: 2rem; + + a { + color: @fg; + } + } +} + header, footer, main { padding: 2rem; } @@ -88,6 +103,15 @@ h1 { h2 { font-size: 2rem; } +h3 { + font-size: 1.9rem; +} +h4 { + font-size: 1.8rem; +} +h5 { + font-size: 1.7rem; +} p { font-size: 1.6rem; }