added config editor (closes #19)
This commit is contained in:
parent
65b33afa05
commit
0923ad56dd
7 changed files with 157 additions and 11 deletions
|
@ -3,6 +3,11 @@
|
||||||
"name": "Input settings"
|
"name": "Input settings"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"input.buffer": {
|
||||||
|
"name": "Enable input buffering",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
|
||||||
"input.touchscreen": {
|
"input.touchscreen": {
|
||||||
"name": "Touchscreen settings"
|
"name": "Touchscreen settings"
|
||||||
},
|
},
|
||||||
|
@ -99,11 +104,6 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
||||||
"input.buffer": {
|
|
||||||
"name": "Enable input buffering",
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
|
|
||||||
"appearance": {
|
"appearance": {
|
||||||
"name": "Appearance"
|
"name": "Appearance"
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,9 +12,14 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<img src="assets/icon256.png">
|
<a href="#"><img src="assets/icon256.png"></a>
|
||||||
<h1>Snek</h1>
|
<h1>Snek</h1>
|
||||||
<h2>A "simple" Snake</h2>
|
<h2>A "simple" Snake</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#">Menu</a></li>
|
||||||
|
<li><a href="#settings">Config</a></li>
|
||||||
|
<li><a href="#help">Help</a></li>
|
||||||
|
</ul>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<nav></nav>
|
<nav></nav>
|
||||||
|
|
94
src/js/configEditor.js
Normal file
94
src/js/configEditor.js
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
|
@ -4,6 +4,7 @@
|
||||||
const assets=require('assets');
|
const assets=require('assets');
|
||||||
const Popup=require('popup');
|
const Popup=require('popup');
|
||||||
const SnekGame=require('snek');
|
const SnekGame=require('snek');
|
||||||
|
const configEditor=require('configEditor');
|
||||||
const input=require('input');
|
const input=require('input');
|
||||||
const levels=require('levels');
|
const levels=require('levels');
|
||||||
const config=require('config');
|
const config=require('config');
|
||||||
|
@ -154,6 +155,13 @@
|
||||||
stopGame();
|
stopGame();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// show config editor
|
||||||
|
settings=async () => {
|
||||||
|
stopGame();
|
||||||
|
await configEditor.show();
|
||||||
|
location.hash='menu';
|
||||||
|
};
|
||||||
|
|
||||||
// display the win popup
|
// display the win popup
|
||||||
handleWin=async snek => {
|
handleWin=async snek => {
|
||||||
// hide the HUD
|
// hide the HUD
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const objToDom=obj => {
|
const objToDom=obj => {
|
||||||
if(obj[Popup.EM]) {
|
if(obj instanceof Node) {
|
||||||
|
return obj;
|
||||||
|
} else if(obj[Popup.EM]) {
|
||||||
let em=document.createElement('em');
|
let em=document.createElement('em');
|
||||||
em.appendChild(document.createTextNode(obj[Popup.EM]));
|
em.appendChild(document.createTextNode(obj[Popup.EM]));
|
||||||
return em;
|
return em;
|
||||||
|
@ -27,10 +29,11 @@ const objToDom=obj => {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Popup {
|
class Popup {
|
||||||
constructor(title, content=[], buttons={}) {
|
constructor(title, content=[], buttons={}, large=false) {
|
||||||
this.title=title;
|
this.title=title;
|
||||||
this.content=content.map(objToDom);
|
this.content=content.map(objToDom);
|
||||||
this.buttons={...buttons};
|
this.buttons={...buttons};
|
||||||
|
this.large=large;
|
||||||
}
|
}
|
||||||
|
|
||||||
addContent(cnt) {
|
addContent(cnt) {
|
||||||
|
@ -45,12 +48,18 @@ class Popup {
|
||||||
addStrong(cnt) {
|
addStrong(cnt) {
|
||||||
this.content.push(objToDom({[Popup.STRONG]: 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) {
|
async display(parent=document.body) {
|
||||||
let outer=document.createElement('div');
|
let outer=document.createElement('div');
|
||||||
outer.classList.add('popup');
|
outer.classList.add('popup');
|
||||||
let popup=outer.appendChild(document.createElement('div'));
|
let popup=outer.appendChild(document.createElement('div'));
|
||||||
popup.classList.add('content');
|
popup.classList.add('content');
|
||||||
|
if(this.large) popup.classList.add('large');
|
||||||
|
|
||||||
let title=popup.appendChild(document.createElement('h1'));
|
let title=popup.appendChild(document.createElement('h1'));
|
||||||
title.innerText=this.title;
|
title.innerText=this.title;
|
||||||
|
|
|
@ -29,15 +29,17 @@
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
max-width: 50vw;
|
|
||||||
max-height: 50vh;
|
|
||||||
|
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
width: 80vw;
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
& > section {
|
& > section {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
margin: .5rem;
|
margin: .5rem;
|
||||||
|
@ -82,6 +85,9 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
label {
|
||||||
|
margin-right: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|
|
@ -33,6 +33,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
em {
|
em {
|
||||||
|
@ -66,6 +67,20 @@ footer img {
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header ul {
|
||||||
|
display: flex;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right: 1ex;
|
||||||
|
font-size: 2rem;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: @fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
header, footer, main {
|
header, footer, main {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +103,15 @@ h1 {
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.9rem;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
font-size: 1.7rem;
|
||||||
|
}
|
||||||
p {
|
p {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue