diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a2cc7..2a12d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ ### Releases +## v1.1.0 +###### *Dec 6, 2020* + +- package.json: update `recoil` version to 0.1.2 +- components: + - Divider: add property `withoutMargins`, change margins based on `orientation` + - Loading: add first class property `position` + - NotFound: add 404 gif from `giphy`, move from `Box` to `Fb` + - Link: fix `export default` style + - Fb: create flexbox component + ## v1.0.2 ###### *Sep 7, 2020* diff --git a/src/App.js b/src/App.js index 2db6e2f..2d0c251 100644 --- a/src/App.js +++ b/src/App.js @@ -2,12 +2,12 @@ import React from 'react'; import { RecoilRoot } from 'recoil'; import CssBaseline from '@material-ui/core/CssBaseline'; -import Box from '@material-ui/core/Box'; import withErrorHandler from 'errorHandling'; import { App as ErrorBoundaryFallback } from 'errorHandling/Fallbacks'; import Layout from 'sections/Layout'; +import Fb from 'components/Fb'; import { ThemeProvider } from 'theme'; import { BrowserRouter as Router } from 'react-router-dom'; @@ -16,12 +16,12 @@ function App() { return ( - + - + ); diff --git a/src/components/Page/styles.js b/src/components/Page/styles.js index 7af1bb8..5ab1c54 100644 --- a/src/components/Page/styles.js +++ b/src/components/Page/styles.js @@ -1,6 +1,6 @@ import { makeStyles } from '@material-ui/core/styles'; -import { isMobile } from 'utils'; +import isMobile from 'utils/isMobile'; const useStyles = makeStyles(theme => ({ root: { diff --git a/src/errorHandling/Fallbacks/App/Component.js b/src/errorHandling/Fallbacks/App/Component.js index 446f07b..60493c5 100644 --- a/src/errorHandling/Fallbacks/App/Component.js +++ b/src/errorHandling/Fallbacks/App/Component.js @@ -6,7 +6,7 @@ import Button from '@material-ui/core/Button'; import { FaRedo as ResetIcon } from 'react-icons/fa'; -import { resetApp } from 'utils'; +import resetApp from 'utils/resetApp'; import { messages, email } from 'config'; import useStyles from './styles'; diff --git a/src/global.css b/src/global.css index 1532074..7953e6c 100644 --- a/src/global.css +++ b/src/global.css @@ -6,3 +6,16 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + +.full-width { + width: 100%; +} + +.full-height { + height: 100%; +} + +.full-size { + width: 100%; + height: 100%; +} diff --git a/src/pages/Welcome/Component.js b/src/pages/Welcome/Component.js index faf5b48..19184fc 100644 --- a/src/pages/Welcome/Component.js +++ b/src/pages/Welcome/Component.js @@ -2,18 +2,18 @@ import React from 'react'; import Container from '@material-ui/core/Container'; import Typography from '@material-ui/core/Typography'; -import Box from '@material-ui/core/Box'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import { FaReact as ReactIcon } from 'react-icons/fa'; +import Fb from 'components/Fb'; import Meta from 'components/Meta'; import useStyles from './styles'; function Welcome() { const matchSmallScreen = useMediaQuery('(max-width: 600px)'); - const classes = useStyles({ isSmallScreen: matchSmallScreen }); + const classes = useStyles(); return ( <> @@ -21,16 +21,16 @@ function Welcome() { title="Welcome" description="Welcome to React PWA" /> - - - + + + React PWA - + ); diff --git a/src/pages/Welcome/styles.js b/src/pages/Welcome/styles.js index 8dfc8a6..9070e32 100644 --- a/src/pages/Welcome/styles.js +++ b/src/pages/Welcome/styles.js @@ -1,16 +1,9 @@ import { makeStyles } from '@material-ui/core/styles'; const useStyles = makeStyles(theme => ({ - root: { - display: 'flex', - 'justify-content': 'center', - 'align-items': 'center', - height: '100%', - }, wrapper: { - display: 'flex', + height: '100%', 'user-select': 'none', - 'align-items': ({ isSmallScreen }) => isSmallScreen ? 'center' : 'initial', 'text-align': 'center', }, icon: { diff --git a/src/routes/index.js b/src/routes/index.js index 5d115c5..1b74bbc 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,4 +1,4 @@ -import { asyncComponentLoader } from 'utils'; +import asyncComponentLoader from 'utils/asyncComponentLoader'; const routes = [ { diff --git a/src/sections/AppBar/Component.js b/src/sections/AppBar/Component.js index b6c3e89..a510b65 100644 --- a/src/sections/AppBar/Component.js +++ b/src/sections/AppBar/Component.js @@ -4,10 +4,7 @@ import Toolbar from '@material-ui/core/Toolbar'; import AppBar from '@material-ui/core/AppBar'; import IconButton from '@material-ui/core/IconButton'; import Button from '@material-ui/core/Button'; -import Box from '@material-ui/core/Box'; -import DividerMU from '@material-ui/core/Divider'; import Tooltip from '@material-ui/core/Tooltip'; -import { withStyles } from '@material-ui/core/styles'; import { FaBrush as BrushIcon, @@ -17,6 +14,8 @@ import { } from 'react-icons/fa'; import Link from 'components/Link'; +import Fb from 'components/Fb'; +import Divider from 'components/Divider'; import useTheme from 'store/theme'; import useSW from 'store/sw'; @@ -25,13 +24,6 @@ import { title, repository } from 'config'; import useStyles from './styles'; -const Divider = withStyles({ - root: { - 'margin-left': 7, - 'margin-right': 7, - }, -})(props => ); - function AppBar_({ onMenuOpen }) { const classes = useStyles(); const [, themeActions] = useTheme(); @@ -53,7 +45,7 @@ function AppBar_({ onMenuOpen }) { elevation={1} > - + - - + + { swState.isUpdated && ( <> @@ -76,7 +68,7 @@ function AppBar_({ onMenuOpen }) { - + ) } @@ -91,7 +83,7 @@ function AppBar_({ onMenuOpen }) { - + - + ); diff --git a/src/sections/Copyright/Component.js b/src/sections/Copyright/Component.js index 7dfe5bc..17356aa 100644 --- a/src/sections/Copyright/Component.js +++ b/src/sections/Copyright/Component.js @@ -1,9 +1,9 @@ import React from 'react'; import Typography from '@material-ui/core/Typography'; -import Box from '@material-ui/core/Box'; import Link from '@material-ui/core/Link'; +import Fb from 'components/Fb'; import { copyright, domain } from 'config'; import useStyles from './styles'; @@ -12,15 +12,15 @@ function Copyright() { const classes = useStyles(); return ( - - + + {copyright.title} {copyright.link} {' '} {new Date().getFullYear()} - + ); } diff --git a/src/sections/Layout/Component.js b/src/sections/Layout/Component.js index 252041b..19e9fe4 100644 --- a/src/sections/Layout/Component.js +++ b/src/sections/Layout/Component.js @@ -1,12 +1,11 @@ import React from 'react'; -import Box from '@material-ui/core/Box'; - import Content from 'sections/Content'; import Copyright from 'sections/Copyright'; import Navigation from 'sections/Navigation'; import Notifications from 'sections/Notifications'; +import Fb from 'components/Fb'; import useStyles from './styles'; function Layout() { @@ -16,13 +15,13 @@ function Layout() { <> - - - + + + - - + + ); } diff --git a/src/sections/Layout/styles.js b/src/sections/Layout/styles.js index 725a185..34fc99a 100644 --- a/src/sections/Layout/styles.js +++ b/src/sections/Layout/styles.js @@ -9,10 +9,8 @@ const useStyles = makeStyles(theme => ({ position: 'relative', }, content: { - display: 'flex', - 'flex-direction': 'column', - 'justify-content': 'space-between', - height: `calc(100% - ${theme.mixins.toolbar.minHeight + 8}px)`, + width: '100%', + height: `calc(100% - ${theme.mixins.toolbar + theme.spacing(1)}px)`, }, })); diff --git a/src/sections/Menu/Component.js b/src/sections/Menu/Component.js index 45afc04..86af424 100644 --- a/src/sections/Menu/Component.js +++ b/src/sections/Menu/Component.js @@ -19,7 +19,7 @@ import { FaBug as BugIcon, } from 'react-icons/fa'; -import { isMobile } from 'utils'; +import isMobile from 'utils/isMobile'; import useStyles from './styles'; diff --git a/src/store/effects/index.js b/src/store/effects/index.js deleted file mode 100644 index 927dc99..0000000 --- a/src/store/effects/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import { resetApp } from 'utils'; -import { v1 as uuidv1 } from 'uuid'; - -const SW = {}; // don't keep it in the store - -const sw = { - update() { - const registrationWaiting = SW.registration && SW.registration.waiting; - - if (registrationWaiting) { - registrationWaiting.postMessage({ type: 'SKIP_WAITING' }); - registrationWaiting.onstatechange = function(e) { - if (e.target.state === 'activated') { - resetApp(); - } - }; - } - }, - saveRegistration(registration) { - SW.registration = registration; - }, -}; - -const theme = { - lsSave(mode) { - localStorage.setItem('theme-mode', mode); - }, -}; - -const genUUID = uuidv1; - -export { sw, theme, genUUID }; diff --git a/src/store/notifications/index.js b/src/store/notifications/index.js index a8e66f1..63c5bb5 100644 --- a/src/store/notifications/index.js +++ b/src/store/notifications/index.js @@ -1,8 +1,9 @@ -import { atom, useRecoilState } from 'recoil'; +import { useCallback, useMemo } from 'react'; -import * as effects from 'store/effects'; +import { atom, useRecoilState } from 'recoil'; import { notifications as notificationsDefaults } from 'config'; +import { v1 as uuidv1 } from 'uuid'; const notificationsState = atom({ key: 'notificationsState', @@ -12,33 +13,38 @@ const notificationsState = atom({ function useNotifications() { const [notifications, setNotifications] = useRecoilState(notificationsState); - function push(notification) { + const push = useCallback(notification => { + const id = uuidv1(); setNotifications(notifications => [...notifications, { ...notification, dismissed: false, options: { ...notificationsDefaults.options, ...notification.options, - key: effects.genUUID(), + key: id, }, }]); - } - function close(key, dismissAll = !key) { + return id; + }, [setNotifications]); + + const close = useCallback((key, dismissAll = !key) => { setNotifications(notifications => notifications.map( notification => (dismissAll || notification.options.key === key) ? { ...notification, dismissed: true } - : { ...notification } + : { ...notification }, )); - } + }, [setNotifications]); - function remove(key) { + const remove = useCallback(key => { setNotifications(notifications => notifications.filter( notification => notification.options.key !== key, )); - } + }, [setNotifications]); + + const actions = useMemo(() => ({ push, close, remove }), [push, close, remove]); - return [notifications, { push, close, remove }]; + return [notifications, actions]; } export default useNotifications; diff --git a/src/store/sw/effects/index.js b/src/store/sw/effects/index.js new file mode 100644 index 0000000..c9071a6 --- /dev/null +++ b/src/store/sw/effects/index.js @@ -0,0 +1,26 @@ +import resetApp from 'utils/resetApp'; +import state from 'state-local'; + +const [getSW, setSW] = state.create({ registration: null }); + +function update() { + const SW = getSW(); + const registrationWaiting = SW.registration?.waiting; + + if (registrationWaiting) { + registrationWaiting.postMessage({ type: 'SKIP_WAITING' }); + registrationWaiting.onstatechange = function(e) { + if (e.target.state === 'activated') { + resetApp(); + } + }; + } +} + +function storeRegistration(registration) { + setSW({ registration }); +} + +const effects = { update, storeRegistration }; + +export default effects; diff --git a/src/store/sw/index.js b/src/store/sw/index.js index 83c4ee6..9ab5c69 100644 --- a/src/store/sw/index.js +++ b/src/store/sw/index.js @@ -1,8 +1,8 @@ import { atom, useRecoilState } from 'recoil'; import state from 'state-local'; -import { noop } from 'utils'; -import * as effects from 'store/effects'; +import noop from 'utils/noop'; +import effects from './effects'; const [getActions, setActions] = state.create({ handleSuccess: noop, @@ -28,11 +28,11 @@ function useSW() { function handleUpdate(registration) { setSW(state => ({ ...state, isUpdated: true })); - effects.sw.saveRegistration(registration); + effects.storeRegistration(registration); } function update() { - effects.sw.update(); + effects.update(); } setActions({ handleSuccess, handleUpdate, update }); diff --git a/src/store/theme/index.js b/src/store/theme/index.js index cf8f13f..455dc27 100644 --- a/src/store/theme/index.js +++ b/src/store/theme/index.js @@ -1,21 +1,27 @@ import { atom, useRecoilState } from 'recoil'; -import * as effects from 'store/effects'; - import { themePair } from 'config'; const themeModeState = atom({ key: 'themeModeState', - default: localStorage.getItem('theme-mode') || 'dark', + default: 'dark', + effects_UNSTABLE: [ + synchronizeWithLocalStorage, + ], }); +function synchronizeWithLocalStorage({ setSelf, onSet }) { + const storedTheme = localStorage.getItem('theme-mode'); + storedTheme && setSelf(storedTheme); + + onSet(value => localStorage.setItem('theme-mode', value)); +} + function useTheme() { const [themeMode, setThemeMode] = useRecoilState(themeModeState); function toggle() { - const mode = themeMode === themePair[0] ? themePair[1] : themePair[0]; - setThemeMode(mode); - effects.theme.lsSave(mode); + setThemeMode(mode => mode === themePair[0] ? themePair[1] : themePair[0]); } return [themeMode, { toggle }]; diff --git a/src/utils/asyncComponentLoader/index.js b/src/utils/asyncComponentLoader/index.js index 07dd201..28e2b6d 100644 --- a/src/utils/asyncComponentLoader/index.js +++ b/src/utils/asyncComponentLoader/index.js @@ -1,4 +1,4 @@ -import _asyncComponentLoader from './loader'; +import _asyncComponentLoader, { getDelayedFallback } from './loader'; import Loading from 'components/Loading'; import LoaderErrorBoundaryFallback from 'errorHandling/Fallbacks/Loader'; @@ -11,4 +11,5 @@ const asyncComponentLoader = ( FallbackFail = LoaderErrorBoundaryFallback, ) => _asyncComponentLoader(loadComponent, loaderOptions, FallbackWaiting, FallbackFail); +export { getDelayedFallback }; export default asyncComponentLoader; diff --git a/src/utils/asyncComponentLoader/loader.js b/src/utils/asyncComponentLoader/loader.js index 043dc11..3921f61 100644 --- a/src/utils/asyncComponentLoader/loader.js +++ b/src/utils/asyncComponentLoader/loader.js @@ -1,6 +1,6 @@ import React, { Suspense, useState, useEffect, lazy } from 'react'; -import { sleep } from 'utils'; +import sleep from 'utils/sleep'; // a little bit complex staff is going on here // let me explain it @@ -98,28 +98,31 @@ const getLazyComponent = (loadComponent, loaderOptions, FallbackFail) => lazy(() // INFO: the usage of `asyncComponentLoader` looks like this: // asyncComponentLoader(() => import('pages/Welcome')) -const asyncComponentLoader = ( +function asyncComponentLoader( loadComponent, loaderOptions, FallbackWaiting, FallbackFail, -) => props => { - - const Fallback = loaderOptions.delay - ? getDelayedFallback(FallbackWaiting, loaderOptions.delay) - : FallbackWaiting; - - const LazyComponent = getLazyComponent( - loadComponent, - loaderOptions, - FallbackFail, - ); - - return ( - }> - - - ); -}; +) { + return function AsyncComponent(props) { + const Fallback = loaderOptions.delay + ? getDelayedFallback(FallbackWaiting, loaderOptions.delay) + : FallbackWaiting; + + const LazyComponent = getLazyComponent( + loadComponent, + loaderOptions, + FallbackFail, + ); + + return ( + }> + + + ); + } +} + +export { getDelayedFallback }; export default asyncComponentLoader; diff --git a/src/utils/index.js b/src/utils/index.js deleted file mode 100644 index 7bff4ca..0000000 --- a/src/utils/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import today from './today'; -import noop from './noop'; -import isMobile from './isMobile'; -import resetApp from './resetApp'; -import downloadFile from './downloadFile'; -import sleep from './sleep'; -import asyncComponentLoader from './asyncComponentLoader'; - -export { - today, - noop, - isMobile, - resetApp, - downloadFile, - sleep, - asyncComponentLoader, -}; diff --git a/yarn.lock b/yarn.lock index 36e7197..8e52924 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9300,10 +9300,10 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" -recoil@^0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.0.10.tgz#679ab22306f559f8a63c46fd5ff5241539f9248f" - integrity sha512-+9gRqehw3yKETmoZbhSnWu4GO10HDb5xYf1CjLF1oXGK2uT6GX5Lu9mfTXwjxV/jXxEKx8MIRUUbgPxvbJ8SEw== +recoil@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.1.2.tgz#844c612f535826dbe54c977761a67ded16f6d063" + integrity sha512-hIRrHlkmW4yITlBFprVYjVPhzPKYrJKoaDrrJtAtbkMeXfXaa/XE5OlyR10n+rNfnKWNToCKb3Z4fo86IGjkzg== recursive-readdir@2.2.2: version "2.2.2"