From 51ea06d8378936acbc0dacff22cc2bfb161c2a56 Mon Sep 17 00:00:00 2001 From: rr- Date: Mon, 1 Aug 2016 20:07:49 +0200 Subject: [PATCH] client/posts: add expanders to edit sidebar --- client/css/main.styl | 20 +++ client/css/posts.styl | 5 +- client/html/post_edit_sidebar.tpl | 139 ++++++++---------- client/js/controls/expander_control.js | 86 +++++++++++ .../js/controls/post_edit_sidebar_control.js | 11 ++ 5 files changed, 185 insertions(+), 76 deletions(-) create mode 100644 client/js/controls/expander_control.js diff --git a/client/css/main.styl b/client/css/main.styl index 2743525f..a9f14d14 100644 --- a/client/css/main.styl +++ b/client/css/main.styl @@ -222,3 +222,23 @@ a .access-key [data-pseudo-content]:before { 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 diff --git a/client/css/posts.styl b/client/css/posts.styl index f66320e5..66335a56 100644 --- a/client/css/posts.styl +++ b/client/css/posts.styl @@ -303,8 +303,9 @@ $safety-unsafe = #F3985F margin-bottom: 0.5em .post-view .edit-sidebar - section - margin-bottom: 1em + .expander-content + section:not(:last-child) + margin-bottom: 1em .safety display: flex diff --git a/client/html/post_edit_sidebar.tpl b/client/html/post_edit_sidebar.tpl index b19896e8..83744d8d 100644 --- a/client/html/post_edit_sidebar.tpl +++ b/client/html/post_edit_sidebar.tpl @@ -1,86 +1,77 @@
-
- <% if (ctx.canEditPostSafety) { %> -
- - <%= ctx.makeRadio({ - name: 'safety', - class: 'safety-safe', - value: 'safe', - selectedValue: ctx.post.safety, - text: 'Safe'}) %> - <%= ctx.makeRadio({ - name: 'safety', - class: 'safety-sketchy', - value: 'sketchy', - selectedValue: ctx.post.safety, - text: 'Sketchy'}) %> - <%= ctx.makeRadio({ - name: 'safety', - value: 'unsafe', - selectedValue: ctx.post.safety, - class: 'safety-unsafe', - text: 'Unsafe'}) %> -
- <% } %> + <% if (ctx.canEditPostSafety) { %> +
+ + <%= ctx.makeRadio({ + name: 'safety', + class: 'safety-safe', + value: 'safe', + selectedValue: ctx.post.safety, + text: 'Safe'}) %> + <%= ctx.makeRadio({ + name: 'safety', + class: 'safety-sketchy', + value: 'sketchy', + selectedValue: ctx.post.safety, + text: 'Sketchy'}) %> + <%= ctx.makeRadio({ + name: 'safety', + value: 'unsafe', + selectedValue: ctx.post.safety, + class: 'safety-unsafe', + text: 'Unsafe'}) %> +
+ <% } %> - <% if (ctx.canEditPostRelations) { %> -
- <%= ctx.makeTextInput({ - text: 'Relations', - name: 'relations', - placeholder: 'space-separated post IDs', - pattern: '^[0-9 ]*$', - value: ctx.post.relations.map(rel => rel.id).join(' '), - }) %> -
- <% } %> + <% if (ctx.canEditPostRelations) { %> +
+ <%= ctx.makeTextInput({ + text: 'Relations', + name: 'relations', + placeholder: 'space-separated post IDs', + pattern: '^[0-9 ]*$', + value: ctx.post.relations.map(rel => rel.id).join(' '), + }) %> +
+ <% } %> - <% if (ctx.canEditPostTags) { %> -
- <%= ctx.makeTextInput({ - text: 'Tags', - value: ctx.post.tags.join(' '), - }) %> -
- <% } %> + <% if (ctx.canEditPostFlags && ctx.post.type === 'video') { %> +
+ + <%= ctx.makeCheckbox({ + text: 'Loop video', + name: 'loop', + checked: ctx.post.flags.includes('loop'), + }) %> +
+ <% } %> - <% if (ctx.canEditPostFlags && ctx.post.type === 'video') { %> -
- + <% if (ctx.canEditPostTags) { %> +
+ <%= ctx.makeTextInput({ + value: ctx.post.tags.join(' '), + }) %> +
+ <% } %> - <%= ctx.makeCheckbox({ - text: 'Loop video', - name: 'loop', - checked: ctx.post.flags.includes('loop'), - }) %> -
- <% } %> + <% if (ctx.canEditPostContent) { %> +
+ +
+
+ <% } %> - <% if (ctx.canEditPostContent) { %> -
- - -
-
- <% } %> - - <% if (ctx.canEditPostThumbnail) { %> -
- - -
- - Discard custom thumbnail -
- <% } %> -
+ <% if (ctx.canEditPostThumbnail) { %> +
+ +
+ Discard custom thumbnail +
+ <% } %>
-
- -
+
diff --git a/client/js/controls/expander_control.js b/client/js/controls/expander_control.js new file mode 100644 index 00000000..36628f3d --- /dev/null +++ b/client/js/controls/expander_control.js @@ -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; diff --git a/client/js/controls/post_edit_sidebar_control.js b/client/js/controls/post_edit_sidebar_control.js index edc5ac82..a3f13776 100644 --- a/client/js/controls/post_edit_sidebar_control.js +++ b/client/js/controls/post_edit_sidebar_control.js @@ -5,6 +5,7 @@ const events = require('../events.js'); const misc = require('../util/misc.js'); const views = require('../util/views.js'); const TagInputControl = require('./tag_input_control.js'); +const ExpanderControl = require('../controls/expander_control.js'); const FileDropperControl = require('../controls/file_dropper_control.js'); const template = views.getTemplate('post-edit-sidebar'); @@ -32,6 +33,16 @@ class PostEditSidebarControl extends events.EventTarget { 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) { this._formNode.addEventListener('submit', e => this._evtSubmit(e)); }