History

Implement dark theme

Closes #73.

Thibaut committed 11 years ago

Commit 649b7b51 parent 200dd0b41 files · +296 −5Browse files

Unified · Split

41 files
  1. assets/images/icons.png +0 −0
  2. assets/images/icons@2x.png +0 −0
  3. assets/javascripts/app/settings.coffee +12 −3
  4. assets/javascripts/news.json +4 −1
  5. assets/javascripts/templates/sidebar_tmpl.coffee +4 −1
  6. assets/javascripts/views/layout/document.coffee +8 −0
  7. assets/javascripts/views/sidebar/sidebar.coffee +3 −0
  8. assets/stylesheets/application-dark.css.scss +72 −0
  9. assets/stylesheets/components/_content.scss +10 −0
  10. assets/stylesheets/components/_header.scss +10 −2
  11. assets/stylesheets/components/_prism.scss +30 −6
  12. assets/stylesheets/components/_sidebar.scss +36 −3
  13. assets/stylesheets/global/_classes.scss +5 −1
  14. assets/stylesheets/global/_icons.scss +8 −1
  15. assets/stylesheets/global/_variables.scss +2 −0
  16. assets/stylesheets/global/variables-dark.scss +82 −0
  17. lib/app.rb +16 −1
  18. public/icons/ui/check-white/SOURCE +1 −0
  19. public/icons/ui/check-white/check-white.png +0 −0
  20. public/icons/ui/check-white/check-white@2x.png +0 −0
  21. public/icons/ui/dir-white/SOURCE +1 −0
  22. public/icons/ui/dir-white/dir-white.png +0 −0
  23. public/icons/ui/dir-white/dir-white@2x.png +0 −0
  24. public/icons/ui/light-white/SOURCE +1 −0
  25. public/icons/ui/light-white/light.png +0 −0
  26. public/icons/ui/light-white/light@2x.png +0 −0
  27. public/icons/ui/light/SOURCE +1 −0
  28. public/icons/ui/light/light.png +0 −0
  29. public/icons/ui/light/light@2x.png +0 −0
  30. public/icons/ui/link-white/SOURCE +1 −0
  31. public/icons/ui/link-white/link-white.png +0 −0
  32. public/icons/ui/link-white/link-white@2x.png +0 −0
  33. public/icons/ui/search-white/SOURCE +1 −0
  34. public/icons/ui/search-white/search-white.png +0 −0
  35. public/icons/ui/search-white/search-white@2x.png +0 −0
  36. public/icons/ui/settings-white/SOURCE +1 −0
  37. public/icons/ui/settings-white/settings-white.png +0 −0
  38. public/icons/ui/settings-white/settings-white@2x.png +0 −0
  39. views/index.erb +1 −1
  40. views/manifest.erb +1 −0
  41. views/other.erb +1 −1
assets/images/icons.png+0−0

Binary file not shown.

assets/images/icons@2x.png+0−0

Binary file not shown.

assets/javascripts/app/settings.coffee+12−3
@@ -1,6 +1,7 @@
11 class app.Settings
22 SETTINGS_KEY = 'settings'
33 DOCS_KEY = 'docs'
4+ DARK_KEY = 'dark'
45
56 @defaults: ->
67 count: 0
@@ -45,13 +46,21 @@ class app.Settings · 38 unmodified lines
4546
4647 setDocs: (docs) ->
4748 try
48− Cookies.set DOCS_KEY, docs.join('/'),
49− path: '/'
50− expires: 1e8
49+ Cookies.set DOCS_KEY, docs.join('/'), path: '/', expires: 1e8
50+ catch
51+ return
52+
53+ setDark: (value) ->
54+ try
55+ if value
56+ Cookies.set DARK_KEY, '1', path: '/', expires: 1e8
57+ else
58+ Cookies.expire DARK_KEY
5159 catch
5260 return
5361
5462 reset: ->
5563 try Cookies.expire DOCS_KEY
64+ try Cookies.expire DARK_KEY
5665 try @store.del(SETTINGS_KEY)
5766 return
assets/javascripts/news.json+4−1
@@ -1,5 +1,8 @@
11 [
2− [ "2015-01-13",
2+ [ "2015-02-08",
3+ "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 :)"
4+ ], [
5+ "2015-01-13",
36 "<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>."
47 ], [
58 "2014-12-21",
assets/javascripts/templates/sidebar_tmpl.coffee+4−1
@@ -51,7 +51,10 @@ templates.sidebarPickerNote = """ · 50 unmodified lines
5151 sidebarFooter = (html) -> """<div class="_sidebar-footer">#{html}</div>"""
5252
5353 templates.sidebarSettings = ->
54− sidebarFooter """<a class="_sidebar-footer-link _sidebar-footer-edit" data-pick-docs>Select documentation</a>"""
54+ sidebarFooter """
55+ <a class="_sidebar-footer-link _sidebar-footer-light" title="Toggle light" data-light></a>
56+ <a class="_sidebar-footer-link _sidebar-footer-edit" data-pick-docs>Select documentation</a>
57+ """
5558
5659 templates.sidebarSave = ->
5760 sidebarFooter """<a class="_sidebar-footer-link _sidebar-footer-save">Save</a>"""
assets/javascripts/views/layout/document.coffee+8−0
@@ -17,6 +17,14 @@ class app.views.Document extends app.View · 16 unmodified lines
1717 @activate()
1818 return
1919
20+ toggleLight: ->
21+ css = $('link[rel="stylesheet"][data-alt]')
22+ alt = css.getAttribute('data-alt')
23+ css.setAttribute('data-alt', css.getAttribute('href'))
24+ css.setAttribute('href', alt)
25+ app.settings.setDark(alt.indexOf('dark') > 0)
26+ return
27+
2028 setTitle: (title) ->
2129 @el.title = if title then "DevDocs/#{title}" else 'DevDocs'
2230
assets/javascripts/views/sidebar/sidebar.coffee+3−0
@@ -79,6 +79,9 @@ class app.views.Sidebar extends app.View · 78 unmodified lines
7979 if event.target.hasAttribute? 'data-reset-list'
8080 $.stopEvent(event)
8181 @reset()
82+ else if event.target.hasAttribute? 'data-light'
83+ $.stopEvent(event)
84+ app.document.toggleLight()
8285 return
8386
8487 onGlobalClick: (event) =>
assets/stylesheets/application-dark.css.scss+72−0
@@ -0,0 +1,72 @@
1+//= depend_on icons.png
2+//= depend_on icons@2x.png
3+
4+//= require vendor/open-sans
5+
6+/*!
7+ * Copyright 2013-2015 Thibaut Courouble and other contributors
8+ *
9+ * This source code is licensed under the terms of the Mozilla
10+ * Public License, v. 2.0, a copy of which may be obtained at:
11+ * http://mozilla.org/MPL/2.0/
12+ */
13+
14+@import 'global/variables-dark',
15+ 'global/icons',
16+ 'global/classes',
17+ 'global/base';
18+
19+@import 'components/app',
20+ 'components/header',
21+ 'components/notif',
22+ 'components/sidebar',
23+ 'components/content',
24+ 'components/page',
25+ 'components/fail',
26+ 'components/notice',
27+ 'components/path',
28+ 'components/prism',
29+ 'components/mobile';
30+
31+@import 'pages/angular',
32+ 'pages/bower',
33+ 'pages/c',
34+ 'pages/chai',
35+ 'pages/coffeescript',
36+ 'pages/cordova',
37+ 'pages/d3',
38+ 'pages/ember',
39+ 'pages/express',
40+ 'pages/go',
41+ 'pages/haskell',
42+ 'pages/jquery',
43+ 'pages/knockout',
44+ 'pages/git',
45+ 'pages/grunt',
46+ 'pages/laravel',
47+ 'pages/less',
48+ 'pages/lodash',
49+ 'pages/marionette',
50+ 'pages/markdown',
51+ 'pages/maxcdn',
52+ 'pages/mdn',
53+ 'pages/modernizr',
54+ 'pages/moment',
55+ 'pages/mongoose',
56+ 'pages/nginx',
57+ 'pages/node',
58+ 'pages/php',
59+ 'pages/phpunit',
60+ 'pages/postgres',
61+ 'pages/rdoc',
62+ 'pages/react',
63+ 'pages/redis',
64+ 'pages/requirejs',
65+ 'pages/rethinkdb',
66+ 'pages/rfc',
67+ 'pages/sinon',
68+ 'pages/socketio',
69+ 'pages/sphinx',
70+ 'pages/underscore',
71+ 'pages/yard',
72+ 'pages/yii';
assets/stylesheets/components/_content.scss+10−0
@@ -425,6 +425,11 @@ · 424 unmodified lines
425425 ._splash-sponsor > ._maxcdn-logo {
426426 background-image: image-url('maxcdn-bw.png');
427427
428+ @if $style == 'dark' {
429+ filter: invert(100%);
430+ -webkit-filter: invert(100%);
431+ }
432+
428433 @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
429434 background-image: image-url('maxcdn-bw@2x.png');
430435 }
@@ -443,6 +448,11 @@ · 12 unmodified lines
443448 ._splash-sponsor > ._shopify-logo {
444449 background-image: image-url('shopify-bw.png');
445450
451+ @if $style == 'dark' {
452+ filter: invert(100%);
453+ -webkit-filter: invert(100%);
454+ }
455+
446456 @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
447457 background-image: image-url('shopify-bw@2x.png');
448458 }
assets/stylesheets/components/_header.scss+10−2
@@ -98,7 +98,11 @@ · 97 unmodified lines
9898 top: 1rem;
9999 left: 1rem;
100100 opacity: .4;
101− @extend %icon, %icon-search;
101+ @if $style == 'dark' {
102+ @extend %icon, %icon-search-white;
103+ } @else {
104+ @extend %icon, %icon-search;
105+ }
102106 }
103107 }
104108
@@ -132,7 +136,11 @@ · 27 unmodified lines
132136 opacity: .3;
133137
134138 &:hover { opacity: .5; }
135− &:before { @extend %icon, %icon-clear; }
139+ @if $style == 'dark' {
140+ &:before { @extend %icon, %icon-close-white; }
141+ } @else {
142+ &:before { @extend %icon, %icon-clear; }
143+ }
136144 ._search-active > & { display: block; }
137145 }
138146
assets/stylesheets/components/_prism.scss+30−6
@@ -17,7 +17,11 @@ · 16 unmodified lines
1717 .token.constant,
1818 .token.symbol,
1919 .token.deleted {
20− color: #905;
20+ @if $style == 'dark' {
21+ color: #cf6a4c;
22+ } @else {
23+ color: #905;
24+ }
2125 }
2226
2327 .token.selector,
@@ -26,7 +30,11 @@ · 2 unmodified lines
2630 .token.char,
2731 .token.builtin,
2832 .token.inserted {
29− color: #5e8e01;
33+ @if $style == 'dark' {
34+ color: #d0c584;
35+ } @else {
36+ color: #5e8e01;
37+ }
3038 }
3139
3240 .token.operator,
@@ -34,23 +42,39 @@ · 1 unmodified line
3442 .token.url,
3543 .language-css .token.string,
3644 .style .token.string {
37− color: #a67f59;
45+ @if $style == 'dark' {
46+ color: #8f9d6a;
47+ } @else {
48+ color: #a67f59;
49+ }
3850 }
3951
4052 .token.atrule,
4153 .token.attr-value,
4254 .token.keyword {
43− color: #0070a3;
55+ @if $style == 'dark' {
56+ color: #7587a6;
57+ } @else {
58+ color: #0070a3;
59+ }
4460 }
4561
4662 .token.function {
47− color: #dd4a68;
63+ @if $style == 'dark' {
64+ color: #ac885b;
65+ } @else {
66+ color: #dd4a68;
67+ }
4868 }
4969
5070 .token.regex,
5171 .token.important,
5272 .token.variable {
53− color: #e90;
73+ @if $style == 'dark' {
74+ color: #e9c062;
75+ } @else {
76+ color: #e90;
77+ }
5478 }
5579
5680 .token.important {
assets/stylesheets/components/_sidebar.scss+36−3
@@ -162,7 +162,11 @@ · 161 unmodified lines
162162 &:hover { opacity: .65; }
163163
164164 &:before {
165− @extend %icon, %icon-dir;
165+ @if $style == 'dark' {
166+ @extend %icon, %icon-dir-white;
167+ } @else {
168+ @extend %icon, %icon-dir;
169+ }
166170
167171 .open > &, .open-title > & {
168172 -webkit-transform: rotate(90deg);
@@ -340,6 +344,7 @@ · 171 unmodified lines
340344 ._sidebar-footer-link {
341345 position: relative;
342346 display: block;
347+ overflow: hidden;
343348 height: 2.5rem;
344349 line-height: 1rem;
345350 padding: .75rem;
@@ -360,7 +365,31 @@ · 14 unmodified lines
360365 }
361366
362367 ._sidebar-footer-edit {
363− &:before { @extend %icon-settings; }
368+ @if $style == 'dark' {
369+ &:before { @extend %icon-settings-white; }
370+ } @else {
371+ &:before { @extend %icon-settings; }
372+ }
373+}
374+
375+._sidebar-footer-light {
376+ float: right;
377+ width: 2.5rem;
378+ padding: 0;
379+ opacity: .6;
380+
381+ &:before {
382+ float: none;
383+ position: absolute;
384+ top: .75rem;
385+ left: .75rem;
386+
387+ @if $style == 'dark' {
388+ @extend %icon-light-white;
389+ } @else {
390+ @extend %icon-light;
391+ }
392+ }
364393 }
365394
366395 ._sidebar-footer-save {
@@ -370,5 +399,9 @@ · 3 unmodified lines
370399 box-shadow: inset 0 1px $noteGreenBorder,
371400 1px 0 $noteGreenBorder;
372401
373− &:before { @extend %icon-check; }
402+ @if $style == 'dark' {
403+ &:before { @extend %icon-check-white; }
404+ } @else {
405+ &:before { @extend %icon-check; }
406+ }
374407 }
assets/stylesheets/global/_classes.scss+5−1
@@ -101,7 +101,11 @@ · 100 unmodified lines
101101 height: .4375rem;
102102 margin: .125rem 0 0 .0625rem;
103103 vertical-align: top;
104− @extend %icon, %icon-link;
104+ @if $style == 'dark' {
105+ @extend %icon, %icon-link-white;
106+ } @else {
107+ @extend %icon, %icon-link;
108+ }
105109 }
106110 }
107111
assets/stylesheets/global/_icons.scss+8−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
44 width: 1rem;
55 height: 1rem;
66 background-image: image-url('icons.png');
7− background-size: 5rem 13rem;
7+ background-size: 5rem 15rem;
88 }
99
1010 @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
@@ -77,3 +77,10 @@ · 66 unmodified lines
7777 ._icon-socketio:before { background-position: -2rem -12rem; }
7878 ._icon-modernizr:before { background-position: -3rem -12rem; }
7979 ._icon-bower:before { background-position: -4rem -12rem; }
80+%icon-search-white { background-position: 0 -13rem; }
81+%icon-dir-white { background-position: -1rem -13rem; }
82+%icon-link-white { background-position: -2.25rem -13.25rem; }
83+%icon-settings-white { background-position: -3rem -13rem; }
84+%icon-check-white { background-position: -4rem -13rem; }
85+%icon-light { background-position: 0 -14rem; }
86+%icon-light-white { background-position: -1rem -14rem; }
assets/stylesheets/global/_variables.scss+2−0
@@ -1,6 +1,8 @@
11 $baseFont: 'Open Sans', Helvetica, Arial, sans-serif;
22 $monoFont: 'Source Code Pro', 'Inconsolata-g', Consolas, Menlo, monospace;
33
4+$style: 'light';
5+
46 $headerHeight: 3rem;
57 $sidebarWidth: 18rem;
68 $sidebarMediumWidth: 16rem;
assets/stylesheets/global/variables-dark.scss+82−0
@@ -0,0 +1,82 @@
1+$baseFont: 'Open Sans', Helvetica, Arial, sans-serif;
2+$monoFont: 'Source Code Pro', 'Inconsolata-g', Consolas, Menlo, monospace;
3+
4+$style: 'dark';
5+
6+$headerHeight: 3rem;
7+$sidebarWidth: 18rem;
8+$sidebarMediumWidth: 16rem;
9+
10+$contentBackground: #2d2d2d;
11+
12+$textColor: #b4b3af;
13+$textColorLight: #7e7d7d;
14+$textColorLighter: #6a6868;
15+
16+$inputFocusBorder: #444;
17+
18+$focusBackground: #3d3d3e;
19+$focusBorder: #3d3d3e;
20+$focusText: #f7f2f2;
21+
22+$loadingText: #616161;
23+$splashText: #616161;
24+$promoText: #616161;
25+
26+$selectionBackground: #346fce;
27+$selectionBorder: #346fce;
28+$selectionText: #fff;
29+
30+$highlightBackground: #3d4449;
31+
32+$linkColor: #f7f2f2;
33+$linkColorHover: #fff;
34+
35+$headerBackground: #1e1e1e;
36+$headerBorder: #1e1e1e;
37+
38+$sidebarBackground: #262626;
39+$sidebarBorder: #262626;
40+
41+$scrollbarColor: #515151;
42+$scrollbarColorHover: #888;
43+
44+$pathBackground: $headerBackground;
45+$pathBorder: $headerBorder;
46+
47+$noticeBackground: #1e1e1e;
48+$noticeBorder: #1e1e1e;
49+
50+$boxBackground: #1e1e1e;
51+$boxBorder: #0a0a0a;
52+$boxBorderLight: #171717;
53+$boxHeaderBackground: #1e1e1e;
54+
55+$noteBackground: #3a3e31;
56+$noteBorder: #1a1c17;
57+
58+$noteGreenBackground: #283e2b;
59+$noteGreenBorder: #111b13;
60+
61+$noteBlueBackground: #1f2f3e;
62+$noteBlueBorder: #101922;
63+
64+$noteOrangeBackground: #3e271d;
65+$noteOrangeBorder: #1f1511;
66+
67+$noteRedBackground: #3e1b1b;
68+$noteRedBorder: #1b0a0a;
69+
70+$labelBackground: #38383a;
71+
72+$notifBackground: rgba(#000, .85);
73+$notifColor: #fff;
74+$notifColorLight: #bbb;
75+
76+$mediumScreen: '(max-width: 800px)';
77+
78+$contentZ: 1;
79+$sidebarZ: 2;
80+$headerZ: 3;
81+$noticeZ: 4;
82+$hoverZ: 5;
lib/app.rb+16−1
@@ -17,7 +17,7 @@ class App < Sinatra::Application · 16 unmodified lines
1717 set :assets_prefix, 'assets'
1818 set :assets_path, -> { File.join(public_folder, assets_prefix) }
1919 set :assets_manifest_path, -> { File.join(assets_path, 'manifest.json') }
20− set :assets_compile, %w(*.png docs.js application.js application.css)
20+ set :assets_compile, %w(*.png docs.js application.js application.css application-dark.css)
2121
2222 require 'yajl/json_gem'
2323 set :docs_prefix, 'docs'
@@ -117,6 +117,21 @@ class App < Sinatra::Application · 93 unmodified lines
117117 def query_string_for_redirection
118118 request.query_string.empty? ? nil : "?#{request.query_string}"
119119 end
120+
121+ def main_stylesheet_path
122+ stylesheet_paths[cookies[:dark].present? ? :dark : :default]
123+ end
124+
125+ def alternate_stylesheet_path
126+ stylesheet_paths[cookies[:dark].present? ? :default : :dark]
127+ end
128+
129+ def stylesheet_paths
130+ @stylesheet_paths ||= {
131+ default: stylesheet_path('application'),
132+ dark: stylesheet_path('application-dark')
133+ }
134+ end
120135 end
121136
122137 before do
public/icons/ui/check-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://happytodesign.com/hicons/
public/icons/ui/check-white/check-white.png+0−0

Binary file not shown.

public/icons/ui/check-white/check-white@2x.png+0−0

Binary file not shown.

public/icons/ui/dir-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://gemicon.net/
public/icons/ui/dir-white/dir-white.png+0−0

Binary file not shown.

public/icons/ui/dir-white/dir-white@2x.png+0−0

Binary file not shown.

public/icons/ui/light-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://www.entypo.com/
public/icons/ui/light-white/light.png+0−0

Binary file not shown.

public/icons/ui/light-white/light@2x.png+0−0

Binary file not shown.

public/icons/ui/light/SOURCE+1−0
@@ -0,0 +1 @@
1+http://www.entypo.com/
public/icons/ui/light/light.png+0−0

Binary file not shown.

public/icons/ui/light/light@2x.png+0−0

Binary file not shown.

public/icons/ui/link-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://www.entypo.com/
public/icons/ui/link-white/link-white.png+0−0

Binary file not shown.

public/icons/ui/link-white/link-white@2x.png+0−0

Binary file not shown.

public/icons/ui/search-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://www.entypo.com/
public/icons/ui/search-white/search-white.png+0−0

Binary file not shown.

public/icons/ui/search-white/search-white@2x.png+0−0

Binary file not shown.

public/icons/ui/settings-white/SOURCE+1−0
@@ -0,0 +1 @@
1+http://gemicon.net/
public/icons/ui/settings-white/settings-white.png+0−0

Binary file not shown.

public/icons/ui/settings-white/settings-white@2x.png+0−0

Binary file not shown.

views/index.erb+1−1
@@ -26,7 +26,7 @@ · 25 unmodified lines
2626 <link rel="apple-touch-icon" sizes="144x144" href="http://maxcdn.devdocs.io/images/apple-icon-144.png">
2727 <link rel="apple-touch-icon" sizes="152x152" href="http://maxcdn.devdocs.io/images/apple-icon-152.png">
2828 <link rel="apple-touch-icon" sizes="160x160" href="http://maxcdn.devdocs.io/images/apple-icon-160.png">
29− <%= stylesheet_tag 'application' %>
29+ <link rel="stylesheet" href="<%= main_stylesheet_path %>" data-alt="<%= alternate_stylesheet_path %>">
3030 <%= javascript_tag 'application', asset_host: false %>
3131 <%= javascript_tag 'docs' %><% unless App.production? %>
3232 <%= javascript_tag 'debug' %><% end %>
views/manifest.erb+1−0
@@ -4,6 +4,7 @@ CACHE: · 3 unmodified lines
44 /
55 <%= javascript_path 'application', asset_host: false %>
66 <%= stylesheet_path 'application' %>
7+<%= stylesheet_path 'application-dark' %>
78 <%= image_path 'icons.png' %>
89 <%= image_path 'icons@2x.png' %>
910 <%= image_path 'maxcdn.png' %>
views/other.erb+1−1
@@ -8,7 +8,7 @@ · 7 unmodified lines
88 <title>DevDocs<%= ": #{@doc['name']} API Documentation" if doc_index_page? %></title>
99 <link rel="icon" type="image/x-icon" href="http://maxcdn.devdocs.io/favicon.ico">
1010 <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Search DevDocs">
11− <%= stylesheet_tag 'application' %>
11+ <link rel="stylesheet" href="<%= main_stylesheet_path %>" data-alt="<%= alternate_stylesheet_path %>">
1212 <%= javascript_tag 'application', asset_host: false %><% unless App.production? %>
1313 <%= javascript_tag 'debug' %><% end %>
1414 <script>app.DOC = <%= @doc.to_json %>;</script>