diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js index 86190eb10..d4dccf7c0 100644 --- a/app/soapbox/containers/soapbox.js +++ b/app/soapbox/containers/soapbox.js @@ -87,7 +87,7 @@ class SoapboxMount extends React.PureComponent { } render() { - const { me, themeCss, reduceMotion, systemFont, dyslexicFont, demetricator, locale } = this.props; + const { me, themeCss, locale } = this.props; if (me === null) return null; const { localeData, messages } = getLocale(); @@ -100,11 +100,11 @@ class SoapboxMount extends React.PureComponent { // return ; // } - const bodyClass = classNames('app-body', { - 'system-font': systemFont, - 'no-reduce-motion': !reduceMotion, - 'dyslexic': dyslexicFont, - 'demetricator': demetricator, + const bodyClass = classNames('app-body', `theme-mode-${this.props.themeMode}`, { + 'system-font': this.props.systemFont, + 'no-reduce-motion': !this.props.reduceMotion, + 'dyslexic': this.props.dyslexicFont, + 'demetricator': this.props.demetricator, }); return ( diff --git a/app/soapbox/reducers/theme.js b/app/soapbox/reducers/theme.js index 42f379b68..d87297e88 100644 --- a/app/soapbox/reducers/theme.js +++ b/app/soapbox/reducers/theme.js @@ -3,45 +3,19 @@ import { THEME_GENERATE, } from '../actions/theme'; import { Map as ImmutableMap } from 'immutable'; -import { brightness, hue, convert } from 'chromatism'; const initialState = ImmutableMap(); -const modes = ImmutableMap({ - light: ImmutableMap({ - 'primary-text-color': '#000000', - 'primary-text-color-faint': 'rgba(0,0,0,0.6)', - 'background-color': '#f2f2f2', - 'foreground-color': '#ffffff', - }), - dark: ImmutableMap({ - 'primary-text-color': '#ffffff', - 'primary-text-color-faint': 'rgba(255,255,255,0.6)', - 'background-color': '#333333', - 'foreground-color': '#222222', - }), -}); - -const cssrgba = (color, a) => { - const { r, g, b } = convert(color).rgb; - return `rgba(${[r, g, b, a].join(',')})`; -}; - -const makeContrast = (percent, color, mode) => { - percent = mode === 'light' ? -percent : percent; - return brightness(percent, color); -}; +const hex2rgb = c => c.substr(1).match(/../g).map(x => + `0x${x}`); export const generateTheme = (brandColor, mode = 'light') => { - if (!brandColor) return modes.get(mode); - return modes.get(mode).merge(ImmutableMap({ - 'brand-color': brandColor, - 'accent-color': brightness(10, hue(-3, brandColor).hex).hex, - 'brand-color-faint': cssrgba(brandColor, 0.1), - 'brand-color-med': cssrgba(brandColor, 0.2), - 'highlight-text-color': makeContrast(5, brandColor, mode).hex, - 'brand-color-hicontrast': makeContrast(15, brandColor, mode).hex, - })); + if (!brandColor) return false; + const [ r, g, b ] = hex2rgb(brandColor); + return ImmutableMap({ + 'brand-color-r': r, + 'brand-color-g': g, + 'brand-color-b': b, + }); }; export const setTheme = themeData => { diff --git a/app/styles/application.scss b/app/styles/application.scss index 0f5cfbe2d..3b5222fe1 100644 --- a/app/styles/application.scss +++ b/app/styles/application.scss @@ -1,4 +1,5 @@ @import 'mixins'; +@import 'themes'; @import 'variables'; @import 'fonts'; @import 'reset'; diff --git a/app/styles/themes.scss b/app/styles/themes.scss new file mode 100644 index 000000000..f6be5fadc --- /dev/null +++ b/app/styles/themes.scss @@ -0,0 +1,50 @@ +body { + --brand-color-rgb: var(--brand-color-r), var(--brand-color-g), var(--brand-color-b); + --brand-color: rgb(var(--brand-color-rgb)); + --brand-color-faint: rgba(var(--brand-color-rgb), 0.1); + --brand-color-med: rgba(var(--brand-color-rgb), 0.2); + --accent-color: rgb( + calc(var(--brand-color-r) + 25), + calc(var(--brand-color-g) + 25), + calc(var(--brand-color-b) + 25) + ); + --primary-text-color-rgb: var(--primary-text-color-r), var(--primary-text-color-g), var(--primary-text-color-b); + --primary-text-color: rgb(var(--primary-text-color-rgb)); + --primary-text-color-faint: rgba(var(--primary-text-color-rgb), 0.6); +} + +body.theme-mode-light { + --primary-text-color-r: 0; + --primary-text-color-g: 0; + --primary-text-color-b: 0; + --background-color: #f2f2f2; + --foreground-color: #ffffff; + --highlight-text-color: rgb( + calc(var(--brand-color-r) - 25), + calc(var(--brand-color-g) - 25), + calc(var(--brand-color-b) - 25) + ); + --brand-color-hicontrast: rgb( + calc(var(--brand-color-r) - 50), + calc(var(--brand-color-g) - 50), + calc(var(--brand-color-b) - 50) + ); +} + +body.theme-mode-dark { + --primary-text-color-r: 255; + --primary-text-color-g: 255; + --primary-text-color-b: 255; + --background-color: #333333; + --foreground-color: #222222; + --highlight-text-color: rgb( + calc(var(--brand-color-r) + 25), + calc(var(--brand-color-g) + 25), + calc(var(--brand-color-b) + 25) + ); + --brand-color-hicontrast: rgb( + calc(var(--brand-color-r) + 50), + calc(var(--brand-color-g) + 50), + calc(var(--brand-color-b) + 50) + ); +} diff --git a/package.json b/package.json index 9aafa764c..8e700dc41 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "babel-runtime": "^6.26.0", "blurhash": "^1.0.0", - "chromatism": "^3.0.0", "classnames": "^2.2.5", "compression-webpack-plugin": "^3.0.0", "cross-env": "^6.0.0", diff --git a/yarn.lock b/yarn.lock index 378e1fd67..8185280d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2445,11 +2445,6 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== -chromatism@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12" - integrity sha1-pySdNTweTzV35ESsQRccTi5iSxI= - chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"