Add settings page
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -16,21 +16,26 @@ class app.AppCache
|
|||
|
||||
update: ->
|
||||
@notifyUpdate = true
|
||||
@notifyProgress = true
|
||||
try @cache.update() catch
|
||||
return
|
||||
|
||||
updateInBackground: ->
|
||||
@notifyUpdate = false
|
||||
@notifyProgress = false
|
||||
try @cache.update() catch
|
||||
return
|
||||
|
||||
reload: ->
|
||||
$.on @cache, 'updateready noupdate error', -> window.location = '/'
|
||||
@updateInBackground()
|
||||
@notifyUpdate = false
|
||||
@notifyProgress = true
|
||||
@cache.update()
|
||||
return
|
||||
|
||||
onProgress: (event) =>
|
||||
@trigger 'progress', event
|
||||
@trigger 'progress', event if @notifyProgress
|
||||
return
|
||||
|
||||
onUpdateReady: =>
|
||||
|
|
|
@ -2,16 +2,17 @@ class app.Router
|
|||
$.extend @prototype, Events
|
||||
|
||||
@routes: [
|
||||
['*', 'before' ]
|
||||
['/', 'root' ]
|
||||
['/offline', 'offline' ]
|
||||
['/about', 'about' ]
|
||||
['/news', 'news' ]
|
||||
['/help', 'help' ]
|
||||
['/:doc-:type/', 'type' ]
|
||||
['/:doc/', 'doc' ]
|
||||
['/:doc/:path(*)', 'entry' ]
|
||||
['*', 'notFound']
|
||||
['*', 'before' ]
|
||||
['/', 'root' ]
|
||||
['/settings', 'settings' ]
|
||||
['/offline', 'offline' ]
|
||||
['/about', 'about' ]
|
||||
['/news', 'news' ]
|
||||
['/help', 'help' ]
|
||||
['/:doc-:type/', 'type' ]
|
||||
['/:doc/', 'doc' ]
|
||||
['/:doc/:path(*)', 'entry' ]
|
||||
['*', 'notFound' ]
|
||||
]
|
||||
|
||||
constructor: ->
|
||||
|
@ -76,6 +77,10 @@ class app.Router
|
|||
@triggerRoute 'root'
|
||||
return
|
||||
|
||||
settings: ->
|
||||
@triggerRoute 'settings'
|
||||
return
|
||||
|
||||
offline: ->
|
||||
@triggerRoute 'offline'
|
||||
return
|
||||
|
|
|
@ -57,6 +57,9 @@ class app.Settings
|
|||
@store.set DARK_KEY, !!value
|
||||
return
|
||||
|
||||
getDark: ->
|
||||
@store.get DARK_KEY
|
||||
|
||||
setLayout: (name, enable) ->
|
||||
layout = (@store.get(LAYOUT_KEY) || '').split(' ')
|
||||
$.arrayDelete(layout, '')
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
"New documentations: <a href=\"/erlang/\">Erlang</a> and <a href=\"/tcl_tk/\">Tcl/Tk</a>"
|
||||
], [
|
||||
"2016-01-24",
|
||||
"“Multi-version support” has landed!\nClick <a href=\"#\" data-pick-docs>Select documentation</a> to pick which versions to use. More versions will be added in the coming weeks.\nIf you notice any bugs, please report them on <a href=\"https://github.com/Thibaut/devdocs/issues\" target=\"_blank\" rel=\"noopener\">GitHub</a>."
|
||||
"“Multi-version support” has landed!"
|
||||
], [
|
||||
"2015-11-22",
|
||||
"New documentations: <a href=\"/phoenix/\">Phoenix</a>, <a href=\"/dojo/\">Dojo</a>, <a href=\"/relay/\">Relay</a> and <a href=\"/flow/\">Flow</a>"
|
||||
|
@ -117,10 +117,10 @@
|
|||
"New <a href=\"/iojs/\">io.js</a>, <a href=\"/symfony/\">Symfony</a>, <a href=\"/clojure/\">Clojure</a>, <a href=\"/lua/\">Lua</a> and <a href=\"/yii1/\">Yii 1.1</a> documentations"
|
||||
], [
|
||||
"2015-02-08",
|
||||
"New dark theme\nClick the icon in the bottom left corner to activate.\n<a href=\"https://github.com/Thibaut/devdocs/issues\" target=\"_blank\" rel=\"noopener\">Feedback</a> welcome :)"
|
||||
"New dark theme"
|
||||
], [
|
||||
"2015-01-13",
|
||||
"<a href=\"/offline\">Offline mode</a> has landed!\nIf you notice any bugs, please report them on <a href=\"https://github.com/Thibaut/devdocs/issues\" target=\"_blank\" rel=\"noopener\">GitHub</a>."
|
||||
"<a href=\"/offline\">Offline mode</a> has landed!"
|
||||
], [
|
||||
"2014-12-21",
|
||||
"New <a href=\"/react/\">React</a>, <a href=\"/rethinkdb/\">RethinkDB</a>, <a href=\"/socketio/\">Socket.IO</a>, <a href=\"/modernizr/\">Modernizr</a> and <a href=\"/bower/\">Bower</a> documentations"
|
||||
|
|
|
@ -6,4 +6,4 @@ app.templates.singleDocNotice = (doc) ->
|
|||
|
||||
app.templates.disabledDocNotice = ->
|
||||
notice """ <strong>This documentation is disabled.</strong>
|
||||
To enable it, click <a href="#" class="_notice-link" data-pick-docs>Select documentation</a>. """
|
||||
To enable it, go to <a href="/settings" class="_notice-link">Preferences</a>. """
|
||||
|
|
|
@ -47,7 +47,7 @@ app.templates.notifUpdates = (docs, disabledDocs) ->
|
|||
for doc in disabledDocs
|
||||
html += "<li>#{doc.name}"
|
||||
html += " <code>→</code> #{doc.release}" if doc.release
|
||||
html += """<span class="_notif-info"><a data-pick-docs>Enable</a></span>"""
|
||||
html += """<span class="_notif-info"><a href="/settings">Enable</a></span>"""
|
||||
html += '</ul></div>'
|
||||
|
||||
notif 'Updates', "#{html}</div>"
|
||||
|
|
|
@ -35,7 +35,7 @@ app.templates.offlinePage = (docs) -> """
|
|||
<dt>How do I uninstall/reset the app?
|
||||
<dd>Click <a href="#" data-behavior="reset">here</a>.
|
||||
<dt>Why aren't all documentations listed above?
|
||||
<dd>You have to <a href="#" data-pick-docs>enable</a> them first.
|
||||
<dd>You have to <a href="/settings">enable</a> them first.
|
||||
</dl>
|
||||
"""
|
||||
|
||||
|
|
|
@ -32,14 +32,14 @@ app.templates.intro = """
|
|||
<p>DevDocs combines multiple API documentations in a fast, organized, and searchable interface.
|
||||
Here's what you should know before you start:
|
||||
<ol class="_intro-list">
|
||||
<li>To enable more docs, click <a class="_intro-link" data-pick-docs>Select documentation</a> in the bottom left corner
|
||||
<li>You don't have to use your mouse — see the list of <a href="/help#shortcuts">keyboard shortcuts</a>
|
||||
<li>The search supports fuzzy matching (e.g. "bgcp" brings up "background-clip")
|
||||
<li>To search a specific documentation, type its name (or an abbreviation), then Tab
|
||||
<li>You can search using your browser's address bar — <a href="/help#browser_search">learn how</a>
|
||||
<li>Open the <a href="/settings">Preferences</a> to enable more docs and customize the UI.
|
||||
<li>You don't have to use your mouse — see the list of <a href="/help#shortcuts">keyboard shortcuts</a>.
|
||||
<li>The search supports fuzzy matching (e.g. "bgcp" brings up "background-clip").
|
||||
<li>To search a specific documentation, type its name (or an abbr.), then Tab.
|
||||
<li>You can search using your browser's address bar — <a href="/help#browser_search">learn how</a>.
|
||||
<li>DevDocs works <a href="/offline">offline</a>, on mobile, and can be installed on <a href="https://chrome.google.com/webstore/detail/devdocs/mnfehgbmkapmjnhcnbodoamcioleeooe">Chrome</a>.
|
||||
<li>For the latest news, follow <a href="https://twitter.com/DevDocs">@DevDocs</a>
|
||||
<li>DevDocs is free and <a href="https://github.com/Thibaut/devdocs">open source</a>
|
||||
<li>For the latest news, follow <a href="https://twitter.com/DevDocs">@DevDocs</a>.
|
||||
<li>DevDocs is free and <a href="https://github.com/Thibaut/devdocs">open source</a>.
|
||||
<iframe class="_github-btn" src="//ghbtns.com/github-btn.html?user=Thibaut&repo=devdocs&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
|
||||
<li>If you like the app, please consider supporting the project on <a href="https://gratipay.com/devdocs/">Gratipay</a>. Thanks!
|
||||
</ol>
|
||||
|
@ -54,11 +54,11 @@ app.templates.mobileIntro = """
|
|||
<p>DevDocs combines multiple API documentations in a fast, organized, and searchable interface.
|
||||
Here's what you should know before you start:
|
||||
<ol class="_intro-list">
|
||||
<li>To pick your docs, click <a data-pick-docs>Select documentation</a> at the bottom of the menu
|
||||
<li>The search supports fuzzy matching (e.g. "bgcp" matches "background-clip")
|
||||
<li>To search a specific documentation, type its name (or an abbreviation), then Space
|
||||
<li>For the latest news, follow <a href="https://twitter.com/DevDocs">@DevDocs</a>
|
||||
<li>DevDocs is <a href="https://github.com/Thibaut/devdocs">open source</a>
|
||||
<li>Pick your docs in the <a href="/settings">Preferences</a>.
|
||||
<li>The search supports fuzzy matching.
|
||||
<li>To search a specific documentation, type its name (or an abbr.), then Space.
|
||||
<li>For the latest news, follow <a href="https://twitter.com/DevDocs">@DevDocs</a>.
|
||||
<li>DevDocs is <a href="https://github.com/Thibaut/devdocs">open source</a>.
|
||||
</ol>
|
||||
<p>Happy coding!
|
||||
<a class="_intro-hide" data-hide-intro>Stop showing this message</a>
|
||||
|
|
27
assets/javascripts/templates/pages/settings_tmpl.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
app.templates.settingsPage = (settings) -> """
|
||||
<h1 class="_lined-heading">Preferences</h1>
|
||||
|
||||
<div class="_settings-fieldset">
|
||||
<h2 class="_settings-legend">General:</h2>
|
||||
|
||||
<div class="_settings-inputs">
|
||||
<label class="_settings-label">
|
||||
<input type="checkbox" name="dark" value="1"#{if settings.dark then ' checked' else ''}>Enable dark theme
|
||||
</label>
|
||||
<label class="_settings-label _settings-max-width">
|
||||
<input type="checkbox" name="layout" value="_max-width"#{if settings['_max-width'] then ' checked' else ''}>Enable fixed-width layout
|
||||
</label>
|
||||
<label class="_settings-label">
|
||||
<input type="checkbox" name="layout" value="_sidebar-hidden"#{if settings['_sidebar-hidden'] then ' checked' else ''}>Automatically hide and show the sidebar
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="_settings-fieldset">
|
||||
<h2 class="_settings-legend">Advanced:</h2>
|
||||
|
||||
<div class="_settings-inputs">
|
||||
<a href="#" class="_settings-link" data-behavior="reset">Reset all settings and data</a>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
|
@ -30,7 +30,7 @@ templates.sidebarResult = (entry) ->
|
|||
templates.sidebarNoResults = ->
|
||||
html = """ <div class="_list-note">No results.</div> """
|
||||
html += """
|
||||
<div class="_list-note">Note: documentations must be <a href="#" class="_list-note-link" data-pick-docs>enabled</a> to appear in the search.</div>
|
||||
<div class="_list-note">Note: documentations must be <a href="/settings" class="_list-note-link">enabled</a> to appear in the search.</div>
|
||||
""" unless app.isSingleDoc() or app.disabledDocs.isEmpty()
|
||||
html
|
||||
|
||||
|
@ -58,19 +58,7 @@ templates.sidebarDisabledList = (html) ->
|
|||
templates.sidebarDisabledVersionedDoc = (doc, versions) ->
|
||||
"""<a class="_list-item _list-dir _icon-#{doc.icon} _list-disabled" data-slug="#{doc.slug_without_version}" tabindex="-1"><span class="_list-arrow"></span>#{doc.name}</a><div class="_list _list-sub">#{versions}</div>"""
|
||||
|
||||
templates.sidebarPickerNote = """
|
||||
templates.docPickerNote = """
|
||||
<div class="_list-note">Tip: for faster and better search results, select only the docs you need.</div>
|
||||
<a href="https://trello.com/b/6BmTulfx/devdocs-documentation" class="_list-link" target="_blank" rel="noopener">Vote for new documentation</a>
|
||||
"""
|
||||
|
||||
sidebarFooter = (html) -> """<div class="_sidebar-footer">#{html}</div>"""
|
||||
|
||||
templates.sidebarSettings = ->
|
||||
sidebarFooter """
|
||||
<button type="button" class="_sidebar-footer-link _sidebar-footer-edit" data-pick-docs>Select documentation</button>
|
||||
<button type="button" class="_sidebar-footer-link _sidebar-footer-light" title="Toggle light" data-light>Toggle light</button>
|
||||
<button type="button" class="_sidebar-footer-link _sidebar-footer-layout" title="Toggle layout" data-layout>Toggle layout</button>
|
||||
"""
|
||||
|
||||
templates.sidebarSave = ->
|
||||
sidebarFooter """<a class="_sidebar-footer-link _sidebar-footer-save" role="button">Save</a>"""
|
||||
|
|
|
@ -23,11 +23,12 @@ class app.views.Content extends app.View
|
|||
@scrollMap = {}
|
||||
@scrollStack = []
|
||||
|
||||
@rootPage = new app.views.RootPage
|
||||
@staticPage = new app.views.StaticPage
|
||||
@offlinePage = new app.views.OfflinePage
|
||||
@typePage = new app.views.TypePage
|
||||
@entryPage = new app.views.EntryPage
|
||||
@rootPage = new app.views.RootPage
|
||||
@staticPage = new app.views.StaticPage
|
||||
@settingsPage = new app.views.SettingsPage
|
||||
@offlinePage = new app.views.OfflinePage
|
||||
@typePage = new app.views.TypePage
|
||||
@entryPage = new app.views.EntryPage
|
||||
|
||||
@entryPage
|
||||
.on 'loading', @onEntryLoading
|
||||
|
@ -148,6 +149,8 @@ class app.views.Content extends app.View
|
|||
@show @entryPage
|
||||
when 'type'
|
||||
@show @typePage
|
||||
when 'settings'
|
||||
@show @settingsPage
|
||||
when 'offline'
|
||||
@show @offlinePage
|
||||
else
|
||||
|
|
52
assets/javascripts/views/content/settings_page.coffee
Normal file
|
@ -0,0 +1,52 @@
|
|||
class app.views.SettingsPage extends app.View
|
||||
LAYOUTS = ['_max-width', '_sidebar-hidden']
|
||||
SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
|
||||
|
||||
@className: '_static'
|
||||
|
||||
@events:
|
||||
change: 'onChange'
|
||||
|
||||
render: ->
|
||||
@html @tmpl('settingsPage', @currentSettings())
|
||||
return
|
||||
|
||||
currentSettings: ->
|
||||
settings = {}
|
||||
settings.dark = app.settings.getDark()
|
||||
settings[layout] = app.settings.hasLayout(layout) for layout in LAYOUTS
|
||||
settings
|
||||
|
||||
getTitle: ->
|
||||
'Preferences'
|
||||
|
||||
toggleDark: (enable) ->
|
||||
css = $('link[rel="stylesheet"][data-alt]')
|
||||
alt = css.getAttribute('data-alt')
|
||||
css.setAttribute('data-alt', css.getAttribute('href'))
|
||||
css.setAttribute('href', alt)
|
||||
app.settings.setDark(enable)
|
||||
app.appCache?.updateInBackground()
|
||||
return
|
||||
|
||||
toggleLayout: (layout, enable) ->
|
||||
app.el.classList[if enable then 'add' else 'remove'](layout) unless layout is SIDEBAR_HIDDEN_LAYOUT
|
||||
app.settings.setLayout(layout, enable)
|
||||
app.appCache?.updateInBackground()
|
||||
return
|
||||
|
||||
onChange: (event) =>
|
||||
input = event.target
|
||||
switch input.name
|
||||
when 'dark'
|
||||
@toggleDark input.checked
|
||||
when 'layout'
|
||||
@toggleLayout input.value, input.checked
|
||||
return
|
||||
|
||||
onRoute: (route) =>
|
||||
if app.isSingleDoc()
|
||||
window.location = "/#/#{route.path}"
|
||||
else
|
||||
@render()
|
||||
return
|
|
@ -1,7 +1,4 @@
|
|||
class app.views.Document extends app.View
|
||||
MAX_WIDTH_LAYOUT = '_max-width'
|
||||
SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
|
||||
|
||||
@el: document
|
||||
|
||||
@events:
|
||||
|
@ -13,44 +10,32 @@ class app.views.Document extends app.View
|
|||
superLeft: 'onBack'
|
||||
superRight: 'onForward'
|
||||
|
||||
@routes:
|
||||
after: 'afterRoute'
|
||||
|
||||
init: ->
|
||||
@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()
|
||||
@settings = new app.views.Settings unless app.isSingleDoc()
|
||||
|
||||
$.on document.body, 'click', @onClick
|
||||
|
||||
@activate()
|
||||
return
|
||||
|
||||
toggleLight: ->
|
||||
css = $('link[rel="stylesheet"][data-alt]')
|
||||
alt = css.getAttribute('data-alt')
|
||||
css.setAttribute('data-alt', css.getAttribute('href'))
|
||||
css.setAttribute('href', alt)
|
||||
app.settings.setDark(alt.indexOf('dark') > 0)
|
||||
app.appCache?.updateInBackground()
|
||||
return
|
||||
|
||||
toggleLayout: ->
|
||||
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
|
||||
|
||||
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) ->
|
||||
@el.title = if title then "DevDocs — #{title}" else 'DevDocs API Documentation'
|
||||
|
||||
afterRoute: (route) =>
|
||||
if route is 'settings'
|
||||
@settings?.activate()
|
||||
else
|
||||
@settings?.deactivate()
|
||||
return
|
||||
|
||||
onVisibilityChange: =>
|
||||
return unless @el.visibilityState is 'visible'
|
||||
@delay ->
|
||||
|
|
|
@ -2,9 +2,10 @@ class app.views.Mobile extends app.View
|
|||
@className: '_mobile'
|
||||
|
||||
@elements:
|
||||
body: 'body'
|
||||
content: '._container'
|
||||
sidebar: '._sidebar'
|
||||
body: 'body'
|
||||
content: '._container'
|
||||
sidebar: '._sidebar'
|
||||
docPicker: '._settings ._sidebar'
|
||||
|
||||
@routes:
|
||||
after: 'afterRoute'
|
||||
|
@ -34,7 +35,6 @@ class app.views.Mobile extends app.View
|
|||
init: ->
|
||||
FastClick.attach @body
|
||||
|
||||
$.on @body, 'click', @onClick
|
||||
$.on $('._search'), 'touchend', @onTapSearch
|
||||
|
||||
@toggleSidebar = $('button[data-toggle-sidebar]')
|
||||
|
@ -49,6 +49,14 @@ class app.views.Mobile extends app.View
|
|||
@forward.removeAttribute('hidden')
|
||||
$.on @forward, 'click', @onClickForward
|
||||
|
||||
@docPickerTab = $('a[data-tab="doc-picker"]')
|
||||
@docPickerTab.removeAttribute('hidden')
|
||||
$.on @docPickerTab, 'click', @onClickDocPickerTab
|
||||
|
||||
@settingsTab = $('a[data-tab="settings"]')
|
||||
@settingsTab.removeAttribute('hidden')
|
||||
$.on @settingsTab, 'click', @onClickSettingsTab
|
||||
|
||||
app.document.sidebar.search
|
||||
.on 'searching', @showSidebar
|
||||
|
||||
|
@ -82,11 +90,6 @@ class app.views.Mobile extends app.View
|
|||
isSidebarShown: ->
|
||||
@sidebar.style.display isnt 'none'
|
||||
|
||||
onClick: (event) =>
|
||||
if event.target.hasAttribute 'data-pick-docs'
|
||||
@showSidebar()
|
||||
return
|
||||
|
||||
onClickBack: =>
|
||||
history.back()
|
||||
|
||||
|
@ -97,12 +100,41 @@ class app.views.Mobile extends app.View
|
|||
if @isSidebarShown() then @hideSidebar() else @showSidebar()
|
||||
return
|
||||
|
||||
onClickDocPickerTab: (event) =>
|
||||
$.stopEvent(event)
|
||||
@showDocPicker()
|
||||
return
|
||||
|
||||
onClickSettingsTab: (event) =>
|
||||
$.stopEvent(event)
|
||||
@showSettings()
|
||||
return
|
||||
|
||||
showDocPicker: ->
|
||||
@docPickerTab.classList.add 'active'
|
||||
@settingsTab.classList.remove 'active'
|
||||
@docPicker.style.display = 'block'
|
||||
@content.style.display = 'none'
|
||||
return
|
||||
|
||||
showSettings: ->
|
||||
@docPickerTab.classList.remove 'active'
|
||||
@settingsTab.classList.add 'active'
|
||||
@docPicker.style.display = 'none'
|
||||
@content.style.display = 'block'
|
||||
return
|
||||
|
||||
onTapSearch: =>
|
||||
window.scrollTo 0, 0
|
||||
|
||||
afterRoute: =>
|
||||
afterRoute: (route) =>
|
||||
@hideSidebar()
|
||||
|
||||
if route is 'settings'
|
||||
@showDocPicker()
|
||||
else
|
||||
@content.style.display = 'block'
|
||||
|
||||
if page.canGoBack()
|
||||
@back.removeAttribute('disabled')
|
||||
else
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
class app.views.Resizer extends app.View
|
||||
@className: '_resizer'
|
||||
@attributes:
|
||||
title: 'Click to toggle sidebar on/off'
|
||||
|
||||
@events:
|
||||
dragstart: 'onDragStart'
|
||||
dragend: 'onDragEnd'
|
||||
click: 'onClick'
|
||||
|
||||
@isSupported: ->
|
||||
'ondragstart' of document.createElement('div') and !app.isMobile()
|
||||
|
@ -34,10 +31,6 @@ class app.views.Resizer extends app.View
|
|||
app.appCache?.updateInBackground()
|
||||
return
|
||||
|
||||
onClick: ->
|
||||
app.document.toggleSidebarLayout()
|
||||
return
|
||||
|
||||
onDragStart: (event) =>
|
||||
@style.removeAttribute('disabled')
|
||||
event.dataTransfer.effectAllowed = 'link'
|
||||
|
|
80
assets/javascripts/views/layout/settings.coffee
Normal file
|
@ -0,0 +1,80 @@
|
|||
class app.views.Settings extends app.View
|
||||
SIDEBAR_HIDDEN_LAYOUT = '_sidebar-hidden'
|
||||
|
||||
@el: '._settings'
|
||||
|
||||
@elements:
|
||||
sidebar: '._sidebar'
|
||||
saveBtn: 'button[type="submit"]'
|
||||
backBtn: 'button[data-back]'
|
||||
|
||||
@events:
|
||||
submit: 'onSubmit'
|
||||
click: 'onClick'
|
||||
focus: 'onFocus'
|
||||
|
||||
@shortcuts:
|
||||
enter: 'onEnter'
|
||||
|
||||
init: ->
|
||||
@addSubview @docPicker = new app.views.DocPicker
|
||||
return
|
||||
|
||||
activate: ->
|
||||
if super
|
||||
@render()
|
||||
app.el.classList.remove(SIDEBAR_HIDDEN_LAYOUT)
|
||||
app.appCache?.on 'progress', @onAppCacheProgress
|
||||
return
|
||||
|
||||
deactivate: ->
|
||||
if super
|
||||
@resetClass()
|
||||
@docPicker.detach()
|
||||
app.el.classList.add(SIDEBAR_HIDDEN_LAYOUT) if app.settings.hasLayout(SIDEBAR_HIDDEN_LAYOUT)
|
||||
app.appCache?.off 'progress', @onAppCacheProgress
|
||||
return
|
||||
|
||||
render: ->
|
||||
@docPicker.appendTo @sidebar
|
||||
@refreshElements()
|
||||
@addClass '_in'
|
||||
return
|
||||
|
||||
save: ->
|
||||
unless @saving
|
||||
@saving = true
|
||||
docs = @docPicker.getSelectedDocs()
|
||||
app.settings.setDocs(docs)
|
||||
@saveBtn.textContent = if app.appCache then 'Downloading\u2026' else 'Saving\u2026'
|
||||
disabledDocs = new app.collections.Docs(doc for doc in app.docs.all() when docs.indexOf(doc.slug) is -1)
|
||||
disabledDocs.uninstall ->
|
||||
app.db.migrate()
|
||||
app.reload()
|
||||
return
|
||||
|
||||
onEnter: =>
|
||||
@save()
|
||||
return
|
||||
|
||||
onSubmit: (event) =>
|
||||
event.preventDefault()
|
||||
@save()
|
||||
return
|
||||
|
||||
onClick: (event) =>
|
||||
return if event.which isnt 1
|
||||
if event.target is @backBtn
|
||||
$.stopEvent(event)
|
||||
app.router.show '/'
|
||||
return
|
||||
|
||||
onFocus: (event) =>
|
||||
$.scrollTo event.target, @el, 'continuous', bottomGap: 2
|
||||
return
|
||||
|
||||
onAppCacheProgress: (event) =>
|
||||
if event.lengthComputable
|
||||
percentage = Math.round event.loaded * 100 / event.total
|
||||
@saveBtn.textContent = "Downloading\u2026 (#{percentage}%)"
|
||||
return
|
|
@ -51,14 +51,6 @@ class app.views.Search extends app.View
|
|||
@autoFocus()
|
||||
return
|
||||
|
||||
disable: ->
|
||||
@input.setAttribute('disabled', 'disabled')
|
||||
return
|
||||
|
||||
enable: ->
|
||||
@input.removeAttribute('disabled')
|
||||
return
|
||||
|
||||
onReady: =>
|
||||
@value = ''
|
||||
@delay @onInput
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
class app.views.DocPicker extends app.View
|
||||
@className: '_list _list-picker'
|
||||
@attributes:
|
||||
role: 'form'
|
||||
|
||||
@elements:
|
||||
saveLink: '._sidebar-footer-save'
|
||||
|
||||
@events:
|
||||
click: 'onClick'
|
||||
mousedown: 'onMouseDown'
|
||||
|
||||
@shortcuts:
|
||||
enter: 'onEnter'
|
||||
|
||||
init: ->
|
||||
@addSubview @listFold = new app.views.ListFold(@el)
|
||||
return
|
||||
|
@ -20,14 +11,12 @@ class app.views.DocPicker extends app.View
|
|||
activate: ->
|
||||
if super
|
||||
@render()
|
||||
app.appCache?.on 'progress', @onAppCacheProgress
|
||||
$.on @el, 'focus', @onDOMFocus, true
|
||||
return
|
||||
|
||||
deactivate: ->
|
||||
if super
|
||||
@empty()
|
||||
app.appCache?.off 'progress', @onAppCacheProgress
|
||||
$.off @el, 'focus', @onDOMFocus, true
|
||||
@focusEl = null
|
||||
return
|
||||
|
@ -43,8 +32,7 @@ class app.views.DocPicker extends app.View
|
|||
else
|
||||
html += @tmpl('sidebarLabel', doc, checked: app.docs.contains(doc))
|
||||
|
||||
@html html + @tmpl('sidebarPickerNote') + @tmpl('sidebarSave')
|
||||
@refreshElements()
|
||||
@html html + @tmpl('docPickerNote')
|
||||
|
||||
$.requestAnimationFrame =>
|
||||
@addClass '_in'
|
||||
|
@ -68,31 +56,13 @@ class app.views.DocPicker extends app.View
|
|||
super
|
||||
return
|
||||
|
||||
save: ->
|
||||
unless @saving
|
||||
@saving = true
|
||||
docs = @getSelectedDocs()
|
||||
app.settings.setDocs(docs)
|
||||
@saveLink.textContent = if app.appCache then 'Downloading\u2026' else 'Saving\u2026'
|
||||
disabledDocs = new app.collections.Docs(doc for doc in app.docs.all() when docs.indexOf(doc.slug) is -1)
|
||||
disabledDocs.uninstall ->
|
||||
app.db.migrate()
|
||||
app.reload()
|
||||
return
|
||||
|
||||
getSelectedDocs: ->
|
||||
for input in @findAllByTag 'input' when input?.checked
|
||||
input.name
|
||||
|
||||
onClick: (event) =>
|
||||
return if event.which isnt 1
|
||||
if event.target is @saveLink
|
||||
$.stopEvent(event)
|
||||
@save()
|
||||
return
|
||||
|
||||
onMouseDown: =>
|
||||
@mouseDown = Date.now()
|
||||
return
|
||||
|
||||
onDOMFocus: (event) =>
|
||||
target = event.target
|
||||
|
@ -112,13 +82,3 @@ class app.views.DocPicker extends app.View
|
|||
@delay -> $('input', target.nextElementSibling).focus()
|
||||
@focusEl = target
|
||||
return
|
||||
|
||||
onEnter: =>
|
||||
@save()
|
||||
return
|
||||
|
||||
onAppCacheProgress: (event) =>
|
||||
if event.lengthComputable
|
||||
percentage = Math.round event.loaded * 100 / event.total
|
||||
@saveLink.textContent = "Downloading\u2026 (#{percentage}%)"
|
||||
return
|
||||
|
|
|
@ -22,10 +22,8 @@ class app.views.Sidebar extends app.View
|
|||
|
||||
@results = new app.views.Results @, @search
|
||||
@docList = new app.views.DocList
|
||||
@docPicker = new app.views.DocPicker unless app.isSingleDoc()
|
||||
|
||||
app.on 'ready', @onReady
|
||||
$.on document, 'click', @onGlobalClick if @docPicker
|
||||
return
|
||||
|
||||
display: ->
|
||||
|
@ -45,23 +43,18 @@ class app.views.Sidebar extends app.View
|
|||
@render()
|
||||
@view.activate()
|
||||
@restoreScrollPosition()
|
||||
if view is @docPicker then @search.disable() else @search.enable()
|
||||
return
|
||||
|
||||
render: ->
|
||||
@html @view
|
||||
@append @tmpl('sidebarSettings') if @view is @docList and @docPicker
|
||||
return
|
||||
|
||||
showDocList: ->
|
||||
@showView @docList
|
||||
return
|
||||
|
||||
showDocPicker: =>
|
||||
@showView @docPicker
|
||||
return
|
||||
|
||||
showResults: =>
|
||||
@display()
|
||||
@showView @results
|
||||
return
|
||||
|
||||
|
@ -101,7 +94,6 @@ class app.views.Sidebar extends app.View
|
|||
return
|
||||
|
||||
onSearching: =>
|
||||
@display()
|
||||
@showResults()
|
||||
return
|
||||
|
||||
|
@ -124,23 +116,6 @@ class app.views.Sidebar extends app.View
|
|||
if event.target.hasAttribute? 'data-reset-list'
|
||||
$.stopEvent(event)
|
||||
@onAltR()
|
||||
else if event.target.hasAttribute? 'data-light'
|
||||
$.stopEvent(event)
|
||||
document.activeElement?.blur()
|
||||
app.document.toggleLight()
|
||||
else if event.target.hasAttribute? 'data-layout'
|
||||
$.stopEvent(event)
|
||||
document.activeElement?.blur()
|
||||
app.document.toggleLayout()
|
||||
return
|
||||
|
||||
onGlobalClick: (event) =>
|
||||
return if event.which isnt 1
|
||||
if event.target.hasAttribute? 'data-pick-docs'
|
||||
$.stopEvent(event)
|
||||
@showDocPicker()
|
||||
else if @view is @docPicker
|
||||
@showDocList() unless $.hasChild @el, event.target
|
||||
return
|
||||
|
||||
onAltR: =>
|
||||
|
@ -157,3 +132,4 @@ class app.views.Sidebar extends app.View
|
|||
onDocEnabled: ->
|
||||
@docList.onEnabled()
|
||||
@reset()
|
||||
return
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
'components/header',
|
||||
'components/notif',
|
||||
'components/sidebar',
|
||||
'components/settings',
|
||||
'components/content',
|
||||
'components/page',
|
||||
'components/fail',
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
'components/header',
|
||||
'components/notif',
|
||||
'components/sidebar',
|
||||
'components/settings',
|
||||
'components/content',
|
||||
'components/page',
|
||||
'components/fail',
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
@media #{$mediumScreen} { margin-left: $sidebarMediumWidth; }
|
||||
|
||||
._sidebar-hidden & { margin-left: $sidebarHiddenWidth; }
|
||||
._sidebar-hidden & { margin-left: 0; }
|
||||
}
|
||||
|
||||
._content {
|
||||
|
@ -283,7 +283,6 @@
|
|||
}
|
||||
|
||||
._docs-label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 1px 0;
|
||||
padding: .375rem .5rem;
|
||||
|
@ -292,8 +291,6 @@
|
|||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin: .25rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
height: $headerHeight;
|
||||
background: $headerBackground;
|
||||
border-bottom: 1px solid $headerBorder;
|
||||
border-right: 1px solid $headerBorder;
|
||||
@extend %border-box;
|
||||
@extend %user-select-none;
|
||||
|
||||
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
|
||||
|
@ -55,17 +57,13 @@
|
|||
// Menu
|
||||
//
|
||||
|
||||
._menu-btn {
|
||||
border-right: 1px solid $headerBorder;
|
||||
}
|
||||
|
||||
._menu {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: .25rem;
|
||||
right: .25rem;
|
||||
width: 8rem;
|
||||
height: calc(11.5rem + 1px);
|
||||
height: calc(13.75rem + 1px);
|
||||
font-size: .875rem;
|
||||
background: $contentBackground;
|
||||
border: 1px solid $headerBorder;
|
||||
|
|
|
@ -11,30 +11,42 @@
|
|||
body { -ms-overflow-style: -ms-autohiding-scrollbar; }
|
||||
|
||||
._app, ._content { overflow: visible; }
|
||||
._app { padding-top: $headerHeight; }
|
||||
._container { margin: 0; }
|
||||
|
||||
._container, ._sidebar {
|
||||
margin: 0;
|
||||
padding-top: $headerHeight;
|
||||
}
|
||||
|
||||
._content {
|
||||
position: static;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: .75rem 1rem 2.5rem;
|
||||
padding: .75rem 1rem 2rem;
|
||||
|
||||
&:before { content: none; }
|
||||
}
|
||||
|
||||
._booting:before, ._content-loading:before { font-size: 3rem; }
|
||||
|
||||
// Header
|
||||
|
||||
._header {
|
||||
._header, ._footer {
|
||||
position: fixed;
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
._header, ._list, ._footer {
|
||||
width: 100%;
|
||||
border-right: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
._settings { position: static; }
|
||||
._settings ._sidebar { padding-bottom: $headerHeight; }
|
||||
._settings-tabs { display: block; }
|
||||
|
||||
// Header
|
||||
|
||||
._header-btn { width: 2.5rem; }
|
||||
._header-btn[hidden] { display: block; }
|
||||
._menu-btn { border-right: 0; }
|
||||
|
||||
._search {
|
||||
padding-right: .125rem;
|
||||
|
@ -53,8 +65,6 @@
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
._header, ._list, ._sidebar-footer { width: 100%; }
|
||||
|
||||
._list-item {
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
|
@ -72,15 +82,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
._list-link { display: none; }
|
||||
|
||||
._sidebar-footer { box-shadow: none; }
|
||||
|
||||
._sidebar-footer-save {
|
||||
margin: 0;
|
||||
box-shadow: 0 1px $noteGreenBorder, 0 -1px $noteGreenBorder;
|
||||
}
|
||||
|
||||
// Notice
|
||||
|
||||
._notice {
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
@media #{$mediumScreen} { left: $sidebarMediumWidth; }
|
||||
|
||||
._sidebar-hidden & { left: $sidebarHiddenWidth; }
|
||||
._sidebar-hidden & { left: 0; }
|
||||
|
||||
~ ._container { padding-bottom: 2.5rem; }
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
@media #{$mediumScreen} { left: $sidebarMediumWidth; }
|
||||
|
||||
._sidebar-hidden & { left: $sidebarHiddenWidth; }
|
||||
._sidebar-hidden & { left: 0; }
|
||||
|
||||
~ ._container { padding-bottom: 2rem; }
|
||||
a:focus { outline: 0; }
|
||||
|
|
146
assets/stylesheets/components/_settings.scss
Normal file
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// Settings
|
||||
//
|
||||
|
||||
._settings {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: $headerZ;
|
||||
|
||||
&._in { display: block; }
|
||||
|
||||
._sidebar {
|
||||
bottom: $headerHeight;
|
||||
|
||||
._sidebar-hidden & { display: block; }
|
||||
}
|
||||
|
||||
._header {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
._settings-fieldset {
|
||||
display: flex;
|
||||
margin: 1.5rem 0;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
._settings-legend {
|
||||
flex: 0 1 10rem;
|
||||
margin: 0;
|
||||
padding-right: .5rem;
|
||||
line-height: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: $boldFontWeight;
|
||||
text-align: right;
|
||||
@extend %border-box;
|
||||
}
|
||||
|
||||
._settings-inputs {
|
||||
flex: 1 1 20rem;
|
||||
}
|
||||
|
||||
._settings-label {
|
||||
margin: 0 0 .375rem;
|
||||
|
||||
> small {
|
||||
display: block;
|
||||
color: $textColorLight;
|
||||
margin-left: 1.75rem;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin: .25rem .375rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $maxWidth) {
|
||||
._settings-max-width { display: none; }
|
||||
}
|
||||
|
||||
._settings-link {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-left: .375rem;
|
||||
|
||||
&[data-behavior=reset] {
|
||||
font-size: .75rem;
|
||||
color: $textColorRed;
|
||||
}
|
||||
}
|
||||
|
||||
._footer {
|
||||
position: absolute;
|
||||
z-index: $headerZ;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: $sidebarWidth;
|
||||
height: $headerHeight;
|
||||
background: $noteGreenBackground;
|
||||
border-top: 1px solid $noteGreenBorder;
|
||||
border-right: 1px solid $noteGreenBorder;
|
||||
@extend %border-box;
|
||||
@extend %user-select-none;
|
||||
|
||||
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
|
||||
}
|
||||
|
||||
._settings-btn {
|
||||
display: block;
|
||||
height: 100%;
|
||||
line-height: 1.5rem;
|
||||
padding: 0 .75rem;
|
||||
font-size: .875rem;
|
||||
font-weight: $boldFontWeight;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
@extend %border-box;
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin-right: .125rem;
|
||||
fill: currentColor;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
._save-btn { width: 100%; }
|
||||
|
||||
//
|
||||
// Header tabs
|
||||
//
|
||||
|
||||
._settings-tabs {
|
||||
display: none; // mobile only
|
||||
margin-right: .5rem;
|
||||
line-height: $headerHeight;
|
||||
}
|
||||
|
||||
._settings-tab {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
padding: 0 .75rem;
|
||||
cursor: pointer;
|
||||
|
||||
&, &:hover {
|
||||
color: $textColorLight;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $textColor;
|
||||
font-weight: $boldFontWeight;
|
||||
text-decoration: none;
|
||||
box-shadow: inset 0 -2px $linkColor;
|
||||
}
|
||||
}
|
|
@ -8,13 +8,13 @@
|
|||
top: $headerHeight;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin-top: 1px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
background: $sidebarBackground;
|
||||
background-clip: content-box;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-ms-overflow-style: none; // IE 10 doesn't support pointer-events
|
||||
@extend %border-box;
|
||||
@extend %user-select-none;
|
||||
|
||||
&::-webkit-scrollbar { -webkit-appearance: none; width: 10px; }
|
||||
|
@ -48,26 +48,7 @@
|
|||
width: 3px;
|
||||
cursor: col-resize;
|
||||
|
||||
._sidebar-hidden & {
|
||||
left: 0;
|
||||
margin-left: 0;
|
||||
background: $headerBackground;
|
||||
border-right: 1px solid $headerBorder;
|
||||
width: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 3px;
|
||||
margin-top: -.5rem;
|
||||
width: 1px;
|
||||
height: 1rem;
|
||||
border-left: 1px solid $textColorLighter;
|
||||
border-right: 1px solid $textColorLighter;
|
||||
}
|
||||
}
|
||||
._sidebar-hidden & { display: none; }
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -84,10 +65,7 @@
|
|||
|
||||
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
|
||||
|
||||
._sidebar > & {
|
||||
min-height: 100%;
|
||||
padding-bottom: 3.5rem;
|
||||
}
|
||||
._sidebar > & { min-height: 100%; }
|
||||
|
||||
a:focus { outline: 0; }
|
||||
}
|
||||
|
@ -342,7 +320,7 @@
|
|||
._list-picker {
|
||||
> ._list, > ._list-item {
|
||||
opacity: 0;
|
||||
transition: .2s;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
&._in { > ._list, > ._list-item { opacity: 1; } }
|
||||
|
||||
|
@ -354,14 +332,11 @@
|
|||
position: absolute;
|
||||
top: .5rem;
|
||||
right: .75rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: .2s;
|
||||
}
|
||||
|
||||
._list-link {
|
||||
display: block;
|
||||
margin-top: .75rem;
|
||||
padding: .75rem 0;
|
||||
font-size: .8125rem;
|
||||
text-align: center;
|
||||
@extend %external-link;
|
||||
|
@ -369,135 +344,3 @@
|
|||
&:after { visibility: hidden; }
|
||||
&:hover:after { visibility: visible; }
|
||||
}
|
||||
|
||||
//
|
||||
// Footer
|
||||
//
|
||||
|
||||
._sidebar-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: $sidebarWidth;
|
||||
background: $sidebarBackground;
|
||||
box-shadow: inset -1px 0 $sidebarBorder;
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
|
||||
@media #{$mediumScreen} { width: $sidebarMediumWidth; }
|
||||
|
||||
._max-width & {
|
||||
left: calc(50% - #{$maxWidth} / 2);
|
||||
@media (max-width: #{$maxWidth}) { left: 0; }
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
right: 1px;
|
||||
height: 1em;
|
||||
background-image: -webkit-linear-gradient(top, rgba($sidebarBackground, 0), rgba($sidebarBackground, .95));
|
||||
background-image: linear-gradient(to bottom, rgba($sidebarBackground, 0), rgba($sidebarBackground, .95));
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
._sidebar-footer-link {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
height: 2.5rem;
|
||||
line-height: 1rem;
|
||||
padding: .75rem .25rem .75rem .75rem;
|
||||
font-size: .875em;
|
||||
cursor: pointer;
|
||||
@extend %border-box;
|
||||
|
||||
&, &:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:before {
|
||||
float: left;
|
||||
margin-right: .625rem;
|
||||
@extend %icon;
|
||||
}
|
||||
}
|
||||
|
||||
._sidebar-footer-edit {
|
||||
display: inline-block;
|
||||
|
||||
@if $style == 'dark' {
|
||||
&:before { @extend %icon-settings-white; }
|
||||
} @else {
|
||||
&:before { @extend %icon-settings; }
|
||||
}
|
||||
}
|
||||
|
||||
._sidebar-footer-light {
|
||||
float: right;
|
||||
width: 2rem;
|
||||
padding: 0;
|
||||
opacity: .65;
|
||||
@extend %hide-text;
|
||||
|
||||
&:before {
|
||||
float: none;
|
||||
position: absolute;
|
||||
top: .75rem;
|
||||
left: .25rem;
|
||||
|
||||
@if $style == 'dark' {
|
||||
@extend %icon-light-white;
|
||||
} @else {
|
||||
@extend %icon-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
._sidebar-footer-layout {
|
||||
float: right;
|
||||
width: 2rem;
|
||||
padding: 0;
|
||||
opacity: .65;
|
||||
@extend %hide-text;
|
||||
|
||||
&:before {
|
||||
float: none;
|
||||
position: absolute;
|
||||
top: .75rem;
|
||||
left: .375rem;
|
||||
@if $style == 'dark' {
|
||||
@extend %icon-expand-white;
|
||||
} @else {
|
||||
@extend %icon-expand;
|
||||
}
|
||||
|
||||
._max-width & {
|
||||
@if $style == 'dark' {
|
||||
@extend %icon-contract-white;
|
||||
} @else {
|
||||
@extend %icon-contract;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$maxWidth + .1rem}) { display: none; }
|
||||
}
|
||||
|
||||
._sidebar-footer-save {
|
||||
margin-right: 1px;
|
||||
font-weight: $boldFontWeight;
|
||||
background: $noteGreenBackground;
|
||||
box-shadow: inset 0 1px $noteGreenBorder,
|
||||
1px 0 $noteGreenBorder;
|
||||
|
||||
@if $style == 'dark' {
|
||||
&:before { @extend %icon-check-white; }
|
||||
} @else {
|
||||
&:before { @extend %icon-check; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,11 @@ section, main {
|
|||
outline: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
@extend %user-select-none;
|
||||
}
|
||||
|
||||
input, button {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
|
@ -175,6 +180,12 @@ input, button {
|
|||
@extend %border-box;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0;
|
||||
background: none;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
width: 1rem;
|
||||
height: 1rem;
|
||||
background-image: image-url('icons.png');
|
||||
background-size: 4rem 6rem;
|
||||
background-size: 4rem 3rem;
|
||||
}
|
||||
|
||||
@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
|
||||
|
@ -35,23 +35,13 @@
|
|||
%icon-search { background-position: -1rem 0; }
|
||||
%icon-link { background-position: -2.25rem -.25rem; }
|
||||
%icon-clear { background-position: -3rem 0; }
|
||||
%icon-settings { background-position: 0 -1rem; }
|
||||
%icon-check { background-position: -1rem -1rem; }
|
||||
%icon-path { background-position: 0 -2rem; }
|
||||
%icon-search-white { background-position: -1rem -2rem; }
|
||||
%icon-dir-white { background-position: -2rem -2rem; }
|
||||
%icon-link-white { background-position: -3.25rem -2.25rem; }
|
||||
%icon-settings-white { background-position: 0 -3rem; }
|
||||
%icon-check-white { background-position: -1rem -3rem; }
|
||||
%icon-light { background-position: -2rem -3rem; }
|
||||
%icon-light-white { background-position: -3rem -3rem; }
|
||||
%icon-expand { background-position: 0 -4rem; }
|
||||
%icon-contract { background-position: -1rem -4rem; }
|
||||
%icon-expand-white { background-position: -2rem -4rem; }
|
||||
%icon-contract-white { background-position: -3rem -4rem; }
|
||||
%icon-clipboard { background-position: 0 -5rem; }
|
||||
%icon-clipboard-white { background-position: -1rem -5rem; }
|
||||
%icon-close-white { background-position: -2rem -5rem; }
|
||||
%icon-path { background-position: 0 -1rem; }
|
||||
%icon-search-white { background-position: -1rem -1rem; }
|
||||
%icon-dir-white { background-position: -2rem -1rem; }
|
||||
%icon-link-white { background-position: -3.25rem -1.25rem; }
|
||||
%icon-clipboard { background-position: 0 -2rem; }
|
||||
%icon-clipboard-white { background-position: -1rem -2rem; }
|
||||
%icon-close-white { background-position: -2rem -2rem; }
|
||||
|
||||
._icon-codeceptjs:before { background-position: -3rem 0; }
|
||||
._icon-codeception:before { background-position: -4rem 0; }
|
||||
|
|
|
@ -9,7 +9,6 @@ $maxWidth: 80rem;
|
|||
$headerHeight: 3rem;
|
||||
$sidebarWidth: 20rem;
|
||||
$sidebarMediumWidth: 16rem;
|
||||
$sidebarHiddenWidth: 9px;
|
||||
|
||||
$contentBackground: #33373a;
|
||||
$documentBackground: $contentBackground;
|
||||
|
@ -17,6 +16,7 @@ $documentBackground: $contentBackground;
|
|||
$textColor: #cbd0d0;
|
||||
$textColorLight: #9da5ad;
|
||||
$textColorLighter: #77787a;
|
||||
$textColorRed: #f44336;
|
||||
|
||||
$inputFocusBorder: false;
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ $maxWidth: 80rem;
|
|||
$headerHeight: 3rem;
|
||||
$sidebarWidth: 20rem;
|
||||
$sidebarMediumWidth: 16rem;
|
||||
$sidebarHiddenWidth: 9px;
|
||||
|
||||
$contentBackground: #fff;
|
||||
$documentBackground: #fafafa;
|
||||
|
@ -17,6 +16,7 @@ $documentBackground: #fafafa;
|
|||
$textColor: #333;
|
||||
$textColorLight: #666;
|
||||
$textColorLighter: #888;
|
||||
$textColorRed: #f44336;
|
||||
|
||||
$inputFocusBorder: #35b5f4;
|
||||
|
||||
|
|
|
@ -235,7 +235,7 @@ class App < Sinatra::Application
|
|||
erb :index
|
||||
end
|
||||
|
||||
%w(offline about news help).each do |page|
|
||||
%w(settings offline about news help).each do |page|
|
||||
get "/#{page}" do
|
||||
if supports_js_redirection?
|
||||
redirect_via_js "/#{page}"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
http://happytodesign.com/hicons/
|
Before Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 158 B |
|
@ -1 +0,0 @@
|
|||
http://happytodesign.com/hicons/
|
Before Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 390 B |
|
@ -1 +0,0 @@
|
|||
http://www.entypo.com/
|
Before Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 522 B |
|
@ -1 +0,0 @@
|
|||
http://www.entypo.com/
|
Before Width: | Height: | Size: 244 B |
Before Width: | Height: | Size: 495 B |
|
@ -1 +0,0 @@
|
|||
http://gemicon.net/
|
Before Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 399 B |
|
@ -1 +0,0 @@
|
|||
http://gemicon.net/
|
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
|
@ -1,2 +1,2 @@
|
|||
User-agent: *
|
||||
Allow: /
|
||||
Disallow: /settings
|
|
@ -1,7 +1,7 @@
|
|||
<div class="_app<%= " #{app_layout}" if app_layout %>" role="application">
|
||||
<header class="_header" role="banner">
|
||||
<button type="button" aria-label="Toggle navigation" class="_header-btn" data-toggle-sidebar hidden>
|
||||
<svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg>
|
||||
<svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /></svg>
|
||||
</button>
|
||||
<form class="_search" role="search">
|
||||
<input type="search" name="q" class="_search-input" placeholder="Search…" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" maxlength="30" aria-label="Search">
|
||||
|
@ -9,17 +9,18 @@
|
|||
<div class="_search-tag"></div>
|
||||
</form>
|
||||
<button type="button" aria-label="Back" class="_header-btn" data-back hidden>
|
||||
<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>
|
||||
<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>
|
||||
</button>
|
||||
<button type="button" aria-label="Forward" class="_header-btn _forward-btn" data-forward hidden>
|
||||
<svg viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></svg>
|
||||
<svg viewBox="0 0 24 24"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" /></svg>
|
||||
</button>
|
||||
<button type="button" aria-label="Toggle menu" title="Toggle menu" class="_header-btn _menu-btn" data-toggle-menu>
|
||||
<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>
|
||||
<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" /></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="/settings" class="_menu-link">Preferences</a>
|
||||
<a href="/offline" class="_menu-link">Offline Data</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>
|
||||
|
@ -37,10 +38,27 @@
|
|||
<div class="_container" role="document">
|
||||
<main class="_content _content-loading" role="main"></main>
|
||||
</div>
|
||||
<form class="_settings" id="settings">
|
||||
<div class="_header">
|
||||
<button type="button" aria-label="Back" class="_settings-btn" data-back>
|
||||
<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> Back
|
||||
</button>
|
||||
<nav class="_settings-tabs">
|
||||
<a class="_settings-tab active" data-tab="doc-picker" hidden>Docs</a>
|
||||
<a class="_settings-tab" data-tab="settings" hidden>Settings</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="_sidebar"></div>
|
||||
<div class="_footer">
|
||||
<button type="submit" class="_settings-btn _save-btn">
|
||||
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" /></svg> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<style data-size="<%= app_size %>" data-resizer>
|
||||
._container { margin-left: <%= app_size %>; }
|
||||
._header, ._list, ._sidebar-footer { width: <%= app_size %>; }
|
||||
._header, ._list, ._footer { width: <%= app_size %>; }
|
||||
._list-hover.clone { min-width: <%= app_size %>; }
|
||||
._notice, ._path, ._resizer { left: <%= app_size %>; }
|
||||
</style>
|
||||
|
|