#{c[0]} © #{c[1]} #{c[2]} " for c in credits).join('')}
- Questions & Answers
+ Questions & Answers
Where can I suggest new docs and features?
You can suggest and vote for new docs on the Trello board .
@@ -56,7 +56,7 @@ app.templates.aboutPage = -> """
For anything else, feel free to email me at thibaut@devdocs.io .
-
Copyright and License
+ Copyright and License
Copyright 2013–2017 Thibaut Courouble and other contributors
This software is licensed under the terms of the Mozilla Public License v2.0.
@@ -64,7 +64,7 @@ app.templates.aboutPage = -> """
For more information, see the COPYRIGHT
and LICENSE files.
-
Plugins and Extensions
+ Plugins and Extensions
- Privacy Policy
+ Privacy Policy
devdocs.io ("App") is operated by Thibaut Courouble ("We").
We do not collect personal information.
diff --git a/assets/javascripts/templates/pages/help_tmpl.coffee b/assets/javascripts/templates/pages/help_tmpl.coffee
index 3cb6ae82..afee16ea 100644
--- a/assets/javascripts/templates/pages/help_tmpl.coffee
+++ b/assets/javascripts/templates/pages/help_tmpl.coffee
@@ -11,7 +11,9 @@ app.templates.helpPage = """
- Search
+ Help
+
+ Search
The search is case-insensitive and supports fuzzy matching (for queries longer than two characters).
For example, searching bgcp
brings up background-clip
.
@@ -42,7 +44,7 @@ app.templates.helpPage = """
these instructions .
-
Keyboard Shortcuts
+ Keyboard Shortcuts
Selection
@@ -110,7 +112,7 @@ app.templates.helpPage = """
Tip: If the cursor is no longer in the search field, press /
or
continue to type and it will refocus the search field and start showing new results.
- Abbreviations
+ Abbreviations
Feel free to suggest new abbreviations on GitHub .
diff --git a/assets/javascripts/templates/pages/news_tmpl.coffee.erb b/assets/javascripts/templates/pages/news_tmpl.coffee.erb
index 32f0e8b9..f4045bd7 100644
--- a/assets/javascripts/templates/pages/news_tmpl.coffee.erb
+++ b/assets/javascripts/templates/pages/news_tmpl.coffee.erb
@@ -15,7 +15,7 @@ app.templates.newsList = (news, options = {}) ->
date = new Date(value[0])
if options.years isnt false and year isnt date.getUTCFullYear()
year = date.getUTCFullYear()
- result += "#{year} "
+ result += """#{year} """
result += newsItem(date, value[1..])
result
diff --git a/assets/javascripts/templates/pages/offline_tmpl.coffee b/assets/javascripts/templates/pages/offline_tmpl.coffee
index c65cc1dc..b6ba31c1 100644
--- a/assets/javascripts/templates/pages/offline_tmpl.coffee
+++ b/assets/javascripts/templates/pages/offline_tmpl.coffee
@@ -21,7 +21,7 @@ app.templates.offlinePage = (docs) -> """
#{docs}
Note: 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.
-
Questions & Answers
+ Questions & Answers
How does this work?
Each page is cached as a key-value pair in IndexedDB (downloaded from a single file).
diff --git a/assets/javascripts/templates/pages/root_tmpl.coffee.erb b/assets/javascripts/templates/pages/root_tmpl.coffee.erb
index c7a768a0..a2420487 100644
--- a/assets/javascripts/templates/pages/root_tmpl.coffee.erb
+++ b/assets/javascripts/templates/pages/root_tmpl.coffee.erb
@@ -48,15 +48,6 @@ app.templates.intro = """
"""
<% end %>
-app.templates.mobileNav = """
-
- Offline
- About
- News
- Help
-
-"""
-
app.templates.mobileIntro = """
Welcome!
diff --git a/assets/javascripts/views/content/root_page.coffee b/assets/javascripts/views/content/root_page.coffee
index fcb2da43..5ab7c278 100644
--- a/assets/javascripts/views/content/root_page.coffee
+++ b/assets/javascripts/views/content/root_page.coffee
@@ -9,7 +9,6 @@ class app.views.RootPage extends app.View
render: ->
@empty()
- @append @tmpl('mobileNav') if app.isMobile()
if app.isAndroidWebview()
@append @tmpl('androidWarning')
else
diff --git a/assets/javascripts/views/layout/document.coffee b/assets/javascripts/views/layout/document.coffee
index 22e69c91..9ec83fd7 100644
--- a/assets/javascripts/views/layout/document.coffee
+++ b/assets/javascripts/views/layout/document.coffee
@@ -1,6 +1,6 @@
class app.views.Document extends app.View
- MAX_WIDTH_CLASS = '_max-width'
- HIDE_SIDEBAR_CLASS = '_sidebar-hidden'
+ MAX_WIDTH_LAYOUT = '_max-width'
+ SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
@el: document
@@ -14,16 +14,12 @@ class app.views.Document extends app.View
superRight: 'onForward'
init: ->
- @addSubview @nav = new app.views.Nav,
+ @addSubview @menu = new app.views.Menu,
@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()
- @sidebar.search
- .on 'searching', @onSearching
- .on 'clear', @onSearchClear
-
$.on document.body, 'click', @onClick
@activate()
@@ -39,39 +35,17 @@ class app.views.Document extends app.View
return
toggleLayout: ->
- wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_CLASS)
- app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_CLASS)
- app.settings.setLayout(MAX_WIDTH_CLASS, wantsMaxWidth)
+ wantsMaxWidth = !app.el.classList.contains(MAX_WIDTH_LAYOUT)
+ app.el.classList[if wantsMaxWidth then 'add' else 'remove'](MAX_WIDTH_LAYOUT)
+ app.settings.setLayout(MAX_WIDTH_LAYOUT, wantsMaxWidth)
app.appCache?.updateInBackground()
return
- showSidebar: (options = {}) ->
- @toggleSidebar(options, true)
- return
-
- 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()
- return
-
- hasSidebar: ->
- !app.settings.hasLayout(HIDE_SIDEBAR_CLASS)
-
- onSearching: =>
- unless @hasSidebar()
- @showSidebar()
- return
-
- onSearchClear: =>
- unless @hasSidebar()
- @hideSidebar()
+ toggleSidebarLayout: ->
+ shouldHide = !app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)
+ app.el.classList[if shouldHide then 'add' else 'remove'](SIDEBAR_HIDDEN_LAYOUT)
+ app.settings.setLayout(SIDEBAR_HIDDEN_LAYOUT, shouldHide)
+ app.appCache?.updateInBackground()
return
setTitle: (title) ->
diff --git a/assets/javascripts/views/layout/menu.coffee b/assets/javascripts/views/layout/menu.coffee
new file mode 100644
index 00000000..01c954f2
--- /dev/null
+++ b/assets/javascripts/views/layout/menu.coffee
@@ -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
diff --git a/assets/javascripts/views/layout/mobile.coffee b/assets/javascripts/views/layout/mobile.coffee
index 4fb70bdb..1774e992 100644
--- a/assets/javascripts/views/layout/mobile.coffee
+++ b/assets/javascripts/views/layout/mobile.coffee
@@ -35,44 +35,48 @@ class app.views.Mobile extends app.View
FastClick.attach @body
$.on @body, 'click', @onClick
- $.on $('._home-btn'), 'click', @onClickHome
- $.on $('._menu-btn'), 'click', @onClickMenu
$.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
- @forward = $('._forward-btn')
+ @forward = $('button[data-forward]')
+ @forward.removeAttribute('hidden')
$.on @forward, 'click', @onClickForward
app.document.sidebar.search
.on 'searching', @showSidebar
- .on 'clear', @hideSidebar
@activate()
return
showSidebar: =>
if @isSidebarShown()
- @body.scrollTop = 0
+ window.scrollTo 0, 0
return
- @contentTop = @body.scrollTop
+ @contentTop = window.scrollY
@content.style.display = 'none'
@sidebar.style.display = 'block'
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
- @body.scrollTop = @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0
+ window.scrollTo 0, @findByClass(app.views.ListFold.activeClass) and @sidebarTop or 0
return
hideSidebar: =>
return unless @isSidebarShown()
- @sidebarTop = @body.scrollTop
+ @sidebarTop = window.scrollY
@sidebar.style.display = 'none'
@content.style.display = 'block'
- @body.scrollTop = @contentTop or 0
+ window.scrollTo 0, @contentTop or 0
return
isSidebarShown: ->
@@ -89,17 +93,12 @@ class app.views.Mobile extends app.View
onClickForward: =>
history.forward()
- onClickHome: =>
- app.shortcuts.trigger 'escape'
- @hideSidebar()
- return
-
- onClickMenu: =>
+ onClickToggleSidebar: =>
if @isSidebarShown() then @hideSidebar() else @showSidebar()
return
onTapSearch: =>
- @body.scrollTop = 0
+ window.scrollTo 0, 0
afterRoute: =>
@hideSidebar()
diff --git a/assets/javascripts/views/layout/nav.coffee b/assets/javascripts/views/layout/nav.coffee
deleted file mode 100644
index f76523b3..00000000
--- a/assets/javascripts/views/layout/nav.coffee
+++ /dev/null
@@ -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()
diff --git a/assets/javascripts/views/layout/resizer.coffee b/assets/javascripts/views/layout/resizer.coffee
index 8399a667..5932f5cd 100644
--- a/assets/javascripts/views/layout/resizer.coffee
+++ b/assets/javascripts/views/layout/resizer.coffee
@@ -35,7 +35,7 @@ class app.views.Resizer extends app.View
return
onClick: ->
- app.document.toggleSidebar(save: true)
+ app.document.toggleSidebarLayout()
return
onDragStart: (event) =>
diff --git a/assets/javascripts/views/list/list_focus.coffee b/assets/javascripts/views/list/list_focus.coffee
index cfa7c827..2ae13b3d 100644
--- a/assets/javascripts/views/list/list_focus.coffee
+++ b/assets/javascripts/views/list/list_focus.coffee
@@ -14,7 +14,7 @@ class app.views.ListFocus extends app.View
constructor: (@el) ->
super
- @focus = $.framify(@focus, @)
+ @focusOnNextFrame = $.framify(@focus, @)
focus: (el) ->
if el and not el.classList.contains @constructor.activeClass
@@ -87,22 +87,22 @@ class app.views.ListFocus extends app.View
onDown: =>
if cursor = @getCursor()
- @focus @findNext(cursor)
+ @focusOnNextFrame @findNext(cursor)
else
- @focus @findByTag('a')
+ @focusOnNextFrame @findByTag('a')
return
onUp: =>
if cursor = @getCursor()
- @focus @findPrev(cursor)
+ @focusOnNextFrame @findPrev(cursor)
else
- @focus @findLastByTag('a')
+ @focusOnNextFrame @findLastByTag('a')
return
onLeft: =>
cursor = @getCursor()
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
onEnter: =>
diff --git a/assets/javascripts/views/misc/notice.coffee b/assets/javascripts/views/misc/notice.coffee
index cf05e6cb..aa8c3d09 100644
--- a/assets/javascripts/views/misc/notice.coffee
+++ b/assets/javascripts/views/misc/notice.coffee
@@ -18,7 +18,6 @@ class app.views.Notice extends app.View
return
show: ->
- @addClass '_top' if @type is 'disabledDoc'
@html @tmpl("#{@type}Notice", @args...)
@prependTo $('._app')
return
diff --git a/assets/javascripts/views/search/search.coffee b/assets/javascripts/views/search/search.coffee
index 2285c017..dc41c876 100644
--- a/assets/javascripts/views/search/search.coffee
+++ b/assets/javascripts/views/search/search.coffee
@@ -130,7 +130,7 @@ class app.views.Search extends app.View
if event.target is @resetLink
$.stopEvent(event)
@reset()
- @focus()
+ app.document.onEscape()
return
onSubmit: (event) ->
diff --git a/assets/javascripts/views/sidebar/doc_list.coffee b/assets/javascripts/views/sidebar/doc_list.coffee
index 4c716aeb..19820d7f 100644
--- a/assets/javascripts/views/sidebar/doc_list.coffee
+++ b/assets/javascripts/views/sidebar/doc_list.coffee
@@ -148,7 +148,7 @@ class app.views.DocList extends app.View
return
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
toggleDisabled: ->
diff --git a/assets/javascripts/views/sidebar/results.coffee b/assets/javascripts/views/sidebar/results.coffee
index 544974d1..a0b06f68 100644
--- a/assets/javascripts/views/sidebar/results.coffee
+++ b/assets/javascripts/views/sidebar/results.coffee
@@ -15,8 +15,8 @@ class app.views.Results extends app.View
return
init: ->
- @addSubview @listSelect = new app.views.ListSelect @el
@addSubview @listFocus = new app.views.ListFocus @el unless app.isMobile()
+ @addSubview @listSelect = new app.views.ListSelect @el
@search
.on 'results', @onResults
@@ -42,7 +42,7 @@ class app.views.Results extends app.View
return
focusFirst: ->
- @listFocus?.focus @el.firstElementChild
+ @listFocus?.focusOnNextFrame @el.firstElementChild
return
openFirst: ->
diff --git a/assets/javascripts/views/sidebar/sidebar.coffee b/assets/javascripts/views/sidebar/sidebar.coffee
index 81792a93..8d67da39 100644
--- a/assets/javascripts/views/sidebar/sidebar.coffee
+++ b/assets/javascripts/views/sidebar/sidebar.coffee
@@ -3,6 +3,7 @@ class app.views.Sidebar extends app.View
@events:
focus: 'onFocus'
+ select: 'onSelect'
click: 'onClick'
@shortcuts:
@@ -14,8 +15,8 @@ class app.views.Sidebar extends app.View
@addSubview @search = new app.views.Search
@search
- .on 'searching', @showResults
- .on 'clear', @showDocList
+ .on 'searching', @onSearching
+ .on 'clear', @onSearchClear
.scope
.on 'change', @onScopeChange
@@ -27,7 +28,15 @@ class app.views.Sidebar extends app.View
$.on document, 'click', @onGlobalClick if @docPicker
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
@hover?.hide()
@saveScrollPosition()
@@ -44,28 +53,29 @@ class app.views.Sidebar extends app.View
@append @tmpl('sidebarSettings') if @view is @docList and @docPicker
return
- showDocList: (reset) =>
- @show @docList
- if reset is true
- @docList.reset(revealCurrent: true)
- @search.reset()
+ showDocList: ->
+ @showView @docList
return
showDocPicker: =>
- @show @docPicker
+ @showView @docPicker
return
showResults: =>
- @show @results
+ @showView @results
+ return
+
+ reset: ->
+ @display()
+ @showDocList()
+ @docList.reset()
+ @search.reset()
return
onReady: =>
@view = @docList
@render()
@view.activate()
-
- reset: ->
- @showDocList true
return
onScopeChange: (newDoc, previousDoc) =>
@@ -90,15 +100,30 @@ class app.views.Sidebar extends app.View
@el.scrollTop = 0
return
+ onSearching: =>
+ @display()
+ @showResults()
+ return
+
+ onSearchClear: =>
+ @resetDisplay()
+ @showDocList()
+ return
+
onFocus: (event) =>
+ @display()
$.scrollTo event.target, @el, 'continuous', bottomGap: 2 unless event.target is @el
return
+ onSelect: =>
+ @resetDisplay()
+ return
+
onClick: (event) =>
return if event.which isnt 1
if event.target.hasAttribute? 'data-reset-list'
$.stopEvent(event)
- @reset()
+ @onAltR()
else if event.target.hasAttribute? 'data-light'
$.stopEvent(event)
document.activeElement?.blur()
@@ -120,6 +145,8 @@ class app.views.Sidebar extends app.View
onAltR: =>
@reset()
+ @docList.reset(revealCurrent: true)
+ @display()
return
onEscape: =>
diff --git a/assets/javascripts/views/view.coffee b/assets/javascripts/views/view.coffee
index 1a8fe835..59000f49 100644
--- a/assets/javascripts/views/view.coffee
+++ b/assets/javascripts/views/view.coffee
@@ -35,6 +35,13 @@ class app.View
@el.classList.remove(name)
return
+ toggleClass: (name) ->
+ @el.classList.toggle(name)
+ return
+
+ hasClass: (name) ->
+ @el.classList.contains(name)
+
resetClass: ->
@el.className = @originalClassName or ''
if @constructor.className
diff --git a/assets/stylesheets/components/_app.scss b/assets/stylesheets/components/_app.scss
index 2d8a8380..1d3165a7 100644
--- a/assets/stylesheets/components/_app.scss
+++ b/assets/stylesheets/components/_app.scss
@@ -2,7 +2,6 @@
position: relative;
z-index: 1;
height: 100%;
- padding-top: $headerHeight;
overflow: hidden;
background: $contentBackground;
-webkit-transition: opacity .2s;
@@ -12,7 +11,7 @@
._booting > & { opacity: 0; }
._noscript > & { display: none; }
- &._max-width {
+ &._max-width {
margin: 0 auto;
max-width: $maxWidth;
box-shadow: 1px 0 $headerBorder, -1px 0 $headerBorder;
@@ -31,7 +30,7 @@
left: 0;
right: 0;
line-height: 1;
- margin-top: -.75em;
+ margin-top: -.6em;
font-size: 4rem;
font-weight: 300;
letter-spacing: -.125rem;
diff --git a/assets/stylesheets/components/_content.scss b/assets/stylesheets/components/_content.scss
index f8dea0b7..3e0031c7 100644
--- a/assets/stylesheets/components/_content.scss
+++ b/assets/stylesheets/components/_content.scss
@@ -20,18 +20,24 @@
height: 100%;
overflow-y: scroll;
margin-left: .875rem;
- padding: 1.25rem 1.5rem 0;
+ padding: 1.125rem 1.5rem 0;
font-size: .875rem;
pointer-events: auto;
-webkit-overflow-scrolling: touch;
@extend %border-box;
- -webkit-padding-start: .75rem;
- -webkit-padding-end: 1rem;
+ -webkit-padding-start: .625rem;
+ -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; }
+ ._sidebar-hidden &:before {
+ content: '';
+ display: block;
+ margin-top: $headerHeight;
+ }
+
&:after { // padding bottom
content: '';
display: block;
@@ -77,15 +83,22 @@
// 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 {
- position: relative;
- display: inline-block;
- vertical-align: top;
max-width: 37rem;
+ margin: .5rem 0;
padding: 1rem 1.25rem;
- text-align: left;
@extend %note, %note-green;
}
@@ -146,23 +159,25 @@
._lined-heading,
%lined-heading {
- white-space: nowrap;
- overflow: hidden;
- word-wrap: normal;
- overflow-wrap: normal;
+ display: flex;
+ justify-content: center;
+ align-items: center;
&:after {
content: '';
display: inline-block;
vertical-align: middle;
- width: 100%;
+ flex-grow: 1;
height: 1px;
line-height: 0;
+ margin-top: .25rem;
margin-left: 1rem;
background: $boxBorderLight;
}
}
+._block-heading { @extend %block-heading; }
+
._heading-links {
float: right;
font-weight: normal;
diff --git a/assets/stylesheets/components/_header.scss b/assets/stylesheets/components/_header.scss
index dd7a4fb1..fe60e315 100644
--- a/assets/stylesheets/components/_header.scss
+++ b/assets/stylesheets/components/_header.scss
@@ -7,79 +7,131 @@
z-index: $headerZ;
top: 0;
left: 0;
- right: 0;
+ display: flex;
+ width: $sidebarWidth;
height: $headerHeight;
- line-height: $headerHeight;
background: $headerBackground;
border-bottom: 1px solid $headerBorder;
@extend %user-select-none;
+
+ @media #{$mediumScreen} { width: $sidebarMediumWidth; }
}
-//
-// Navigation menu
-//
+._header-left {
+ float: left;
+ height: 100%;
+}
-._nav {
+._header-right {
float: right;
- margin-right: .5rem;
- font-size: .875rem;
- color: $textColor;
+ height: 100%;
}
-._nav-link,
-._nav-link:hover {
+._header-btn {
position: relative;
- float: left;
- padding: 0 1.25rem;
- color: inherit;
- text-decoration: none;
+ width: 2.25rem;
+ height: 100%;
+ color: $textColorLight;
+ text-align: center;
- @media #{$mediumScreen} { padding: 0 .75rem; }
-}
+ &[hidden] { display: none; }
-._nav-link {
- &:before, &:after {
- position: absolute;
- left: 50%;
- bottom: 0;
- width: 0;
- height: 0;
- margin-left: -.375rem;
- border: .375rem solid transparent;
- border-bottom-color: darken($headerBorder, 2%);
+ &[disabled] {
+ opacity: .3;
+ cursor: not-allowed;
}
- &:after {
- bottom: -1px;
- border-bottom-color: $contentBackground;
+ > svg {
+ display: inline-block;
+ 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;
}
-//
-// Logo
-//
+._menu {
+ 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 {
- position: relative;
- float: left;
- height: $headerHeight;
+ &:hover,
+ &.active,
+ ._menu-btn:hover + &,
+ ._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;
- line-height: inherit;
- font-size: inherit;
+ line-height: 1.5rem;
+ font-size: 1rem;
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 {
- float: none;
- margin-left: .75rem;
- padding: 0 .25rem;
+._menu-link {
+ display: block;
+ padding: 0 1rem;
+ 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 {
+ flex-grow: 1;
position: relative;
- float: left;
- width: $sidebarWidth;
height: 100%;
padding: .5rem 0 .5rem .5rem;
@extend %border-box;
- @media #{$mediumScreen} { width: $sidebarMediumWidth; }
-
&:before {
position: absolute;
+ z-index: 1;
top: 1rem;
left: 1rem;
opacity: .4;
+ pointer-events: none;
@if $style == 'dark' {
@extend %icon, %icon-search-white;
} @else {
@@ -110,6 +161,7 @@
}
._search-input {
+ position: relative;
display: block;
width: 100%;
height: 100%;
@@ -164,6 +216,7 @@
._search-tag {
display: none;
position: absolute;
+ z-index: 2;
top: .875rem;
left: .875rem;
padding: 0 .5rem;
diff --git a/assets/stylesheets/components/_mobile.scss b/assets/stylesheets/components/_mobile.scss
index d6f3b3e9..5ca8463e 100644
--- a/assets/stylesheets/components/_mobile.scss
+++ b/assets/stylesheets/components/_mobile.scss
@@ -10,18 +10,17 @@
body { -ms-overflow-style: -ms-autohiding-scrollbar; }
- ._app, ._container, ._content { overflow: visible; }
-
- ._container {
- margin: 0;
- border: 0;
- }
+ ._app, ._content { overflow: visible; }
+ ._app { padding-top: $headerHeight; }
+ ._container { margin: 0; }
._content {
position: static;
height: auto;
margin: 0;
padding: .75rem 1rem 2.5rem;
+
+ &:before { content: none; }
}
._booting:before, ._content-loading:before { font-size: 3rem; }
@@ -33,16 +32,13 @@
max-width: 100vw;
}
- ._logo, ._nav { display: none; }
- ._mobile-btn { display: block; }
+ ._header-btn { width: 2.5rem; }
+ ._header-btn[hidden] { display: block; }
+ ._menu-btn { border-right: 0; }
._search {
- float: none;
- width: auto;
- overflow: hidden;
- padding-left: 2px;
- padding-right: 2px;
- border-right: 0;
+ padding-right: .125rem;
+ padding-left: .125rem;
&:before { left: .5rem; }
}
@@ -57,7 +53,7 @@
overflow: visible;
}
- ._list, ._sidebar-footer { width: 100%; }
+ ._header, ._list, ._sidebar-footer { width: 100%; }
._list-item {
white-space: normal;
@@ -85,33 +81,12 @@
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 {
position: fixed;
left: 0;
padding: 0 .5rem;
-
- ~ ._sidebar {
- margin-top: 2.5rem;
- padding-bottom: 4rem;
- }
}
._notice-text { font-size: .75em; }
@@ -143,76 +118,10 @@
// 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 {
- width: 2.25rem;
- -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;
- }
-}
+ margin-right: -.5rem;
-._menu-btn {
- float: right;
-
- &:before { @extend %icon-menu; }
-}
-
-//
-// 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;
+ > svg { margin-left: -.375rem; }
}
//
@@ -222,14 +131,11 @@
._mobile-intro {
> ._intro-list { padding-left: 1.5rem; }
- > ._intro-hide,
- > ._intro-sponsors {
+ ._intro-hide {
position: static;
float: none;
display: block;
margin-top: .75rem;
text-align: center;
}
-
- ._intro-sponsor { margin: .5em .75em; }
}
diff --git a/assets/stylesheets/components/_notice.scss b/assets/stylesheets/components/_notice.scss
index 56991951..993ec3d6 100644
--- a/assets/stylesheets/components/_notice.scss
+++ b/assets/stylesheets/components/_notice.scss
@@ -12,17 +12,7 @@
@media #{$mediumScreen} { left: $sidebarMediumWidth; }
._sidebar-hidden & { left: $sidebarHiddenWidth; }
-
- &: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; }
- }
+ ~ ._container { padding-bottom: 2.5rem; }
}
._notice-text {
diff --git a/assets/stylesheets/components/_sidebar.scss b/assets/stylesheets/components/_sidebar.scss
index 8301a8f4..c330e61c 100644
--- a/assets/stylesheets/components/_sidebar.scss
+++ b/assets/stylesheets/components/_sidebar.scss
@@ -40,7 +40,7 @@
._resizer {
position: absolute;
- z-index: $sidebarZ + 1;
+ z-index: $sidebarZ;
top: $headerHeight;
bottom: 0;
left: $sidebarWidth;
diff --git a/assets/stylesheets/global/_icons.scss b/assets/stylesheets/global/_icons.scss
index 6e807c1e..9bf033a3 100644
--- a/assets/stylesheets/global/_icons.scss
+++ b/assets/stylesheets/global/_icons.scss
@@ -37,8 +37,6 @@
%icon-clear { background-position: -3rem 0; }
%icon-settings { background-position: 0 -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-search-white { background-position: -1rem -2rem; }
%icon-dir-white { background-position: -2rem -2rem; }
@@ -54,7 +52,6 @@
%icon-clipboard { background-position: 0 -5rem; }
%icon-clipboard-white { background-position: -1rem -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-codeception:before { background-position: -4rem 0; }
diff --git a/assets/stylesheets/global/_variables-dark.scss b/assets/stylesheets/global/_variables-dark.scss
index c9bc91a4..9b4ee78f 100644
--- a/assets/stylesheets/global/_variables-dark.scss
+++ b/assets/stylesheets/global/_variables-dark.scss
@@ -7,7 +7,7 @@ $style: 'dark';
$maxWidth: 80rem;
$headerHeight: 3rem;
-$sidebarWidth: 18rem;
+$sidebarWidth: 20rem;
$sidebarMediumWidth: 16rem;
$sidebarHiddenWidth: 9px;
@@ -37,7 +37,7 @@ $linkColor: $textColor;
$linkColorHover: white;
$linkTextDecoration: underline;
-$headerBackground: #1e1e1e;
+$headerBackground: #1c1c1c;
$headerBorder: #000;
$sidebarBackground: #24282a;
diff --git a/assets/stylesheets/global/_variables.scss b/assets/stylesheets/global/_variables.scss
index 67c8d738..68d4358b 100644
--- a/assets/stylesheets/global/_variables.scss
+++ b/assets/stylesheets/global/_variables.scss
@@ -7,7 +7,7 @@ $style: 'light';
$maxWidth: 80rem;
$headerHeight: 3rem;
-$sidebarWidth: 18rem;
+$sidebarWidth: 20rem;
$sidebarMediumWidth: 16rem;
$sidebarHiddenWidth: 9px;
@@ -37,11 +37,11 @@ $linkColor: #3377c0;
$linkColorHover: #2f6cb6;
$linkTextDecoration: none;
-$headerBackground: #f0f0f0;
-$headerBorder: #d9d9d9;
+$headerBackground: #eee;
+$headerBorder: #d7d7d7;
$sidebarBackground: #f9f9f9;
-$sidebarBorder: #e3e3e3;
+$sidebarBorder: #e1e1e1;
$scrollbarColor: #d2d2d2;
$scrollbarColorHover: #aaa;
diff --git a/lib/app.rb b/lib/app.rb
index eb7d371d..bb19a046 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -184,7 +184,7 @@ class App < Sinatra::Application
end
def app_size
- @app_size ||= cookies[:size].nil? ? '18rem' : "#{cookies[:size]}px"
+ @app_size ||= cookies[:size].nil? ? '20rem' : "#{cookies[:size]}px"
end
def app_layout
diff --git a/public/icons/ui/back/16.png b/public/icons/ui/back/16.png
deleted file mode 100644
index 5f86f40c..00000000
Binary files a/public/icons/ui/back/16.png and /dev/null differ
diff --git a/public/icons/ui/back/16@2x.png b/public/icons/ui/back/16@2x.png
deleted file mode 100644
index 59efadf4..00000000
Binary files a/public/icons/ui/back/16@2x.png and /dev/null differ
diff --git a/public/icons/ui/home/16.png b/public/icons/ui/home/16.png
deleted file mode 100644
index 2dc8382a..00000000
Binary files a/public/icons/ui/home/16.png and /dev/null differ
diff --git a/public/icons/ui/home/16@2x.png b/public/icons/ui/home/16@2x.png
deleted file mode 100644
index e8b7fcec..00000000
Binary files a/public/icons/ui/home/16@2x.png and /dev/null differ
diff --git a/public/icons/ui/home/SOURCE b/public/icons/ui/home/SOURCE
deleted file mode 100644
index ffa79609..00000000
--- a/public/icons/ui/home/SOURCE
+++ /dev/null
@@ -1 +0,0 @@
-http://www.entypo.com/
diff --git a/public/icons/ui/menu/16.png b/public/icons/ui/menu/16.png
deleted file mode 100644
index d2d341d5..00000000
Binary files a/public/icons/ui/menu/16.png and /dev/null differ
diff --git a/public/icons/ui/menu/16@2x.png b/public/icons/ui/menu/16@2x.png
deleted file mode 100644
index 4aef06fd..00000000
Binary files a/public/icons/ui/menu/16@2x.png and /dev/null differ
diff --git a/test/app_test.rb b/test/app_test.rb
index 68e8f9d3..5ead42e2 100644
--- a/test/app_test.rb
+++ b/test/app_test.rb
@@ -31,7 +31,7 @@ class AppTest < MiniTest::Spec
it "sets default size" do
get '/'
- assert_includes last_response.body, 'data-size="18rem"'
+ assert_includes last_response.body, 'data-size="20rem"'
end
it "sets size from cookie" do
@@ -115,7 +115,7 @@ class AppTest < MiniTest::Spec
it "sets default size" do
get '/manifest.appcache'
- assert_includes last_response.body, '18rem'
+ assert_includes last_response.body, '20rem'
end
it "sets size from cookie" do
diff --git a/views/app.erb b/views/app.erb
index ea98de63..e11411cb 100644
--- a/views/app.erb
+++ b/views/app.erb
@@ -1,22 +1,28 @@
" role="application">