diff options
author | Stefan Malzner <stefan@adlk.io> | 2018-11-24 20:15:39 +0100 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2018-11-24 20:15:39 +0100 |
commit | 4ea044ae6b2e27e48d45bc3be1c366f4882bbda5 (patch) | |
tree | d19064b7370cb66ef66407de082bedad4c3128d4 /src | |
parent | disable import/prefer-default-export (diff) | |
download | ferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.tar.gz ferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.tar.zst ferdium-app-4ea044ae6b2e27e48d45bc3be1c366f4882bbda5.zip |
feat(App): Lay groundwork for general themeing support
Diffstat (limited to 'src')
-rw-r--r-- | src/components/settings/navigation/SettingsNavigation.js | 3 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 43 | ||||
-rw-r--r-- | src/stores/UIStore.js | 10 | ||||
-rw-r--r-- | src/styles/colors.scss | 50 | ||||
-rw-r--r-- | src/styles/type-helper.scss | 100 | ||||
-rw-r--r-- | src/theme/dark/index.js | 5 | ||||
-rw-r--r-- | src/theme/default/index.js | 12 | ||||
-rw-r--r-- | src/theme/default/legacy.js | 39 |
8 files changed, 216 insertions, 46 deletions
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 | 35 | export default @inject('stores') @observer class SettingsNavigation extends Component { |
36 | export 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 @@ | |||
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
4 | import { ThemeProvider } from 'react-jss'; | ||
4 | 5 | ||
5 | import AppStore from '../../stores/AppStore'; | 6 | import AppStore from '../../stores/AppStore'; |
6 | import RecipesStore from '../../stores/RecipesStore'; | 7 | import 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 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { action, observable, computed } from 'mobx'; |
2 | 2 | ||
3 | import Store from './lib/Store'; | 3 | import Store from './lib/Store'; |
4 | import * as themeDefault from '../theme/default'; | ||
5 | import * as themeDark from '../theme/dark'; | ||
4 | 6 | ||
5 | export default class UIStore extends Store { | 7 | export 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 @@ | |||
1 | import * as legacyStyles from '../default/legacy'; | ||
2 | |||
3 | export const colorBackground = legacyStyles.darkThemeGrayDarkest; | ||
4 | |||
5 | export 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 @@ | |||
1 | import * as legacyStyles from './legacy'; | ||
2 | |||
3 | /* legacy config, injected into sass */ | ||
4 | export const themeBrandPrimary = '#3498db'; | ||
5 | export const themeBrandSuccess = '#5cb85c'; | ||
6 | export const themeBrandInfo = '#5bc0de'; | ||
7 | export const themeBrandWarning = '#FF9F00'; | ||
8 | export const themeBrandDanger = '#d9534f'; | ||
9 | |||
10 | export const colorBackground = legacyStyles.themeGrayLighter; | ||
11 | |||
12 | export 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 */ | ||
2 | export const themeBrandPrimary = '#3498db'; | ||
3 | export const themeBrandSuccess = '#5cb85c'; | ||
4 | export const themeBrandInfo = '#5bc0de'; | ||
5 | export const themeBrandWarning = '#FF9F00'; | ||
6 | export const themeBrandDanger = '#d9534f'; | ||
7 | |||
8 | export const themeGrayDark = '#373a3c'; | ||
9 | export const themeGray = '#55595c'; | ||
10 | export const themeGrayLight = '#818a91'; | ||
11 | export const themeGrayLighter = '#eceeef'; | ||
12 | export const themeGrayLightest = '#f7f7f9'; | ||
13 | |||
14 | export const themeBorderRadius = '6px'; | ||
15 | export const themeBorderRadiusSmall = '3px'; | ||
16 | |||
17 | export const themeSidebarWidth = '68px'; | ||
18 | |||
19 | export const themeTextColor = themeGrayDark; | ||
20 | |||
21 | export const themeTransitionTime = '.5s'; | ||
22 | |||
23 | export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)'; | ||
24 | |||
25 | |||
26 | export const darkThemeBlack = '#1A1A1A'; | ||
27 | |||
28 | export const darkThemeGrayDarkest = '#1E1E1E'; | ||
29 | export const darkThemeGrayDarker = '#2D2F31'; | ||
30 | export const darkThemeGrayDark = '#383A3B'; | ||
31 | |||
32 | export const darkThemeGray = '#47494B'; | ||
33 | |||
34 | export const darkThemeGrayLight = '#515355'; | ||
35 | export const darkThemeGrayLighter = '#8a8b8b'; | ||
36 | export const darkThemeGrayLightest = '#FFFFFF'; | ||
37 | |||
38 | export const darkThemeGraySmoke = '#CED0D1'; | ||
39 | export const darkThemeTextColor = '#FFFFFF'; | ||