Implement dark theme

Closes #73.
pull/165/head
Thibaut 10 years ago
parent 200dd0b43f
commit 649b7b5546

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 67 KiB

@ -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

@ -1,5 +1,8 @@
[
[ "2015-01-13",
[ "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\">Feedback</a> welcome :)"
], [
"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\">GitHub</a>."
], [
"2014-12-21",

@ -51,7 +51,10 @@ templates.sidebarPickerNote = """
sidebarFooter = (html) -> """<div class="_sidebar-footer">#{html}</div>"""
templates.sidebarSettings = ->
sidebarFooter """<a class="_sidebar-footer-link _sidebar-footer-edit" data-pick-docs>Select documentation</a>"""
sidebarFooter """
<a class="_sidebar-footer-link _sidebar-footer-light" title="Toggle light" data-light></a>
<a class="_sidebar-footer-link _sidebar-footer-edit" data-pick-docs>Select documentation</a>
"""
templates.sidebarSave = ->
sidebarFooter """<a class="_sidebar-footer-link _sidebar-footer-save">Save</a>"""

@ -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'

@ -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) =>

@ -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';

@ -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');
}

@ -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; }
}

@ -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 {

@ -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; }
}
}

@ -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;
}
}
}

@ -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; }

@ -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;

@ -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;

@ -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

@ -0,0 +1 @@
http://happytodesign.com/hicons/

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

@ -0,0 +1 @@
http://gemicon.net/

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

@ -26,7 +26,7 @@
<link rel="apple-touch-icon" sizes="144x144" href="http://maxcdn.devdocs.io/images/apple-icon-144.png">
<link rel="apple-touch-icon" sizes="152x152" href="http://maxcdn.devdocs.io/images/apple-icon-152.png">
<link rel="apple-touch-icon" sizes="160x160" href="http://maxcdn.devdocs.io/images/apple-icon-160.png">
<%= stylesheet_tag 'application' %>
<link rel="stylesheet" href="<%= main_stylesheet_path %>" data-alt="<%= alternate_stylesheet_path %>">
<%= javascript_tag 'application', asset_host: false %>
<%= javascript_tag 'docs' %><% unless App.production? %>
<%= javascript_tag 'debug' %><% end %>

@ -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' %>

@ -8,7 +8,7 @@
<title>DevDocs<%= ": #{@doc['name']} API Documentation" if doc_index_page? %></title>
<link rel="icon" type="image/x-icon" href="http://maxcdn.devdocs.io/favicon.ico">
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Search DevDocs">
<%= stylesheet_tag 'application' %>
<link rel="stylesheet" href="<%= main_stylesheet_path %>" data-alt="<%= alternate_stylesheet_path %>">
<%= javascript_tag 'application', asset_host: false %><% unless App.production? %>
<%= javascript_tag 'debug' %><% end %>
<script>app.DOC = <%= @doc.to_json %>;</script>

Loading…
Cancel
Save