diff --git a/assets/images/icons.png b/assets/images/icons.png index 2364ed92..527b5394 100644 Binary files a/assets/images/icons.png and b/assets/images/icons.png differ diff --git a/assets/images/icons@2x.png b/assets/images/icons@2x.png index 2847dbd1..c76958fd 100644 Binary files a/assets/images/icons@2x.png and b/assets/images/icons@2x.png differ diff --git a/assets/javascripts/app/settings.coffee b/assets/javascripts/app/settings.coffee index 015a3b5d..b33ef857 100644 --- a/assets/javascripts/app/settings.coffee +++ b/assets/javascripts/app/settings.coffee @@ -1,6 +1,7 @@ class app.Settings SETTINGS_KEY = 'settings' DOCS_KEY = 'docs' + DARK_KEY = 'dark' @defaults: -> count: 0 @@ -45,13 +46,21 @@ class app.Settings setDocs: (docs) -> try - Cookies.set DOCS_KEY, docs.join('/'), - path: '/' - expires: 1e8 + Cookies.set DOCS_KEY, docs.join('/'), path: '/', expires: 1e8 + catch + return + + setDark: (value) -> + try + if value + Cookies.set DARK_KEY, '1', path: '/', expires: 1e8 + else + Cookies.expire DARK_KEY catch return reset: -> try Cookies.expire DOCS_KEY + try Cookies.expire DARK_KEY try @store.del(SETTINGS_KEY) return diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json index e0557456..493be49d 100644 --- a/assets/javascripts/news.json +++ b/assets/javascripts/news.json @@ -1,5 +1,8 @@ [ - [ "2015-01-13", + [ "2015-02-08", + "New dark theme\nClick the icon in the bottom left corner to activate.\nFeedback welcome :)" + ], [ + "2015-01-13", "Offline mode has landed!\nIf you notice any bugs, please report them on GitHub." ], [ "2014-12-21", diff --git a/assets/javascripts/templates/sidebar_tmpl.coffee b/assets/javascripts/templates/sidebar_tmpl.coffee index 3fb0c805..119b17f7 100644 --- a/assets/javascripts/templates/sidebar_tmpl.coffee +++ b/assets/javascripts/templates/sidebar_tmpl.coffee @@ -51,7 +51,10 @@ templates.sidebarPickerNote = """ sidebarFooter = (html) -> """""" templates.sidebarSettings = -> - sidebarFooter """Select documentation""" + sidebarFooter """ + + Select documentation + """ templates.sidebarSave = -> sidebarFooter """Save""" diff --git a/assets/javascripts/views/layout/document.coffee b/assets/javascripts/views/layout/document.coffee index 7dc0c21a..f128fbc6 100644 --- a/assets/javascripts/views/layout/document.coffee +++ b/assets/javascripts/views/layout/document.coffee @@ -17,6 +17,14 @@ class app.views.Document extends app.View @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) + return + setTitle: (title) -> @el.title = if title then "DevDocs/#{title}" else 'DevDocs' diff --git a/assets/javascripts/views/sidebar/sidebar.coffee b/assets/javascripts/views/sidebar/sidebar.coffee index 14ab6522..4cd10a1d 100644 --- a/assets/javascripts/views/sidebar/sidebar.coffee +++ b/assets/javascripts/views/sidebar/sidebar.coffee @@ -79,6 +79,9 @@ class app.views.Sidebar extends app.View if event.target.hasAttribute? 'data-reset-list' $.stopEvent(event) @reset() + else if event.target.hasAttribute? 'data-light' + $.stopEvent(event) + app.document.toggleLight() return onGlobalClick: (event) => diff --git a/assets/stylesheets/application-dark.css.scss b/assets/stylesheets/application-dark.css.scss new file mode 100644 index 00000000..a8a4d877 --- /dev/null +++ b/assets/stylesheets/application-dark.css.scss @@ -0,0 +1,72 @@ +//= depend_on icons.png +//= depend_on icons@2x.png + +//= require vendor/open-sans + +/*! + * Copyright 2013-2015 Thibaut Courouble and other contributors + * + * This source code is licensed under the terms of the Mozilla + * Public License, v. 2.0, a copy of which may be obtained at: + * http://mozilla.org/MPL/2.0/ + */ + +@import 'global/variables-dark', + 'global/icons', + 'global/classes', + 'global/base'; + +@import 'components/app', + 'components/header', + 'components/notif', + 'components/sidebar', + 'components/content', + 'components/page', + 'components/fail', + 'components/notice', + 'components/path', + 'components/prism', + 'components/mobile'; + +@import 'pages/angular', + 'pages/bower', + 'pages/c', + 'pages/chai', + 'pages/coffeescript', + 'pages/cordova', + 'pages/d3', + 'pages/ember', + 'pages/express', + 'pages/go', + 'pages/haskell', + 'pages/jquery', + 'pages/knockout', + 'pages/git', + 'pages/grunt', + 'pages/laravel', + 'pages/less', + 'pages/lodash', + 'pages/marionette', + 'pages/markdown', + 'pages/maxcdn', + 'pages/mdn', + 'pages/modernizr', + 'pages/moment', + 'pages/mongoose', + 'pages/nginx', + 'pages/node', + 'pages/php', + 'pages/phpunit', + 'pages/postgres', + 'pages/rdoc', + 'pages/react', + 'pages/redis', + 'pages/requirejs', + 'pages/rethinkdb', + 'pages/rfc', + 'pages/sinon', + 'pages/socketio', + 'pages/sphinx', + 'pages/underscore', + 'pages/yard', + 'pages/yii'; diff --git a/assets/stylesheets/components/_content.scss b/assets/stylesheets/components/_content.scss index 16c4f3f1..fc11154a 100644 --- a/assets/stylesheets/components/_content.scss +++ b/assets/stylesheets/components/_content.scss @@ -425,6 +425,11 @@ ._splash-sponsor > ._maxcdn-logo { background-image: image-url('maxcdn-bw.png'); + @if $style == 'dark' { + filter: invert(100%); + -webkit-filter: invert(100%); + } + @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { background-image: image-url('maxcdn-bw@2x.png'); } @@ -443,6 +448,11 @@ ._splash-sponsor > ._shopify-logo { background-image: image-url('shopify-bw.png'); + @if $style == 'dark' { + filter: invert(100%); + -webkit-filter: invert(100%); + } + @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { background-image: image-url('shopify-bw@2x.png'); } diff --git a/assets/stylesheets/components/_header.scss b/assets/stylesheets/components/_header.scss index 39db0b4f..4c96aae6 100644 --- a/assets/stylesheets/components/_header.scss +++ b/assets/stylesheets/components/_header.scss @@ -98,7 +98,11 @@ top: 1rem; left: 1rem; opacity: .4; - @extend %icon, %icon-search; + @if $style == 'dark' { + @extend %icon, %icon-search-white; + } @else { + @extend %icon, %icon-search; + } } } @@ -132,7 +136,11 @@ opacity: .3; &:hover { opacity: .5; } - &:before { @extend %icon, %icon-clear; } + @if $style == 'dark' { + &:before { @extend %icon, %icon-close-white; } + } @else { + &:before { @extend %icon, %icon-clear; } + } ._search-active > & { display: block; } } diff --git a/assets/stylesheets/components/_prism.scss b/assets/stylesheets/components/_prism.scss index 43d6020d..2d18d4ed 100644 --- a/assets/stylesheets/components/_prism.scss +++ b/assets/stylesheets/components/_prism.scss @@ -17,7 +17,11 @@ .token.constant, .token.symbol, .token.deleted { - color: #905; + @if $style == 'dark' { + color: #cf6a4c; + } @else { + color: #905; + } } .token.selector, @@ -26,7 +30,11 @@ .token.char, .token.builtin, .token.inserted { - color: #5e8e01; + @if $style == 'dark' { + color: #d0c584; + } @else { + color: #5e8e01; + } } .token.operator, @@ -34,23 +42,39 @@ .token.url, .language-css .token.string, .style .token.string { - color: #a67f59; + @if $style == 'dark' { + color: #8f9d6a; + } @else { + color: #a67f59; + } } .token.atrule, .token.attr-value, .token.keyword { - color: #0070a3; + @if $style == 'dark' { + color: #7587a6; + } @else { + color: #0070a3; + } } .token.function { - color: #dd4a68; + @if $style == 'dark' { + color: #ac885b; + } @else { + color: #dd4a68; + } } .token.regex, .token.important, .token.variable { - color: #e90; + @if $style == 'dark' { + color: #e9c062; + } @else { + color: #e90; + } } .token.important { diff --git a/assets/stylesheets/components/_sidebar.scss b/assets/stylesheets/components/_sidebar.scss index 9a6d72c8..2e417f98 100644 --- a/assets/stylesheets/components/_sidebar.scss +++ b/assets/stylesheets/components/_sidebar.scss @@ -162,7 +162,11 @@ &:hover { opacity: .65; } &:before { - @extend %icon, %icon-dir; + @if $style == 'dark' { + @extend %icon, %icon-dir-white; + } @else { + @extend %icon, %icon-dir; + } .open > &, .open-title > & { -webkit-transform: rotate(90deg); @@ -340,6 +344,7 @@ ._sidebar-footer-link { position: relative; display: block; + overflow: hidden; height: 2.5rem; line-height: 1rem; padding: .75rem; @@ -360,7 +365,31 @@ } ._sidebar-footer-edit { - &:before { @extend %icon-settings; } + @if $style == 'dark' { + &:before { @extend %icon-settings-white; } + } @else { + &:before { @extend %icon-settings; } + } +} + +._sidebar-footer-light { + float: right; + width: 2.5rem; + padding: 0; + opacity: .6; + + &:before { + float: none; + position: absolute; + top: .75rem; + left: .75rem; + + @if $style == 'dark' { + @extend %icon-light-white; + } @else { + @extend %icon-light; + } + } } ._sidebar-footer-save { @@ -370,5 +399,9 @@ box-shadow: inset 0 1px $noteGreenBorder, 1px 0 $noteGreenBorder; - &:before { @extend %icon-check; } + @if $style == 'dark' { + &:before { @extend %icon-check-white; } + } @else { + &:before { @extend %icon-check; } + } } diff --git a/assets/stylesheets/global/_classes.scss b/assets/stylesheets/global/_classes.scss index 7e6bff78..33d209f4 100644 --- a/assets/stylesheets/global/_classes.scss +++ b/assets/stylesheets/global/_classes.scss @@ -101,7 +101,11 @@ height: .4375rem; margin: .125rem 0 0 .0625rem; vertical-align: top; - @extend %icon, %icon-link; + @if $style == 'dark' { + @extend %icon, %icon-link-white; + } @else { + @extend %icon, %icon-link; + } } } diff --git a/assets/stylesheets/global/_icons.scss b/assets/stylesheets/global/_icons.scss index d3a28521..f5471821 100644 --- a/assets/stylesheets/global/_icons.scss +++ b/assets/stylesheets/global/_icons.scss @@ -4,7 +4,7 @@ width: 1rem; height: 1rem; background-image: image-url('icons.png'); - background-size: 5rem 13rem; + background-size: 5rem 15rem; } @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { @@ -77,3 +77,10 @@ ._icon-socketio:before { background-position: -2rem -12rem; } ._icon-modernizr:before { background-position: -3rem -12rem; } ._icon-bower:before { background-position: -4rem -12rem; } +%icon-search-white { background-position: 0 -13rem; } +%icon-dir-white { background-position: -1rem -13rem; } +%icon-link-white { background-position: -2.25rem -13.25rem; } +%icon-settings-white { background-position: -3rem -13rem; } +%icon-check-white { background-position: -4rem -13rem; } +%icon-light { background-position: 0 -14rem; } +%icon-light-white { background-position: -1rem -14rem; } diff --git a/assets/stylesheets/global/_variables.scss b/assets/stylesheets/global/_variables.scss index a2fc51b3..eff01fd9 100644 --- a/assets/stylesheets/global/_variables.scss +++ b/assets/stylesheets/global/_variables.scss @@ -1,6 +1,8 @@ $baseFont: 'Open Sans', Helvetica, Arial, sans-serif; $monoFont: 'Source Code Pro', 'Inconsolata-g', Consolas, Menlo, monospace; +$style: 'light'; + $headerHeight: 3rem; $sidebarWidth: 18rem; $sidebarMediumWidth: 16rem; diff --git a/assets/stylesheets/global/variables-dark.scss b/assets/stylesheets/global/variables-dark.scss new file mode 100644 index 00000000..41ef7b69 --- /dev/null +++ b/assets/stylesheets/global/variables-dark.scss @@ -0,0 +1,82 @@ +$baseFont: 'Open Sans', Helvetica, Arial, sans-serif; +$monoFont: 'Source Code Pro', 'Inconsolata-g', Consolas, Menlo, monospace; + +$style: 'dark'; + +$headerHeight: 3rem; +$sidebarWidth: 18rem; +$sidebarMediumWidth: 16rem; + +$contentBackground: #2d2d2d; + +$textColor: #b4b3af; +$textColorLight: #7e7d7d; +$textColorLighter: #6a6868; + +$inputFocusBorder: #444; + +$focusBackground: #3d3d3e; +$focusBorder: #3d3d3e; +$focusText: #f7f2f2; + +$loadingText: #616161; +$splashText: #616161; +$promoText: #616161; + +$selectionBackground: #346fce; +$selectionBorder: #346fce; +$selectionText: #fff; + +$highlightBackground: #3d4449; + +$linkColor: #f7f2f2; +$linkColorHover: #fff; + +$headerBackground: #1e1e1e; +$headerBorder: #1e1e1e; + +$sidebarBackground: #262626; +$sidebarBorder: #262626; + +$scrollbarColor: #515151; +$scrollbarColorHover: #888; + +$pathBackground: $headerBackground; +$pathBorder: $headerBorder; + +$noticeBackground: #1e1e1e; +$noticeBorder: #1e1e1e; + +$boxBackground: #1e1e1e; +$boxBorder: #0a0a0a; +$boxBorderLight: #171717; +$boxHeaderBackground: #1e1e1e; + +$noteBackground: #3a3e31; +$noteBorder: #1a1c17; + +$noteGreenBackground: #283e2b; +$noteGreenBorder: #111b13; + +$noteBlueBackground: #1f2f3e; +$noteBlueBorder: #101922; + +$noteOrangeBackground: #3e271d; +$noteOrangeBorder: #1f1511; + +$noteRedBackground: #3e1b1b; +$noteRedBorder: #1b0a0a; + +$labelBackground: #38383a; + +$notifBackground: rgba(#000, .85); +$notifColor: #fff; +$notifColorLight: #bbb; + +$mediumScreen: '(max-width: 800px)'; + +$contentZ: 1; +$sidebarZ: 2; +$headerZ: 3; +$noticeZ: 4; +$hoverZ: 5; diff --git a/lib/app.rb b/lib/app.rb index 25bdf23e..59f1ec81 100644 --- a/lib/app.rb +++ b/lib/app.rb @@ -17,7 +17,7 @@ class App < Sinatra::Application set :assets_prefix, 'assets' set :assets_path, -> { File.join(public_folder, assets_prefix) } set :assets_manifest_path, -> { File.join(assets_path, 'manifest.json') } - set :assets_compile, %w(*.png docs.js application.js application.css) + set :assets_compile, %w(*.png docs.js application.js application.css application-dark.css) require 'yajl/json_gem' set :docs_prefix, 'docs' @@ -117,6 +117,21 @@ class App < Sinatra::Application def query_string_for_redirection request.query_string.empty? ? nil : "?#{request.query_string}" end + + def main_stylesheet_path + stylesheet_paths[cookies[:dark].present? ? :dark : :default] + end + + def alternate_stylesheet_path + stylesheet_paths[cookies[:dark].present? ? :default : :dark] + end + + def stylesheet_paths + @stylesheet_paths ||= { + default: stylesheet_path('application'), + dark: stylesheet_path('application-dark') + } + end end before do diff --git a/public/icons/ui/check-white/SOURCE b/public/icons/ui/check-white/SOURCE new file mode 100644 index 00000000..766f1fbe --- /dev/null +++ b/public/icons/ui/check-white/SOURCE @@ -0,0 +1 @@ +http://happytodesign.com/hicons/ diff --git a/public/icons/ui/check-white/check-white.png b/public/icons/ui/check-white/check-white.png new file mode 100644 index 00000000..a9f4e476 Binary files /dev/null and b/public/icons/ui/check-white/check-white.png differ diff --git a/public/icons/ui/check-white/check-white@2x.png b/public/icons/ui/check-white/check-white@2x.png new file mode 100644 index 00000000..e6fcff05 Binary files /dev/null and b/public/icons/ui/check-white/check-white@2x.png differ diff --git a/public/icons/ui/dir-white/SOURCE b/public/icons/ui/dir-white/SOURCE new file mode 100644 index 00000000..fa3cf541 --- /dev/null +++ b/public/icons/ui/dir-white/SOURCE @@ -0,0 +1 @@ +http://gemicon.net/ diff --git a/public/icons/ui/dir-white/dir-white.png b/public/icons/ui/dir-white/dir-white.png new file mode 100644 index 00000000..0da24520 Binary files /dev/null and b/public/icons/ui/dir-white/dir-white.png differ diff --git a/public/icons/ui/dir-white/dir-white@2x.png b/public/icons/ui/dir-white/dir-white@2x.png new file mode 100644 index 00000000..7486a520 Binary files /dev/null and b/public/icons/ui/dir-white/dir-white@2x.png differ diff --git a/public/icons/ui/light-white/SOURCE b/public/icons/ui/light-white/SOURCE new file mode 100644 index 00000000..ffa79609 --- /dev/null +++ b/public/icons/ui/light-white/SOURCE @@ -0,0 +1 @@ +http://www.entypo.com/ diff --git a/public/icons/ui/light-white/light.png b/public/icons/ui/light-white/light.png new file mode 100644 index 00000000..cacc3f9d Binary files /dev/null and b/public/icons/ui/light-white/light.png differ diff --git a/public/icons/ui/light-white/light@2x.png b/public/icons/ui/light-white/light@2x.png new file mode 100644 index 00000000..39e76205 Binary files /dev/null and b/public/icons/ui/light-white/light@2x.png differ diff --git a/public/icons/ui/light/SOURCE b/public/icons/ui/light/SOURCE new file mode 100644 index 00000000..ffa79609 --- /dev/null +++ b/public/icons/ui/light/SOURCE @@ -0,0 +1 @@ +http://www.entypo.com/ diff --git a/public/icons/ui/light/light.png b/public/icons/ui/light/light.png new file mode 100644 index 00000000..4e76ed5f Binary files /dev/null and b/public/icons/ui/light/light.png differ diff --git a/public/icons/ui/light/light@2x.png b/public/icons/ui/light/light@2x.png new file mode 100644 index 00000000..73594f24 Binary files /dev/null and b/public/icons/ui/light/light@2x.png differ diff --git a/public/icons/ui/link-white/SOURCE b/public/icons/ui/link-white/SOURCE new file mode 100644 index 00000000..ffa79609 --- /dev/null +++ b/public/icons/ui/link-white/SOURCE @@ -0,0 +1 @@ +http://www.entypo.com/ diff --git a/public/icons/ui/link-white/link-white.png b/public/icons/ui/link-white/link-white.png new file mode 100644 index 00000000..a26fd062 Binary files /dev/null and b/public/icons/ui/link-white/link-white.png differ diff --git a/public/icons/ui/link-white/link-white@2x.png b/public/icons/ui/link-white/link-white@2x.png new file mode 100644 index 00000000..97bd1ce5 Binary files /dev/null and b/public/icons/ui/link-white/link-white@2x.png differ diff --git a/public/icons/ui/search-white/SOURCE b/public/icons/ui/search-white/SOURCE new file mode 100644 index 00000000..ffa79609 --- /dev/null +++ b/public/icons/ui/search-white/SOURCE @@ -0,0 +1 @@ +http://www.entypo.com/ diff --git a/public/icons/ui/search-white/search-white.png b/public/icons/ui/search-white/search-white.png new file mode 100644 index 00000000..758df5a6 Binary files /dev/null and b/public/icons/ui/search-white/search-white.png differ diff --git a/public/icons/ui/search-white/search-white@2x.png b/public/icons/ui/search-white/search-white@2x.png new file mode 100644 index 00000000..e8d4f9fb Binary files /dev/null and b/public/icons/ui/search-white/search-white@2x.png differ diff --git a/public/icons/ui/settings-white/SOURCE b/public/icons/ui/settings-white/SOURCE new file mode 100644 index 00000000..fa3cf541 --- /dev/null +++ b/public/icons/ui/settings-white/SOURCE @@ -0,0 +1 @@ +http://gemicon.net/ diff --git a/public/icons/ui/settings-white/settings-white.png b/public/icons/ui/settings-white/settings-white.png new file mode 100755 index 00000000..49c53a40 Binary files /dev/null and b/public/icons/ui/settings-white/settings-white.png differ diff --git a/public/icons/ui/settings-white/settings-white@2x.png b/public/icons/ui/settings-white/settings-white@2x.png new file mode 100755 index 00000000..adfda16b Binary files /dev/null and b/public/icons/ui/settings-white/settings-white@2x.png differ diff --git a/views/index.erb b/views/index.erb index b9e53a39..ce6b892c 100644 --- a/views/index.erb +++ b/views/index.erb @@ -26,7 +26,7 @@ - <%= stylesheet_tag 'application' %> + <%= javascript_tag 'application', asset_host: false %> <%= javascript_tag 'docs' %><% unless App.production? %> <%= javascript_tag 'debug' %><% end %> diff --git a/views/manifest.erb b/views/manifest.erb index c8b474d4..b107bcb9 100644 --- a/views/manifest.erb +++ b/views/manifest.erb @@ -4,6 +4,7 @@ CACHE: / <%= javascript_path 'application', asset_host: false %> <%= stylesheet_path 'application' %> +<%= stylesheet_path 'application-dark' %> <%= image_path 'icons.png' %> <%= image_path 'icons@2x.png' %> <%= image_path 'maxcdn.png' %> diff --git a/views/other.erb b/views/other.erb index 317abb9a..f76bf7b2 100644 --- a/views/other.erb +++ b/views/other.erb @@ -8,7 +8,7 @@ DevDocs<%= ": #{@doc['name']} API Documentation" if doc_index_page? %> - <%= stylesheet_tag 'application' %> + <%= javascript_tag 'application', asset_host: false %><% unless App.production? %> <%= javascript_tag 'debug' %><% end %>