client/posts: add expanders to edit sidebar

This commit is contained in:
rr- 2016-08-01 20:07:49 +02:00
parent b9f2db1c63
commit 51ea06d837
5 changed files with 185 additions and 76 deletions

View file

@ -222,3 +222,23 @@ a .access-key
[data-pseudo-content]:before { [data-pseudo-content]:before {
content: attr(data-pseudo-content) content: attr(data-pseudo-content)
} }
.expander
&.collapsed
margin-bottom: 1em
&>*
display: none
&>header
display: block
header
background: $active-tab-background-color
line-height: 2em
a
padding: 0 0.5em
display: block
color: $inactive-link-color
i
float: right
line-height: 2em
.expander-content
padding: 1em 0.5em

View file

@ -303,8 +303,9 @@ $safety-unsafe = #F3985F
margin-bottom: 0.5em margin-bottom: 0.5em
.post-view .edit-sidebar .post-view .edit-sidebar
section .expander-content
margin-bottom: 1em section:not(:last-child)
margin-bottom: 1em
.safety .safety
display: flex display: flex

View file

@ -1,86 +1,77 @@
<div class='edit-sidebar'> <div class='edit-sidebar'>
<form autocomplete='off'> <form autocomplete='off'>
<div class='input'> <% if (ctx.canEditPostSafety) { %>
<% if (ctx.canEditPostSafety) { %> <section class='safety'>
<section class='safety'> <label>Safety</label>
<label>Safety</label> <%= ctx.makeRadio({
<%= ctx.makeRadio({ name: 'safety',
name: 'safety', class: 'safety-safe',
class: 'safety-safe', value: 'safe',
value: 'safe', selectedValue: ctx.post.safety,
selectedValue: ctx.post.safety, text: 'Safe'}) %>
text: 'Safe'}) %> <%= ctx.makeRadio({
<%= ctx.makeRadio({ name: 'safety',
name: 'safety', class: 'safety-sketchy',
class: 'safety-sketchy', value: 'sketchy',
value: 'sketchy', selectedValue: ctx.post.safety,
selectedValue: ctx.post.safety, text: 'Sketchy'}) %>
text: 'Sketchy'}) %> <%= ctx.makeRadio({
<%= ctx.makeRadio({ name: 'safety',
name: 'safety', value: 'unsafe',
value: 'unsafe', selectedValue: ctx.post.safety,
selectedValue: ctx.post.safety, class: 'safety-unsafe',
class: 'safety-unsafe', text: 'Unsafe'}) %>
text: 'Unsafe'}) %> </section>
</section> <% } %>
<% } %>
<% if (ctx.canEditPostRelations) { %> <% if (ctx.canEditPostRelations) { %>
<section class='relations'> <section class='relations'>
<%= ctx.makeTextInput({ <%= ctx.makeTextInput({
text: 'Relations', text: 'Relations',
name: 'relations', name: 'relations',
placeholder: 'space-separated post IDs', placeholder: 'space-separated post IDs',
pattern: '^[0-9 ]*$', pattern: '^[0-9 ]*$',
value: ctx.post.relations.map(rel => rel.id).join(' '), value: ctx.post.relations.map(rel => rel.id).join(' '),
}) %> }) %>
</section> </section>
<% } %> <% } %>
<% if (ctx.canEditPostTags) { %> <% if (ctx.canEditPostFlags && ctx.post.type === 'video') { %>
<section class='tags'> <section class='flags'>
<%= ctx.makeTextInput({ <label>Miscellaneous</label>
text: 'Tags', <%= ctx.makeCheckbox({
value: ctx.post.tags.join(' '), text: 'Loop video',
}) %> name: 'loop',
</section> checked: ctx.post.flags.includes('loop'),
<% } %> }) %>
</section>
<% } %>
<% if (ctx.canEditPostFlags && ctx.post.type === 'video') { %> <% if (ctx.canEditPostTags) { %>
<section class='flags'> <section class='tags'>
<label>Miscellaneous</label> <%= ctx.makeTextInput({
value: ctx.post.tags.join(' '),
}) %>
</section>
<% } %>
<%= ctx.makeCheckbox({ <% if (ctx.canEditPostContent) { %>
text: 'Loop video', <section class='post-content'>
name: 'loop', <label>Content</label>
checked: ctx.post.flags.includes('loop'), <div class='dropper-container'></div>
}) %> </section>
</section> <% } %>
<% } %>
<% if (ctx.canEditPostContent) { %> <% if (ctx.canEditPostThumbnail) { %>
<section class='post-content'> <section class='post-thumbnail'>
<label>Content</label> <label>Thumbnail</label>
<div class='dropper-container'></div>
<div class='dropper-container'></div> <a>Discard custom thumbnail</a>
</section> </section>
<% } %> <% } %>
<% if (ctx.canEditPostThumbnail) { %>
<section class='post-thumbnail'>
<label>Thumbnail</label>
<div class='dropper-container'></div>
<a>Discard custom thumbnail</a>
</section>
<% } %>
</div>
<div class='messages'></div> <div class='messages'></div>
<div class='buttons'> <input type='submit' value='Submit' class='submit'/>
<input class='encourage' type='submit' value='Submit' class='submit'/>
</div>
</form> </form>
</div> </div>

View file

@ -0,0 +1,86 @@
'use strict';
const ICON_CLASS_OPENED = 'fa-chevron-down';
const ICON_CLASS_CLOSED = 'fa-chevron-up';
class ExpanderControl {
constructor(title, nodes) {
this._title = title;
nodes = Array.from(nodes).filter(n => n);
if (!nodes.length) {
return;
}
const expanderNode = document.createElement('section');
expanderNode.classList.add('expander');
const toggleLinkNode = document.createElement('a');
const toggleIconNode = document.createElement('i');
toggleIconNode.classList.add('fa');
toggleLinkNode.textContent = title;
toggleLinkNode.appendChild(toggleIconNode);
toggleLinkNode.addEventListener('click', e => this._evtToggleClick(e));
const headerNode = document.createElement('header');
headerNode.appendChild(toggleLinkNode);
expanderNode.appendChild(headerNode);
const expanderContentNode = document.createElement('div');
expanderContentNode.classList.add('expander-content');
expanderNode.appendChild(expanderContentNode);
nodes[0].parentNode.insertBefore(expanderNode, nodes[0]);
for (let node of nodes) {
expanderContentNode.appendChild(node);
}
this._expanderNode = expanderNode;
this._toggleIconNode = toggleIconNode;
expanderNode.classList.toggle(
'collapsed',
this._allStates[this._title] === undefined ?
false :
!this._allStates[this._title]);
this._syncIcon();
}
get _isOpened() {
return !this._expanderNode.classList.contains('collapsed');
}
get _allStates() {
try {
return JSON.parse(localStorage.getItem('expander')) || {};
} catch (e) {
return {};
}
}
_save() {
const newStates = Object.assign({}, this._allStates);
newStates[this._title] = this._isOpened;
localStorage.setItem('expander', JSON.stringify(newStates));
}
_evtToggleClick(e) {
e.preventDefault();
this._expanderNode.classList.toggle('collapsed');
this._save();
this._syncIcon();
}
_syncIcon() {
if (this._isOpened) {
this._toggleIconNode.classList.add(ICON_CLASS_OPENED);
this._toggleIconNode.classList.remove(ICON_CLASS_CLOSED);
} else {
this._toggleIconNode.classList.add(ICON_CLASS_CLOSED);
this._toggleIconNode.classList.remove(ICON_CLASS_OPENED);
}
}
}
module.exports = ExpanderControl;

View file

@ -5,6 +5,7 @@ const events = require('../events.js');
const misc = require('../util/misc.js'); const misc = require('../util/misc.js');
const views = require('../util/views.js'); const views = require('../util/views.js');
const TagInputControl = require('./tag_input_control.js'); const TagInputControl = require('./tag_input_control.js');
const ExpanderControl = require('../controls/expander_control.js');
const FileDropperControl = require('../controls/file_dropper_control.js'); const FileDropperControl = require('../controls/file_dropper_control.js');
const template = views.getTemplate('post-edit-sidebar'); const template = views.getTemplate('post-edit-sidebar');
@ -32,6 +33,16 @@ class PostEditSidebarControl extends events.EventTarget {
canFeaturePosts: api.hasPrivilege('posts:feature'), canFeaturePosts: api.hasPrivilege('posts:feature'),
})); }));
new ExpanderControl(
'Basic info',
this._hostNode.querySelectorAll('.safety, .relations, .flags'));
new ExpanderControl(
'Tags',
this._hostNode.querySelectorAll('.tags'));
new ExpanderControl(
'Content',
this._hostNode.querySelectorAll('.post-content, .post-thumbnail'));
if (this._formNode) { if (this._formNode) {
this._formNode.addEventListener('submit', e => this._evtSubmit(e)); this._formNode.addEventListener('submit', e => this._evtSubmit(e));
} }