From a4eb8e11c3df0805ef347eb14ba4c77674638b47 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 23 May 2018 10:25:10 +0100 Subject: [PATCH] Collapse sidebar tabs --- editor/js/ui/common/popover.js | 8 +- editor/js/ui/common/tabs.js | 194 ++++++++++++++++---- editor/js/ui/projects/tab-versionControl.js | 2 + editor/js/ui/sidebar.js | 7 +- editor/js/ui/tab-config.js | 3 +- editor/js/ui/tab-info.js | 2 + editor/sass/popover.scss | 30 ++- editor/sass/tabs.scss | 61 +++++- nodes/core/core/58-debug.html | 4 +- 9 files changed, 269 insertions(+), 42 deletions(-) diff --git a/editor/js/ui/common/popover.js b/editor/js/ui/common/popover.js index 6a0bc9fdf..0170f7070 100644 --- a/editor/js/ui/common/popover.js +++ b/editor/js/ui/common/popover.js @@ -19,12 +19,14 @@ RED.popover = (function() { "default": { top: 10, leftRight: 17, - leftLeft: 25 + leftLeft: 25, + leftBottom: 8, }, "small": { top: 5, leftRight: 17, - leftLeft: 16 + leftLeft: 16, + leftBottom: 3, } } function createPopover(options) { @@ -69,6 +71,8 @@ RED.popover = (function() { div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight}); } else if (direction === 'left') { div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth}); + } else if (direction === 'bottom') { + div.css({top: targetPos.top+targetHeight+deltaSizes[size].top,left:targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom}); } if (instant) { div.show(); diff --git a/editor/js/ui/common/tabs.js b/editor/js/ui/common/tabs.js index f66b95421..23b69f5d1 100644 --- a/editor/js/ui/common/tabs.js +++ b/editor/js/ui/common/tabs.js @@ -19,8 +19,10 @@ RED.tabs = (function() { function createTabs(options) { var tabs = {}; + var pinnedTabsCount = 0; var currentTabWidth; var currentActiveTabWidth = 0; + var collapsibleMenu; var ul = options.element || $("#"+options.id); var wrapper = ul.wrap( "
" ).parent(); @@ -50,6 +52,55 @@ RED.tabs = (function() { scrollRight = $('
').appendTo(wrapper).find("a"); scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();}); } + + if (options.collapsible) { + // var dropDown = $('
',{class:"red-ui-tabs-select"}).appendTo(wrapper); + // ul.hide(); + wrapper.addClass("red-ui-tabs-collapsible"); + + var collapsedButtonsRow = $('').appendTo(wrapper); + + var selectButton = $('').appendTo(collapsedButtonsRow); + selectButton.addClass("red-ui-tab-link-button-menu") + selectButton.click(function(evt) { + evt.preventDefault(); + if (!collapsibleMenu) { + var pinnedOptions = []; + var options = []; + ul.children().each(function(i,el) { + var id = $(el).data('tabId'); + var opt = { + id:"red-ui-tabs-menu-option-"+id, + label: tabs[id].name, + onselect: function() { + activateTab(id); + } + }; + if (tabs[id].pinned) { + pinnedOptions.push(opt); + } else { + options.push(opt); + } + }); + options = pinnedOptions.concat(options); + collapsibleMenu = RED.menu.init({id:"debug-message-option-menu",options: options}); + collapsibleMenu.css({ + position: "absolute" + }) + collapsibleMenu.on('mouseleave', function(){ $(this).hide() }); + collapsibleMenu.on('mouseup', function() { $(this).hide() }); + collapsibleMenu.appendTo("body"); + var elementPos = selectButton.offset(); + collapsibleMenu.css({ + top: (elementPos.top+selectButton.height()-20)+"px", + left: (elementPos.left - collapsibleMenu.width() + selectButton.width())+"px" + }) + } + collapsibleMenu.toggle(); + }) + + } + function scrollEventHandler(evt,dir) { evt.preventDefault(); if ($(this).hasClass('disabled')) { @@ -118,6 +169,9 @@ RED.tabs = (function() { ul.children().removeClass("active"); ul.children().css({"transition": "width 100ms"}); link.parent().addClass("active"); + var parentId = link.parent().attr('id'); + wrapper.find(".red-ui-tab-link-button").removeClass("active"); + $("#"+parentId+"-link-button").addClass("active"); if (options.scrollable) { var pos = link.parent().position().left; if (pos-21 < 0) { @@ -155,41 +209,70 @@ RED.tabs = (function() { var tabs = ul.find("li.red-ui-tab"); var width = wrapper.width(); var tabCount = tabs.size(); - var tabWidth = (width-12-(tabCount*6))/tabCount; - currentTabWidth = (100*tabWidth/width)+"%"; - currentActiveTabWidth = currentTabWidth+"%"; - if (options.scrollable) { - tabWidth = Math.max(tabWidth,140); - currentTabWidth = tabWidth+"px"; - currentActiveTabWidth = 0; - var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount); - ul.width(listWidth); - updateScroll(); - } else if (options.hasOwnProperty("minimumActiveTabWidth")) { - if (tabWidth < options.minimumActiveTabWidth) { - tabCount -= 1; - tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount; - currentTabWidth = (100*tabWidth/width)+"%"; - currentActiveTabWidth = options.minimumActiveTabWidth+"px"; + var tabWidth; + + if (options.collapsible) { + tabWidth = width - collapsedButtonsRow.width()-10; + if (tabWidth < 198) { + var delta = 198 - tabWidth; + var b = collapsedButtonsRow.find("a:last").prev(); + while (b.is(":not(:visible)")) { + b = b.prev(); + } + if (!b.hasClass("red-ui-tab-link-button-pinned")) { + b.hide(); + } + tabWidth = width - collapsedButtonsRow.width()-10; } else { - currentActiveTabWidth = 0; + var space = width - 198 - collapsedButtonsRow.width(); + if (space > 40) { + collapsedButtonsRow.find("a:not(:visible):first").show(); + tabWidth = width - collapsedButtonsRow.width()-10; + } } - } - tabs.css({width:currentTabWidth}); - if (tabWidth < 50) { - ul.find(".red-ui-tab-close").hide(); - ul.find(".red-ui-tab-icon").hide(); - ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"}) + tabs.css({width:tabWidth}); + } else { - ul.find(".red-ui-tab-close").show(); - ul.find(".red-ui-tab-icon").show(); - ul.find(".red-ui-tab-label").css({paddingLeft:""}) - } - if (currentActiveTabWidth !== 0) { - ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth}); - ul.find("li.red-ui-tab.active .red-ui-tab-close").show(); - ul.find("li.red-ui-tab.active .red-ui-tab-icon").show(); - ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""}) + var tabWidth = (width-12-(tabCount*6))/tabCount; + currentTabWidth = (100*tabWidth/width)+"%"; + currentActiveTabWidth = currentTabWidth+"%"; + if (options.scrollable) { + tabWidth = Math.max(tabWidth,140); + currentTabWidth = tabWidth+"px"; + currentActiveTabWidth = 0; + var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount); + ul.width(listWidth); + updateScroll(); + } else if (options.hasOwnProperty("minimumActiveTabWidth")) { + if (tabWidth < options.minimumActiveTabWidth) { + tabCount -= 1; + tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount; + currentTabWidth = (100*tabWidth/width)+"%"; + currentActiveTabWidth = options.minimumActiveTabWidth+"px"; + } else { + currentActiveTabWidth = 0; + } + } + if (options.collapsible) { + console.log(currentTabWidth); + } + + tabs.css({width:currentTabWidth}); + if (tabWidth < 50) { + ul.find(".red-ui-tab-close").hide(); + ul.find(".red-ui-tab-icon").hide(); + ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"}) + } else { + ul.find(".red-ui-tab-close").show(); + ul.find(".red-ui-tab-icon").show(); + ul.find(".red-ui-tab-label").css({paddingLeft:""}) + } + if (currentActiveTabWidth !== 0) { + ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth}); + ul.find("li.red-ui-tab.active .red-ui-tab-close").show(); + ul.find("li.red-ui-tab.active .red-ui-tab-icon").show(); + ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""}) + } } } @@ -210,11 +293,15 @@ RED.tabs = (function() { activateTab(tab.find("a")); } li.remove(); + if (tabs[id].pinned) { + pinnedTabsCount--; + } if (options.onremove) { options.onremove(tabs[id]); } delete tabs[id]; updateTabWidths(); + collapsibleMenu = null; } return { @@ -223,13 +310,55 @@ RED.tabs = (function() { var li = $("
  • ",{class:"red-ui-tab"}).appendTo(ul); li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-"))); li.data("tabId",tab.id); + + if (options.maximumTabWidth) { + li.css("maxWidth",options.maximumTabWidth+"px"); + } var link = $("",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li); if (tab.icon) { $('').appendTo(link); + } else if (tab.iconClass) { + $('',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link); } var span = $('',{class:"bidiAware"}).text(tab.label).appendTo(link); span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label)); + if (options.collapsible) { + li.addClass("red-ui-tab-pinned"); + var pinnedLink = $(''); + if (tab.pinned) { + if (pinnedTabsCount === 0) { + pinnedLink.prependTo(collapsedButtonsRow) + } else { + pinnedLink.insertAfter(collapsedButtonsRow.find("a.red-ui-tab-link-button-pinned:last")); + } + } else { + pinnedLink.insertBefore(collapsedButtonsRow.find("a:last")); + } + pinnedLink.attr('id',li.attr('id')+"-link-button"); + if (tab.iconClass) { + $('',{class:tab.iconClass}).appendTo(pinnedLink); + } else { + $('',{class:"fa fa-lemon-o"}).appendTo(pinnedLink); + } + pinnedLink.click(function(evt) { + evt.preventDefault(); + activateTab(tab.id); + }); + if (tab.pinned) { + pinnedLink.addClass("red-ui-tab-link-button-pinned"); + pinnedTabsCount++; + } + RED.popover.create({ + target:$(pinnedLink), + trigger: "hover", + size: "small", + direction: "bottom", + content: tab.name, + delay: { show: 550, hide: 10 } + }); + + } link.on("click",onTabClick); link.on("dblclick",onTabDblClick); if (tab.closeable) { @@ -326,6 +455,7 @@ RED.tabs = (function() { } }) } + collapsibleMenu = null; }, removeTab: removeTab, activateTab: activateTab, diff --git a/editor/js/ui/projects/tab-versionControl.js b/editor/js/ui/projects/tab-versionControl.js index 44b602019..4560a56e5 100644 --- a/editor/js/ui/projects/tab-versionControl.js +++ b/editor/js/ui/projects/tab-versionControl.js @@ -1003,6 +1003,8 @@ RED.sidebar.versionControl = (function() { name: "Project History", content: sidebarContent, enableOnEdit: false, + pinned: true, + iconClass: "fa fa-code-fork", onchange: function() { setTimeout(function() { sections.resize(); diff --git a/editor/js/ui/sidebar.js b/editor/js/ui/sidebar.js index 222217668..d9f302885 100644 --- a/editor/js/ui/sidebar.js +++ b/editor/js/ui/sidebar.js @@ -35,7 +35,8 @@ RED.sidebar = (function() { tab.onremove.call(tab); } }, - minimumActiveTabWidth: 70 + // minimumActiveTabWidth: 70, + collapsible: true // scrollable: true }); @@ -59,6 +60,8 @@ RED.sidebar = (function() { options = title; } + delete options.closeable; + options.wrapper = $('
    ',{style:"height:100%"}).appendTo("#sidebar-content") options.wrapper.append(options.content); options.wrapper.hide(); @@ -82,6 +85,8 @@ RED.sidebar = (function() { group: "sidebar-tabs" }); + options.iconClass = options.iconClass || "fa fa-square-o" + knownTabs[options.id] = options; if (options.visible !== false) { diff --git a/editor/js/ui/tab-config.js b/editor/js/ui/tab-config.js index 9a4619b28..00caea6cd 100644 --- a/editor/js/ui/tab-config.js +++ b/editor/js/ui/tab-config.js @@ -221,8 +221,7 @@ RED.sidebar.config = (function() { name: RED._("sidebar.config.name"), content: content, toolbar: toolbar, - closeable: true, - visible: false, + iconClass: "fa fa-cog", onchange: function() { refreshConfigNodeList(); } }); RED.actions.add("core:show-config-tab",function() {RED.sidebar.show('config')}); diff --git a/editor/js/ui/tab-info.js b/editor/js/ui/tab-info.js index b4cf87d46..340a6bd74 100644 --- a/editor/js/ui/tab-info.js +++ b/editor/js/ui/tab-info.js @@ -83,7 +83,9 @@ RED.sidebar.info = (function() { id: "info", label: RED._("sidebar.info.label"), name: RED._("sidebar.info.name"), + iconClass: "fa fa-info", content: content, + pinned: true, enableOnEdit: true }); if (tips.enabled()) { diff --git a/editor/sass/popover.scss b/editor/sass/popover.scss index d3c077e6d..691acd5c8 100644 --- a/editor/sass/popover.scss +++ b/editor/sass/popover.scss @@ -30,7 +30,6 @@ } .red-ui-popover:after, .red-ui-popover:before { - top: 50%; border: solid transparent; content: " "; height: 0; @@ -39,12 +38,18 @@ pointer-events: none; } .red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before { + top: 50%; right: 100%; } .red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before { + top: 50%; left: 100%; } +.red-ui-popover.red-ui-popover-bottom:after, .red-ui-popover.red-ui-popover-bottom:before { + bottom: 100%; + left: 50%; +} .red-ui-popover.red-ui-popover-right:after { border-color: rgba(136, 183, 213, 0); @@ -72,6 +77,21 @@ margin-top: -11px; } + +.red-ui-popover.red-ui-popover-bottom:after { + border-color: rgba(136, 183, 213, 0); + border-bottom-color: #fff; + border-width: 10px; + margin-left: -10px; +} +.red-ui-popover.red-ui-popover-bottom:before { + border-color: rgba(194, 225, 245, 0); + border-bottom-color: $primary-border-color; + border-width: 11px; + margin-left: -11px; +} + + .red-ui-popover-size-small { font-size: 11px; padding: 5px; @@ -93,4 +113,12 @@ border-width: 6px; margin-top: -6px; } + &.red-ui-popover-bottom:after { + border-width: 5px; + margin-left: -5px; + } + &.red-ui-popover-bottom:before { + border-width: 6px; + margin-left: -6px; + } } diff --git a/editor/sass/tabs.scss b/editor/sass/tabs.scss index 4b2dc7f5d..488f4f3c9 100644 --- a/editor/sass/tabs.scss +++ b/editor/sass/tabs.scss @@ -93,7 +93,7 @@ color: $workspace-button-color-hover; } } - .red-ui-tab-icon { + img.red-ui-tab-icon { opacity: 0.2; } } @@ -113,6 +113,21 @@ &.red-ui-tabs-add.red-ui-tabs-scrollable { padding-right: 59px; } + &.red-ui-tabs-collapsible { + li:not(.active) { + display: none; + &.red-ui-tab-pinned { + a { + padding-left: 0; + text-align: center; + } + span { + display: none; + } + width: 32px; + } + } + } &.red-ui-tabs-vertical { box-sizing: border-box; @@ -157,6 +172,15 @@ } } } + .red-ui-tabs-select { + position: absolute; + top:0; + bottom: 0; + left: 0; + right: 0; + opacity: 0.4; + background: red; + } } .red-ui-tab-button { position: absolute; @@ -180,7 +204,33 @@ z-index: 2; } } - +.red-ui-tab-link-buttons { + position: absolute; + box-sizing: border-box; + top: 0; + right: 0; + height: 35px; + background: #fff; + border-bottom: 1px solid $primary-border-color; + z-index: 2; + a { + @include workspace-button; + line-height: 26px; + height: 28px; + width: 28px; + margin: 4px 3px 3px; + border: 1px solid $primary-border-color; + z-index: 2; + &.red-ui-tab-link-button { + &:not(.active) { + background: #eee; + } + } + &.red-ui-tab-link-button-menu { + border-color: white; + } + } +} .red-ui-tab-scroll { width: 21px; top: 0; @@ -216,7 +266,7 @@ right: 38px; } -.red-ui-tab-icon { +img.red-ui-tab-icon { margin-left: -8px; margin-right: 3px; margin-top: -2px; @@ -225,6 +275,11 @@ height: 20px; vertical-align: middle; } +i.red-ui-tab-icon { + opacity: 0.7; + width: 18px; + height: 20px; +} .red-ui-tabs-badges { position: absolute; diff --git a/nodes/core/core/58-debug.html b/nodes/core/core/58-debug.html index 7317d7064..95b55d7f5 100644 --- a/nodes/core/core/58-debug.html +++ b/nodes/core/core/58-debug.html @@ -154,7 +154,9 @@ name: this._("debug.sidebar.name"), content: uiComponents.content, toolbar: uiComponents.footer, - enableOnEdit: true + enableOnEdit: true, + pinned: true, + iconClass: "fa fa-wrench" }); RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });