From 2bf8e0cfbc244c4ee28922953e8bcd024b8e2eb5 Mon Sep 17 00:00:00 2001 From: David Ralph Date: Sun, 21 Mar 2021 17:45:34 +0000 Subject: [PATCH] refactor: Reduce bundle size, replace date picker and merge function, add widget order feature etc Co-authored-by: Alex Sparkes --- .gitignore | 1 + package.json | 7 ++- public/icons/undraw_celebration.svg | 2 +- .../modals/main/scss/settings/_buttons.scss | 21 +++++++++ .../modals/main/scss/settings/_main.scss | 13 ++++- .../main/settings/sections/Appearance.jsx | 5 +- .../main/settings/sections/Background.jsx | 2 +- .../main/settings/sections/Greeting.jsx | 5 +- .../modals/main/settings/sections/Order.jsx | 47 +++++++++++++++++++ .../modals/main/settings/sections/Time.jsx | 2 +- src/components/modals/main/tabs/Settings.jsx | 2 + .../modals/main/tabs/backend/Tab.jsx | 2 + src/components/widgets/Widgets.jsx | 34 ++++++++++---- src/index.js | 2 +- src/modules/default_settings.json | 4 ++ src/modules/helpers/merge.js | 19 -------- 16 files changed, 129 insertions(+), 39 deletions(-) create mode 100644 src/components/modals/main/settings/sections/Order.jsx delete mode 100644 src/modules/helpers/merge.js diff --git a/.gitignore b/.gitignore index c43278be..7fb56cff 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ build/ package-lock.json yarn-error.log .eslintcache +stats.json yarn.lock diff --git a/package.json b/package.json index aeb6c8c9..81dc5414 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,14 @@ "@fontsource/roboto": "^4.2.2", "@material-ui/core": "4.11.3", "@material-ui/icons": "4.11.2", + "array-move": "^3.0.1", "react": "17.0.1", "react-clock": "^3.0.0", "react-color-gradient-picker": "^0.1.2", - "react-date-picker": "^8.1.0", + "react-day-picker": "^7.4.10", "react-dom": "17.0.1", "react-modal": "3.12.1", + "react-sortable-hoc": "^2.0.0", "react-toastify": "7.0.3" }, "devDependencies": { @@ -39,12 +41,13 @@ "sass": "^1.32.8", "sass-loader": "^11.0.1", "webpack": "^5.27.0", + "webpack-bundle-analyzer": "^4.4.0", "webpack-cli": "^4.5.0", "webpack-dev-server": "^3.11.2" }, "scripts": { "start": "webpack serve", - "build": "rm -rf build && webpack --mode=production", + "build": "rm -rf build && webpack --mode=production -json > stats.json", "chrome": "cp manifest/chrome.json build/manifest.json", "firefox": "cp manifest/firefox.json build/manifest.json", "opera": "cp manifest/opera.json build/manifest.json && cp manifest/background-opera.js build/" diff --git a/public/icons/undraw_celebration.svg b/public/icons/undraw_celebration.svg index f0fcc804..5cce689d 100644 --- a/public/icons/undraw_celebration.svg +++ b/public/icons/undraw_celebration.svg @@ -1 +1 @@ -celebration \ No newline at end of file + \ No newline at end of file diff --git a/src/components/modals/main/scss/settings/_buttons.scss b/src/components/modals/main/scss/settings/_buttons.scss index 7883c50e..22a48035 100644 --- a/src/components/modals/main/scss/settings/_buttons.scss +++ b/src/components/modals/main/scss/settings/_buttons.scss @@ -214,4 +214,25 @@ input[type=number]::-webkit-outer-spin-button { legend { color: var(--modal-text) !important; +} + +.sortableitem { + background: var(--sidebar) !important; + padding: 10px 80px; + padding-left: 10px; + border-radius: 15px; + margin-bottom: 10px; + font-size: 1.5rem; + svg { + font-size: 1.3rem; + } + &:hover { + box-shadow: 0 2px 5px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); + transition: 0.3s; + } + z-index: 999 !important; +} + +li.stortableitem { + width: 200px; } \ No newline at end of file diff --git a/src/components/modals/main/scss/settings/_main.scss b/src/components/modals/main/scss/settings/_main.scss index f2ca1e3f..a08c89ae 100644 --- a/src/components/modals/main/scss/settings/_main.scss +++ b/src/components/modals/main/scss/settings/_main.scss @@ -3,7 +3,7 @@ } input { - &[type=text] { + &[type=text] { width: 200px; color: var(--modal-text); background: var(--sidebar); @@ -26,6 +26,17 @@ input { } } +.DayPickerInput { + input { + width: 200px; + color: var(--modal-text); + background: var(--sidebar); + border: none; + padding: 10px 10px; + border-radius: 5px; + } +} + h4, .switch { display: inline; diff --git a/src/components/modals/main/settings/sections/Appearance.jsx b/src/components/modals/main/settings/sections/Appearance.jsx index 85a93dc8..b13ac0d7 100644 --- a/src/components/modals/main/settings/sections/Appearance.jsx +++ b/src/components/modals/main/settings/sections/Appearance.jsx @@ -34,7 +34,8 @@ export default function AppearanceSettings(props) {

{appearance.font.title}

-

+
+ {/* names are taken from https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight */} @@ -52,8 +53,6 @@ export default function AppearanceSettings(props) { -
-

{appearance.accessibility.title}

diff --git a/src/components/modals/main/settings/sections/Background.jsx b/src/components/modals/main/settings/sections/Background.jsx index af01789d..62b29fa3 100644 --- a/src/components/modals/main/settings/sections/Background.jsx +++ b/src/components/modals/main/settings/sections/Background.jsx @@ -110,7 +110,7 @@ export default class BackgroundSettings extends React.PureComponent { const newState = { gradientSettings: { ...s.gradientSettings, - gradient: [...initGradients, lastGradient, { 'colour': localStorage.getItem('darkTheme') === 'true' ? '#000000' : '#ffffff', stop: 100 }].sort((a, b) => (a.stop > b.stop) ? 1 : -1) + gradient: [...initGradients, lastGradient, { 'colour': localStorage.getItem('theme') === 'dark' ? '#000000' : '#ffffff', stop: 100 }].sort((a, b) => (a.stop > b.stop) ? 1 : -1) } }; return newState; diff --git a/src/components/modals/main/settings/sections/Greeting.jsx b/src/components/modals/main/settings/sections/Greeting.jsx index 3123cc13..02ebe850 100644 --- a/src/components/modals/main/settings/sections/Greeting.jsx +++ b/src/components/modals/main/settings/sections/Greeting.jsx @@ -4,7 +4,8 @@ import Checkbox from '../Checkbox'; import Switch from '../Switch'; import Text from '../Text'; -import DatePicker from 'react-date-picker'; +import DayPickerInput from 'react-day-picker/DayPickerInput'; +import 'react-day-picker/lib/style.css'; export default class GreetingSettings extends React.PureComponent { constructor(...args) { @@ -39,7 +40,7 @@ export default class GreetingSettings extends React.PureComponent {

    {greeting.birthday_date}

    - this.changeDate(data)} value={this.state.birthday}/> + this.changeDate(data)} value={this.state.birthday} />
); diff --git a/src/components/modals/main/settings/sections/Order.jsx b/src/components/modals/main/settings/sections/Order.jsx new file mode 100644 index 00000000..dad87d0d --- /dev/null +++ b/src/components/modals/main/settings/sections/Order.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { sortableContainer, sortableElement } from 'react-sortable-hoc'; +import arrayMove from 'array-move'; +import DragHandleIcon from '@material-ui/icons/DragIndicator'; + +const SortableItem = sortableElement(({value}) => ( +
  • + + {value.charAt(0).toUpperCase() + value.slice(1)} +
  • +)); + +const SortableContainer = sortableContainer(({children}) => { + return
      {children}
    ; +}); + +export default class OrderSettings extends React.PureComponent { + constructor(...args) { + super(...args); + this.state = { + items: JSON.parse(localStorage.getItem('order')) + }; + } + + onSortEnd = ({oldIndex, newIndex}) => { + this.setState(({items}) => ({ + items: arrayMove(items, oldIndex, newIndex) + })); + }; + + componentDidUpdate() { + localStorage.setItem('order', JSON.stringify(this.state.items)); + } + + render() { + return ( +
    +

    Order

    + + {this.state.items.map((value, index) => ( + + ))} + +
    + ); + } +} diff --git a/src/components/modals/main/settings/sections/Time.jsx b/src/components/modals/main/settings/sections/Time.jsx index 71f35ead..637872e4 100644 --- a/src/components/modals/main/settings/sections/Time.jsx +++ b/src/components/modals/main/settings/sections/Time.jsx @@ -64,7 +64,7 @@ export default class TimeSettings extends React.PureComponent { {timeSettings}

    {time.date.title}

    - + diff --git a/src/components/modals/main/tabs/Settings.jsx b/src/components/modals/main/tabs/Settings.jsx index bb107378..5333a7c2 100644 --- a/src/components/modals/main/tabs/Settings.jsx +++ b/src/components/modals/main/tabs/Settings.jsx @@ -10,6 +10,7 @@ import Appearance from '../settings/sections/Appearance'; import Background from '../settings/sections/Background'; import Advanced from '../settings/sections/Advanced'; import Changelog from '../settings/sections/Changelog'; +import Order from '../settings/sections/Order'; import SettingsTabs from './backend/Tabs'; @@ -25,6 +26,7 @@ export default function Settings () {
    +
    diff --git a/src/components/modals/main/tabs/backend/Tab.jsx b/src/components/modals/main/tabs/backend/Tab.jsx index 2c696e5c..9418c94e 100644 --- a/src/components/modals/main/tabs/backend/Tab.jsx +++ b/src/components/modals/main/tabs/backend/Tab.jsx @@ -16,6 +16,7 @@ import Language from '@material-ui/icons/Translate'; import Changelog from '@material-ui/icons/NewReleasesRounded'; import About from '@material-ui/icons/Info'; import Experimental from '@material-ui/icons/BugReport'; +import Order from '@material-ui/icons/List'; // Store import Colors from '@material-ui/icons/ColorLens'; @@ -49,6 +50,7 @@ export default function Tab(props) { case 'Background': icon = ; break; case 'Search': icon = ; break; case 'Appearance': icon = ; break; + case 'Order': icon = ; break; case 'Language': icon = ; divider = true; break; case 'Advanced': icon = ; break; case 'Experimental': icon = ; divider = true; break; diff --git a/src/components/widgets/Widgets.jsx b/src/components/widgets/Widgets.jsx index 740bb65c..483ee345 100644 --- a/src/components/widgets/Widgets.jsx +++ b/src/components/widgets/Widgets.jsx @@ -9,6 +9,17 @@ import Favourite from './background/Favourite'; import Date from './time/Date'; export default class Widgets extends React.PureComponent { + constructor(...args) { + super(...args); + // widgets we can re-order + this.widgets = { + time: this.enabled('time') ? : null, + greeting: this.enabled('greeting') ? : null, + quote: this.enabled('quote') ? : null, + date: this.enabled('date') ? : null + } + } + enabled(key) { const stringValue = localStorage.getItem(key); let enabled = true; @@ -57,17 +68,24 @@ export default class Widgets extends React.PureComponent { } render() { - const enabled = this.enabled; + // allow for re-ordering widgets + let elements = []; + const order = JSON.parse(localStorage.getItem('order')); + + if (order) { + order.forEach(element => { + elements.push(this.widgets[element]); + }); + } else { + elements = ['greeting', 'time', 'quote', 'date']; + } return (
    - {enabled('searchBar') ? : null} - {enabled('greeting') ? : null} - {enabled('time') ? : null} - {enabled('date') ? : null} - {enabled('quote') ? : null} - {enabled('view') ? : null} - {enabled('favouriteEnabled') ? : null} + {this.enabled('searchBar') ? : null} + {elements} + {this.enabled('view') ? : null} + {this.enabled('favouriteEnabled') ? : null}
    ); } diff --git a/src/index.js b/src/index.js index 145cdc1e..8fb8f1cb 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,7 @@ import '@fontsource/lexend-deca/latin-400.css'; import '@fontsource/roboto/cyrillic-400.css'; // language -import merge from './modules/helpers/merge'; +import merge from '@material-ui/utils/deepmerge'; const languagecode = localStorage.getItem('language') || 'en-GB'; // we set things to window. so they're global and we avoid passing the translation strings as props to each component window.languagecode = languagecode; diff --git a/src/modules/default_settings.json b/src/modules/default_settings.json index fa92eda5..e850791c 100644 --- a/src/modules/default_settings.json +++ b/src/modules/default_settings.json @@ -126,5 +126,9 @@ { "name": "fontweight", "value": 400 + }, + { + "name": "order", + "value": "[\"greeting\", \"time\", \"quote\", \"date\"]" } ] diff --git a/src/modules/helpers/merge.js b/src/modules/helpers/merge.js deleted file mode 100644 index 23146f66..00000000 --- a/src/modules/helpers/merge.js +++ /dev/null @@ -1,19 +0,0 @@ -export default function deepmerge(...objects) { - let target = {}; - - const merge = (obj) => { - for (let prop in obj) { - if (obj.hasOwnProperty(prop)) { - if (typeof obj[prop] === 'object') { - target[prop] = deepmerge(target[prop], obj[prop]); - } else { - target[prop] = obj[prop]; - } - } - } - }; - - objects.forEach(object => merge(object)); - - return target; -}