From 6319a8c6e0774d3ce7716521a3a565fee67fe25d Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 20 Sep 2020 21:31:53 -0700 Subject: [PATCH] Refactored menu buttons. --- components/common/DropDown.js | 9 ++- components/common/Menu.js | 3 +- components/common/Menu.module.css | 4 ++ components/common/MenuButton.js | 58 +++++++++++++++++++ .../MenuButton.module.css} | 0 components/common/UserButton.module.css | 25 -------- components/layout/Header.js | 2 +- components/settings/LanguageButton.js | 50 ++++------------ components/settings/ThemeButton.js | 4 +- components/{common => settings}/UserButton.js | 45 +++----------- components/settings/UserButton.module.css | 7 +++ lib/lang.js | 24 ++++---- package.json | 2 +- 13 files changed, 114 insertions(+), 119 deletions(-) create mode 100644 components/common/MenuButton.js rename components/{settings/LanguageButton.module.css => common/MenuButton.module.css} (100%) delete mode 100644 components/common/UserButton.module.css rename components/{common => settings}/UserButton.js (52%) create mode 100644 components/settings/UserButton.module.css diff --git a/components/common/DropDown.js b/components/common/DropDown.js index df559ef9..b6b2357b 100644 --- a/components/common/DropDown.js +++ b/components/common/DropDown.js @@ -15,6 +15,7 @@ export default function DropDown({ }) { const [showMenu, setShowMenu] = useState(false); const ref = useRef(); + const selectedOption = options.find(e => e.value === value); function handleShowMenu() { setShowMenu(state => !state); @@ -40,7 +41,13 @@ export default function DropDown({ } className={styles.icon} size="small" /> {showMenu && ( - + )} ); diff --git a/components/common/Menu.js b/components/common/Menu.js index 283ee1fb..6421ba55 100644 --- a/components/common/Menu.js +++ b/components/common/Menu.js @@ -33,7 +33,8 @@ export default function Menu({
onSelect(value, e)} diff --git a/components/common/Menu.module.css b/components/common/Menu.module.css index 65551837..369e37c8 100644 --- a/components/common/Menu.module.css +++ b/components/common/Menu.module.css @@ -44,3 +44,7 @@ .divider { border-top: 1px solid var(--gray300); } + +.selected { + font-weight: 600; +} diff --git a/components/common/MenuButton.js b/components/common/MenuButton.js new file mode 100644 index 00000000..4798ab1d --- /dev/null +++ b/components/common/MenuButton.js @@ -0,0 +1,58 @@ +import React, { useState, useRef } from 'react'; +import classNames from 'classnames'; +import Menu from 'components/common/Menu'; +import Button from 'components/common/Button'; +import useDocumentClick from 'hooks/useDocumentClick'; +import styles from './MenuButton.module.css'; + +export default function MenuButton({ + icon, + value, + options, + menuPosition = 'bottom', + menuAlign = 'right', + onSelect, + renderValue, +}) { + const [showMenu, setShowMenu] = useState(false); + const ref = useRef(); + const selectedOption = options.find(e => e.value === value); + + function handleSelect(value) { + onSelect(value); + setShowMenu(false); + } + + function toggleMenu() { + setShowMenu(state => !state); + } + + useDocumentClick(e => { + if (!ref.current.contains(e.target)) { + setShowMenu(false); + } + }); + + return ( +
+ + {showMenu && ( + + )} +
+ ); +} diff --git a/components/settings/LanguageButton.module.css b/components/common/MenuButton.module.css similarity index 100% rename from components/settings/LanguageButton.module.css rename to components/common/MenuButton.module.css diff --git a/components/common/UserButton.module.css b/components/common/UserButton.module.css deleted file mode 100644 index a0b2c2ab..00000000 --- a/components/common/UserButton.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.container { - display: flex; - position: relative; - cursor: pointer; -} - -.username { - border-bottom: 1px solid var(--gray500); -} - -.username:hover { - background: var(--gray50); -} - -.menu { - z-index: 100; -} - -.open { - background: var(--gray200); -} - -.open:hover { - background: var(--gray200); -} diff --git a/components/layout/Header.js b/components/layout/Header.js index ee027ee9..639db7ea 100644 --- a/components/layout/Header.js +++ b/components/layout/Header.js @@ -3,10 +3,10 @@ import { FormattedMessage } from 'react-intl'; import { useSelector } from 'react-redux'; import classNames from 'classnames'; import Link from 'components/common/Link'; -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 UserButton from 'components/settings/UserButton'; import Logo from 'assets/logo.svg'; import styles from './Header.module.css'; diff --git a/components/settings/LanguageButton.js b/components/settings/LanguageButton.js index 63a09712..e643f070 100644 --- a/components/settings/LanguageButton.js +++ b/components/settings/LanguageButton.js @@ -1,35 +1,17 @@ -import React, { useState, useRef } from 'react'; -import classNames from 'classnames'; +import React from 'react'; import Head from 'next/head'; -import Menu from 'components/common/Menu'; -import Button from 'components/common/Button'; import { menuOptions } from 'lib/lang'; import useLocale from 'hooks/useLocale'; -import useDocumentClick from 'hooks/useDocumentClick'; +import MenuButton from 'components/common/MenuButton'; import Globe from 'assets/globe.svg'; -import styles from './LanguageButton.module.css'; -export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'left' }) { - const [showMenu, setShowMenu] = useState(false); +export default function LanguageButton() { const [locale, setLocale] = useLocale(); - const ref = useRef(); - const selectedLocale = menuOptions.find(e => e.value === locale)?.display; function handleSelect(value) { setLocale(value); - setShowMenu(false); } - function toggleMenu() { - setShowMenu(state => !state); - } - - useDocumentClick(e => { - if (!ref.current.contains(e.target)) { - setShowMenu(false); - } - }); - return ( <> @@ -46,25 +28,13 @@ export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'l /> )} -
- - {showMenu && ( - - )} -
+ } + options={menuOptions} + value={locale} + renderValue={option => option?.display} + onSelect={handleSelect} + /> ); } diff --git a/components/settings/ThemeButton.js b/components/settings/ThemeButton.js index 2c036079..a31440b7 100644 --- a/components/settings/ThemeButton.js +++ b/components/settings/ThemeButton.js @@ -13,12 +13,12 @@ export default function ThemeButton() { const transitions = useTransition(theme, theme => theme, { from: { opacity: 0, - transform: `translateY(${theme === 'light' ? '-20px' : '20px'}) scale(0.5)`, + transform: `translateY(${theme === 'light' ? '20px' : '-20px'}) scale(0.5)`, }, enter: { opacity: 1, transform: 'translateY(0px) scale(1)' }, leave: { opacity: 0, - transform: `translateY(${theme === 'light' ? '20px' : '-20px'}) scale(0.5)`, + transform: `translateY(${theme === 'light' ? '-20px' : '20px'}) scale(0.5)`, }, }); diff --git a/components/common/UserButton.js b/components/settings/UserButton.js similarity index 52% rename from components/common/UserButton.js rename to components/settings/UserButton.js index a4e70276..c7604cb5 100644 --- a/components/common/UserButton.js +++ b/components/settings/UserButton.js @@ -1,20 +1,15 @@ -import React, { useState, useRef } from 'react'; +import React from 'react'; import { FormattedMessage } from 'react-intl'; import { useSelector } from 'react-redux'; import { useRouter } from 'next/router'; -import Menu from './Menu'; -import Icon from './Icon'; -import Button from './Button'; -import useDocumentClick from 'hooks/useDocumentClick'; +import MenuButton from 'components/common/MenuButton'; +import Icon from 'components/common/Icon'; import User from 'assets/user.svg'; import Chevron from 'assets/chevron-down.svg'; import styles from './UserButton.module.css'; -import classNames from 'classnames'; export default function UserButton() { - const [showMenu, setShowMenu] = useState(false); const user = useSelector(state => state.user); - const ref = useRef(); const router = useRouter(); const menuOptions = [ @@ -34,8 +29,6 @@ export default function UserButton() { ]; function handleSelect(value) { - setShowMenu(false); - if (value === 'logout') { router.push('/logout'); } else if (value === 'profile') { @@ -43,32 +36,12 @@ export default function UserButton() { } } - useDocumentClick(e => { - if (!ref.current.contains(e.target)) { - setShowMenu(false); - } - }); - return ( -
- - {showMenu && ( - - )} -
+ } size="large" />} + value={} size="small" />} + options={menuOptions} + onSelect={handleSelect} + /> ); } diff --git a/components/settings/UserButton.module.css b/components/settings/UserButton.module.css new file mode 100644 index 00000000..dbb616ff --- /dev/null +++ b/components/settings/UserButton.module.css @@ -0,0 +1,7 @@ +.username { + border-bottom: 1px solid var(--gray500); +} + +.username:hover { + background: var(--gray50); +} diff --git a/lib/lang.js b/lib/lang.js index 54dfa6de..58c38e33 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -44,18 +44,18 @@ export const dateLocales = { }; export const menuOptions = [ - { label: 'English', value: 'en-US', display: 'EN' }, - { label: '中文', value: 'zh-CN', display: 'CN' }, - { label: 'Dansk', value: 'da-DK', display: 'DA' }, - { label: 'Deutsch', value: 'de-DE', display: 'DE' }, - { label: 'Español', value: 'es-MX', display: 'ES' }, - { label: 'Français', value: 'fr-FR', display: 'FR' }, - { label: '日本語', value: 'ja-JP', display: 'JA' }, - { label: 'Монгол', value: 'mn-MN', display: 'MN' }, - { label: 'Nederlands', value: 'nl-NL', display: 'NL' }, - { label: 'Русский', value: 'ru-RU', display: 'RU' }, - { label: 'Svenska', value: 'sv-SE', display: 'SV' }, - { label: 'Turkish', value: 'tr-TR', display: 'TR' }, + { label: 'English', value: 'en-US', display: 'en' }, + { label: '中文', value: 'zh-CN', display: 'cn' }, + { label: 'Dansk', value: 'da-DK', display: 'da' }, + { label: 'Deutsch', value: 'de-DE', display: 'de' }, + { label: 'Español', value: 'es-MX', display: 'es' }, + { label: 'Français', value: 'fr-FR', display: 'fr' }, + { label: '日本語', value: 'ja-JP', display: 'ja' }, + { label: 'Монгол', value: 'mn-MN', display: 'mn' }, + { label: 'Nederlands', value: 'nl-NL', display: 'nl' }, + { label: 'Русский', value: 'ru-RU', display: 'ru' }, + { label: 'Svenska', value: 'sv-SE', display: 'sv' }, + { label: 'Turkish', value: 'tr-TR', display: 'tr' }, ]; export function dateFormat(date, str, locale) { diff --git a/package.json b/package.json index a87cb324..fdcd512b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.45.0", + "version": "0.46.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT",