From d78ce3b2190a20840d4d4b81fb2b85d7d5cc4624 Mon Sep 17 00:00:00 2001
From: Marius BALTEANU <marius.balteanu@zitec.com>
Date: Thu, 5 Sep 2019 00:08:15 +0300
Subject: [PATCH] Collapsible sidebar with expand on hover

---
 app/views/layouts/base.html.erb    | 10 ++++-
 public/javascripts/application.js  | 71 ++++++++++++++++++++++++++++++
 public/stylesheets/application.css | 33 ++++++++++++--
 3 files changed, 109 insertions(+), 5 deletions(-)

diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb
index 7572dff5d..f41674be3 100644
--- a/app/views/layouts/base.html.erb
+++ b/app/views/layouts/base.html.erb
@@ -23,7 +23,6 @@
 
 <div class="flyout-menu js-flyout-menu">
 
-
     <% if User.current.logged? || !Setting.login_required? %>
         <div class="flyout-menu__search">
             <%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
@@ -99,8 +98,15 @@
     <% end %>
 </div>
 
-<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>">
+<div id="main" class="<%= sidebar_content? ? 'collapsiblesidebar' : 'nosidebar' %>">
+<%= javascript_tag "$('#main.collapsiblesidebar').collapsibleSidebar();" if sidebar_content? %>
     <div id="sidebar">
+        <% if sidebar_content? %>
+          <div id="sidebar-switch-panel" style="visibility: hidden;">
+            <a id="sidebar-switch-button" href="#">&raquo;</a>
+          </div>
+          <%= javascript_tag "$('#sidebar-switch-panel').css('visibility', 'visible');" %>
+        <% end %>
         <%= yield :sidebar %>
         <%= view_layouts_base_sidebar_hook_response %>
     </div>
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index a3fc9248d..bc2161d46 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -1006,6 +1006,77 @@ $(function () {
         }
     });
 });
+// collapsible sidebar jQuery plugin
+(function($) {
+  // main container this is applied to
+  var main;
+  // triggers show/hide
+  var button;
+  // the key to use in local storage
+  // this will later be expanded using the current controller and action to
+  // allow for different sidebar states for different pages
+  var localStorageKey = 'redmine-sidebar-state';
+  // true if local storage is available
+  var canUseLocalStorage = function(){
+    try {
+      if('localStorage' in window){
+        localStorage.setItem('redmine.test.storage', 'ok');
+        var item = localStorage.getItem('redmine.test.storage');
+        localStorage.removeItem('redmine.test.storage');
+        if(item === 'ok') return true;
+      }
+    } catch (err) {}
+    return false;
+  }();
+  // function to set current sidebar state
+  var setState = function(state){
+    if(canUseLocalStorage){
+      localStorage.setItem(localStorageKey, state);
+    }
+  };
+  var applyState = function(){
+    if(main.hasClass('collapsedsidebar')){
+      button.html("&laquo;");
+      setState('hidden');
+    } else {
+      button.html("&raquo;");
+      setState('visible');
+    }
+  };
+  var setupToggleButton = function(){
+    button = $('#sidebar-switch-button');
+    button.click(function(e){
+      main.addClass("animate");
+      main.toggleClass('collapsedsidebar');
+      applyState();
+      e.preventDefault();
+      return false;
+    });
+    applyState();
+  };
+  $.fn.collapsibleSidebar = function() {
+    main = this;
+    // determine previously stored sidebar state for this page
+    if(canUseLocalStorage) {
+      // determine current controller/action pair and use them as storage key
+      var bodyClass = $('body').attr('class');
+      if(bodyClass){
+        try {
+          localStorageKey += '-' + bodyClass.split(/\s+/).filter(function(s){
+            return s.match(/(action|controller)-.*/);
+          }).sort().join('-');
+        } catch(e) {
+          // in case of error (probably IE8), continue with the unmodified key
+        }
+      }
+      var storedState = localStorage.getItem(localStorageKey);
+      main.toggleClass('collapsedsidebar', storedState === 'hidden');
+    }
+    // draw the toggle button once the DOM is complete
+    $(document).ready(setupToggleButton);
+  };
+}(jQuery));
+
 $(document).ready(setupAjaxIndicator);
 $(document).ready(hideOnLoad);
 $(document).ready(addFormObserversForDoubleSubmit);
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 7a9c6497d..33ee57a5c 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -84,9 +84,11 @@ div[id^="wrapper"] { min-height: inherit; }
 #admin-menu li {margin: 0;  padding: 0 0 6px 0; list-style-type:none;}
 
 #main {flex-grow: 2; display: flex; flex-direction: row-reverse;}
+#main.nosidebar #sidebar {display: none;}
 
-#sidebar{ flex-shrink: 0; width: 22%; padding-left: 20px; background: #EEEEEE; border-left: 1px solid #ddd}
-#sidebar h3{ font-size: 14px; margin-top:14px; color: #666;  }
+#sidebar{ flex-shrink: 0; width: 22%; padding-left: 20px; background: #EEEEEE; border-left: 1px solid #ddd; z-index: 1;}
+#sidebar h3 { font-size: 14px; margin-top:14px; color: #666;  }
+#sidebar h3:first-of-type { margin-top: 4px ; }
 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
 #sidebar .contextual { margin-right: 1em; }
@@ -99,7 +101,32 @@ div[id^="wrapper"] { min-height: inherit; }
 html>body #content { min-height: 600px; }
 * html body #content { height: 600px; } /* IE */
 
-#main.nosidebar #sidebar{ display: none; }
+#main.collapsedsidebar #sidebar { display: block; width: 0px; }
+#main.collapsedsidebar #sidebar:hover { width: 22%; position: absolute; height:100%; }
+#main.collapsedsidebar #sidebar:hover ~ #content { padding-right: 30px; }
+
+
+#sidebar-switch-panel {
+  font-size: 20px;
+  width: 100%;
+  color: #666;
+  display: block;
+  margin-left: -21px;
+  padding-right: 21px;
+  border-bottom: 1px solid #ddd;
+  padding-left: 4px;
+}
+#sidebar-switch-panel:hover {
+  background-color: #e6e6e6;
+}
+#sidebar-switch-button {
+  color: #666;
+  width: 100%;
+  display: block;
+}
+#sidebar-switch-button:hover {
+  text-decoration: none;
+}
 
 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
 
-- 
2.22.0

