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;
}