From aa265d1d426396788d52e49b874e69e132510c74 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 20 Sep 2020 01:33:39 -0700 Subject: [PATCH] Dark mode. --- components/common/Button.module.css | 3 +- components/common/ButtonGroup.module.css | 4 +- components/common/Dropdown.module.css | 2 +- components/common/Link.module.css | 4 +- components/common/Menu.module.css | 4 +- components/common/Modal.module.css | 4 +- components/common/NavMenu.module.css | 2 + components/common/Toast.module.css | 2 +- components/common/WorldMap.js | 60 ++++++++++++------- components/common/WorldMap.module.css | 1 - components/forms/DatePickerForm.js | 2 +- components/layout/FormLayout.module.css | 2 +- components/layout/Header.js | 13 ++-- components/layout/Layout.js | 2 +- components/layout/Layout.module.css | 6 ++ components/metrics/BarChart.js | 26 +++++++- components/metrics/BarChart.module.css | 2 +- components/metrics/MetricsTable.module.css | 2 +- .../{common => settings}/LanguageButton.js | 4 +- .../LanguageButton.module.css | 0 components/settings/ThemeButton.js | 13 ++++ components/settings/TimezoneSetting.js | 4 +- hooks/useLocale.js | 8 +-- hooks/useTheme.js | 21 +++++++ lib/constants.js | 32 ++++++++++ package.json | 2 +- redux/actions/app.js | 17 ++++-- styles/index.css | 10 +++- styles/variables.css | 29 +++++++++ 29 files changed, 221 insertions(+), 60 deletions(-) create mode 100644 components/layout/Layout.module.css rename components/{common => settings}/LanguageButton.js (95%) rename components/{common => settings}/LanguageButton.module.css (100%) create mode 100644 components/settings/ThemeButton.js create mode 100644 hooks/useTheme.js diff --git a/components/common/Button.module.css b/components/common/Button.module.css index faae656b..351f5ecc 100644 --- a/components/common/Button.module.css +++ b/components/common/Button.module.css @@ -3,6 +3,7 @@ justify-content: center; align-items: center; font-size: var(--font-size-normal); + color: var(--gray900); background: var(--gray100); padding: 8px 16px; border-radius: 4px; @@ -18,7 +19,7 @@ } .button:active { - color: initial; + color: var(--gray700); } .large { diff --git a/components/common/ButtonGroup.module.css b/components/common/ButtonGroup.module.css index d18a8e9c..bc60f8d3 100644 --- a/components/common/ButtonGroup.module.css +++ b/components/common/ButtonGroup.module.css @@ -7,6 +7,7 @@ .group .button { border-radius: 0; + color: var(--gray800); background: var(--gray50); border-left: 1px solid var(--gray500); padding: 4px 8px; @@ -24,6 +25,7 @@ margin: 0; } -.selected { +.group .button.selected { + color: var(--gray900); font-weight: 600; } diff --git a/components/common/Dropdown.module.css b/components/common/Dropdown.module.css index 250e6c29..4b94f58f 100644 --- a/components/common/Dropdown.module.css +++ b/components/common/Dropdown.module.css @@ -20,5 +20,5 @@ } .icon { - padding-left: 10px; + padding-left: 20px; } diff --git a/components/common/Link.module.css b/components/common/Link.module.css index d6dc0536..24d8f84c 100644 --- a/components/common/Link.module.css +++ b/components/common/Link.module.css @@ -2,7 +2,7 @@ a.link, a.link:active, a.link:visited { position: relative; - color: #2c2c2c; + color: var(--gray900); text-decoration: none; } @@ -12,7 +12,7 @@ a.link:before { bottom: -2px; width: 0; height: 2px; - background: #2680eb; + background: var(--primary400); opacity: 0.5; transition: width 100ms; } diff --git a/components/common/Menu.module.css b/components/common/Menu.module.css index 9bcd642f..65551837 100644 --- a/components/common/Menu.module.css +++ b/components/common/Menu.module.css @@ -8,14 +8,14 @@ .option { font-size: var(--font-size-small); font-weight: normal; - background: #fff; + background: var(--gray50); padding: 4px 16px; cursor: pointer; white-space: nowrap; } .option:hover { - background: #f5f5f5; + background: var(--gray100); } .float { diff --git a/components/common/Modal.module.css b/components/common/Modal.module.css index 3702e774..bf2491c7 100644 --- a/components/common/Modal.module.css +++ b/components/common/Modal.module.css @@ -16,8 +16,8 @@ right: 0; bottom: 0; margin: auto; - background: var(--gray900); - opacity: 0.1; + background: #000; + opacity: 0.5; } .content { diff --git a/components/common/NavMenu.module.css b/components/common/NavMenu.module.css index c5d6c9db..7be73973 100644 --- a/components/common/NavMenu.module.css +++ b/components/common/NavMenu.module.css @@ -1,4 +1,5 @@ .menu { + color: var(--gray800); border: 1px solid var(--gray500); border-radius: 4px; overflow: hidden; @@ -16,5 +17,6 @@ } .selected { + color: var(--gray900); font-weight: 600; } diff --git a/components/common/Toast.module.css b/components/common/Toast.module.css index bfcd26bb..a65abfd1 100644 --- a/components/common/Toast.module.css +++ b/components/common/Toast.module.css @@ -9,7 +9,7 @@ justify-content: space-between; align-items: center; padding: 8px 16px; - color: var(--gray50); + color: var(--msgColor); background: var(--green400); margin: auto; z-index: 2; diff --git a/components/common/WorldMap.js b/components/common/WorldMap.js index f10dd542..f6eec8d6 100644 --- a/components/common/WorldMap.js +++ b/components/common/WorldMap.js @@ -1,44 +1,57 @@ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import ReactTooltip from 'react-tooltip'; +import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; import classNames from 'classnames'; import tinycolor from 'tinycolor2'; -import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; +import useTheme from 'hooks/useTheme'; +import { THEME_COLORS } from 'lib/constants'; import styles from './WorldMap.module.css'; const geoUrl = '/world-110m.json'; -export default function WorldMap({ - data, - className, - baseColor = '#e9f3fd', - fillColor = '#f5f5f5', - strokeColor = '#2680eb', - hoverColor = '#2680eb', -}) { +export default function WorldMap({ data, className }) { const [tooltip, setTooltip] = useState(); + const [theme] = useTheme(); + const colors = useMemo( + () => ({ + baseColor: THEME_COLORS[theme].primary, + fillColor: THEME_COLORS[theme].gray100, + strokeColor: THEME_COLORS[theme].primary, + hoverColor: THEME_COLORS[theme].primary, + }), + [theme], + ); function getFillColor(code) { - if (code === 'AQ') return '#ffffff'; + if (code === 'AQ') return; const country = data?.find(({ x }) => x === code); - return country ? tinycolor(baseColor).darken(country.z) : fillColor; + + if (!country) { + return colors.fillColor; + } + + return tinycolor(colors.baseColor)[theme === 'light' ? 'lighten' : 'darken']( + 40 * (1.0 - country.z / 100), + ); } - function getStrokeColor(code) { - return code === 'AQ' ? '#ffffff' : strokeColor; - } - - function getHoverColor(code) { - return code === 'AQ' ? '#ffffff' : hoverColor; + function getOpacity(code) { + return code === 'AQ' ? 0 : 1; } function handleHover({ ISO_A2: code, NAME: name }) { + if (code === 'AQ') return; const country = data?.find(({ x }) => x === code); setTooltip(`${name}: ${country?.y || 0} visitors`); } return ( -
- +
+ {({ geographies }) => { @@ -50,10 +63,11 @@ export default function WorldMap({ key={geo.rsmKey} geography={geo} fill={getFillColor(code)} - stroke={getStrokeColor(code)} + stroke={colors.strokeColor} + opacity={getOpacity(code)} style={{ default: { outline: 'none' }, - hover: { outline: 'none', fill: getHoverColor(code) }, + hover: { outline: 'none', fill: colors.hoverColor }, pressed: { outline: 'none' }, }} onMouseOver={() => handleHover(geo.properties)} @@ -65,7 +79,7 @@ export default function WorldMap({ - {tooltip} + {tooltip}
); } diff --git a/components/common/WorldMap.module.css b/components/common/WorldMap.module.css index bf84d697..c2528038 100644 --- a/components/common/WorldMap.module.css +++ b/components/common/WorldMap.module.css @@ -1,5 +1,4 @@ .container { overflow: hidden; position: relative; - background: #fff; } diff --git a/components/forms/DatePickerForm.js b/components/forms/DatePickerForm.js index f8b6416e..673cd7bd 100644 --- a/components/forms/DatePickerForm.js +++ b/components/forms/DatePickerForm.js @@ -6,7 +6,7 @@ import Button from 'components/common/Button'; import { FormButtons } from 'components/layout/FormLayout'; import { getDateRangeValues } from 'lib/date'; import styles from './DatePickerForm.module.css'; -import ButtonGroup from '../common/ButtonGroup'; +import ButtonGroup from 'components/common/ButtonGroup'; const FILTER_DAY = 0; const FILTER_RANGE = 1; diff --git a/components/layout/FormLayout.module.css b/components/layout/FormLayout.module.css index 0b82ee7c..90e1b8c2 100644 --- a/components/layout/FormLayout.module.css +++ b/components/layout/FormLayout.module.css @@ -39,7 +39,7 @@ } .msg { - color: var(--gray50); + color: var(--msgColor); background: var(--red400); font-size: var(--font-size-small); padding: 4px 8px; diff --git a/components/layout/Header.js b/components/layout/Header.js index f275bda3..46c9b3e4 100644 --- a/components/layout/Header.js +++ b/components/layout/Header.js @@ -3,11 +3,12 @@ import { FormattedMessage } from 'react-intl'; import { useSelector } from 'react-redux'; import classNames from 'classnames'; import Link from 'components/common/Link'; -import UserButton from '../common/UserButton'; -import Icon from '../common/Icon'; +import UserButton from 'components/common/UserButton'; +import Icon from 'components/common/Icon'; +import LanguageButton from 'components/settings/LanguageButton'; +import ThemeButton from 'components/settings/ThemeButton'; import Logo from 'assets/logo.svg'; import styles from './Header.module.css'; -import LanguageButton from '../common/LanguageButton'; export default function Header() { const user = useSelector(state => state.user); @@ -32,10 +33,14 @@ export default function Header() { + ) : ( - + <> + + + )}
diff --git a/components/layout/Layout.js b/components/layout/Layout.js index 021745cc..b16a0717 100644 --- a/components/layout/Layout.js +++ b/components/layout/Layout.js @@ -16,8 +16,8 @@ export default function Layout({ title, children, header = true, footer = true } {header &&
}
{children}
-
{footer &&