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 */}
Thin
@@ -52,8 +53,6 @@ export default function AppearanceSettings(props) {
Italic
Oblique
-
-
{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 ;
+});
+
+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;
-}