UI improvements

pull/570/merge
Thibaut Courouble 8 years ago
parent fd03ac1133
commit 0f238609da

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -10,7 +10,7 @@ app.templates.aboutPage = -> """
</ul> </ul>
</nav> </nav>
<h1 class="_lined-heading">API Documentation Browser</h1> <h1 class="_lined-heading">DevDocs: API Documentation Browser</h1>
<p>DevDocs combines multiple API documentations in a fast, organized, and searchable interface. <p>DevDocs combines multiple API documentations in a fast, organized, and searchable interface.
<ul> <ul>
<li>Created and maintained by <a href="http://thibaut.me">Thibaut Courouble</a> <li>Created and maintained by <a href="http://thibaut.me">Thibaut Courouble</a>
@ -26,7 +26,7 @@ app.templates.aboutPage = -> """
<p class="_note _note-green">If you like DevDocs, please consider supporting my work on <p class="_note _note-green">If you like DevDocs, please consider supporting my work on
<a href="https://gratipay.com/devdocs/">Gratipay</a>. Thanks!<br> <a href="https://gratipay.com/devdocs/">Gratipay</a>. Thanks!<br>
<h2 class="_lined-heading" id="credits">Credits</h2> <h2 class="_block-heading" id="credits">Credits</h2>
<p><strong>Special thanks to:</strong> <p><strong>Special thanks to:</strong>
<ul> <ul>
@ -45,7 +45,7 @@ app.templates.aboutPage = -> """
#{("<tr><td>#{c[0]}<td>&copy; #{c[1]}<td><a href=\"#{c[3]}\">#{c[2]}</a>" for c in credits).join('')} #{("<tr><td>#{c[0]}<td>&copy; #{c[1]}<td><a href=\"#{c[3]}\">#{c[2]}</a>" for c in credits).join('')}
</table> </table>
<h2 class="_lined-heading" id="faq">Questions & Answers</h2> <h2 class="_block-heading" id="faq">Questions & Answers</h2>
<dl> <dl>
<dt>Where can I suggest new docs and features? <dt>Where can I suggest new docs and features?
<dd>You can suggest and vote for new docs on the <a href="https://trello.com/b/6BmTulfx/devdocs-documentation">Trello board</a>.<br> <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 = -> """
</dl> </dl>
<p>For anything else, feel free to email me at <a href="mailto:thibaut@devdocs.io">thibaut@devdocs.io</a>. <p>For anything else, feel free to email me at <a href="mailto:thibaut@devdocs.io">thibaut@devdocs.io</a>.
<h2 class="_lined-heading" id="copyright">Copyright and License</h2> <h2 class="_block-heading" id="copyright">Copyright and License</h2>
<p class="_note"> <p class="_note">
<strong>Copyright 2013&ndash;2017 Thibaut Courouble and <a href="https://github.com/Thibaut/devdocs/graphs/contributors">other contributors</a></strong><br> <strong>Copyright 2013&ndash;2017 Thibaut Courouble and <a href="https://github.com/Thibaut/devdocs/graphs/contributors">other contributors</a></strong><br>
This software is licensed under the terms of the Mozilla Public License v2.0.<br> This software is licensed under the terms of the Mozilla Public License v2.0.<br>
@ -64,7 +64,7 @@ app.templates.aboutPage = -> """
For more information, see the <a href="https://github.com/Thibaut/devdocs/blob/master/COPYRIGHT">COPYRIGHT</a> For more information, see the <a href="https://github.com/Thibaut/devdocs/blob/master/COPYRIGHT">COPYRIGHT</a>
and <a href="https://github.com/Thibaut/devdocs/blob/master/LICENSE">LICENSE</a> files. and <a href="https://github.com/Thibaut/devdocs/blob/master/LICENSE">LICENSE</a> files.
<h2 class="_lined-heading" id="plugins">Plugins and Extensions</h2> <h2 class="_block-heading" id="plugins">Plugins and Extensions</h2>
<ul> <ul>
<li><a href="https://chrome.google.com/webstore/detail/devdocs/mnfehgbmkapmjnhcnbodoamcioleeooe">Chrome web app</a> <li><a href="https://chrome.google.com/webstore/detail/devdocs/mnfehgbmkapmjnhcnbodoamcioleeooe">Chrome web app</a>
<li><a href="https://sublime.wbond.net/packages/DevDocs">Sublime Text plugin</a> <li><a href="https://sublime.wbond.net/packages/DevDocs">Sublime Text plugin</a>
@ -73,7 +73,7 @@ app.templates.aboutPage = -> """
<li><a href="https://github.com/xuchunyang/DevDocs.el">Emacs Package</a> <li><a href="https://github.com/xuchunyang/DevDocs.el">Emacs Package</a>
</ul> </ul>
<h2 class="_lined-heading" id="privacy">Privacy Policy</h2> <h2 class="_block-heading" id="privacy">Privacy Policy</h2>
<ul> <ul>
<li><a href="http://devdocs.io">devdocs.io</a> ("App") is operated by Thibaut Courouble ("We"). <li><a href="http://devdocs.io">devdocs.io</a> ("App") is operated by Thibaut Courouble ("We").
<li>We do not collect personal information. <li>We do not collect personal information.

@ -11,7 +11,9 @@ app.templates.helpPage = """
</ul> </ul>
</nav> </nav>
<h2 class="_lined-heading" id="search">Search</h2> <h1 class="_lined-heading" id="search">Help</h2>
<h2 class="_block-heading" id="search">Search</h2>
<p> <p>
The search is case-insensitive and supports fuzzy matching (for queries longer than two characters). The search is case-insensitive and supports fuzzy matching (for queries longer than two characters).
For example, searching <code class="_label">bgcp</code> brings up <code class="_label">background-clip</code>.<br> For example, searching <code class="_label">bgcp</code> brings up <code class="_label">background-clip</code>.<br>
@ -42,7 +44,7 @@ app.templates.helpPage = """
<a href="https://support.mozilla.org/en-US/kb/how-search-from-address-bar">these instructions</a>. <a href="https://support.mozilla.org/en-US/kb/how-search-from-address-bar">these instructions</a>.
</dl> </dl>
<h2 class="_lined-heading" id="shortcuts">Keyboard Shortcuts</h2> <h2 class="_block-heading" id="shortcuts">Keyboard Shortcuts</h2>
<h3 class="_shortcuts-title">Selection</h3> <h3 class="_shortcuts-title">Selection</h3>
<dl class="_shortcuts-dl"> <dl class="_shortcuts-dl">
<dt class="_shortcuts-dt"> <dt class="_shortcuts-dt">
@ -110,7 +112,7 @@ app.templates.helpPage = """
<strong>Tip:</strong> If the cursor is no longer in the search field, press <code class="_label">/</code> or <strong>Tip:</strong> If the cursor is no longer in the search field, press <code class="_label">/</code> or
continue to type and it will refocus the search field and start showing new results. continue to type and it will refocus the search field and start showing new results.
<h2 class="_lined-heading" id="abbreviations">Abbreviations</h2> <h2 class="_block-heading" id="abbreviations">Abbreviations</h2>
<p>Feel free to suggest new abbreviations on <a href="https://github.com/Thibaut/devdocs/issues/new">GitHub</a>. <p>Feel free to suggest new abbreviations on <a href="https://github.com/Thibaut/devdocs/issues/new">GitHub</a>.
<table class="_abbreviations"> <table class="_abbreviations">
<tr> <tr>

@ -15,7 +15,7 @@ app.templates.newsList = (news, options = {}) ->
date = new Date(value[0]) date = new Date(value[0])
if options.years isnt false and year isnt date.getUTCFullYear() if options.years isnt false and year isnt date.getUTCFullYear()
year = date.getUTCFullYear() year = date.getUTCFullYear()
result += "<h4>#{year}</h4>" result += """<h2 class="_block-heading">#{year}</h2>"""
result += newsItem(date, value[1..]) result += newsItem(date, value[1..])
result result

@ -21,7 +21,7 @@ app.templates.offlinePage = (docs) -> """
#{docs} #{docs}
</table> </table>
<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. <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.
<h1 class="_lined-heading">Questions & Answers</h1> <h2 class="_block-heading">Questions & Answers</h2>
<dl> <dl>
<dt>How does this work? <dt>How does this work?
<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> <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>

@ -48,15 +48,6 @@ app.templates.intro = """
""" """
<% end %> <% end %>
app.templates.mobileNav = """
<nav class="_mobile-nav">
<a href="/offline" class="_mobile-nav-link">Offline</a>
<a href="/about" class="_mobile-nav-link">About</a>
<a href="/news" class="_mobile-nav-link">News</a>
<a href="/help" class="_mobile-nav-link">Help</a>
</nav>
"""
app.templates.mobileIntro = """ app.templates.mobileIntro = """
<div class="_mobile-intro"> <div class="_mobile-intro">
<h2 class="_intro-title">Welcome!</h2> <h2 class="_intro-title">Welcome!</h2>

@ -9,7 +9,6 @@ class app.views.RootPage extends app.View
render: -> render: ->
@empty() @empty()
@append @tmpl('mobileNav') if app.isMobile()
if app.isAndroidWebview() if app.isAndroidWebview()
@append @tmpl('androidWarning') @append @tmpl('androidWarning')
else else

@ -1,6 +1,6 @@
class app.views.Document extends app.View class app.views.Document extends app.View
MAX_WIDTH_CLASS = '_max-width' MAX_WIDTH_LAYOUT = '_max-width'
HIDE_SIDEBAR_CLASS = '_sidebar-hidden' SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
@el: document @el: document
@ -14,16 +14,12 @@ class app.views.Document extends app.View
superRight: 'onForward' superRight: 'onForward'
init: -> init: ->
@addSubview @nav = new app.views.Nav, @addSubview @menu = new app.views.Menu,
@addSubview @sidebar = new app.views.Sidebar @addSubview @sidebar = new app.views.Sidebar
@addSubview @resizer = new app.views.Resizer if app.views.Resizer.isSupported() @addSubview @resizer = new app.views.Resizer if app.views.Resizer.isSupported()
@addSubview @content = new app.views.Content @addSubview @content = new app.views.Content
@addSubview @path = new app.views.Path unless app.isSingleDoc() or app.isMobile() @addSubview @path = new app.views.Path unless app.isSingleDoc() or app.isMobile()
@sidebar.search
.on 'searching', @onSearching
.on 'clear', @onSearchClear
$.on document.body, 'click', @onClick $.on document.body, 'click', @onClick
@activate() @activate()
@ -39,41 +35,19 @@ class app.views.Document extends app.View
return return
toggleLayout: -> toggleLayout: ->
wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_CLASS) wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_LAYOUT)
app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_CLASS) app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_LAYOUT)
app.settings.setLayout(MAX_WIDTH_CLASS, wantsMaxWidth) app.settings.setLayout(MAX_WIDTH_LAYOUT, wantsMaxWidth)
app.appCache?.updateInBackground() app.appCache?.updateInBackground()
return return
showSidebar: (options = {}) -> toggleSidebarLayout: ->
@toggleSidebar(options, true) shouldHide = !app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)
return app.el.classList[if shouldHide then 'add' else 'remove'](SIDEBAR_HIDDEN_LAYOUT)
app.settings.setLayout(SIDEBAR_HIDDEN_LAYOUT, shouldHide)
hideSidebar: (options = {}) ->
@toggleSidebar(options, false)
return
toggleSidebar: (options = {}, shouldShow) ->
shouldShow ?= if options.save then !@hasSidebar() else app.el.classList.contains(HIDE_SIDEBAR_CLASS)
app.el.classList[if shouldShow then 'remove' else 'add'](HIDE_SIDEBAR_CLASS)
if options.save
app.settings.setLayout(HIDE_SIDEBAR_CLASS, !shouldShow)
app.appCache?.updateInBackground() app.appCache?.updateInBackground()
return return
hasSidebar: ->
!app.settings.hasLayout(HIDE_SIDEBAR_CLASS)
onSearching: =>
unless @hasSidebar()
@showSidebar()
return
onSearchClear: =>
unless @hasSidebar()
@hideSidebar()
return
setTitle: (title) -> setTitle: (title) ->
@el.title = if title then "DevDocs — #{title}" else 'DevDocs API Documentation' @el.title = if title then "DevDocs — #{title}" else 'DevDocs API Documentation'

@ -0,0 +1,24 @@
class app.views.Menu extends app.View
@el: '._menu'
@activeClass: 'active'
@events:
click: 'onClick'
init: ->
$.on document.body, 'click', @onGlobalClick
return
onClick: =>
prev = @el.previousElementSibling
$.remove @el
$.requestAnimationFrame => $.after(prev, @el)
return
onGlobalClick: (event) =>
return if event.which isnt 1
if event.target.hasAttribute?('data-toggle-menu')
@toggleClass @constructor.activeClass
else if @hasClass @constructor.activeClass
@removeClass @constructor.activeClass
return

@ -35,44 +35,48 @@ class app.views.Mobile extends app.View
FastClick.attach @body FastClick.attach @body
$.on @body, 'click', @onClick $.on @body, 'click', @onClick
$.on $('._home-btn'), 'click', @onClickHome
$.on $('._menu-btn'), 'click', @onClickMenu
$.on $('._search'), 'touchend', @onTapSearch $.on $('._search'), 'touchend', @onTapSearch
@back = $('._back-btn') @toggleSidebar = $('button[data-toggle-sidebar]')
@toggleSidebar.removeAttribute('hidden')
$.on @toggleSidebar, 'click', @onClickToggleSidebar
@back = $('button[data-back]')
@back.removeAttribute('hidden')
$.on @back, 'click', @onClickBack $.on @back, 'click', @onClickBack
@forward = $('._forward-btn') @forward = $('button[data-forward]')
@forward.removeAttribute('hidden')
$.on @forward, 'click', @onClickForward $.on @forward, 'click', @onClickForward
app.document.sidebar.search app.document.sidebar.search
.on 'searching', @showSidebar .on 'searching', @showSidebar
.on 'clear', @hideSidebar
@activate() @activate()
return return
showSidebar: => showSidebar: =>
if @isSidebarShown() if @isSidebarShown()
@body.scrollTop = 0 window.scrollTo 0, 0
return return
@contentTop = @body.scrollTop @contentTop = window.scrollY
@content.style.display = 'none' @content.style.display = 'none'
@sidebar.style.display = 'block' @sidebar.style.display = 'block'
if selection = @findByClass app.views.ListSelect.activeClass if selection = @findByClass app.views.ListSelect.activeClass
$.scrollTo selection, @body, 'center' scrollContainer = if window.scrollY is @body.scrollTop then @body else document.documentElement
$.scrollTo selection, scrollContainer, 'center'
else else
@body.scrollTop = @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0 window.scrollTo 0, @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0
return return
hideSidebar: => hideSidebar: =>
return unless @isSidebarShown() return unless @isSidebarShown()
@sidebarTop = @body.scrollTop @sidebarTop = window.scrollY
@sidebar.style.display = 'none' @sidebar.style.display = 'none'
@content.style.display = 'block' @content.style.display = 'block'
@body.scrollTop = @contentTop or 0 window.scrollTo 0, @contentTop or 0
return return
isSidebarShown: -> isSidebarShown: ->
@ -89,17 +93,12 @@ class app.views.Mobile extends app.View
onClickForward: => onClickForward: =>
history.forward() history.forward()
onClickHome: => onClickToggleSidebar: =>
app.shortcuts.trigger 'escape'
@hideSidebar()
return
onClickMenu: =>
if @isSidebarShown() then @hideSidebar() else @showSidebar() if @isSidebarShown() then @hideSidebar() else @showSidebar()
return return
onTapSearch: => onTapSearch: =>
@body.scrollTop = 0 window.scrollTo 0, 0
afterRoute: => afterRoute: =>
@hideSidebar() @hideSidebar()

@ -1,26 +0,0 @@
class app.views.Nav extends app.View
@el: '._nav'
@activeClass: '_nav-current'
@routes:
after: 'afterRoute'
select: (href) ->
@deselect()
if @current = @find "a[href='#{href}']"
@current.classList.add @constructor.activeClass
@current.setAttribute 'tabindex', '-1'
return
deselect: ->
if @current
@current.classList.remove @constructor.activeClass
@current.removeAttribute 'tabindex'
@current = null
return
afterRoute: (route, context) =>
if route in ['page', 'offline']
@select context.pathname
else
@deselect()

@ -35,7 +35,7 @@ class app.views.Resizer extends app.View
return return
onClick: -> onClick: ->
app.document.toggleSidebar(save: true) app.document.toggleSidebarLayout()
return return
onDragStart: (event) => onDragStart: (event) =>

@ -14,7 +14,7 @@ class app.views.ListFocus extends app.View
constructor: (@el) -> constructor: (@el) ->
super super
@focus = $.framify(@focus, @) @focusOnNextFrame = $.framify(@focus, @)
focus: (el) -> focus: (el) ->
if el and not el.classList.contains @constructor.activeClass if el and not el.classList.contains @constructor.activeClass
@ -87,22 +87,22 @@ class app.views.ListFocus extends app.View
onDown: => onDown: =>
if cursor = @getCursor() if cursor = @getCursor()
@focus @findNext(cursor) @focusOnNextFrame @findNext(cursor)
else else
@focus @findByTag('a') @focusOnNextFrame @findByTag('a')
return return
onUp: => onUp: =>
if cursor = @getCursor() if cursor = @getCursor()
@focus @findPrev(cursor) @focusOnNextFrame @findPrev(cursor)
else else
@focus @findLastByTag('a') @focusOnNextFrame @findLastByTag('a')
return return
onLeft: => onLeft: =>
cursor = @getCursor() cursor = @getCursor()
if cursor and not cursor.classList.contains(app.views.ListFold.activeClass) and cursor.parentElement isnt @el if cursor and not cursor.classList.contains(app.views.ListFold.activeClass) and cursor.parentElement isnt @el
@focus cursor.parentElement.previousSibling @focusOnNextFrame cursor.parentElement.previousSibling
return return
onEnter: => onEnter: =>

@ -18,7 +18,6 @@ class app.views.Notice extends app.View
return return
show: -> show: ->
@addClass '_top' if @type is 'disabledDoc'
@html @tmpl("#{@type}Notice", @args...) @html @tmpl("#{@type}Notice", @args...)
@prependTo $('._app') @prependTo $('._app')
return return

@ -130,7 +130,7 @@ class app.views.Search extends app.View
if event.target is @resetLink if event.target is @resetLink
$.stopEvent(event) $.stopEvent(event)
@reset() @reset()
@focus() app.document.onEscape()
return return
onSubmit: (event) -> onSubmit: (event) ->

@ -148,7 +148,7 @@ class app.views.DocList extends app.View
return return
scrollTo: (model) -> scrollTo: (model) ->
$.scrollTo @find("a[href='#{model.fullPath()}']"), null, 'top', margin: 0 $.scrollTo @find("a[href='#{model.fullPath()}']"), null, 'top', margin: if app.isMobile() then 48 else 0
return return
toggleDisabled: -> toggleDisabled: ->

@ -15,8 +15,8 @@ class app.views.Results extends app.View
return return
init: -> init: ->
@addSubview @listSelect = new app.views.ListSelect @el
@addSubview @listFocus = new app.views.ListFocus @el unless app.isMobile() @addSubview @listFocus = new app.views.ListFocus @el unless app.isMobile()
@addSubview @listSelect = new app.views.ListSelect @el
@search @search
.on 'results', @onResults .on 'results', @onResults
@ -42,7 +42,7 @@ class app.views.Results extends app.View
return return
focusFirst: -> focusFirst: ->
@listFocus?.focus @el.firstElementChild @listFocus?.focusOnNextFrame @el.firstElementChild
return return
openFirst: -> openFirst: ->

@ -3,6 +3,7 @@ class app.views.Sidebar extends app.View
@events: @events:
focus: 'onFocus' focus: 'onFocus'
select: 'onSelect'
click: 'onClick' click: 'onClick'
@shortcuts: @shortcuts:
@ -14,8 +15,8 @@ class app.views.Sidebar extends app.View
@addSubview @search = new app.views.Search @addSubview @search = new app.views.Search
@search @search
.on 'searching', @showResults .on 'searching', @onSearching
.on 'clear', @showDocList .on 'clear', @onSearchClear
.scope .scope
.on 'change', @onScopeChange .on 'change', @onScopeChange
@ -27,7 +28,15 @@ class app.views.Sidebar extends app.View
$.on document, 'click', @onGlobalClick if @docPicker $.on document, 'click', @onGlobalClick if @docPicker
return return
show: (view) -> display: ->
@el.style.display = 'block'
return
resetDisplay: ->
@el.style.display = '' unless @el.style.display is 'none'
return
showView: (view) ->
unless @view is view unless @view is view
@hover?.hide() @hover?.hide()
@saveScrollPosition() @saveScrollPosition()
@ -44,28 +53,29 @@ class app.views.Sidebar extends app.View
@append @tmpl('sidebarSettings') if @view is @docList and @docPicker @append @tmpl('sidebarSettings') if @view is @docList and @docPicker
return return
showDocList: (reset) => showDocList: ->
@show @docList @showView @docList
if reset is true
@docList.reset(revealCurrent: true)
@search.reset()
return return
showDocPicker: => showDocPicker: =>
@show @docPicker @showView @docPicker
return return
showResults: => showResults: =>
@show @results @showView @results
return
reset: ->
@display()
@showDocList()
@docList.reset()
@search.reset()
return return
onReady: => onReady: =>
@view = @docList @view = @docList
@render() @render()
@view.activate() @view.activate()
reset: ->
@showDocList true
return return
onScopeChange: (newDoc, previousDoc) => onScopeChange: (newDoc, previousDoc) =>
@ -90,15 +100,30 @@ class app.views.Sidebar extends app.View
@el.scrollTop = 0 @el.scrollTop = 0
return return
onSearching: =>
@display()
@showResults()
return
onSearchClear: =>
@resetDisplay()
@showDocList()
return
onFocus: (event) => onFocus: (event) =>
@display()
$.scrollTo event.target, @el, 'continuous', bottomGap: 2 unless event.target is @el $.scrollTo event.target, @el, 'continuous', bottomGap: 2 unless event.target is @el
return return
onSelect: =>
@resetDisplay()
return
onClick: (event) => onClick: (event) =>
return if event.which isnt 1 return if event.which isnt 1
if event.target.hasAttribute? 'data-reset-list' if event.target.hasAttribute? 'data-reset-list'
$.stopEvent(event) $.stopEvent(event)
@reset() @onAltR()
else if event.target.hasAttribute? 'data-light' else if event.target.hasAttribute? 'data-light'
$.stopEvent(event) $.stopEvent(event)
document.activeElement?.blur() document.activeElement?.blur()
@ -120,6 +145,8 @@ class app.views.Sidebar extends app.View
onAltR: => onAltR: =>
@reset() @reset()
@docList.reset(revealCurrent: true)
@display()
return return
onEscape: => onEscape: =>

@ -35,6 +35,13 @@ class app.View
@el.classList.remove(name) @el.classList.remove(name)
return return
toggleClass: (name) ->
@el.classList.toggle(name)
return
hasClass: (name) ->
@el.classList.contains(name)
resetClass: -> resetClass: ->
@el.className = @originalClassName or '' @el.className = @originalClassName or ''
if @constructor.className if @constructor.className

@ -2,7 +2,6 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
height: 100%; height: 100%;
padding-top: $headerHeight;
overflow: hidden; overflow: hidden;
background: $contentBackground; background: $contentBackground;
-webkit-transition: opacity .2s; -webkit-transition: opacity .2s;
@ -31,7 +30,7 @@
left: 0; left: 0;
right: 0; right: 0;
line-height: 1; line-height: 1;
margin-top: -.75em; margin-top: -.6em;
font-size: 4rem; font-size: 4rem;
font-weight: 300; font-weight: 300;
letter-spacing: -.125rem; letter-spacing: -.125rem;

@ -20,18 +20,24 @@
height: 100%; height: 100%;
overflow-y: scroll; overflow-y: scroll;
margin-left: .875rem; margin-left: .875rem;
padding: 1.25rem 1.5rem 0; padding: 1.125rem 1.5rem 0;
font-size: .875rem; font-size: .875rem;
pointer-events: auto; pointer-events: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
@extend %border-box; @extend %border-box;
-webkit-padding-start: .75rem; -webkit-padding-start: .625rem;
-webkit-padding-end: 1rem; -webkit-padding-end: .75rem;
@media (-moz-overlay-scrollbars) { padding-left: .75rem; } @media (-moz-overlay-scrollbars) { padding-left: .625rem; }
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { margin-left: 0; } @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { margin-left: 0; }
._sidebar-hidden &:before {
content: '';
display: block;
margin-top: $headerHeight;
}
&:after { // padding bottom &:after { // padding bottom
content: ''; content: '';
display: block; display: block;
@ -77,15 +83,22 @@
// Intro // Intro
// //
._intro { text-align: center; } ._intro {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: calc(100vh - 2.375rem);
._sidebar-hidden & {
min-height: calc(100vh - 2.375rem - #{$headerHeight});
}
}
._intro-message { ._intro-message {
position: relative;
display: inline-block;
vertical-align: top;
max-width: 37rem; max-width: 37rem;
margin: .5rem 0;
padding: 1rem 1.25rem; padding: 1rem 1.25rem;
text-align: left;
@extend %note, %note-green; @extend %note, %note-green;
} }
@ -146,23 +159,25 @@
._lined-heading, ._lined-heading,
%lined-heading { %lined-heading {
white-space: nowrap; display: flex;
overflow: hidden; justify-content: center;
word-wrap: normal; align-items: center;
overflow-wrap: normal;
&:after { &:after {
content: ''; content: '';
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
width: 100%; flex-grow: 1;
height: 1px; height: 1px;
line-height: 0; line-height: 0;
margin-top: .25rem;
margin-left: 1rem; margin-left: 1rem;
background: $boxBorderLight; background: $boxBorderLight;
} }
} }
._block-heading { @extend %block-heading; }
._heading-links { ._heading-links {
float: right; float: right;
font-weight: normal; font-weight: normal;

@ -7,79 +7,131 @@
z-index: $headerZ; z-index: $headerZ;
top: 0; top: 0;
left: 0; left: 0;
right: 0; display: flex;
width: $sidebarWidth;
height: $headerHeight; height: $headerHeight;
line-height: $headerHeight;
background: $headerBackground; background: $headerBackground;
border-bottom: 1px solid $headerBorder; border-bottom: 1px solid $headerBorder;
@extend %user-select-none; @extend %user-select-none;
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
} }
// ._header-left {
// Navigation menu float: left;
// height: 100%;
}
._nav { ._header-right {
float: right; float: right;
margin-right: .5rem; height: 100%;
font-size: .875rem;
color: $textColor;
} }
._nav-link, ._header-btn {
._nav-link:hover {
position: relative; position: relative;
float: left; width: 2.25rem;
padding: 0 1.25rem; height: 100%;
color: inherit; color: $textColorLight;
text-decoration: none; text-align: center;
@media #{$mediumScreen} { padding: 0 .75rem; } &[hidden] { display: none; }
}
._nav-link { &[disabled] {
&:before, &:after { opacity: .3;
position: absolute; cursor: not-allowed;
left: 50%;
bottom: 0;
width: 0;
height: 0;
margin-left: -.375rem;
border: .375rem solid transparent;
border-bottom-color: darken($headerBorder, 2%);
} }
&:after { > svg {
bottom: -1px; display: inline-block;
border-bottom-color: $contentBackground; vertical-align: top;
width: 1.5rem;
height: 1.5rem;
fill: currentColor;
pointer-events: none;
} }
} }
._nav-current { //
outline: 0; // Menu
//
&:before, &:after { content: ''; } ._menu-btn {
border-right: 1px solid $headerBorder;
} }
// ._menu {
// Logo position: absolute;
// z-index: 1;
top: .25rem;
right: .25rem;
width: 8rem;
height: calc(11.5rem + 1px);
font-size: .875rem;
background: $contentBackground;
border: 1px solid $headerBorder;
border-radius: 3px;
box-shadow: -1px 1px 1px rgba(black, .05);
transition: all 250ms cubic-bezier(0.23, 1, 0.32, 1);
opacity: 0;
-webkit-transform: scale(0, 0);
transform: scale(0, 0);
-webkit-transform-origin: 100% 0;
transform-origin: 100% 0;
&:hover,
._menu-btn:hover + & {
transition-delay: 100ms;
}
._logo { &:hover,
position: relative; &.active,
float: left; ._menu-btn:hover + &,
height: $headerHeight; ._menu-btn:focus + & {
opacity: 1;
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
&:focus-within {
opacity: 1;
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
}
}
._menu-title {
margin: 0; margin: 0;
line-height: inherit; line-height: 1.5rem;
font-size: inherit; font-size: 1rem;
font-weight: $boldFontWeight; font-weight: $boldFontWeight;
cursor: default; letter-spacing: -.5px;
background: $sidebarBackground;
border-bottom: 1px solid $sidebarBorder;
border-radius: 2px 2px 0 0;
}
._menu-title-link,
._menu-title-link:hover {
display: block;
padding: .5rem 1rem;
color: $focusText;
text-decoration: none;
}
> ._nav-link { ._menu-link {
float: none; display: block;
margin-left: .75rem; padding: 0 1rem;
padding: 0 .25rem; line-height: 2.25rem;
color: inherit;
text-decoration: none;
&:hover {
color: $focusText;
text-decoration: none;
background: $sidebarBackground;
} }
&:last-child { border-radius: 0 0 2px 2px; }
} }
// //
@ -87,20 +139,19 @@
// //
._search { ._search {
flex-grow: 1;
position: relative; position: relative;
float: left;
width: $sidebarWidth;
height: 100%; height: 100%;
padding: .5rem 0 .5rem .5rem; padding: .5rem 0 .5rem .5rem;
@extend %border-box; @extend %border-box;
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
&:before { &:before {
position: absolute; position: absolute;
z-index: 1;
top: 1rem; top: 1rem;
left: 1rem; left: 1rem;
opacity: .4; opacity: .4;
pointer-events: none;
@if $style == 'dark' { @if $style == 'dark' {
@extend %icon, %icon-search-white; @extend %icon, %icon-search-white;
} @else { } @else {
@ -110,6 +161,7 @@
} }
._search-input { ._search-input {
position: relative;
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -164,6 +216,7 @@
._search-tag { ._search-tag {
display: none; display: none;
position: absolute; position: absolute;
z-index: 2;
top: .875rem; top: .875rem;
left: .875rem; left: .875rem;
padding: 0 .5rem; padding: 0 .5rem;

@ -10,18 +10,17 @@
body { -ms-overflow-style: -ms-autohiding-scrollbar; } body { -ms-overflow-style: -ms-autohiding-scrollbar; }
._app, ._container, ._content { overflow: visible; } ._app, ._content { overflow: visible; }
._app { padding-top: $headerHeight; }
._container { ._container { margin: 0; }
margin: 0;
border: 0;
}
._content { ._content {
position: static; position: static;
height: auto; height: auto;
margin: 0; margin: 0;
padding: .75rem 1rem 2.5rem; padding: .75rem 1rem 2.5rem;
&:before { content: none; }
} }
._booting:before, ._content-loading:before { font-size: 3rem; } ._booting:before, ._content-loading:before { font-size: 3rem; }
@ -33,16 +32,13 @@
max-width: 100vw; max-width: 100vw;
} }
._logo, ._nav { display: none; } ._header-btn { width: 2.5rem; }
._mobile-btn { display: block; } ._header-btn[hidden] { display: block; }
._menu-btn { border-right: 0; }
._search { ._search {
float: none; padding-right: .125rem;
width: auto; padding-left: .125rem;
overflow: hidden;
padding-left: 2px;
padding-right: 2px;
border-right: 0;
&:before { left: .5rem; } &:before { left: .5rem; }
} }
@ -57,7 +53,7 @@
overflow: visible; overflow: visible;
} }
._list, ._sidebar-footer { width: 100%; } ._header, ._list, ._sidebar-footer { width: 100%; }
._list-item { ._list-item {
white-space: normal; white-space: normal;
@ -85,33 +81,12 @@
box-shadow: 0 1px $noteGreenBorder, 0 -1px $noteGreenBorder; box-shadow: 0 1px $noteGreenBorder, 0 -1px $noteGreenBorder;
} }
// Splash
._splash-sponsors { margin-top: 1rem; }
._splash-sponsor {
position: static;
._logo-info {
left: 1rem;
right: 1rem;
width: auto;
max-width: none;
margin: 0;
}
}
// Notice // Notice
._notice { ._notice {
position: fixed; position: fixed;
left: 0; left: 0;
padding: 0 .5rem; padding: 0 .5rem;
~ ._sidebar {
margin-top: 2.5rem;
padding-bottom: 4rem;
}
} }
._notice-text { font-size: .75em; } ._notice-text { font-size: .75em; }
@ -143,76 +118,10 @@
// Header buttons // Header buttons
// //
._mobile-btn {
display: none;
position: relative;
float: left;
width: 2.5rem;
height: 100%;
@extend %hide-text;
&[disabled] {
opacity: .3;
cursor: not-allowed;
}
&:before {
position: absolute;
top: 50%;
left: 50%;
margin: -.5rem 0 0 -.5rem;
@extend %icon;
}
}
._back-btn {
&:before { @extend %icon-back; }
}
._forward-btn { ._forward-btn {
width: 2.25rem; margin-right: -.5rem;
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
&:before {
margin-left: -.375rem;
@extend %icon-back;
}
}
._home-btn {
float: right;
width: 2rem;
&:before {
margin-left: -.375rem;
@extend %icon-home;
}
}
._menu-btn {
float: right;
&:before { @extend %icon-menu; } > svg { margin-left: -.375rem; }
}
//
// Navigation menu
//
._mobile-nav {
margin: .25rem 0 1.25rem;
padding: 0;
line-height: 2.8;
overflow: hidden;
@extend %box;
}
._mobile-nav-link {
float: left;
width: 25%;
text-align: center;
font-weight: $boldFontWeight;
} }
// //
@ -222,14 +131,11 @@
._mobile-intro { ._mobile-intro {
> ._intro-list { padding-left: 1.5rem; } > ._intro-list { padding-left: 1.5rem; }
> ._intro-hide, ._intro-hide {
> ._intro-sponsors {
position: static; position: static;
float: none; float: none;
display: block; display: block;
margin-top: .75rem; margin-top: .75rem;
text-align: center; text-align: center;
} }
._intro-sponsor { margin: .5em .75em; }
} }

@ -12,17 +12,7 @@
@media #{$mediumScreen} { left: $sidebarMediumWidth; } @media #{$mediumScreen} { left: $sidebarMediumWidth; }
._sidebar-hidden & { left: $sidebarHiddenWidth; } ._sidebar-hidden & { left: $sidebarHiddenWidth; }
~ ._container { padding-bottom: 2.5rem; }
&:not(._top) ~ ._container { padding-bottom: 2.5rem; }
&._top {
bottom: auto;
top: $headerHeight;
margin-top: 1px;
box-shadow: inset 0 -1px $noticeBorder;
~ ._container { padding-top: 2.5rem; }
}
} }
._notice-text { ._notice-text {

@ -40,7 +40,7 @@
._resizer { ._resizer {
position: absolute; position: absolute;
z-index: $sidebarZ + 1; z-index: $sidebarZ;
top: $headerHeight; top: $headerHeight;
bottom: 0; bottom: 0;
left: $sidebarWidth; left: $sidebarWidth;

@ -37,8 +37,6 @@
%icon-clear { background-position: -3rem 0; } %icon-clear { background-position: -3rem 0; }
%icon-settings { background-position: 0 -1rem; } %icon-settings { background-position: 0 -1rem; }
%icon-check { background-position: -1rem -1rem; } %icon-check { background-position: -1rem -1rem; }
%icon-menu { background-position: -2rem -1rem; @extend %darkIconFix !optional; }
%icon-home { background-position: -3rem -1rem; @extend %darkIconFix !optional; }
%icon-path { background-position: 0 -2rem; } %icon-path { background-position: 0 -2rem; }
%icon-search-white { background-position: -1rem -2rem; } %icon-search-white { background-position: -1rem -2rem; }
%icon-dir-white { background-position: -2rem -2rem; } %icon-dir-white { background-position: -2rem -2rem; }
@ -54,7 +52,6 @@
%icon-clipboard { background-position: 0 -5rem; } %icon-clipboard { background-position: 0 -5rem; }
%icon-clipboard-white { background-position: -1rem -5rem; } %icon-clipboard-white { background-position: -1rem -5rem; }
%icon-close-white { background-position: -2rem -5rem; } %icon-close-white { background-position: -2rem -5rem; }
%icon-back { background-position: -3rem -5rem; @extend %darkIconFix !optional; }
._icon-codeceptjs:before { background-position: -3rem 0; } ._icon-codeceptjs:before { background-position: -3rem 0; }
._icon-codeception:before { background-position: -4rem 0; } ._icon-codeception:before { background-position: -4rem 0; }

@ -7,7 +7,7 @@ $style: 'dark';
$maxWidth: 80rem; $maxWidth: 80rem;
$headerHeight: 3rem; $headerHeight: 3rem;
$sidebarWidth: 18rem; $sidebarWidth: 20rem;
$sidebarMediumWidth: 16rem; $sidebarMediumWidth: 16rem;
$sidebarHiddenWidth: 9px; $sidebarHiddenWidth: 9px;
@ -37,7 +37,7 @@ $linkColor: $textColor;
$linkColorHover: white; $linkColorHover: white;
$linkTextDecoration: underline; $linkTextDecoration: underline;
$headerBackground: #1e1e1e; $headerBackground: #1c1c1c;
$headerBorder: #000; $headerBorder: #000;
$sidebarBackground: #24282a; $sidebarBackground: #24282a;

@ -7,7 +7,7 @@ $style: 'light';
$maxWidth: 80rem; $maxWidth: 80rem;
$headerHeight: 3rem; $headerHeight: 3rem;
$sidebarWidth: 18rem; $sidebarWidth: 20rem;
$sidebarMediumWidth: 16rem; $sidebarMediumWidth: 16rem;
$sidebarHiddenWidth: 9px; $sidebarHiddenWidth: 9px;
@ -37,11 +37,11 @@ $linkColor: #3377c0;
$linkColorHover: #2f6cb6; $linkColorHover: #2f6cb6;
$linkTextDecoration: none; $linkTextDecoration: none;
$headerBackground: #f0f0f0; $headerBackground: #eee;
$headerBorder: #d9d9d9; $headerBorder: #d7d7d7;
$sidebarBackground: #f9f9f9; $sidebarBackground: #f9f9f9;
$sidebarBorder: #e3e3e3; $sidebarBorder: #e1e1e1;
$scrollbarColor: #d2d2d2; $scrollbarColor: #d2d2d2;
$scrollbarColorHover: #aaa; $scrollbarColorHover: #aaa;

@ -184,7 +184,7 @@ class App < Sinatra::Application
end end
def app_size def app_size
@app_size ||= cookies[:size].nil? ? '18rem' : "#{cookies[:size]}px" @app_size ||= cookies[:size].nil? ? '20rem' : "#{cookies[:size]}px"
end end
def app_layout def app_layout

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

@ -1 +0,0 @@
http://www.entypo.com/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

@ -31,7 +31,7 @@ class AppTest < MiniTest::Spec
it "sets default size" do it "sets default size" do
get '/' get '/'
assert_includes last_response.body, 'data-size="18rem"' assert_includes last_response.body, 'data-size="20rem"'
end end
it "sets size from cookie" do it "sets size from cookie" do
@ -115,7 +115,7 @@ class AppTest < MiniTest::Spec
it "sets default size" do it "sets default size" do
get '/manifest.appcache' get '/manifest.appcache'
assert_includes last_response.body, '18rem' assert_includes last_response.body, '20rem'
end end
it "sets size from cookie" do it "sets size from cookie" do

@ -1,22 +1,28 @@
<div class="_app<%= " #{app_layout}" if app_layout %>" role="application"> <div class="_app<%= " #{app_layout}" if app_layout %>" role="application">
<header class="_header" role="banner"> <header class="_header" role="banner">
<button type="button" class="_mobile-btn _back-btn">Back</button> <button type="button" aria-label="Toggle navigation" class="_header-btn" data-toggle-sidebar hidden>
<button type="button" class="_mobile-btn _forward-btn">Forward</button> <svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg>
<button type="button" class="_mobile-btn _menu-btn">Menu</button> </button>
<button type="button" class="_mobile-btn _home-btn">Home</button>
<form class="_search" role="search"> <form class="_search" role="search">
<input type="search" name="q" class="_search-input" placeholder="Search&hellip;" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" maxlength="30" aria-label="Search"> <input type="search" name="q" class="_search-input" placeholder="Search&hellip;" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" maxlength="30" aria-label="Search">
<button type="reset" class="_search-clear" title="Clear search">Clear search</button> <button type="reset" class="_search-clear" title="Clear search">Clear search</button>
<div class="_search-tag"></div> <div class="_search-tag"></div>
</form> </form>
<h1 class="_logo"> <button type="button" aria-label="Back" class="_header-btn" data-back hidden>
<a href="/" class="_nav-link" title="Offline API Documentation Browser">DevDocs</a><%= "/ #{@doc['full_name']}" if @doc %> <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>
</h1> </button>
<nav class="_nav" role="navigation"> <button type="button" aria-label="Forward" class="_header-btn _forward-btn" data-forward hidden>
<a href="/offline" class="_nav-link">Offline</a> <svg viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></svg>
<a href="/about" class="_nav-link">About</a> </button>
<a href="/news" class="_nav-link">News</a> <button type="button" aria-label="Toggle menu" title="Toggle menu" class="_header-btn _menu-btn" data-toggle-menu>
<a href="/help" class="_nav-link">Tips</a> <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>
</button>
<nav class="_menu" role="navigation">
<h1 class="_menu-title"><a href="/" class="_menu-title-link">DevDocs</a></h1>
<a href="/offline" class="_menu-link">Offline</a>
<a href="/news" class="_menu-link">Changelog</a>
<a href="/help" class="_menu-link">Help</a>
<a href="/about" class="_menu-link">About</a>
</nav> </nav>
</header> </header>
<section class="_sidebar" tabindex="-1"> <section class="_sidebar" tabindex="-1">
@ -34,7 +40,7 @@
</div> </div>
<style data-size="<%= app_size %>" data-resizer> <style data-size="<%= app_size %>" data-resizer>
._container { margin-left: <%= app_size %>; } ._container { margin-left: <%= app_size %>; }
._search, ._list, ._sidebar-footer { width: <%= app_size %>; } ._header, ._list, ._sidebar-footer { width: <%= app_size %>; }
._list-hover.clone { min-width: <%= app_size %>; } ._list-hover.clone { min-width: <%= app_size %>; }
._notice, ._path, ._resizer { left: <%= app_size %>; } ._notice, ._path, ._resizer { left: <%= app_size %>; }
</style> </style>

Loading…
Cancel
Save