Feature #21808 » 0001-Collapsible-sidebar-with-expand-on-hover.patch
app/views/layouts/base.html.erb | ||
---|---|---|
23 | 23 | |
24 | 24 |
<div class="flyout-menu js-flyout-menu"> |
25 | 25 | |
26 | ||
27 | 26 |
<% if User.current.logged? || !Setting.login_required? %> |
28 | 27 |
<div class="flyout-menu__search"> |
29 | 28 |
<%= form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %> |
... | ... | |
99 | 98 |
<% end %> |
100 | 99 |
</div> |
101 | 100 | |
102 |
<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>"> |
|
101 |
<div id="main" class="<%= sidebar_content? ? 'collapsiblesidebar' : 'nosidebar' %>"> |
|
102 |
<%= javascript_tag "$('#main.collapsiblesidebar').collapsibleSidebar();" if sidebar_content? %> |
|
103 | 103 |
<div id="sidebar"> |
104 |
<% if sidebar_content? %> |
|
105 |
<div id="sidebar-switch-panel" style="visibility: hidden;"> |
|
106 |
<a id="sidebar-switch-button" href="#">»</a> |
|
107 |
</div> |
|
108 |
<%= javascript_tag "$('#sidebar-switch-panel').css('visibility', 'visible');" %> |
|
109 |
<% end %> |
|
104 | 110 |
<%= yield :sidebar %> |
105 | 111 |
<%= view_layouts_base_sidebar_hook_response %> |
106 | 112 |
</div> |
public/javascripts/application.js | ||
---|---|---|
1006 | 1006 |
} |
1007 | 1007 |
}); |
1008 | 1008 |
}); |
1009 |
// collapsible sidebar jQuery plugin |
|
1010 |
(function($) { |
|
1011 |
// main container this is applied to |
|
1012 |
var main; |
|
1013 |
// triggers show/hide |
|
1014 |
var button; |
|
1015 |
// the key to use in local storage |
|
1016 |
// this will later be expanded using the current controller and action to |
|
1017 |
// allow for different sidebar states for different pages |
|
1018 |
var localStorageKey = 'redmine-sidebar-state'; |
|
1019 |
// true if local storage is available |
|
1020 |
var canUseLocalStorage = function(){ |
|
1021 |
try { |
|
1022 |
if('localStorage' in window){ |
|
1023 |
localStorage.setItem('redmine.test.storage', 'ok'); |
|
1024 |
var item = localStorage.getItem('redmine.test.storage'); |
|
1025 |
localStorage.removeItem('redmine.test.storage'); |
|
1026 |
if(item === 'ok') return true; |
|
1027 |
} |
|
1028 |
} catch (err) {} |
|
1029 |
return false; |
|
1030 |
}(); |
|
1031 |
// function to set current sidebar state |
|
1032 |
var setState = function(state){ |
|
1033 |
if(canUseLocalStorage){ |
|
1034 |
localStorage.setItem(localStorageKey, state); |
|
1035 |
} |
|
1036 |
}; |
|
1037 |
var applyState = function(){ |
|
1038 |
if(main.hasClass('collapsedsidebar')){ |
|
1039 |
button.html("«"); |
|
1040 |
setState('hidden'); |
|
1041 |
} else { |
|
1042 |
button.html("»"); |
|
1043 |
setState('visible'); |
|
1044 |
} |
|
1045 |
}; |
|
1046 |
var setupToggleButton = function(){ |
|
1047 |
button = $('#sidebar-switch-button'); |
|
1048 |
button.click(function(e){ |
|
1049 |
main.addClass("animate"); |
|
1050 |
main.toggleClass('collapsedsidebar'); |
|
1051 |
applyState(); |
|
1052 |
e.preventDefault(); |
|
1053 |
return false; |
|
1054 |
}); |
|
1055 |
applyState(); |
|
1056 |
}; |
|
1057 |
$.fn.collapsibleSidebar = function() { |
|
1058 |
main = this; |
|
1059 |
// determine previously stored sidebar state for this page |
|
1060 |
if(canUseLocalStorage) { |
|
1061 |
// determine current controller/action pair and use them as storage key |
|
1062 |
var bodyClass = $('body').attr('class'); |
|
1063 |
if(bodyClass){ |
|
1064 |
try { |
|
1065 |
localStorageKey += '-' + bodyClass.split(/\s+/).filter(function(s){ |
|
1066 |
return s.match(/(action|controller)-.*/); |
|
1067 |
}).sort().join('-'); |
|
1068 |
} catch(e) { |
|
1069 |
// in case of error (probably IE8), continue with the unmodified key |
|
1070 |
} |
|
1071 |
} |
|
1072 |
var storedState = localStorage.getItem(localStorageKey); |
|
1073 |
main.toggleClass('collapsedsidebar', storedState === 'hidden'); |
|
1074 |
} |
|
1075 |
// draw the toggle button once the DOM is complete |
|
1076 |
$(document).ready(setupToggleButton); |
|
1077 |
}; |
|
1078 |
}(jQuery)); |
|
1079 | ||
1009 | 1080 |
$(document).ready(setupAjaxIndicator); |
1010 | 1081 |
$(document).ready(hideOnLoad); |
1011 | 1082 |
$(document).ready(addFormObserversForDoubleSubmit); |
public/stylesheets/application.css | ||
---|---|---|
84 | 84 |
#admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;} |
85 | 85 | |
86 | 86 |
#main {flex-grow: 2; display: flex; flex-direction: row-reverse;} |
87 |
#main.nosidebar #sidebar {display: none;} |
|
87 | 88 | |
88 |
#sidebar{ flex-shrink: 0; width: 22%; padding-left: 20px; background: #EEEEEE; border-left: 1px solid #ddd} |
|
89 |
#sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } |
|
89 |
#sidebar{ flex-shrink: 0; width: 22%; padding-left: 20px; background: #EEEEEE; border-left: 1px solid #ddd; z-index: 1;} |
|
90 |
#sidebar h3 { font-size: 14px; margin-top:14px; color: #666; } |
|
91 |
#sidebar h3:first-of-type { margin-top: 4px ; } |
|
90 | 92 |
#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } |
91 | 93 |
* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } |
92 | 94 |
#sidebar .contextual { margin-right: 1em; } |
... | ... | |
99 | 101 |
html>body #content { min-height: 600px; } |
100 | 102 |
* html body #content { height: 600px; } /* IE */ |
101 | 103 | |
102 |
#main.nosidebar #sidebar{ display: none; } |
|
104 |
#main.collapsedsidebar #sidebar { display: block; width: 0px; } |
|
105 |
#main.collapsedsidebar #sidebar:hover { width: 22%; position: absolute; height:100%; } |
|
106 |
#main.collapsedsidebar #sidebar:hover ~ #content { padding-right: 30px; } |
|
107 | ||
108 | ||
109 |
#sidebar-switch-panel { |
|
110 |
font-size: 20px; |
|
111 |
width: 100%; |
|
112 |
color: #666; |
|
113 |
display: block; |
|
114 |
margin-left: -21px; |
|
115 |
padding-right: 21px; |
|
116 |
border-bottom: 1px solid #ddd; |
|
117 |
padding-left: 4px; |
|
118 |
} |
|
119 |
#sidebar-switch-panel:hover { |
|
120 |
background-color: #e6e6e6; |
|
121 |
} |
|
122 |
#sidebar-switch-button { |
|
123 |
color: #666; |
|
124 |
width: 100%; |
|
125 |
display: block; |
|
126 |
} |
|
127 |
#sidebar-switch-button:hover { |
|
128 |
text-decoration: none; |
|
129 |
} |
|
103 | 130 | |
104 | 131 |
#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} |
105 | 132 |