diff --git a/Architype.js b/Architype.js index 025f6cb..4d35b07 100644 --- a/Architype.js +++ b/Architype.js @@ -33,6 +33,9 @@ class Architype { } this.unserialize(JSON.parse(localStorage.getItem('currentState'))); + if (this.editor_.getEntries().length == 0) { + this.editor_.addHelpAfter(); + } this.editor_.selectNext(); this.observer_ = new MutationObserver(e => { this.onChange(e); }); diff --git a/Editor.js b/Editor.js index b5dcc95..da9c8c7 100644 --- a/Editor.js +++ b/Editor.js @@ -9,7 +9,9 @@ class Editor extends List { [EditorGroup, [0, Number.POSITIVE_INFINITY]], [EditorLink, [0, Number.POSITIVE_INFINITY]], [EditorLabel, [0, 1]], + [EditorHelp, [0, Number.POSITIVE_INFINITY]], ]); + // TODO: do something with global EditorLabel this.container_.classList.add('editor'); // Needs to accept focus to receive keydown, but shouldn't be in the normal @@ -34,7 +36,12 @@ class Editor extends List { unserialize(ser) { for (let entry of ser) { - this.container_.appendChild(EditorEntryBase.unserialize(entry)); + let elem = EditorEntryBase.unserialize(entry); + if (elem) { + this.container_.appendChild(elem); + } else { + console.log('failed to unserialize', entry); + } } } @@ -107,6 +114,12 @@ class Editor extends List { EditorGroup.addBefore(this.container_, this.getSelected()); } } + + addHelpAfter() { + if (this.mayAdd(EditorHelp)) { + EditorHelp.addAfter(this.container_, this.getSelected()); + } + } onKeyDown(e) { switch (e.key) { @@ -157,6 +170,12 @@ class Editor extends List { e.stopPropagation(); e.preventDefault(); return; + + case '?': + this.addHelpAfter(); + e.stopPropagation(); + e.preventDefault(); + return; } super.onKeyDown(e); @@ -165,6 +184,7 @@ class Editor extends List { + diff --git a/EditorEntryBase.js b/EditorEntryBase.js index f184765..769dde4 100644 --- a/EditorEntryBase.js +++ b/EditorEntryBase.js @@ -33,6 +33,10 @@ class EditorEntryBase extends ListenUtils { return false; } + getElement() { + return this.elem_; + } + onElemFocus() { this.elem_.scrollIntoView({block: 'nearest'}); } @@ -59,6 +63,8 @@ class EditorEntryBase extends ListenUtils { switch (ser.type) { case 'group': return EditorGroup.unserialize(ser); + case 'help': + return EditorHelp.unserialize(ser); case 'label': return EditorLabel.unserialize(ser); case 'link': diff --git a/EditorGroup.js b/EditorGroup.js index 0325572..e603def 100644 --- a/EditorGroup.js +++ b/EditorGroup.js @@ -46,10 +46,6 @@ class EditorGroup extends EditorEntryBase { } } - getElement() { - return this.elem_; - } - onKeyDown(e) { super.onKeyDown(e); diff --git a/EditorHelp.js b/EditorHelp.js new file mode 100644 index 0000000..f199ef6 --- /dev/null +++ b/EditorHelp.js @@ -0,0 +1,85 @@ +class EditorHelp extends EditorEntryBase { + constructor() { + super(); + + this.elem_.classList.add('help'); + + this.addLine(); + this.addText('Navigation'); + + this.addLine(); + this.addKey('←', '↓', '↑', '→'); + + this.addLine(); + this.addKey('h', 'j', 'k', 'l'); + + this.addLine(); + this.addKey('␛', '', '', '⏎'); + + this.addLine(); + + this.addLine(); + this.addKey('n'); + this.addText('Node '); + this.addKey('g'); + this.addText('Group'); + + this.addLine(); + this.addKey('i'); + this.addText('Link '); + this.addKey('a'); + this.addText('Label'); + + this.addLine(); + this.addKey('⇧'); + this.addText('+'); + this.addKey('n'); + this.addText('Node above'); + + this.addLine(); + this.addKey('d'); + this.addText('Delete '); + + this.addLine(); + this.addKey('⇧'); + this.addText('+'); + this.addKey('d'); + this.addText('Delete all'); + } + + addLine() { + this.line_ = document.createElement('div'); + this.elem_.appendChild(this.line_); + } + + addText(text) { + let elem = document.createElement('span'); + elem.classList.add('text'); + elem.innerText = text; + this.line_.appendChild(elem); + } + + addKey(...symbols) { + for (let symbol of symbols) { + let key = document.createElement('div'); + key.classList.add('key'); + key.innerText = symbol; + this.line_.appendChild(key); + } + } + + afterDomAdd() { + this.elem_.focus(); + } + + serialize() { + return { + type: 'help', + }; + } + + static unserialize(ser) { + return (new EditorHelp()).getElement(); + } +} + diff --git a/EditorLabel.js b/EditorLabel.js index acc67e9..76b7cdd 100644 --- a/EditorLabel.js +++ b/EditorLabel.js @@ -33,10 +33,6 @@ class EditorLabel extends EditorEntryBase { this.onInput(); } - getElement() { - return this.elem_; - } - wantFocus() { return this.getLabel() == ''; } diff --git a/EditorLink.js b/EditorLink.js index 458b0ee..9006ae4 100644 --- a/EditorLink.js +++ b/EditorLink.js @@ -52,10 +52,6 @@ class EditorLink extends EditorEntryBase { } } - getElement() { - return this.elem_; - } - onKeyDown(e) { super.onKeyDown(e); diff --git a/EditorNode.js b/EditorNode.js index a63a95d..bfc196a 100644 --- a/EditorNode.js +++ b/EditorNode.js @@ -32,10 +32,6 @@ class EditorNode extends EditorEntryBase { this.onInput(); } - getElement() { - return this.elem_; - } - wantFocus() { return this.getLabel() == ''; } diff --git a/architype.css b/architype.css index f15275d..4cc131c 100644 --- a/architype.css +++ b/architype.css @@ -96,6 +96,38 @@ body { background-color: var(--label); } +.editor li.help { + padding: 10px; + font-size: 16px; + flex-direction: column; +} + +.editor li.help > div { + min-height: 10px; +} + +.editor li.help .key { + display: inline-flex; + width: 20px; + height: 20px; + justify-content: center; + align-items: center; + vertical-align: middle; + font-size: 20px; + border: 1px solid white; + border-radius: 5px; + padding: 5px; + margin: 3px; + overflow: hidden; +} + +.editor li.help .key:empty { + visibility: hidden; +} + +.editor li.help .text { + margin: 5px; +} .editor li:focus { border-left: 10px solid var(--focus) !important;