From 4ea044ae6b2e27e48d45bc3be1c366f4882bbda5 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Sat, 24 Nov 2018 20:15:39 +0100 Subject: feat(App): Lay groundwork for general themeing support --- .../settings/navigation/SettingsNavigation.js | 3 +- src/containers/layout/AppLayoutContainer.js | 43 ++++----- src/stores/UIStore.js | 10 +++ src/styles/colors.scss | 50 ++++++----- src/styles/type-helper.scss | 100 +++++++++++++++++++++ src/theme/dark/index.js | 5 ++ src/theme/default/index.js | 12 +++ src/theme/default/legacy.js | 39 ++++++++ 8 files changed, 216 insertions(+), 46 deletions(-) create mode 100644 src/styles/type-helper.scss create mode 100644 src/theme/dark/index.js create mode 100644 src/theme/default/index.js create mode 100644 src/theme/default/legacy.js (limited to 'src') 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({ }, }); -@inject('stores') @observer -export default class SettingsNavigation extends Component { +export default @inject('stores') @observer class SettingsNavigation extends Component { static propTypes = { serviceCount: PropTypes.number.isRequired, }; 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 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; +import { ThemeProvider } from 'react-jss'; import AppStore from '../../stores/AppStore'; import RecipesStore from '../../stores/RecipesStore'; @@ -109,26 +110,28 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e ); return ( - - {React.Children.count(children) > 0 ? children : null} - + + + {React.Children.count(children) > 0 ? children : null} + + ); } } 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 @@ import { action, observable, computed } from 'mobx'; import Store from './lib/Store'; +import * as themeDefault from '../theme/default'; +import * as themeDark from '../theme/dark'; export default class UIStore extends Store { @observable showServicesUpdatedInfoBar = false; @@ -20,6 +22,14 @@ export default class UIStore extends Store { return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; } + @computed get theme() { + if (this.stores.settings.all.app.darkMode) { + return Object.assign({}, themeDefault, themeDark); + } + + return themeDefault; + } + // Actions @action _openSettings({ path = '/settings' }) { 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 @@ -$theme-brand-primary: #3498db; -$theme-brand-success: #5cb85c; -$theme-brand-info: #5bc0de; -$theme-brand-warning: #FF9F00; -$theme-brand-danger: #d9534f; +@import "./type-helper"; -$theme-gray-dark: #373a3c; -$theme-gray: #55595c; -$theme-gray-light: #818a91; -$theme-gray-lighter: #eceeef; -$theme-gray-lightest: #f7f7f9; +$theme-brand-primary: convert-rgb-string-to-color($raw-theme-brand-primary); +$theme-brand-success: convert-rgb-string-to-color($raw-theme-brand-success); +$theme-brand-info: convert-rgb-string-to-color($raw-theme-brand-info); +$theme-brand-warning: convert-rgb-string-to-color($raw-theme-brand-warning); +$theme-brand-danger: convert-rgb-string-to-color($raw-theme-brand-danger); -$theme-border-radius: 6px; -$theme-border-radius-small: 3px; +$theme-gray-dark: convert-rgb-string-to-color($raw-theme-gray-dark); +$theme-gray: convert-rgb-string-to-color($raw-theme-gray); +$theme-gray-light: convert-rgb-string-to-color($raw-theme-gray-light); +$theme-gray-lighter: convert-rgb-string-to-color($raw-theme-gray-lighter); +$theme-gray-lightest: convert-rgb-string-to-color($raw-theme-gray-lightest); -$theme-sidebar-width: 68px; +$theme-border-radius: to-number($raw-theme-border-radius); +$theme-border-radius-small: to-number($raw-theme-border-radius-small); -$theme-text-color: $theme-gray-dark; +$theme-sidebar-width: to-number($raw-theme-sidebar-width); + +$theme-text-color: convert-rgb-string-to-color($raw-theme-gray-dark); $theme-transition-time: .5s; $theme-inset-shadow: inset 0 2px 5px rgba(0, 0, 0, .03); // Dark Theme -$dark-theme-black: #1A1A1A; +$dark-theme-black: convert-rgb-string-to-color($raw-dark-theme-black); -$dark-theme-gray-darkest: #1E1E1E; -$dark-theme-gray-darker: #2D2F31; -$dark-theme-gray-dark: #383A3B; +$dark-theme-gray-darkest: convert-rgb-string-to-color($raw-dark-theme-gray-darkest); +$dark-theme-gray-darker: convert-rgb-string-to-color($raw-dark-theme-gray-darker); +$dark-theme-gray-dark: convert-rgb-string-to-color($raw-dark-theme-gray-dark); -$dark-theme-gray: #47494B; +$dark-theme-gray: convert-rgb-string-to-color($raw-dark-theme-gray); -$dark-theme-gray-light: #515355; -$dark-theme-gray-lighter: #8a8b8b; -$dark-theme-gray-lightest: #FFF; +$dark-theme-gray-light: convert-rgb-string-to-color($raw-dark-theme-gray-light); +$dark-theme-gray-lighter: convert-rgb-string-to-color($raw-dark-theme-gray-lighter); +$dark-theme-gray-lightest: convert-rgb-string-to-color($raw-dark-theme-gray-lightest); -$dark-theme-gray-smoke: #CED0D1; -$dark-theme-text-color: #FFF; +$dark-theme-gray-smoke: convert-rgb-string-to-color($raw-dark-theme-gray-smoke); +$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 @@ +@function str-split($string, $separator) { + // empty array/list + $split-arr: (); + // first index of separator in string + $index : str-index($string, $separator); + // loop through string + @while $index != null { + // get the substring from the first character to the separator + $item: str-slice($string, 1, $index - 1); + // push item to array + $split-arr: append($split-arr, $item); + // remove item and separator from string + $string: str-slice($string, $index + 1); + // find new index of separator + $index : str-index($string, $separator); + } + // add the remaining string to list (the last item) + $split-arr: append($split-arr, $string); + + @return $split-arr; +} + +// ---- +// Sass (v3.4.13) +// Compass (v1.0.3) +// ---- + +/// String to number converter +/// @author Hugo Giraudel +/// @access private + + +/// Casts a string into a number +/// +/// @param {String | Number} $value - Value to be parsed +/// +/// @return {Number} + +@function to-number($value) { + @if type-of($value) == 'number' { + @return $value; + } @else if type-of($value) != 'string' { + $_: log('Value for `to-number` should be a number or a string.'); + } + + $result: 0; + $digits: 0; + $minus: str-slice($value, 1, 1) == '-'; + $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9); + + @for $i from if($minus, 2, 1) through str-length($value) { + $character: str-slice($value, $i, $i); + + @if not (index(map-keys($numbers), $character) or $character == '.') { + @return to-length(if($minus, -$result, $result), str-slice($value, $i)) + } + + @if $character == '.' { + $digits: 1; + } @else if $digits == 0 { + $result: $result * 10 + map-get($numbers, $character); + } @else { + $digits: $digits * 10; + $result: $result + map-get($numbers, $character) / $digits; + } + } + + @return if($minus, -$result, $result);; +} + + +/// Add `$unit` to `$value` +/// +/// @param {Number} $value - Value to add unit to +/// @param {String} $unit - String representation of the unit +/// +/// @return {Number} - `$value` expressed in `$unit` +@function to-length($value, $unit) { + $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); + + @if not index(map-keys($units), $unit) { + $_: log('Invalid unit `#{$unit}`.'); + } + + @return $value * map-get($units, $unit); +} + + + +/// converts injectes rgb strings to sass colors +@function convert-rgb-string-to-color($string) { + $values: str-split($string, ','); + $colorList: (); + @each $value in $values { + $colorList: append($colorList, to-number($value)); + } + + $rgbaColor: rgb(nth($colorList, 1), nth($colorList, 2), nth($colorList, 3)); + @return $rgbaColor; +} \ 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 @@ +import * as legacyStyles from '../default/legacy'; + +export const colorBackground = legacyStyles.darkThemeGrayDarkest; + +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 @@ +import * as legacyStyles from './legacy'; + +/* legacy config, injected into sass */ +export const themeBrandPrimary = '#3498db'; +export const themeBrandSuccess = '#5cb85c'; +export const themeBrandInfo = '#5bc0de'; +export const themeBrandWarning = '#FF9F00'; +export const themeBrandDanger = '#d9534f'; + +export const colorBackground = legacyStyles.themeGrayLighter; + +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 @@ +/* legacy config, injected into sass */ +export const themeBrandPrimary = '#3498db'; +export const themeBrandSuccess = '#5cb85c'; +export const themeBrandInfo = '#5bc0de'; +export const themeBrandWarning = '#FF9F00'; +export const themeBrandDanger = '#d9534f'; + +export const themeGrayDark = '#373a3c'; +export const themeGray = '#55595c'; +export const themeGrayLight = '#818a91'; +export const themeGrayLighter = '#eceeef'; +export const themeGrayLightest = '#f7f7f9'; + +export const themeBorderRadius = '6px'; +export const themeBorderRadiusSmall = '3px'; + +export const themeSidebarWidth = '68px'; + +export const themeTextColor = themeGrayDark; + +export const themeTransitionTime = '.5s'; + +export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)'; + + +export const darkThemeBlack = '#1A1A1A'; + +export const darkThemeGrayDarkest = '#1E1E1E'; +export const darkThemeGrayDarker = '#2D2F31'; +export const darkThemeGrayDark = '#383A3B'; + +export const darkThemeGray = '#47494B'; + +export const darkThemeGrayLight = '#515355'; +export const darkThemeGrayLighter = '#8a8b8b'; +export const darkThemeGrayLightest = '#FFFFFF'; + +export const darkThemeGraySmoke = '#CED0D1'; +export const darkThemeTextColor = '#FFFFFF'; -- cgit v1.2.3-70-g09d2