Browse Source

Implement resizable sidebar

Closes #88.
Thibaut 10 years ago
parent
commit
e2afa6e494

+ 8 - 0
assets/javascripts/app/settings.coffee

@@ -2,6 +2,7 @@ class app.Settings
   SETTINGS_KEY = 'settings'
   DOCS_KEY = 'docs'
   DARK_KEY = 'dark'
+  SIZE_KEY = 'size'
 
   @defaults: ->
     count: 0
@@ -59,8 +60,15 @@ class app.Settings
     catch
     return
 
+  setSize: (value) ->
+    try
+      Cookies.set SIZE_KEY, value, path: '/', expires: 1e8
+    catch
+    return
+
   reset: ->
     try Cookies.expire DOCS_KEY
     try Cookies.expire DARK_KEY
+    try Cookies.expire SIZE_KEY
     try @store.del(SETTINGS_KEY)
     return

+ 4 - 1
assets/javascripts/news.json

@@ -1,5 +1,8 @@
 [
-  [ "2015-02-15",
+  [ "2015-02-16",
+    "The sidebar is now resizable (drag & drop)."
+  ], [
+    "2015-02-15",
     "New <a href=\"/iojs/\">io.js</a>, <a href=\"/symfony/\">Symfony</a>, <a href=\"/clojure/\">Clojure</a>, <a href=\"/lua/\">Lua</a> and <a href=\"/yii1/\">Yii 1.1</a> documentations"
   ], [
     "2015-02-08",

+ 1 - 0
assets/javascripts/views/layout/document.coffee

@@ -10,6 +10,7 @@ class app.views.Document extends app.View
   init: ->
     @addSubview @nav     = new app.views.Nav,
     @addSubview @sidebar = new app.views.Sidebar
+    @addSubview @resizer = new app.views.Resizer if app.views.Resizer.isSupported()
     @addSubview @content = new app.views.Content
     @addSubview @path    = new app.views.Path unless app.isSingleDoc() or app.isMobile()
 

+ 46 - 0
assets/javascripts/views/layout/resizer.coffee

@@ -0,0 +1,46 @@
+class app.views.Resizer extends app.View
+  @className: '_resizer'
+
+  @events:
+    dragstart: 'onDragStart'
+    dragend: 'onDragEnd'
+    drag: 'onDrag'
+
+  @isSupported: ->
+    'ondragstart' of document.createElement('div') and !app.isMobile()
+
+  init: ->
+    @el.setAttribute('draggable', 'true')
+    @appendTo $('._app')
+
+    @style = $('style[data-resizer]')
+    @size = @style.getAttribute('data-size')
+    return
+
+  MIN = 250
+  MAX = 600
+
+  resize: (newSize) ->
+    return unless newSize > 0
+    newSize = Math.min(Math.max(Math.round(newSize), MIN), MAX)
+    app.settings.setSize(newSize)
+    newSize = "#{newSize}px"
+    @style.innerHTML = @style.innerHTML.replace(new RegExp(@size, 'g'), newSize)
+    @size = newSize
+    return
+
+  onDragStart: (event) =>
+    @style.removeAttribute('disabled')
+    event.dataTransfer.effectAllowed = 'link'
+    event.dataTransfer.setData('text/plain', '')
+    return
+
+  onDrag: (event) =>
+    return if @lastDrag and @lastDrag > Date.now() - 50
+    @lastDrag = Date.now()
+    @resize event.clientX
+    return
+
+  onDragEnd: (event) =>
+    @resize event.screenX - window.screenX
+    return

+ 11 - 0
assets/stylesheets/components/_sidebar.scss

@@ -35,6 +35,17 @@
   a:focus { outline: 0; }
 }
 
+._resizer {
+  position: absolute;
+  z-index: $sidebarZ + 1;
+  top: $headerHeight;
+  bottom: 0;
+  left: $sidebarWidth;
+  margin-left: -2px;
+  width: 3px;
+  cursor: col-resize;
+}
+
 //
 // List
 //

+ 4 - 0
lib/app.rb

@@ -136,6 +136,10 @@ class App < Sinatra::Application
         dark: stylesheet_path('application-dark')
       }
     end
+
+    def size
+      @size ||= cookies[:size].nil? ? '18rem' : "#{cookies[:size]}px"
+    end
   end
 
   before do

+ 11 - 0
test/app_test.rb

@@ -20,6 +20,17 @@ class AppTest < MiniTest::Spec
       assert last_response.redirect?
       assert_equal 'http://example.org/', last_response['Location']
     end
+
+    it "sets default size" do
+      get '/'
+      assert_includes last_response.body, 'data-size="18rem"'
+    end
+
+    it "sets size from cookie" do
+      set_cookie('size=42')
+      get '/'
+      assert_includes last_response.body, 'data-size="42px"'
+    end
   end
 
   describe "/[static-page]" do

+ 6 - 0
views/app.erb

@@ -44,3 +44,9 @@
   a.src="//secure.gaug.es/track.js";var b=document.getElementsByTagName("script")[0];
   b.parentNode.insertBefore(a,b)}();
 </script><% end %>
+<style data-size="<%= size %>" data-resizer disabled>
+  ._container { margin-left: <%= size %>; }
+  ._search, ._list, ._sidebar-footer { width: <%= size %>; }
+  ._list-hover.clone { min-width: <%= size %>; }
+  ._notice, ._path, ._resizer { left: <%= size %>; }
+</style>