Project

General

Profile

Feature #21808 » collapsible-sidebar-with-expand-on-hover-for_r23166.patch

Mizuki ISHIKAWA, 2024-10-28 06:39

View differences:

app/assets/javascripts/application.js
1261 1261
    tribute.attach(element);
1262 1262
}
1263 1263

  
1264
// collapsible sidebar jQuery plugin
1265
(function($) {
1266
  // main container this is applied to
1267
  var main;
1268
  // triggers show/hide
1269
  var button;
1270
  // the key to use in local storage
1271
  // this will later be expanded using the current controller and action to
1272
  // allow for different sidebar states for different pages
1273
  var localStorageKey = 'redmine-sidebar-state';
1274
  // true if local storage is available
1275
  var canUseLocalStorage = function(){
1276
    try {
1277
      if('localStorage' in window){
1278
        localStorage.setItem('redmine.test.storage', 'ok');
1279
        var item = localStorage.getItem('redmine.test.storage');
1280
        localStorage.removeItem('redmine.test.storage');
1281
        if(item === 'ok') return true;
1282
      }
1283
    } catch (err) {}
1284
    return false;
1285
  }();
1286
  // function to set current sidebar state
1287
  var setState = function(state){
1288
    if(canUseLocalStorage){
1289
      localStorage.setItem(localStorageKey, state);
1290
    }
1291
  };
1292
  var applyState = function(){
1293
    if(main.hasClass('collapsedsidebar')){
1294
      button.html("«");
1295
      setState('hidden');
1296
    } else {
1297
      button.html("»");
1298
      setState('visible');
1299
    }
1300
  };
1301
  var setupToggleButton = function(){
1302
    button = $('#sidebar-switch-button');
1303
    button.click(function(e){
1304
      main.addClass("animate");
1305
      main.toggleClass('collapsedsidebar');
1306
      applyState();
1307
      e.preventDefault();
1308
      return false;
1309
    });
1310
    applyState();
1311
  };
1312
  $.fn.collapsibleSidebar = function() {
1313
    main = this;
1314
    // determine previously stored sidebar state for this page
1315
    if(canUseLocalStorage) {
1316
      // determine current controller/action pair and use them as storage key
1317
      var bodyClass = $('body').attr('class');
1318
      if(bodyClass){
1319
        try {
1320
          localStorageKey += '-' + bodyClass.split(/\s+/).filter(function(s){
1321
            return s.match(/(action|controller)-.*/);
1322
          }).sort().join('-');
1323
        } catch(e) {
1324
          // in case of error (probably IE8), continue with the unmodified key
1325
        }
1326
      }
1327
      var storedState = localStorage.getItem(localStorageKey);
1328
      main.toggleClass('collapsedsidebar', storedState === 'hidden');
1329
    }
1330
    // draw the toggle button once the DOM is complete
1331
    $(document).ready(setupToggleButton);
1332
  };
1333
}(jQuery));
1334

  
1264 1335
$(document).ready(setupAjaxIndicator);
1265 1336
$(document).ready(hideOnLoad);
1266 1337
$(document).ready(addFormObserversForDoubleSubmit);
app/assets/stylesheets/application.css
135 135

  
136 136
#main {flex-grow: 2; display: flex; flex-direction: row-reverse;}
137 137

  
138
#sidebar{ font-size: 0.8125rem; flex-shrink: 0; padding-left: 20px; padding-right: 8px; background: #f9fafb; border-left: 1px solid #d0d7de}
138
#main.nosidebar #sidebar{ display: none; }
139
#sidebar{ font-size: 0.8125rem; flex-shrink: 0; padding-left: 20px; padding-right: 8px; background: #f9fafb; border-left: 1px solid #d0d7de; z-index: 1;}
140

  
139 141
@media screen and (min-width: 0px) and (max-width: 1089px) {#sidebar{width: 22%;}}
140 142
@media screen and (min-width: 1090px) and (max-width: 1279px) {#sidebar{width: 240px;}}
141 143
@media screen and (min-width: 1280px) and (max-width: 1599px) {#sidebar{width: 280px;}}
......
143 145
@media screen and (min-width: 1920px) and (max-width: 2559px) {#sidebar{width: 360px;}}
144 146
@media screen and (min-width: 2560px) {#sidebar{width: 380px;}}
145 147
#sidebar h3{ font-size: 0.875rem; margin-top:14px; color: #555; }
148
#sidebar h3:first-of-type { margin-top: 4px ; }
146 149
#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
147 150
#sidebar .contextual { margin-right: 1em; }
148 151
#sidebar ul, ul.flat {margin: 0;  padding: 0;}
......
154 157
#sidebar span.icon-warning {margin-left: 5px;}
155 158
#sidebar li input[type=checkbox] {height: 20px;}
156 159

  
157
#content { flex-grow: 1; background-color: #fff; margin: 0px; padding: 10px 16px 10px 16px; overflow-x: auto;}
160
#main.collapsedsidebar #sidebar { display: block; width: 0px !important; position: absolute; box-sizing: border-box; height: 100%; overflow: hidden; transition: 0.35s; }
161
#main.collapsedsidebar #sidebar:hover { width: 22% !important; }
162
#main:not(.collapsedsidebar) #content { margin-right: 0; }
163
#main.collapsedsidebar #sidebar > :not(#sidebar-switch-panel) {
164
    visibility: hidden;
165
}
166
#main.collapsedsidebar #sidebar:hover > :not(#sidebar-switch-panel) {
167
    visibility: visible;
168
}
169
body div#content {
170
    margin-right: 30px;
171
}
172
body #main {
173
    position: relative;
174
}
175
#sidebar-switch-panel {
176
  position: relative;
177
  left: 6px;
178
  font-size: 20px;
179
  width: 100% !important;
180
  color: #666;
181
  display: block;
182
  margin-left: -21px;
183
  padding-right: 21px;
184
  border-bottom: 1px solid #ddd;
185
  padding-left: 4px;
186
}
187
#sidebar-switch-panel:hover {
188
  background-color: #e6e6e6;
189
}
190
#sidebar-switch-button {
191
  color: #666;
192
  width: 100% !important;
193
  display: block;
194
}
195
#sidebar-switch-button:hover {
196
  text-decoration: none;
197
}
158 198

  
159
#main.nosidebar #sidebar{ display: none; }
199
#content { flex-grow: 1; background-color: #fff; margin: 0px; padding: 10px 16px 10px 16px; overflow-x: auto;}
160 200

  
161 201
#footer {clear: both; border-top: 1px solid #d0d7de; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
162 202

  
app/views/layouts/base.html.erb
100 100
    <% end %>
101 101
</div>
102 102

  
103
<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>">
103
<div id="main" class="<%= sidebar_content? ? 'collapsiblesidebar' : 'nosidebar' %>">
104
<%= javascript_tag "$('#main.collapsiblesidebar').collapsibleSidebar();" if sidebar_content? %>
104 105
    <div id="sidebar">
106
        <% if sidebar_content? %>
107
            <div id="sidebar-switch-panel" style="visibility: hidden;">
108
            <a id="sidebar-switch-button" href="#">&raquo;</a>
109
            </div>
110
            <%= javascript_tag "$('#sidebar-switch-panel').css('visibility', 'visible');" %>
111
        <% end %>
105 112
        <%= yield :sidebar %>
106 113
        <%= view_layouts_base_sidebar_hook_response %>
107 114
    </div>
(19-19/22)