History

UI improvements

Thibaut Courouble committed 9 years ago

Commit 0f238601 parent fd03ac139 files · +295 −334Browse files

Unified · Split

39 files
  1. assets/images/icons.png +0 −0
  2. assets/images/icons@2x.png +0 −0
  3. assets/javascripts/templates/pages/about_tmpl.coffee +6 −6
  4. assets/javascripts/templates/pages/help_tmpl.coffee +5 −3
  5. assets/javascripts/templates/pages/news_tmpl.coffee.erb +1 −1
  6. assets/javascripts/templates/pages/offline_tmpl.coffee +1 −1
  7. assets/javascripts/templates/pages/root_tmpl.coffee.erb +0 −9
  8. assets/javascripts/views/content/root_page.coffee +0 −1
  9. assets/javascripts/views/layout/document.coffee +11 −37
  10. assets/javascripts/views/layout/menu.coffee +24 −0
  11. assets/javascripts/views/layout/mobile.coffee +17 −18
  12. assets/javascripts/views/layout/nav.coffee +0 −26
  13. assets/javascripts/views/layout/resizer.coffee +1 −1
  14. assets/javascripts/views/list/list_focus.coffee +6 −6
  15. assets/javascripts/views/misc/notice.coffee +0 −1
  16. assets/javascripts/views/search/search.coffee +1 −1
  17. assets/javascripts/views/sidebar/doc_list.coffee +1 −1
  18. assets/javascripts/views/sidebar/results.coffee +2 −2
  19. assets/javascripts/views/sidebar/sidebar.coffee +41 −14
  20. assets/javascripts/views/view.coffee +7 −0
  21. assets/stylesheets/components/_app.scss +2 −3
  22. assets/stylesheets/components/_content.scss +29 −14
  23. assets/stylesheets/components/_header.scss +104 −51
  24. assets/stylesheets/components/_mobile.scss +14 −108
  25. assets/stylesheets/components/_notice.scss +1 −11
  26. assets/stylesheets/components/_sidebar.scss +1 −1
  27. assets/stylesheets/global/_icons.scss +0 −3
  28. assets/stylesheets/global/_variables-dark.scss +2 −2
  29. assets/stylesheets/global/_variables.scss +4 −4
  30. lib/app.rb +1 −1
  31. public/icons/ui/back/16.png +0 −0
  32. public/icons/ui/back/16@2x.png +0 −0
  33. public/icons/ui/home/16.png +0 −0
  34. public/icons/ui/home/16@2x.png +0 −0
  35. public/icons/ui/home/SOURCE +0 −1
  36. public/icons/ui/menu/16.png +0 −0
  37. public/icons/ui/menu/16@2x.png +0 −0
  38. test/app_test.rb +2 −2
  39. views/app.erb +19 −13
assets/images/icons.png+0−0

Binary file not shown.

assets/images/icons@2x.png+0−0

Binary file not shown.

assets/javascripts/templates/pages/about_tmpl.coffee+6−6
@@ -10,7 +10,7 @@ app.templates.aboutPage = -> """ · 9 unmodified lines
1010 </ul>
1111 </nav>
1212
13− <h1 class="_lined-heading">API Documentation Browser</h1>
13+ <h1 class="_lined-heading">DevDocs: API Documentation Browser</h1>
1414 <p>DevDocs combines multiple API documentations in a fast, organized, and searchable interface.
1515 <ul>
1616 <li>Created and maintained by <a href="http://thibaut.me">Thibaut Courouble</a>
@@ -26,7 +26,7 @@ app.templates.aboutPage = -> """ · 9 unmodified lines
2626 <p class="_note _note-green">If you like DevDocs, please consider supporting my work on
2727 <a href="https://gratipay.com/devdocs/">Gratipay</a>. Thanks!<br>
2828
29− <h2 class="_lined-heading" id="credits">Credits</h2>
29+ <h2 class="_block-heading" id="credits">Credits</h2>
3030
3131 <p><strong>Special thanks to:</strong>
3232 <ul>
@@ -45,7 +45,7 @@ app.templates.aboutPage = -> """ · 12 unmodified lines
4545 #{("<tr><td>#{c[0]}<td>&copy; #{c[1]}<td><a href=\"#{c[3]}\">#{c[2]}</a>" for c in credits).join('')}
4646 </table>
4747
48− <h2 class="_lined-heading" id="faq">Questions & Answers</h2>
48+ <h2 class="_block-heading" id="faq">Questions & Answers</h2>
4949 <dl>
5050 <dt>Where can I suggest new docs and features?
5151 <dd>You can suggest and vote for new docs on the <a href="https://trello.com/b/6BmTulfx/devdocs-documentation">Trello board</a>.<br>
@@ -56,7 +56,7 @@ app.templates.aboutPage = -> """ · 4 unmodified lines
5656 </dl>
5757 <p>For anything else, feel free to email me at <a href="mailto:thibaut@devdocs.io">thibaut@devdocs.io</a>.
5858
59− <h2 class="_lined-heading" id="copyright">Copyright and License</h2>
59+ <h2 class="_block-heading" id="copyright">Copyright and License</h2>
6060 <p class="_note">
6161 <strong>Copyright 2013&ndash;2017 Thibaut Courouble and <a href="https://github.com/Thibaut/devdocs/graphs/contributors">other contributors</a></strong><br>
6262 This software is licensed under the terms of the Mozilla Public License v2.0.<br>
@@ -64,7 +64,7 @@ app.templates.aboutPage = -> """ · 1 unmodified line
6464 For more information, see the <a href="https://github.com/Thibaut/devdocs/blob/master/COPYRIGHT">COPYRIGHT</a>
6565 and <a href="https://github.com/Thibaut/devdocs/blob/master/LICENSE">LICENSE</a> files.
6666
67− <h2 class="_lined-heading" id="plugins">Plugins and Extensions</h2>
67+ <h2 class="_block-heading" id="plugins">Plugins and Extensions</h2>
6868 <ul>
6969 <li><a href="https://chrome.google.com/webstore/detail/devdocs/mnfehgbmkapmjnhcnbodoamcioleeooe">Chrome web app</a>
7070 <li><a href="https://sublime.wbond.net/packages/DevDocs">Sublime Text plugin</a>
@@ -73,7 +73,7 @@ app.templates.aboutPage = -> """ · 2 unmodified lines
7373 <li><a href="https://github.com/xuchunyang/DevDocs.el">Emacs Package</a>
7474 </ul>
7575
76− <h2 class="_lined-heading" id="privacy">Privacy Policy</h2>
76+ <h2 class="_block-heading" id="privacy">Privacy Policy</h2>
7777 <ul>
7878 <li><a href="http://devdocs.io">devdocs.io</a> ("App") is operated by Thibaut Courouble ("We").
7979 <li>We do not collect personal information.
assets/javascripts/templates/pages/help_tmpl.coffee+5−3
@@ -11,7 +11,9 @@ app.templates.helpPage = """ · 10 unmodified lines
1111 </ul>
1212 </nav>
1313
14− <h2 class="_lined-heading" id="search">Search</h2>
14+ <h1 class="_lined-heading" id="search">Help</h2>
15+
16+ <h2 class="_block-heading" id="search">Search</h2>
1517 <p>
1618 The search is case-insensitive and supports fuzzy matching (for queries longer than two characters).
1719 For example, searching <code class="_label">bgcp</code> brings up <code class="_label">background-clip</code>.<br>
@@ -42,7 +44,7 @@ app.templates.helpPage = """ · 24 unmodified lines
4244 <a href="https://support.mozilla.org/en-US/kb/how-search-from-address-bar">these instructions</a>.
4345 </dl>
4446
45− <h2 class="_lined-heading" id="shortcuts">Keyboard Shortcuts</h2>
47+ <h2 class="_block-heading" id="shortcuts">Keyboard Shortcuts</h2>
4648 <h3 class="_shortcuts-title">Selection</h3>
4749 <dl class="_shortcuts-dl">
4850 <dt class="_shortcuts-dt">
@@ -110,7 +112,7 @@ app.templates.helpPage = """ · 61 unmodified lines
110112 <strong>Tip:</strong> If the cursor is no longer in the search field, press <code class="_label">/</code> or
111113 continue to type and it will refocus the search field and start showing new results.
112114
113− <h2 class="_lined-heading" id="abbreviations">Abbreviations</h2>
115+ <h2 class="_block-heading" id="abbreviations">Abbreviations</h2>
114116 <p>Feel free to suggest new abbreviations on <a href="https://github.com/Thibaut/devdocs/issues/new">GitHub</a>.
115117 <table class="_abbreviations">
116118 <tr>
assets/javascripts/templates/pages/news_tmpl.coffee.erb+1−1
@@ -15,7 +15,7 @@ app.templates.newsList = (news, options = {}) -> · 14 unmodified lines
1515 date = new Date(value[0])
1616 if options.years isnt false and year isnt date.getUTCFullYear()
1717 year = date.getUTCFullYear()
18− result += "<h4>#{year}</h4>"
18+ result += """<h2 class="_block-heading">#{year}</h2>"""
1919 result += newsItem(date, value[1..])
2020
2121 result
assets/javascripts/templates/pages/offline_tmpl.coffee+1−1
@@ -21,7 +21,7 @@ app.templates.offlinePage = (docs) -> """ · 20 unmodified lines
2121 #{docs}
2222 </table>
2323 <p class="_note"><strong>Note:</strong> your browser may delete DevDocs's offline data if your computer is running low on disk space and you haven't used the app in a while. Load this page before going offline to make sure the data is still there.
24− <h1 class="_lined-heading">Questions & Answers</h1>
24+ <h2 class="_block-heading">Questions & Answers</h2>
2525 <dl>
2626 <dt>How does this work?
2727 <dd>Each page is cached as a key-value pair in <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> (downloaded from a single file).<br>
assets/javascripts/templates/pages/root_tmpl.coffee.erb+0−9
@@ -48,15 +48,6 @@ app.templates.intro = """ · 47 unmodified lines
4848 """
4949 <% end %>
5050
51−app.templates.mobileNav = """
52− <nav class="_mobile-nav">
53− <a href="/offline" class="_mobile-nav-link">Offline</a>
54− <a href="/about" class="_mobile-nav-link">About</a>
55− <a href="/news" class="_mobile-nav-link">News</a>
56− <a href="/help" class="_mobile-nav-link">Help</a>
57− </nav>
58−"""
59−
6051 app.templates.mobileIntro = """
6152 <div class="_mobile-intro">
6253 <h2 class="_intro-title">Welcome!</h2>
assets/javascripts/views/content/root_page.coffee+0−1
@@ -9,7 +9,6 @@ class app.views.RootPage extends app.View · 8 unmodified lines
99
1010 render: ->
1111 @empty()
12− @append @tmpl('mobileNav') if app.isMobile()
1312 if app.isAndroidWebview()
1413 @append @tmpl('androidWarning')
1514 else
assets/javascripts/views/layout/document.coffee+11−37
@@ -1,6 +1,6 @@
11 class app.views.Document extends app.View
2− MAX_WIDTH_CLASS = '_max-width'
3− HIDE_SIDEBAR_CLASS = '_sidebar-hidden'
2+ MAX_WIDTH_LAYOUT = '_max-width'
3+ SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
44
55 @el: document
66
@@ -14,16 +14,12 @@ class app.views.Document extends app.View · 7 unmodified lines
1414 superRight: 'onForward'
1515
1616 init: ->
17− @addSubview @nav = new app.views.Nav,
17+ @addSubview @menu = new app.views.Menu,
1818 @addSubview @sidebar = new app.views.Sidebar
1919 @addSubview @resizer = new app.views.Resizer if app.views.Resizer.isSupported()
2020 @addSubview @content = new app.views.Content
2121 @addSubview @path = new app.views.Path unless app.isSingleDoc() or app.isMobile()
2222
23− @sidebar.search
24− .on 'searching', @onSearching
25− .on 'clear', @onSearchClear
26−
2723 $.on document.body, 'click', @onClick
2824
2925 @activate()
@@ -39,39 +35,17 @@ class app.views.Document extends app.View · 9 unmodified lines
3935 return
4036
4137 toggleLayout: ->
42− wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_CLASS)
43− app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_CLASS)
44− app.settings.setLayout(MAX_WIDTH_CLASS, wantsMaxWidth)
38+ wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_LAYOUT)
39+ app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_LAYOUT)
40+ app.settings.setLayout(MAX_WIDTH_LAYOUT, wantsMaxWidth)
4541 app.appCache?.updateInBackground()
4642 return
4743
48− showSidebar: (options = {}) ->
49− @toggleSidebar(options, true)
50− return
51−
52− hideSidebar: (options = {}) ->
53− @toggleSidebar(options, false)
54− return
55−
56− toggleSidebar: (options = {}, shouldShow) ->
57− shouldShow ?= if options.save then !@hasSidebar() else app.el.classList.contains(HIDE_SIDEBAR_CLASS)
58− app.el.classList[if shouldShow then 'remove' else 'add'](HIDE_SIDEBAR_CLASS)
59− if options.save
60− app.settings.setLayout(HIDE_SIDEBAR_CLASS, !shouldShow)
61− app.appCache?.updateInBackground()
62− return
63−
64− hasSidebar: ->
65− !app.settings.hasLayout(HIDE_SIDEBAR_CLASS)
66−
67− onSearching: =>
68− unless @hasSidebar()
69− @showSidebar()
70− return
71−
72− onSearchClear: =>
73− unless @hasSidebar()
74− @hideSidebar()
44+ toggleSidebarLayout: ->
45+ shouldHide = !app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)
46+ app.el.classList[if shouldHide then 'add' else 'remove'](SIDEBAR_HIDDEN_LAYOUT)
47+ app.settings.setLayout(SIDEBAR_HIDDEN_LAYOUT, shouldHide)
48+ app.appCache?.updateInBackground()
7549 return
7650
7751 setTitle: (title) ->
assets/javascripts/views/layout/menu.coffee+24−0
@@ -0,0 +1,24 @@
1+class app.views.Menu extends app.View
2+ @el: '._menu'
3+ @activeClass: 'active'
4+
5+ @events:
6+ click: 'onClick'
7+
8+ init: ->
9+ $.on document.body, 'click', @onGlobalClick
10+ return
11+
12+ onClick: =>
13+ prev = @el.previousElementSibling
14+ $.remove @el
15+ $.requestAnimationFrame => $.after(prev, @el)
16+ return
17+
18+ onGlobalClick: (event) =>
19+ return if event.which isnt 1
20+ if event.target.hasAttribute?('data-toggle-menu')
21+ @toggleClass @constructor.activeClass
22+ else if @hasClass @constructor.activeClass
23+ @removeClass @constructor.activeClass
24+ return
assets/javascripts/views/layout/mobile.coffee+17−18
@@ -35,44 +35,48 @@ class app.views.Mobile extends app.View · 34 unmodified lines
3535 FastClick.attach @body
3636
3737 $.on @body, 'click', @onClick
38− $.on $('._home-btn'), 'click', @onClickHome
39− $.on $('._menu-btn'), 'click', @onClickMenu
4038 $.on $('._search'), 'touchend', @onTapSearch
4139
42− @back = $('._back-btn')
40+ @toggleSidebar = $('button[data-toggle-sidebar]')
41+ @toggleSidebar.removeAttribute('hidden')
42+ $.on @toggleSidebar, 'click', @onClickToggleSidebar
43+
44+ @back = $('button[data-back]')
45+ @back.removeAttribute('hidden')
4346 $.on @back, 'click', @onClickBack
4447
45− @forward = $('._forward-btn')
48+ @forward = $('button[data-forward]')
49+ @forward.removeAttribute('hidden')
4650 $.on @forward, 'click', @onClickForward
4751
4852 app.document.sidebar.search
4953 .on 'searching', @showSidebar
50− .on 'clear', @hideSidebar
5154
5255 @activate()
5356 return
5457
5558 showSidebar: =>
5659 if @isSidebarShown()
57− @body.scrollTop = 0
60+ window.scrollTo 0, 0
5861 return
5962
60− @contentTop = @body.scrollTop
63+ @contentTop = window.scrollY
6164 @content.style.display = 'none'
6265 @sidebar.style.display = 'block'
6366
6467 if selection = @findByClass app.views.ListSelect.activeClass
65− $.scrollTo selection, @body, 'center'
68+ scrollContainer = if window.scrollY is @body.scrollTop then @body else document.documentElement
69+ $.scrollTo selection, scrollContainer, 'center'
6670 else
67− @body.scrollTop = @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0
71+ window.scrollTo 0, @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0
6872 return
6973
7074 hideSidebar: =>
7175 return unless @isSidebarShown()
72− @sidebarTop = @body.scrollTop
76+ @sidebarTop = window.scrollY
7377 @sidebar.style.display = 'none'
7478 @content.style.display = 'block'
75− @body.scrollTop = @contentTop or 0
79+ window.scrollTo 0, @contentTop or 0
7680 return
7781
7882 isSidebarShown: ->
@@ -89,17 +93,12 @@ class app.views.Mobile extends app.View · 10 unmodified lines
8993 onClickForward: =>
9094 history.forward()
9195
92− onClickHome: =>
93− app.shortcuts.trigger 'escape'
94− @hideSidebar()
95− return
96−
97− onClickMenu: =>
96+ onClickToggleSidebar: =>
9897 if @isSidebarShown() then @hideSidebar() else @showSidebar()
9998 return
10099
101100 onTapSearch: =>
102− @body.scrollTop = 0
101+ window.scrollTo 0, 0
103102
104103 afterRoute: =>
105104 @hideSidebar()
assets/javascripts/views/layout/nav.coffee+0−26
@@ -1,26 +0,0 @@
1−class app.views.Nav extends app.View
2− @el: '._nav'
3− @activeClass: '_nav-current'
4−
5− @routes:
6− after: 'afterRoute'
7−
8− select: (href) ->
9− @deselect()
10− if @current = @find "a[href='#{href}']"
11− @current.classList.add @constructor.activeClass
12− @current.setAttribute 'tabindex', '-1'
13− return
14−
15− deselect: ->
16− if @current
17− @current.classList.remove @constructor.activeClass
18− @current.removeAttribute 'tabindex'
19− @current = null
20− return
21−
22− afterRoute: (route, context) =>
23− if route in ['page', 'offline']
24− @select context.pathname
25− else
26− @deselect()
assets/javascripts/views/layout/resizer.coffee+1−1
@@ -35,7 +35,7 @@ class app.views.Resizer extends app.View · 34 unmodified lines
3535 return
3636
3737 onClick: ->
38− app.document.toggleSidebar(save: true)
38+ app.document.toggleSidebarLayout()
3939 return
4040
4141 onDragStart: (event) =>
assets/javascripts/views/list/list_focus.coffee+6−6
@@ -14,7 +14,7 @@ class app.views.ListFocus extends app.View · 13 unmodified lines
1414
1515 constructor: (@el) ->
1616 super
17− @focus = $.framify(@focus, @)
17+ @focusOnNextFrame = $.framify(@focus, @)
1818
1919 focus: (el) ->
2020 if el and not el.classList.contains @constructor.activeClass
@@ -87,22 +87,22 @@ class app.views.ListFocus extends app.View · 66 unmodified lines
8787
8888 onDown: =>
8989 if cursor = @getCursor()
90− @focus @findNext(cursor)
90+ @focusOnNextFrame @findNext(cursor)
9191 else
92− @focus @findByTag('a')
92+ @focusOnNextFrame @findByTag('a')
9393 return
9494
9595 onUp: =>
9696 if cursor = @getCursor()
97− @focus @findPrev(cursor)
97+ @focusOnNextFrame @findPrev(cursor)
9898 else
99− @focus @findLastByTag('a')
99+ @focusOnNextFrame @findLastByTag('a')
100100 return
101101
102102 onLeft: =>
103103 cursor = @getCursor()
104104 if cursor and not cursor.classList.contains(app.views.ListFold.activeClass) and cursor.parentElement isnt @el
105− @focus cursor.parentElement.previousSibling
105+ @focusOnNextFrame cursor.parentElement.previousSibling
106106 return
107107
108108 onEnter: =>
assets/javascripts/views/misc/notice.coffee+0−1
@@ -18,7 +18,6 @@ class app.views.Notice extends app.View · 17 unmodified lines
1818 return
1919
2020 show: ->
21− @addClass '_top' if @type is 'disabledDoc'
2221 @html @tmpl("#{@type}Notice", @args...)
2322 @prependTo $('._app')
2423 return
assets/javascripts/views/search/search.coffee+1−1
@@ -130,7 +130,7 @@ class app.views.Search extends app.View · 129 unmodified lines
130130 if event.target is @resetLink
131131 $.stopEvent(event)
132132 @reset()
133− @focus()
133+ app.document.onEscape()
134134 return
135135
136136 onSubmit: (event) ->
assets/javascripts/views/sidebar/doc_list.coffee+1−1
@@ -148,7 +148,7 @@ class app.views.DocList extends app.View · 147 unmodified lines
148148 return
149149
150150 scrollTo: (model) ->
151− $.scrollTo @find("a[href='#{model.fullPath()}']"), null, 'top', margin: 0
151+ $.scrollTo @find("a[href='#{model.fullPath()}']"), null, 'top', margin: if app.isMobile() then 48 else 0
152152 return
153153
154154 toggleDisabled: ->
assets/javascripts/views/sidebar/results.coffee+2−2
@@ -15,8 +15,8 @@ class app.views.Results extends app.View · 14 unmodified lines
1515 return
1616
1717 init: ->
18− @addSubview @listSelect = new app.views.ListSelect @el
1918 @addSubview @listFocus = new app.views.ListFocus @el unless app.isMobile()
19+ @addSubview @listSelect = new app.views.ListSelect @el
2020
2121 @search
2222 .on 'results', @onResults
@@ -42,7 +42,7 @@ class app.views.Results extends app.View · 19 unmodified lines
4242 return
4343
4444 focusFirst: ->
45− @listFocus?.focus @el.firstElementChild
45+ @listFocus?.focusOnNextFrame @el.firstElementChild
4646 return
4747
4848 openFirst: ->
assets/javascripts/views/sidebar/sidebar.coffee+41−14
@@ -3,6 +3,7 @@ class app.views.Sidebar extends app.View · 2 unmodified lines
33
44 @events:
55 focus: 'onFocus'
6+ select: 'onSelect'
67 click: 'onClick'
78
89 @shortcuts:
@@ -14,8 +15,8 @@ class app.views.Sidebar extends app.View · 5 unmodified lines
1415 @addSubview @search = new app.views.Search
1516
1617 @search
17− .on 'searching', @showResults
18− .on 'clear', @showDocList
18+ .on 'searching', @onSearching
19+ .on 'clear', @onSearchClear
1920 .scope
2021 .on 'change', @onScopeChange
2122
@@ -27,7 +28,15 @@ class app.views.Sidebar extends app.View · 5 unmodified lines
2728 $.on document, 'click', @onGlobalClick if @docPicker
2829 return
2930
30− show: (view) ->
31+ display: ->
32+ @el.style.display = 'block'
33+ return
34+
35+ resetDisplay: ->
36+ @el.style.display = '' unless @el.style.display is 'none'
37+ return
38+
39+ showView: (view) ->
3140 unless @view is view
3241 @hover?.hide()
3342 @saveScrollPosition()
@@ -44,28 +53,29 @@ class app.views.Sidebar extends app.View · 10 unmodified lines
4453 @append @tmpl('sidebarSettings') if @view is @docList and @docPicker
4554 return
4655
47− showDocList: (reset) =>
48− @show @docList
49− if reset is true
50− @docList.reset(revealCurrent: true)
51− @search.reset()
56+ showDocList: ->
57+ @showView @docList
5258 return
5359
5460 showDocPicker: =>
55− @show @docPicker
61+ @showView @docPicker
5662 return
5763
5864 showResults: =>
59− @show @results
65+ @showView @results
66+ return
67+
68+ reset: ->
69+ @display()
70+ @showDocList()
71+ @docList.reset()
72+ @search.reset()
6073 return
6174
6275 onReady: =>
6376 @view = @docList
6477 @render()
6578 @view.activate()
66−
67− reset: ->
68− @showDocList true
6979 return
7080
7181 onScopeChange: (newDoc, previousDoc) =>
@@ -90,15 +100,30 @@ class app.views.Sidebar extends app.View · 18 unmodified lines
90100 @el.scrollTop = 0
91101 return
92102
103+ onSearching: =>
104+ @display()
105+ @showResults()
106+ return
107+
108+ onSearchClear: =>
109+ @resetDisplay()
110+ @showDocList()
111+ return
112+
93113 onFocus: (event) =>
114+ @display()
94115 $.scrollTo event.target, @el, 'continuous', bottomGap: 2 unless event.target is @el
95116 return
96117
118+ onSelect: =>
119+ @resetDisplay()
120+ return
121+
97122 onClick: (event) =>
98123 return if event.which isnt 1
99124 if event.target.hasAttribute? 'data-reset-list'
100125 $.stopEvent(event)
101− @reset()
126+ @onAltR()
102127 else if event.target.hasAttribute? 'data-light'
103128 $.stopEvent(event)
104129 document.activeElement?.blur()
@@ -120,6 +145,8 @@ class app.views.Sidebar extends app.View · 15 unmodified lines
120145
121146 onAltR: =>
122147 @reset()
148+ @docList.reset(revealCurrent: true)
149+ @display()
123150 return
124151
125152 onEscape: =>
assets/javascripts/views/view.coffee+7−0
@@ -35,6 +35,13 @@ class app.View · 34 unmodified lines
3535 @el.classList.remove(name)
3636 return
3737
38+ toggleClass: (name) ->
39+ @el.classList.toggle(name)
40+ return
41+
42+ hasClass: (name) ->
43+ @el.classList.contains(name)
44+
3845 resetClass: ->
3946 @el.className = @originalClassName or ''
4047 if @constructor.className
assets/stylesheets/components/_app.scss+2−3
@@ -2,7 +2,6 @@ · 1 unmodified line
22 position: relative;
33 z-index: 1;
44 height: 100%;
5− padding-top: $headerHeight;
65 overflow: hidden;
76 background: $contentBackground;
87 -webkit-transition: opacity .2s;
@@ -12,7 +11,7 @@ · 3 unmodified lines
1211 ._booting > & { opacity: 0; }
1312 ._noscript > & { display: none; }
1413
15− &._max-width {
14+ &._max-width {
1615 margin: 0 auto;
1716 max-width: $maxWidth;
1817 box-shadow: 1px 0 $headerBorder, -1px 0 $headerBorder;
@@ -31,7 +30,7 @@ · 12 unmodified lines
3130 left: 0;
3231 right: 0;
3332 line-height: 1;
34− margin-top: -.75em;
33+ margin-top: -.6em;
3534 font-size: 4rem;
3635 font-weight: 300;
3736 letter-spacing: -.125rem;
assets/stylesheets/components/_content.scss+29−14
@@ -20,18 +20,24 @@ · 19 unmodified lines
2020 height: 100%;
2121 overflow-y: scroll;
2222 margin-left: .875rem;
23− padding: 1.25rem 1.5rem 0;
23+ padding: 1.125rem 1.5rem 0;
2424 font-size: .875rem;
2525 pointer-events: auto;
2626 -webkit-overflow-scrolling: touch;
2727 @extend %border-box;
2828
29− -webkit-padding-start: .75rem;
30− -webkit-padding-end: 1rem;
29+ -webkit-padding-start: .625rem;
30+ -webkit-padding-end: .75rem;
3131
32− @media (-moz-overlay-scrollbars) { padding-left: .75rem; }
32+ @media (-moz-overlay-scrollbars) { padding-left: .625rem; }
3333 @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { margin-left: 0; }
3434
35+ ._sidebar-hidden &:before {
36+ content: '';
37+ display: block;
38+ margin-top: $headerHeight;
39+ }
40+
3541 &:after { // padding bottom
3642 content: '';
3743 display: block;
@@ -77,15 +83,22 @@ · 39 unmodified lines
7783 // Intro
7884 //
7985
80−._intro { text-align: center; }
86+._intro {
87+ display: flex;
88+ flex-direction: column;
89+ justify-content: center;
90+ align-items: center;
91+ min-height: calc(100vh - 2.375rem);
92+
93+ ._sidebar-hidden & {
94+ min-height: calc(100vh - 2.375rem - #{$headerHeight});
95+ }
96+}
8197
8298 ._intro-message {
83− position: relative;
84− display: inline-block;
85− vertical-align: top;
8699 max-width: 37rem;
100+ margin: .5rem 0;
87101 padding: 1rem 1.25rem;
88− text-align: left;
89102 @extend %note, %note-green;
90103 }
91104
@@ -146,23 +159,25 @@ · 54 unmodified lines
146159
147160 ._lined-heading,
148161 %lined-heading {
149− white-space: nowrap;
150− overflow: hidden;
151− word-wrap: normal;
152− overflow-wrap: normal;
162+ display: flex;
163+ justify-content: center;
164+ align-items: center;
153165
154166 &:after {
155167 content: '';
156168 display: inline-block;
157169 vertical-align: middle;
158− width: 100%;
170+ flex-grow: 1;
159171 height: 1px;
160172 line-height: 0;
173+ margin-top: .25rem;
161174 margin-left: 1rem;
162175 background: $boxBorderLight;
163176 }
164177 }
165178
179+._block-heading { @extend %block-heading; }
180+
166181 ._heading-links {
167182 float: right;
168183 font-weight: normal;
assets/stylesheets/components/_header.scss+104−51
@@ -7,79 +7,131 @@ · 6 unmodified lines
77 z-index: $headerZ;
88 top: 0;
99 left: 0;
10− right: 0;
10+ display: flex;
11+ width: $sidebarWidth;
1112 height: $headerHeight;
12− line-height: $headerHeight;
1313 background: $headerBackground;
1414 border-bottom: 1px solid $headerBorder;
1515 @extend %user-select-none;
16+
17+ @media #{$mediumScreen} { width: $sidebarMediumWidth; }
1618 }
1719
18−//
19−// Navigation menu
20−//
20+._header-left {
21+ float: left;
22+ height: 100%;
23+}
2124
22−._nav {
25+._header-right {
2326 float: right;
24− margin-right: .5rem;
25− font-size: .875rem;
26− color: $textColor;
27+ height: 100%;
2728 }
2829
29−._nav-link,
30−._nav-link:hover {
30+._header-btn {
3131 position: relative;
32− float: left;
33− padding: 0 1.25rem;
34− color: inherit;
35− text-decoration: none;
32+ width: 2.25rem;
33+ height: 100%;
34+ color: $textColorLight;
35+ text-align: center;
3636
37− @media #{$mediumScreen} { padding: 0 .75rem; }
38−}
37+ &[hidden] { display: none; }
3938
40−._nav-link {
41− &:before, &:after {
42− position: absolute;
43− left: 50%;
44− bottom: 0;
45− width: 0;
46− height: 0;
47− margin-left: -.375rem;
48− border: .375rem solid transparent;
49− border-bottom-color: darken($headerBorder, 2%);
39+ &[disabled] {
40+ opacity: .3;
41+ cursor: not-allowed;
5042 }
5143
52− &:after {
53− bottom: -1px;
54− border-bottom-color: $contentBackground;
44+ > svg {
45+ display: inline-block;
46+ vertical-align: top;
47+ width: 1.5rem;
48+ height: 1.5rem;
49+ fill: currentColor;
50+ pointer-events: none;
5551 }
5652 }
5753
58−._nav-current {
59− outline: 0;
54+//
55+// Menu
56+//
6057
61− &:before, &:after { content: ''; }
58+._menu-btn {
59+ border-right: 1px solid $headerBorder;
6260 }
6361
64−//
65−// Logo
66−//
62+._menu {
63+ position: absolute;
64+ z-index: 1;
65+ top: .25rem;
66+ right: .25rem;
67+ width: 8rem;
68+ height: calc(11.5rem + 1px);
69+ font-size: .875rem;
70+ background: $contentBackground;
71+ border: 1px solid $headerBorder;
72+ border-radius: 3px;
73+ box-shadow: -1px 1px 1px rgba(black, .05);
74+ transition: all 250ms cubic-bezier(0.23, 1, 0.32, 1);
75+ opacity: 0;
76+ -webkit-transform: scale(0, 0);
77+ transform: scale(0, 0);
78+ -webkit-transform-origin: 100% 0;
79+ transform-origin: 100% 0;
80+
81+ &:hover,
82+ ._menu-btn:hover + & {
83+ transition-delay: 100ms;
84+ }
6785
68−._logo {
69− position: relative;
70− float: left;
71− height: $headerHeight;
86+ &:hover,
87+ &.active,
88+ ._menu-btn:hover + &,
89+ ._menu-btn:focus + & {
90+ opacity: 1;
91+ -webkit-transform: scale(1, 1);
92+ transform: scale(1, 1);
93+ }
94+
95+ &:focus-within {
96+ opacity: 1;
97+ -webkit-transform: scale(1, 1);
98+ transform: scale(1, 1);
99+ }
100+}
101+
102+._menu-title {
72103 margin: 0;
73− line-height: inherit;
74− font-size: inherit;
104+ line-height: 1.5rem;
105+ font-size: 1rem;
75106 font-weight: $boldFontWeight;
76− cursor: default;
107+ letter-spacing: -.5px;
108+ background: $sidebarBackground;
109+ border-bottom: 1px solid $sidebarBorder;
110+ border-radius: 2px 2px 0 0;
111+}
112+
113+._menu-title-link,
114+._menu-title-link:hover {
115+ display: block;
116+ padding: .5rem 1rem;
117+ color: $focusText;
118+ text-decoration: none;
119+}
77120
78− > ._nav-link {
79− float: none;
80− margin-left: .75rem;
81− padding: 0 .25rem;
121+._menu-link {
122+ display: block;
123+ padding: 0 1rem;
124+ line-height: 2.25rem;
125+ color: inherit;
126+ text-decoration: none;
127+
128+ &:hover {
129+ color: $focusText;
130+ text-decoration: none;
131+ background: $sidebarBackground;
82132 }
133+
134+ &:last-child { border-radius: 0 0 2px 2px; }
83135 }
84136
85137 //
@@ -87,20 +139,19 @@ · 1 unmodified line
87139 //
88140
89141 ._search {
142+ flex-grow: 1;
90143 position: relative;
91− float: left;
92− width: $sidebarWidth;
93144 height: 100%;
94145 padding: .5rem 0 .5rem .5rem;
95146 @extend %border-box;
96147
97− @media #{$mediumScreen} { width: $sidebarMediumWidth; }
98−
99148 &:before {
100149 position: absolute;
150+ z-index: 1;
101151 top: 1rem;
102152 left: 1rem;
103153 opacity: .4;
154+ pointer-events: none;
104155 @if $style == 'dark' {
105156 @extend %icon, %icon-search-white;
106157 } @else {
@@ -110,6 +161,7 @@ · 3 unmodified lines
110161 }
111162
112163 ._search-input {
164+ position: relative;
113165 display: block;
114166 width: 100%;
115167 height: 100%;
@@ -164,6 +216,7 @@ · 48 unmodified lines
164216 ._search-tag {
165217 display: none;
166218 position: absolute;
219+ z-index: 2;
167220 top: .875rem;
168221 left: .875rem;
169222 padding: 0 .5rem;
assets/stylesheets/components/_mobile.scss+14−108
@@ -10,18 +10,17 @@ · 9 unmodified lines
1010
1111 body { -ms-overflow-style: -ms-autohiding-scrollbar; }
1212
13− ._app, ._container, ._content { overflow: visible; }
14−
15− ._container {
16− margin: 0;
17− border: 0;
18− }
13+ ._app, ._content { overflow: visible; }
14+ ._app { padding-top: $headerHeight; }
15+ ._container { margin: 0; }
1916
2017 ._content {
2118 position: static;
2219 height: auto;
2320 margin: 0;
2421 padding: .75rem 1rem 2.5rem;
22+
23+ &:before { content: none; }
2524 }
2625
2726 ._booting:before, ._content-loading:before { font-size: 3rem; }
@@ -33,16 +32,13 @@ · 5 unmodified lines
3332 max-width: 100vw;
3433 }
3534
36− ._logo, ._nav { display: none; }
37− ._mobile-btn { display: block; }
35+ ._header-btn { width: 2.5rem; }
36+ ._header-btn[hidden] { display: block; }
37+ ._menu-btn { border-right: 0; }
3838
3939 ._search {
40− float: none;
41− width: auto;
42− overflow: hidden;
43− padding-left: 2px;
44− padding-right: 2px;
45− border-right: 0;
40+ padding-right: .125rem;
41+ padding-left: .125rem;
4642
4743 &:before { left: .5rem; }
4844 }
@@ -57,7 +53,7 @@ · 8 unmodified lines
5753 overflow: visible;
5854 }
5955
60− ._list, ._sidebar-footer { width: 100%; }
56+ ._header, ._list, ._sidebar-footer { width: 100%; }
6157
6258 ._list-item {
6359 white-space: normal;
@@ -85,33 +81,12 @@ · 21 unmodified lines
8581 box-shadow: 0 1px $noteGreenBorder, 0 -1px $noteGreenBorder;
8682 }
8783
88− // Splash
89−
90− ._splash-sponsors { margin-top: 1rem; }
91−
92− ._splash-sponsor {
93− position: static;
94−
95− ._logo-info {
96− left: 1rem;
97− right: 1rem;
98− width: auto;
99− max-width: none;
100− margin: 0;
101− }
102− }
103−
10484 // Notice
10585
10686 ._notice {
10787 position: fixed;
10888 left: 0;
10989 padding: 0 .5rem;
110−
111− ~ ._sidebar {
112− margin-top: 2.5rem;
113− padding-bottom: 4rem;
114− }
11590 }
11691
11792 ._notice-text { font-size: .75em; }
@@ -143,76 +118,10 @@ · 25 unmodified lines
143118 // Header buttons
144119 //
145120
146−._mobile-btn {
147− display: none;
148− position: relative;
149− float: left;
150− width: 2.5rem;
151− height: 100%;
152− @extend %hide-text;
153−
154− &[disabled] {
155− opacity: .3;
156− cursor: not-allowed;
157− }
158−
159− &:before {
160− position: absolute;
161− top: 50%;
162− left: 50%;
163− margin: -.5rem 0 0 -.5rem;
164− @extend %icon;
165− }
166−}
167−
168−._back-btn {
169− &:before { @extend %icon-back; }
170−}
171−
172121 ._forward-btn {
173− width: 2.25rem;
174− -webkit-transform: rotate(180deg);
175− transform: rotate(180deg);
176−
177− &:before {
178− margin-left: -.375rem;
179− @extend %icon-back;
180− }
181−}
182−
183−._home-btn {
184− float: right;
185− width: 2rem;
186−
187− &:before {
188− margin-left: -.375rem;
189− @extend %icon-home;
190− }
191−}
122+ margin-right: -.5rem;
192123
193−._menu-btn {
194− float: right;
195−
196− &:before { @extend %icon-menu; }
197−}
198−
199−//
200−// Navigation menu
201−//
202−
203−._mobile-nav {
204− margin: .25rem 0 1.25rem;
205− padding: 0;
206− line-height: 2.8;
207− overflow: hidden;
208− @extend %box;
209−}
210−
211−._mobile-nav-link {
212− float: left;
213− width: 25%;
214− text-align: center;
215− font-weight: $boldFontWeight;
124+ > svg { margin-left: -.375rem; }
216125 }
217126
218127 //
@@ -222,14 +131,11 @@ · 3 unmodified lines
222131 ._mobile-intro {
223132 > ._intro-list { padding-left: 1.5rem; }
224133
225− > ._intro-hide,
226− > ._intro-sponsors {
134+ ._intro-hide {
227135 position: static;
228136 float: none;
229137 display: block;
230138 margin-top: .75rem;
231139 text-align: center;
232140 }
233−
234− ._intro-sponsor { margin: .5em .75em; }
235141 }
assets/stylesheets/components/_notice.scss+1−11
@@ -12,17 +12,7 @@ · 11 unmodified lines
1212 @media #{$mediumScreen} { left: $sidebarMediumWidth; }
1313
1414 ._sidebar-hidden & { left: $sidebarHiddenWidth; }
15−
16− &:not(._top) ~ ._container { padding-bottom: 2.5rem; }
17−
18− &._top {
19− bottom: auto;
20− top: $headerHeight;
21− margin-top: 1px;
22− box-shadow: inset 0 -1px $noticeBorder;
23−
24− ~ ._container { padding-top: 2.5rem; }
25− }
15+ ~ ._container { padding-bottom: 2.5rem; }
2616 }
2717
2818 ._notice-text {
assets/stylesheets/components/_sidebar.scss+1−1
@@ -40,7 +40,7 @@ · 39 unmodified lines
4040
4141 ._resizer {
4242 position: absolute;
43− z-index: $sidebarZ + 1;
43+ z-index: $sidebarZ;
4444 top: $headerHeight;
4545 bottom: 0;
4646 left: $sidebarWidth;
assets/stylesheets/global/_icons.scss+0−3
@@ -37,8 +37,6 @@ · 36 unmodified lines
3737 %icon-clear { background-position: -3rem 0; }
3838 %icon-settings { background-position: 0 -1rem; }
3939 %icon-check { background-position: -1rem -1rem; }
40−%icon-menu { background-position: -2rem -1rem; @extend %darkIconFix !optional; }
41−%icon-home { background-position: -3rem -1rem; @extend %darkIconFix !optional; }
4240 %icon-path { background-position: 0 -2rem; }
4341 %icon-search-white { background-position: -1rem -2rem; }
4442 %icon-dir-white { background-position: -2rem -2rem; }
@@ -54,7 +52,6 @@ · 9 unmodified lines
5452 %icon-clipboard { background-position: 0 -5rem; }
5553 %icon-clipboard-white { background-position: -1rem -5rem; }
5654 %icon-close-white { background-position: -2rem -5rem; }
57−%icon-back { background-position: -3rem -5rem; @extend %darkIconFix !optional; }
5855
5956 ._icon-codeceptjs:before { background-position: -3rem 0; }
6057 ._icon-codeception:before { background-position: -4rem 0; }
assets/stylesheets/global/_variables-dark.scss+2−2
@@ -7,7 +7,7 @@ $style: 'dark'; · 6 unmodified lines
77
88 $maxWidth: 80rem;
99 $headerHeight: 3rem;
10−$sidebarWidth: 18rem;
10+$sidebarWidth: 20rem;
1111 $sidebarMediumWidth: 16rem;
1212 $sidebarHiddenWidth: 9px;
1313
@@ -37,7 +37,7 @@ $linkColor: $textColor; · 23 unmodified lines
3737 $linkColorHover: white;
3838 $linkTextDecoration: underline;
3939
40−$headerBackground: #1e1e1e;
40+$headerBackground: #1c1c1c;
4141 $headerBorder: #000;
4242
4343 $sidebarBackground: #24282a;
assets/stylesheets/global/_variables.scss+4−4
@@ -7,7 +7,7 @@ $style: 'light'; · 6 unmodified lines
77
88 $maxWidth: 80rem;
99 $headerHeight: 3rem;
10−$sidebarWidth: 18rem;
10+$sidebarWidth: 20rem;
1111 $sidebarMediumWidth: 16rem;
1212 $sidebarHiddenWidth: 9px;
1313
@@ -37,11 +37,11 @@ $linkColor: #3377c0; · 23 unmodified lines
3737 $linkColorHover: #2f6cb6;
3838 $linkTextDecoration: none;
3939
40−$headerBackground: #f0f0f0;
41−$headerBorder: #d9d9d9;
40+$headerBackground: #eee;
41+$headerBorder: #d7d7d7;
4242
4343 $sidebarBackground: #f9f9f9;
44−$sidebarBorder: #e3e3e3;
44+$sidebarBorder: #e1e1e1;
4545
4646 $scrollbarColor: #d2d2d2;
4747 $scrollbarColorHover: #aaa;
lib/app.rb+1−1
@@ -184,7 +184,7 @@ class App < Sinatra::Application · 183 unmodified lines
184184 end
185185
186186 def app_size
187− @app_size ||= cookies[:size].nil? ? '18rem' : "#{cookies[:size]}px"
187+ @app_size ||= cookies[:size].nil? ? '20rem' : "#{cookies[:size]}px"
188188 end
189189
190190 def app_layout
public/icons/ui/back/16.png+0−0

Binary file not shown.

public/icons/ui/back/16@2x.png+0−0

Binary file not shown.

public/icons/ui/home/16.png+0−0

Binary file not shown.

public/icons/ui/home/16@2x.png+0−0

Binary file not shown.

public/icons/ui/home/SOURCE+0−1
@@ -1 +0,0 @@
1−http://www.entypo.com/
public/icons/ui/menu/16.png+0−0

Binary file not shown.

public/icons/ui/menu/16@2x.png+0−0

Binary file not shown.

test/app_test.rb+2−2
@@ -31,7 +31,7 @@ class AppTest < MiniTest::Spec · 30 unmodified lines
3131
3232 it "sets default size" do
3333 get '/'
34− assert_includes last_response.body, 'data-size="18rem"'
34+ assert_includes last_response.body, 'data-size="20rem"'
3535 end
3636
3737 it "sets size from cookie" do
@@ -115,7 +115,7 @@ class AppTest < MiniTest::Spec · 77 unmodified lines
115115
116116 it "sets default size" do
117117 get '/manifest.appcache'
118− assert_includes last_response.body, '18rem'
118+ assert_includes last_response.body, '20rem'
119119 end
120120
121121 it "sets size from cookie" do
views/app.erb+19−13
@@ -1,22 +1,28 @@
11 <div class="_app<%= " #{app_layout}" if app_layout %>" role="application">
22 <header class="_header" role="banner">
3− <button type="button" class="_mobile-btn _back-btn">Back</button>
4− <button type="button" class="_mobile-btn _forward-btn">Forward</button>
5− <button type="button" class="_mobile-btn _menu-btn">Menu</button>
6− <button type="button" class="_mobile-btn _home-btn">Home</button>
3+ <button type="button" aria-label="Toggle navigation" class="_header-btn" data-toggle-sidebar hidden>
4+ <svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg>
5+ </button>
76 <form class="_search" role="search">
87 <input type="search" name="q" class="_search-input" placeholder="Search&hellip;" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" maxlength="30" aria-label="Search">
98 <button type="reset" class="_search-clear" title="Clear search">Clear search</button>
109 <div class="_search-tag"></div>
1110 </form>
12− <h1 class="_logo">
13− <a href="/" class="_nav-link" title="Offline API Documentation Browser">DevDocs</a><%= "/ #{@doc['full_name']}" if @doc %>
14− </h1>
15− <nav class="_nav" role="navigation">
16− <a href="/offline" class="_nav-link">Offline</a>
17− <a href="/about" class="_nav-link">About</a>
18− <a href="/news" class="_nav-link">News</a>
19− <a href="/help" class="_nav-link">Tips</a>
11+ <button type="button" aria-label="Back" class="_header-btn" data-back hidden>
12+ <svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></svg>
13+ </button>
14+ <button type="button" aria-label="Forward" class="_header-btn _forward-btn" data-forward hidden>
15+ <svg viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></svg>
16+ </button>
17+ <button type="button" aria-label="Toggle menu" title="Toggle menu" class="_header-btn _menu-btn" data-toggle-menu>
18+ <svg viewBox="0 0 24 24"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg>
19+ </button>
20+ <nav class="_menu" role="navigation">
21+ <h1 class="_menu-title"><a href="/" class="_menu-title-link">DevDocs</a></h1>
22+ <a href="/offline" class="_menu-link">Offline</a>
23+ <a href="/news" class="_menu-link">Changelog</a>
24+ <a href="/help" class="_menu-link">Help</a>
25+ <a href="/about" class="_menu-link">About</a>
2026 </nav>
2127 </header>
2228 <section class="_sidebar" tabindex="-1">
@@ -34,7 +40,7 @@ · 11 unmodified lines
3440 </div>
3541 <style data-size="<%= app_size %>" data-resizer>
3642 ._container { margin-left: <%= app_size %>; }
37− ._search, ._list, ._sidebar-footer { width: <%= app_size %>; }
43+ ._header, ._list, ._sidebar-footer { width: <%= app_size %>; }
3844 ._list-hover.clone { min-width: <%= app_size %>; }
3945 ._notice, ._path, ._resizer { left: <%= app_size %>; }
4046 </style>