aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2018-11-24 20:15:39 +0100
committerLibravatar Stefan Malzner <stefan@adlk.io>2018-11-24 20:15:39 +0100
commit4ea044ae6b2e27e48d45bc3be1c366f4882bbda5 (patch)
treed19064b7370cb66ef66407de082bedad4c3128d4
parentdisable import/prefer-default-export (diff)
downloadferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.tar.gz
ferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.tar.zst
ferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.zip
feat(App): Lay groundwork for general themeing support
-rw-r--r--gulpfile.babel.js13
-rw-r--r--package-lock.json165
-rw-r--r--package.json5
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js3
-rw-r--r--src/containers/layout/AppLayoutContainer.js43
-rw-r--r--src/stores/UIStore.js10
-rw-r--r--src/styles/colors.scss50
-rw-r--r--src/styles/type-helper.scss100
-rw-r--r--src/theme/dark/index.js5
-rw-r--r--src/theme/default/index.js12
-rw-r--r--src/theme/default/legacy.js39
11 files changed, 396 insertions, 49 deletions
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index ad8adda2e..cea42d6c9 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -7,11 +7,20 @@ import { exec } from 'child_process';
7import dotenv from 'dotenv'; 7import dotenv from 'dotenv';
8import sassVariables from 'gulp-sass-variables'; 8import sassVariables from 'gulp-sass-variables';
9import { removeSync } from 'fs-extra'; 9import { removeSync } from 'fs-extra';
10import kebabCase from 'kebab-case';
11import hexRgb from 'hex-rgb';
10 12
11import config from './package.json'; 13import config from './package.json';
12 14
15import * as rawStyleConfig from './src/theme/default/legacy.js';
16
13dotenv.config(); 17dotenv.config();
14 18
19const styleConfig = Object.keys(rawStyleConfig).map((key) => {
20 const isHex = /^#[0-9A-F]{6}$/i.test(rawStyleConfig[key]);
21 return ({ [`$raw_${kebabCase(key)}`]: isHex ? hexRgb(rawStyleConfig[key], { format: 'array' }).splice(0, 3).join(',') : rawStyleConfig[key] });
22});
23
15const paths = { 24const paths = {
16 src: 'src', 25 src: 'src',
17 dest: 'build', 26 dest: 'build',
@@ -83,9 +92,9 @@ export function html() {
83 92
84export function styles() { 93export function styles() {
85 return gulp.src(paths.styles.src) 94 return gulp.src(paths.styles.src)
86 .pipe(sassVariables({ 95 .pipe(sassVariables(Object.assign({
87 $env: process.env.NODE_ENV === 'development' ? 'development' : 'production', 96 $env: process.env.NODE_ENV === 'development' ? 'development' : 'production',
88 })) 97 }, ...styleConfig)))
89 .pipe(sass({ 98 .pipe(sass({
90 includePaths: [ 99 includePaths: [
91 './node_modules', 100 './node_modules',
diff --git a/package-lock.json b/package-lock.json
index 1dcd57e01..6f1f11eba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2006,6 +2006,11 @@
2006 } 2006 }
2007 } 2007 }
2008 }, 2008 },
2009 "brcast": {
2010 "version": "3.0.1",
2011 "resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz",
2012 "integrity": "sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg=="
2013 },
2009 "browserslist": { 2014 "browserslist": {
2010 "version": "4.3.2", 2015 "version": "4.3.2",
2011 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.2.tgz", 2016 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.2.tgz",
@@ -3010,6 +3015,14 @@
3010 "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", 3015 "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
3011 "dev": true 3016 "dev": true
3012 }, 3017 },
3018 "css-vendor": {
3019 "version": "0.3.8",
3020 "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz",
3021 "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=",
3022 "requires": {
3023 "is-in-browser": "^1.0.2"
3024 }
3025 },
3013 "currently-unhandled": { 3026 "currently-unhandled": {
3014 "version": "0.4.1", 3027 "version": "0.4.1",
3015 "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 3028 "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -6745,6 +6758,12 @@
6745 "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.2.2.tgz", 6758 "resolved": "https://registry.npmjs.org/hashids/-/hashids-1.2.2.tgz",
6746 "integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw==" 6759 "integrity": "sha512-dEHCG2LraR6PNvSGxosZHIRgxF5sNLOIBFEHbj8lfP9WWmu/PWPMzsip1drdVSOFi51N2pU7gZavrgn7sbGFuw=="
6747 }, 6760 },
6761 "hex-rgb": {
6762 "version": "3.0.0",
6763 "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-3.0.0.tgz",
6764 "integrity": "sha512-iWOUTZu7KQGhErV8JfTQDH5F/M2D0HVd0sexS4Grg4e4RYAiN3c4jfpPqKgfedqeebKcNZBl2z3zlgCtFjpFJQ==",
6765 "dev": true
6766 },
6748 "history": { 6767 "history": {
6749 "version": "3.3.0", 6768 "version": "3.3.0",
6750 "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", 6769 "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz",
@@ -6967,6 +6986,11 @@
6967 } 6986 }
6968 } 6987 }
6969 }, 6988 },
6989 "hyphenate-style-name": {
6990 "version": "1.0.2",
6991 "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
6992 "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
6993 },
6970 "iconv-lite": { 6994 "iconv-lite": {
6971 "version": "0.4.24", 6995 "version": "0.4.24",
6972 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 6996 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7352,6 +7376,11 @@
7352 "number-is-nan": "^1.0.0" 7376 "number-is-nan": "^1.0.0"
7353 } 7377 }
7354 }, 7378 },
7379 "is-function": {
7380 "version": "1.0.1",
7381 "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz",
7382 "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU="
7383 },
7355 "is-glob": { 7384 "is-glob": {
7356 "version": "4.0.0", 7385 "version": "4.0.0",
7357 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", 7386 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
@@ -7361,6 +7390,11 @@
7361 "is-extglob": "^2.1.1" 7390 "is-extglob": "^2.1.1"
7362 } 7391 }
7363 }, 7392 },
7393 "is-in-browser": {
7394 "version": "1.1.3",
7395 "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
7396 "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
7397 },
7364 "is-installed-globally": { 7398 "is-installed-globally": {
7365 "version": "0.1.0", 7399 "version": "0.1.0",
7366 "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", 7400 "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
@@ -7727,6 +7761,108 @@
7727 "verror": "1.10.0" 7761 "verror": "1.10.0"
7728 } 7762 }
7729 }, 7763 },
7764 "jss": {
7765 "version": "9.8.7",
7766 "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz",
7767 "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==",
7768 "requires": {
7769 "is-in-browser": "^1.1.3",
7770 "symbol-observable": "^1.1.0",
7771 "warning": "^3.0.0"
7772 },
7773 "dependencies": {
7774 "symbol-observable": {
7775 "version": "1.2.0",
7776 "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
7777 "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
7778 }
7779 }
7780 },
7781 "jss-camel-case": {
7782 "version": "6.1.0",
7783 "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz",
7784 "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==",
7785 "requires": {
7786 "hyphenate-style-name": "^1.0.2"
7787 }
7788 },
7789 "jss-compose": {
7790 "version": "5.0.0",
7791 "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz",
7792 "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==",
7793 "requires": {
7794 "warning": "^3.0.0"
7795 }
7796 },
7797 "jss-default-unit": {
7798 "version": "8.0.2",
7799 "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz",
7800 "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg=="
7801 },
7802 "jss-expand": {
7803 "version": "5.3.0",
7804 "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz",
7805 "integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg=="
7806 },
7807 "jss-extend": {
7808 "version": "6.2.0",
7809 "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz",
7810 "integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==",
7811 "requires": {
7812 "warning": "^3.0.0"
7813 }
7814 },
7815 "jss-global": {
7816 "version": "3.0.0",
7817 "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz",
7818 "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q=="
7819 },
7820 "jss-nested": {
7821 "version": "6.0.1",
7822 "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz",
7823 "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==",
7824 "requires": {
7825 "warning": "^3.0.0"
7826 }
7827 },
7828 "jss-preset-default": {
7829 "version": "4.5.0",
7830 "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz",
7831 "integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==",
7832 "requires": {
7833 "jss-camel-case": "^6.1.0",
7834 "jss-compose": "^5.0.0",
7835 "jss-default-unit": "^8.0.2",
7836 "jss-expand": "^5.3.0",
7837 "jss-extend": "^6.2.0",
7838 "jss-global": "^3.0.0",
7839 "jss-nested": "^6.0.1",
7840 "jss-props-sort": "^6.0.0",
7841 "jss-template": "^1.0.1",
7842 "jss-vendor-prefixer": "^7.0.0"
7843 }
7844 },
7845 "jss-props-sort": {
7846 "version": "6.0.0",
7847 "resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz",
7848 "integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g=="
7849 },
7850 "jss-template": {
7851 "version": "1.0.1",
7852 "resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz",
7853 "integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==",
7854 "requires": {
7855 "warning": "^3.0.0"
7856 }
7857 },
7858 "jss-vendor-prefixer": {
7859 "version": "7.0.0",
7860 "resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz",
7861 "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==",
7862 "requires": {
7863 "css-vendor": "^0.3.8"
7864 }
7865 },
7730 "jsx-ast-utils": { 7866 "jsx-ast-utils": {
7731 "version": "1.4.1", 7867 "version": "1.4.1",
7732 "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", 7868 "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
@@ -7758,6 +7894,12 @@
7758 "safe-buffer": "^5.0.1" 7894 "safe-buffer": "^5.0.1"
7759 } 7895 }
7760 }, 7896 },
7897 "kebab-case": {
7898 "version": "1.0.0",
7899 "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.0.tgz",
7900 "integrity": "sha1-P55JkK3K0MaGwOcB92RYaPdfkes=",
7901 "dev": true
7902 },
7761 "keymaster": { 7903 "keymaster": {
7762 "version": "1.6.2", 7904 "version": "1.6.2",
7763 "resolved": "https://registry.npmjs.org/keymaster/-/keymaster-1.6.2.tgz", 7905 "resolved": "https://registry.npmjs.org/keymaster/-/keymaster-1.6.2.tgz",
@@ -9690,6 +9832,18 @@
9690 "invariant": "^2.1.1" 9832 "invariant": "^2.1.1"
9691 } 9833 }
9692 }, 9834 },
9835 "react-jss": {
9836 "version": "8.6.1",
9837 "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz",
9838 "integrity": "sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==",
9839 "requires": {
9840 "hoist-non-react-statics": "^2.5.0",
9841 "jss": "^9.7.0",
9842 "jss-preset-default": "^4.3.0",
9843 "prop-types": "^15.6.0",
9844 "theming": "^1.3.0"
9845 }
9846 },
9693 "react-lifecycles-compat": { 9847 "react-lifecycles-compat": {
9694 "version": "3.0.4", 9848 "version": "3.0.4",
9695 "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", 9849 "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
@@ -11168,6 +11322,17 @@
11168 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 11322 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
11169 "dev": true 11323 "dev": true
11170 }, 11324 },
11325 "theming": {
11326 "version": "1.3.0",
11327 "resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz",
11328 "integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==",
11329 "requires": {
11330 "brcast": "^3.0.1",
11331 "is-function": "^1.0.1",
11332 "is-plain-object": "^2.0.1",
11333 "prop-types": "^15.5.8"
11334 }
11335 },
11171 "throttleit": { 11336 "throttleit": {
11172 "version": "0.0.2", 11337 "version": "0.0.2",
11173 "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", 11338 "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
diff --git a/package.json b/package.json
index ee2b12e99..8ec2d4f67 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
11 "private": true, 11 "private": true,
12 "scripts": { 12 "scripts": {
13 "prestart": "npm run rebuild", 13 "prestart": "npm run rebuild",
14 "start": "DEBUG=Franz:* electron ./build", 14 "start": "electron ./build",
15 "start:local": "cross-env LOCAL_API=1 npm start", 15 "start:local": "cross-env LOCAL_API=1 npm start",
16 "start:live": "cross-env LIVE_API=1 npm start", 16 "start:live": "cross-env LIVE_API=1 npm start",
17 "dev": "cross-env NODE_ENV=development gulp dev", 17 "dev": "cross-env NODE_ENV=development gulp dev",
@@ -67,6 +67,7 @@
67 "react-dropzone": "^4.2.1", 67 "react-dropzone": "^4.2.1",
68 "react-electron-web-view": "^2.0.1", 68 "react-electron-web-view": "^2.0.1",
69 "react-intl": "^2.3.0", 69 "react-intl": "^2.3.0",
70 "react-jss": "8.6.1",
70 "react-loader": "^2.4.0", 71 "react-loader": "^2.4.0",
71 "react-router": "^3.0.2", 72 "react-router": "^3.0.2",
72 "react-router-transition": "^0.1.1", 73 "react-router-transition": "^0.1.1",
@@ -108,7 +109,9 @@
108 "gulp-sass": "^4.0.2", 109 "gulp-sass": "^4.0.2",
109 "gulp-sass-variables": "^1.1.1", 110 "gulp-sass-variables": "^1.1.1",
110 "gulp-server-livereload": "^1.9.2", 111 "gulp-server-livereload": "^1.9.2",
112 "hex-rgb": "3.0.0",
111 "husky": "^1.1.4", 113 "husky": "^1.1.4",
114 "kebab-case": "1.0.0",
112 "node-sass": "^4.7.2", 115 "node-sass": "^4.7.2",
113 "prettier": "1.15.2" 116 "prettier": "1.15.2"
114 }, 117 },
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index 46b2f82fc..d8b410aaf 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -32,8 +32,7 @@ const messages = defineMessages({
32 }, 32 },
33}); 33});
34 34
35@inject('stores') @observer 35export default @inject('stores') @observer class SettingsNavigation extends Component {
36export default class SettingsNavigation extends Component {
37 static propTypes = { 36 static propTypes = {
38 serviceCount: PropTypes.number.isRequired, 37 serviceCount: PropTypes.number.isRequired,
39 }; 38 };
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js
index affc1a0a2..c5c9c6850 100644
--- a/src/containers/layout/AppLayoutContainer.js
+++ b/src/containers/layout/AppLayoutContainer.js
@@ -1,6 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import { ThemeProvider } from 'react-jss';
4 5
5import AppStore from '../../stores/AppStore'; 6import AppStore from '../../stores/AppStore';
6import RecipesStore from '../../stores/RecipesStore'; 7import RecipesStore from '../../stores/RecipesStore';
@@ -109,26 +110,28 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e
109 ); 110 );
110 111
111 return ( 112 return (
112 <AppLayout 113 <ThemeProvider theme={ui.theme}>
113 isFullScreen={app.isFullScreen} 114 <AppLayout
114 isOnline={app.isOnline} 115 isFullScreen={app.isFullScreen}
115 showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} 116 isOnline={app.isOnline}
116 appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} 117 showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar}
117 sidebar={sidebar} 118 appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED}
118 services={servicesContainer} 119 sidebar={sidebar}
119 news={news.latest} 120 services={servicesContainer}
120 removeNewsItem={hide} 121 news={news.latest}
121 reloadServicesAfterUpdate={reloadUpdatedServices} 122 removeNewsItem={hide}
122 installAppUpdate={installUpdate} 123 reloadServicesAfterUpdate={reloadUpdatedServices}
123 globalError={globalError.error} 124 installAppUpdate={installUpdate}
124 showRequiredRequestsError={requests.showRequiredRequestsError} 125 globalError={globalError.error}
125 areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} 126 showRequiredRequestsError={requests.showRequiredRequestsError}
126 retryRequiredRequests={retryRequiredRequests} 127 areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful}
127 areRequiredRequestsLoading={requests.areRequiredRequestsLoading} 128 retryRequiredRequests={retryRequiredRequests}
128 darkMode={settings.all.app.darkMode} 129 areRequiredRequestsLoading={requests.areRequiredRequestsLoading}
129 > 130 darkMode={settings.all.app.darkMode}
130 {React.Children.count(children) > 0 ? children : null} 131 >
131 </AppLayout> 132 {React.Children.count(children) > 0 ? children : null}
133 </AppLayout>
134 </ThemeProvider>
132 ); 135 );
133 } 136 }
134} 137}
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js
index bee6c8bcf..d37ebe4c7 100644
--- a/src/stores/UIStore.js
+++ b/src/stores/UIStore.js
@@ -1,6 +1,8 @@
1import { action, observable, computed } from 'mobx'; 1import { action, observable, computed } from 'mobx';
2 2
3import Store from './lib/Store'; 3import Store from './lib/Store';
4import * as themeDefault from '../theme/default';
5import * as themeDark from '../theme/dark';
4 6
5export default class UIStore extends Store { 7export default class UIStore extends Store {
6 @observable showServicesUpdatedInfoBar = false; 8 @observable showServicesUpdatedInfoBar = false;
@@ -20,6 +22,14 @@ export default class UIStore extends Store {
20 return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; 22 return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted;
21 } 23 }
22 24
25 @computed get theme() {
26 if (this.stores.settings.all.app.darkMode) {
27 return Object.assign({}, themeDefault, themeDark);
28 }
29
30 return themeDefault;
31 }
32
23 // Actions 33 // Actions
24 @action _openSettings({ path = '/settings' }) { 34 @action _openSettings({ path = '/settings' }) {
25 const settingsPath = path !== '/settings' ? `/settings/${path}` : path; 35 const settingsPath = path !== '/settings' ? `/settings/${path}` : path;
diff --git a/src/styles/colors.scss b/src/styles/colors.scss
index 4411a0e81..80c2fb633 100644
--- a/src/styles/colors.scss
+++ b/src/styles/colors.scss
@@ -1,38 +1,40 @@
1$theme-brand-primary: #3498db; 1@import "./type-helper";
2$theme-brand-success: #5cb85c;
3$theme-brand-info: #5bc0de;
4$theme-brand-warning: #FF9F00;
5$theme-brand-danger: #d9534f;
6 2
7$theme-gray-dark: #373a3c; 3$theme-brand-primary: convert-rgb-string-to-color($raw-theme-brand-primary);
8$theme-gray: #55595c; 4$theme-brand-success: convert-rgb-string-to-color($raw-theme-brand-success);
9$theme-gray-light: #818a91; 5$theme-brand-info: convert-rgb-string-to-color($raw-theme-brand-info);
10$theme-gray-lighter: #eceeef; 6$theme-brand-warning: convert-rgb-string-to-color($raw-theme-brand-warning);
11$theme-gray-lightest: #f7f7f9; 7$theme-brand-danger: convert-rgb-string-to-color($raw-theme-brand-danger);
12 8
13$theme-border-radius: 6px; 9$theme-gray-dark: convert-rgb-string-to-color($raw-theme-gray-dark);
14$theme-border-radius-small: 3px; 10$theme-gray: convert-rgb-string-to-color($raw-theme-gray);
11$theme-gray-light: convert-rgb-string-to-color($raw-theme-gray-light);
12$theme-gray-lighter: convert-rgb-string-to-color($raw-theme-gray-lighter);
13$theme-gray-lightest: convert-rgb-string-to-color($raw-theme-gray-lightest);
15 14
16$theme-sidebar-width: 68px; 15$theme-border-radius: to-number($raw-theme-border-radius);
16$theme-border-radius-small: to-number($raw-theme-border-radius-small);
17 17
18$theme-text-color: $theme-gray-dark; 18$theme-sidebar-width: to-number($raw-theme-sidebar-width);
19
20$theme-text-color: convert-rgb-string-to-color($raw-theme-gray-dark);
19 21
20$theme-transition-time: .5s; 22$theme-transition-time: .5s;
21 23
22$theme-inset-shadow: inset 0 2px 5px rgba(0, 0, 0, .03); 24$theme-inset-shadow: inset 0 2px 5px rgba(0, 0, 0, .03);
23 25
24// Dark Theme 26// Dark Theme
25$dark-theme-black: #1A1A1A; 27$dark-theme-black: convert-rgb-string-to-color($raw-dark-theme-black);
26 28
27$dark-theme-gray-darkest: #1E1E1E; 29$dark-theme-gray-darkest: convert-rgb-string-to-color($raw-dark-theme-gray-darkest);
28$dark-theme-gray-darker: #2D2F31; 30$dark-theme-gray-darker: convert-rgb-string-to-color($raw-dark-theme-gray-darker);
29$dark-theme-gray-dark: #383A3B; 31$dark-theme-gray-dark: convert-rgb-string-to-color($raw-dark-theme-gray-dark);
30 32
31$dark-theme-gray: #47494B; 33$dark-theme-gray: convert-rgb-string-to-color($raw-dark-theme-gray);
32 34
33$dark-theme-gray-light: #515355; 35$dark-theme-gray-light: convert-rgb-string-to-color($raw-dark-theme-gray-light);
34$dark-theme-gray-lighter: #8a8b8b; 36$dark-theme-gray-lighter: convert-rgb-string-to-color($raw-dark-theme-gray-lighter);
35$dark-theme-gray-lightest: #FFF; 37$dark-theme-gray-lightest: convert-rgb-string-to-color($raw-dark-theme-gray-lightest);
36 38
37$dark-theme-gray-smoke: #CED0D1; 39$dark-theme-gray-smoke: convert-rgb-string-to-color($raw-dark-theme-gray-smoke);
38$dark-theme-text-color: #FFF; 40$dark-theme-text-color: convert-rgb-string-to-color($raw-dark-theme-text-color);
diff --git a/src/styles/type-helper.scss b/src/styles/type-helper.scss
new file mode 100644
index 000000000..b1da394b5
--- /dev/null
+++ b/src/styles/type-helper.scss
@@ -0,0 +1,100 @@
1@function str-split($string, $separator) {
2 // empty array/list
3 $split-arr: ();
4 // first index of separator in string
5 $index : str-index($string, $separator);
6 // loop through string
7 @while $index != null {
8 // get the substring from the first character to the separator
9 $item: str-slice($string, 1, $index - 1);
10 // push item to array
11 $split-arr: append($split-arr, $item);
12 // remove item and separator from string
13 $string: str-slice($string, $index + 1);
14 // find new index of separator
15 $index : str-index($string, $separator);
16 }
17 // add the remaining string to list (the last item)
18 $split-arr: append($split-arr, $string);
19
20 @return $split-arr;
21}
22
23// ----
24// Sass (v3.4.13)
25// Compass (v1.0.3)
26// ----
27
28/// String to number converter
29/// @author Hugo Giraudel
30/// @access private
31
32
33/// Casts a string into a number
34///
35/// @param {String | Number} $value - Value to be parsed
36///
37/// @return {Number}
38
39@function to-number($value) {
40 @if type-of($value) == 'number' {
41 @return $value;
42 } @else if type-of($value) != 'string' {
43 $_: log('Value for `to-number` should be a number or a string.');
44 }
45
46 $result: 0;
47 $digits: 0;
48 $minus: str-slice($value, 1, 1) == '-';
49 $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
50
51 @for $i from if($minus, 2, 1) through str-length($value) {
52 $character: str-slice($value, $i, $i);
53
54 @if not (index(map-keys($numbers), $character) or $character == '.') {
55 @return to-length(if($minus, -$result, $result), str-slice($value, $i))
56 }
57
58 @if $character == '.' {
59 $digits: 1;
60 } @else if $digits == 0 {
61 $result: $result * 10 + map-get($numbers, $character);
62 } @else {
63 $digits: $digits * 10;
64 $result: $result + map-get($numbers, $character) / $digits;
65 }
66 }
67
68 @return if($minus, -$result, $result);;
69}
70
71
72/// Add `$unit` to `$value`
73///
74/// @param {Number} $value - Value to add unit to
75/// @param {String} $unit - String representation of the unit
76///
77/// @return {Number} - `$value` expressed in `$unit`
78@function to-length($value, $unit) {
79 $units: ('px': 1px, 'cm': 1cm, 'mm': 1mm, '%': 1%, 'ch': 1ch, 'pc': 1pc, 'in': 1in, 'em': 1em, 'rem': 1rem, 'pt': 1pt, 'ex': 1ex, 'vw': 1vw, 'vh': 1vh, 'vmin': 1vmin, 'vmax': 1vmax);
80
81 @if not index(map-keys($units), $unit) {
82 $_: log('Invalid unit `#{$unit}`.');
83 }
84
85 @return $value * map-get($units, $unit);
86}
87
88
89
90/// converts injectes rgb strings to sass colors
91@function convert-rgb-string-to-color($string) {
92 $values: str-split($string, ',');
93 $colorList: ();
94 @each $value in $values {
95 $colorList: append($colorList, to-number($value));
96 }
97
98 $rgbaColor: rgb(nth($colorList, 1), nth($colorList, 2), nth($colorList, 3));
99 @return $rgbaColor;
100} \ No newline at end of file
diff --git a/src/theme/dark/index.js b/src/theme/dark/index.js
new file mode 100644
index 000000000..e0e017c7c
--- /dev/null
+++ b/src/theme/dark/index.js
@@ -0,0 +1,5 @@
1import * as legacyStyles from '../default/legacy';
2
3export const colorBackground = legacyStyles.darkThemeGrayDarkest;
4
5export const colorHeadline = legacyStyles.darkThemeTextColor;
diff --git a/src/theme/default/index.js b/src/theme/default/index.js
new file mode 100644
index 000000000..f8b6e898d
--- /dev/null
+++ b/src/theme/default/index.js
@@ -0,0 +1,12 @@
1import * as legacyStyles from './legacy';
2
3/* legacy config, injected into sass */
4export const themeBrandPrimary = '#3498db';
5export const themeBrandSuccess = '#5cb85c';
6export const themeBrandInfo = '#5bc0de';
7export const themeBrandWarning = '#FF9F00';
8export const themeBrandDanger = '#d9534f';
9
10export const colorBackground = legacyStyles.themeGrayLighter;
11
12export const colorHeadline = legacyStyles.themeGrayDark;
diff --git a/src/theme/default/legacy.js b/src/theme/default/legacy.js
new file mode 100644
index 000000000..b676dc1d9
--- /dev/null
+++ b/src/theme/default/legacy.js
@@ -0,0 +1,39 @@
1/* legacy config, injected into sass */
2export const themeBrandPrimary = '#3498db';
3export const themeBrandSuccess = '#5cb85c';
4export const themeBrandInfo = '#5bc0de';
5export const themeBrandWarning = '#FF9F00';
6export const themeBrandDanger = '#d9534f';
7
8export const themeGrayDark = '#373a3c';
9export const themeGray = '#55595c';
10export const themeGrayLight = '#818a91';
11export const themeGrayLighter = '#eceeef';
12export const themeGrayLightest = '#f7f7f9';
13
14export const themeBorderRadius = '6px';
15export const themeBorderRadiusSmall = '3px';
16
17export const themeSidebarWidth = '68px';
18
19export const themeTextColor = themeGrayDark;
20
21export const themeTransitionTime = '.5s';
22
23export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)';
24
25
26export const darkThemeBlack = '#1A1A1A';
27
28export const darkThemeGrayDarkest = '#1E1E1E';
29export const darkThemeGrayDarker = '#2D2F31';
30export const darkThemeGrayDark = '#383A3B';
31
32export const darkThemeGray = '#47494B';
33
34export const darkThemeGrayLight = '#515355';
35export const darkThemeGrayLighter = '#8a8b8b';
36export const darkThemeGrayLightest = '#FFFFFF';
37
38export const darkThemeGraySmoke = '#CED0D1';
39export const darkThemeTextColor = '#FFFFFF';