diff --git a/package.json b/package.json index 5f3ec564..543a1527 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "embla-carousel-react": "^7.1.0", "fast-blurhash": "^1.1.2", "image-conversion": "^2.1.1", + "prop-types": "^15.8.1", "react": "^18.2.0", "react-clock": "4.1.0", "react-color-gradient-picker": "0.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b151c0e..04e0314a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,7 @@ specifiers: husky: ^8.0.3 image-conversion: ^2.1.1 prettier: ^2.8.4 + prop-types: ^15.8.1 react: ^18.2.0 react-clock: 4.1.0 react-color-gradient-picker: 0.1.2 @@ -52,13 +53,14 @@ dependencies: embla-carousel-react: 7.1.0_react@18.2.0 fast-blurhash: 1.1.2 image-conversion: 2.1.1 + prop-types: 15.8.1 react: 18.2.0 react-clock: 4.1.0_biqbaboplfbrettd7655fr4n2y react-color-gradient-picker: 0.1.2_biqbaboplfbrettd7655fr4n2y react-dom: 18.2.0_react@18.2.0 react-icons: 4.8.0_react@18.2.0 react-modal: 3.16.1_biqbaboplfbrettd7655fr4n2y - react-sortable-hoc: 2.0.0_biqbaboplfbrettd7655fr4n2y + react-sortable-hoc: 2.0.0_v2m5e27vhdewzwhryxwfaorcca react-toastify: 9.1.1_biqbaboplfbrettd7655fr4n2y devDependencies: @@ -5207,9 +5209,10 @@ packages: warning: 4.0.3 dev: false - /react-sortable-hoc/2.0.0_biqbaboplfbrettd7655fr4n2y: + /react-sortable-hoc/2.0.0_v2m5e27vhdewzwhryxwfaorcca: resolution: {integrity: sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==} peerDependencies: + prop-types: ^15.5.7 react: ^16.3.0 || ^17.0.0 react-dom: ^16.3.0 || ^17.0.0 dependencies: diff --git a/scripts/updatetranslations.js b/scripts/updatetranslations.js index 081adc25..e3c4bf0b 100644 --- a/scripts/updatetranslations.js +++ b/scripts/updatetranslations.js @@ -2,6 +2,12 @@ const fs = require('fs'); const merge = require('@eartharoid/deep-merge'); +/** + * It recursively compares the keys of two JSON objects and removes the keys from the first object that + * are not present in the second object + * @param json1 - The JSON object that you want to remove keys from. + * @param json2 - The JSON object that you want to compare against. + */ const compareAndRemoveKeys = (json1, json2) => { for (let key in json1) { if (json2.hasOwnProperty(key)) { @@ -12,7 +18,7 @@ const compareAndRemoveKeys = (json1, json2) => { delete json1[key]; } } -} +}; fs.readdirSync('../src/translations').forEach((file) => { if (file === 'en_GB.json') { diff --git a/src/components/helpers/autocomplete/Autocomplete.jsx b/src/components/helpers/autocomplete/Autocomplete.jsx index 40dfd67f..841fb47d 100644 --- a/src/components/helpers/autocomplete/Autocomplete.jsx +++ b/src/components/helpers/autocomplete/Autocomplete.jsx @@ -1,10 +1,11 @@ import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import EventBus from 'modules/helpers/eventbus'; import './autocomplete.scss'; -export default class Autocomplete extends PureComponent { +class Autocomplete extends PureComponent { constructor(props) { super(props); this.state = { @@ -91,3 +92,12 @@ export default class Autocomplete extends PureComponent { ); } } + +Autocomplete.propTypes = { + suggestions: PropTypes.arrayOf(PropTypes.string).isRequired, + onChange: PropTypes.func.isRequired, + onClick: PropTypes.func.isRequired, + placeholder: PropTypes.string, +}; + +export default Autocomplete; diff --git a/src/components/helpers/carousel/Carousel.jsx b/src/components/helpers/carousel/Carousel.jsx index 2ff9d8f3..6d6101ce 100644 --- a/src/components/helpers/carousel/Carousel.jsx +++ b/src/components/helpers/carousel/Carousel.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback, useRef, memo } from 'react'; +import PropTypes from 'prop-types'; import { MdOutlineArrowForwardIos, MdOutlineArrowBackIos } from 'react-icons/md'; import useEmblaCarousel from 'embla-carousel-react'; import Autoplay from 'embla-carousel-autoplay'; @@ -77,4 +78,8 @@ function EmblaCarousel({ data }) { ); } +EmblaCarousel.propTypes = { + data: PropTypes.arrayOf(PropTypes.object).isRequired, +}; + export default memo(EmblaCarousel); diff --git a/src/components/helpers/preview/Preview.jsx b/src/components/helpers/preview/Preview.jsx index e5789d8a..a88ba044 100644 --- a/src/components/helpers/preview/Preview.jsx +++ b/src/components/helpers/preview/Preview.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import variables from 'modules/variables'; import './preview.scss'; @@ -14,4 +15,8 @@ function Preview(props) { ); } +Preview.propTypes = { + setup: PropTypes.func.isRequired, +}; + export default memo(Preview); diff --git a/src/components/helpers/sharemodal/ShareModal.jsx b/src/components/helpers/sharemodal/ShareModal.jsx index d7c7a8f0..25925ea6 100644 --- a/src/components/helpers/sharemodal/ShareModal.jsx +++ b/src/components/helpers/sharemodal/ShareModal.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import variables from 'modules/variables'; import { MdClose, MdEmail, MdContentCopy } from 'react-icons/md'; import { FaTwitter, FaFacebookF } from 'react-icons/fa'; @@ -118,4 +119,9 @@ function ShareModal({ modalClose, data }) { ); } +ShareModal.propTypes = { + modalClose: PropTypes.func.isRequired, + data: PropTypes.string.isRequired, +}; + export default memo(ShareModal); diff --git a/src/components/helpers/tooltip/Tooltip.jsx b/src/components/helpers/tooltip/Tooltip.jsx index 61a55d39..64b3a21c 100644 --- a/src/components/helpers/tooltip/Tooltip.jsx +++ b/src/components/helpers/tooltip/Tooltip.jsx @@ -1,4 +1,5 @@ import { useState, memo } from 'react'; +import PropTypes from 'prop-types'; import { useFloating, flip, offset, shift } from '@floating-ui/react-dom'; import './tooltip.scss'; @@ -42,4 +43,12 @@ function Tooltip({ children, title, style, placement, subtitle }) { ); } +Tooltip.propTypes = { + children: PropTypes.node.isRequired, + title: PropTypes.string.isRequired, + style: PropTypes.object, + placement: PropTypes.string, + subtitle: PropTypes.string.isRequired, +}; + export default memo(Tooltip); diff --git a/src/components/helpers/tooltip/infoTooltip.jsx b/src/components/helpers/tooltip/infoTooltip.jsx index 02dad8f7..d6e33ecc 100644 --- a/src/components/helpers/tooltip/infoTooltip.jsx +++ b/src/components/helpers/tooltip/infoTooltip.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { useState, memo } from 'react'; +import PropTypes from 'prop-types'; import { useFloating, flip, offset, shift } from '@floating-ui/react-dom'; import { MdClose, MdInfo, MdOpenInNew } from 'react-icons/md'; import Tooltip from './Tooltip'; @@ -44,4 +45,11 @@ function InfoTooltip({ title, style, placement, subtitle }) { ); } +InfoTooltip.propTypes = { + title: PropTypes.string.isRequired, + style: PropTypes.object, + placement: PropTypes.string, + subtitle: PropTypes.string.isRequired, +}; + export default memo(InfoTooltip); diff --git a/src/components/modals/ErrorBoundary.jsx b/src/components/modals/ErrorBoundary.jsx index a39709ca..a6448f3a 100644 --- a/src/components/modals/ErrorBoundary.jsx +++ b/src/components/modals/ErrorBoundary.jsx @@ -1,9 +1,11 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; + import { MdErrorOutline } from 'react-icons/md'; import { captureException } from '@sentry/react'; -export default class ErrorBoundary extends PureComponent { +class ErrorBoundary extends PureComponent { constructor(props) { super(props); this.state = { @@ -13,6 +15,11 @@ export default class ErrorBoundary extends PureComponent { }; } + /** + * If an error occurs, log the error, and set the state to error: true, and errorData: error. + * @param {Error} error The error that occurred. + * @returns An object with two properties: error and errorData. + */ static getDerivedStateFromError(error) { console.log(error); variables.stats.postEvent('modal', 'Error occurred'); @@ -63,3 +70,9 @@ export default class ErrorBoundary extends PureComponent { return this.props.children; } } + +ErrorBoundary.propTypes = { + children: PropTypes.node.isRequired, +}; + +export default ErrorBoundary; diff --git a/src/components/modals/Modals.jsx b/src/components/modals/Modals.jsx index 2cc5dfb8..6780be11 100644 --- a/src/components/modals/Modals.jsx +++ b/src/components/modals/Modals.jsx @@ -35,8 +35,8 @@ export default class Modals extends PureComponent { if (window.location.search === '?nointro=true') { if (localStorage.getItem('showWelcome') === 'true') { localStorage.setItem('showWelcome', false); - EventBus.dispatch('refresh', 'widgets'); - EventBus.dispatch('refresh', 'backgroundwelcome'); + EventBus.emit('refresh', 'widgets'); + EventBus.emit('refresh', 'backgroundwelcome'); } } @@ -49,9 +49,9 @@ export default class Modals extends PureComponent { this.setState({ welcomeModal: false, }); - EventBus.dispatch('refresh', 'widgetsWelcomeDone'); - EventBus.dispatch('refresh', 'widgets'); - EventBus.dispatch('refresh', 'backgroundwelcome'); + EventBus.emit('refresh', 'widgetsWelcomeDone'); + EventBus.emit('refresh', 'widgets'); + EventBus.emit('refresh', 'backgroundwelcome'); } previewWelcome() { @@ -61,7 +61,7 @@ export default class Modals extends PureComponent { welcomeModal: false, preview: true, }); - EventBus.dispatch('refresh', 'widgetsWelcome'); + EventBus.emit('refresh', 'widgetsWelcome'); } toggleModal(type, action) { diff --git a/src/components/modals/main/Main.jsx b/src/components/modals/main/Main.jsx index 40d4f061..669baece 100644 --- a/src/components/modals/main/Main.jsx +++ b/src/components/modals/main/Main.jsx @@ -1,7 +1,7 @@ import variables from 'modules/variables'; -import { Suspense, lazy, useState } from 'react'; +import { Suspense, lazy, useState, memo } from 'react'; +import PropTypes from 'prop-types'; -import { memo } from 'react'; import { MdClose } from 'react-icons/md'; import './scss/index.scss'; @@ -69,4 +69,8 @@ function MainModal({ modalClose }) { ); } +MainModal.propTypes = { + modalClose: PropTypes.func.isRequired, +}; + export default memo(MainModal); diff --git a/src/components/modals/main/marketplace/Item.jsx b/src/components/modals/main/marketplace/Item.jsx index c1727f8c..0119fe2d 100644 --- a/src/components/modals/main/marketplace/Item.jsx +++ b/src/components/modals/main/marketplace/Item.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { PureComponent, Fragment } from 'react'; +import PropTypes from 'prop-types'; import Tooltip from 'components/helpers/tooltip/Tooltip'; import ImageCarousel from 'components/helpers/carousel/Carousel'; import { toast } from 'react-toastify'; @@ -22,7 +23,7 @@ import { install, uninstall } from 'modules/helpers/marketplace'; import ShareModal from 'components/helpers/sharemodal/ShareModal'; -export default class Item extends PureComponent { +class Item extends PureComponent { constructor(props) { super(props); this.state = { @@ -327,3 +328,12 @@ export default class Item extends PureComponent { ); } } + +Item.propTypes = { + data: PropTypes.object, + addonInstalled: PropTypes.bool, + addonInstalledVersion: PropTypes.string, + toggleFunction: PropTypes.func, +}; + +export default Item; diff --git a/src/components/modals/main/marketplace/Items.jsx b/src/components/modals/main/marketplace/Items.jsx index c8e1d10b..4628a8cc 100644 --- a/src/components/modals/main/marketplace/Items.jsx +++ b/src/components/modals/main/marketplace/Items.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import React, { memo } from 'react'; +import PropTypes from 'prop-types'; import { MdAutoFixHigh, MdOutlineArrowForward, MdOutlineOpenInNew } from 'react-icons/md'; function Items({ @@ -118,4 +119,14 @@ function Items({ ); } +Items.propTypes = { + type: PropTypes.string.isRequired, + items: PropTypes.arrayOf(PropTypes.object).isRequired, + collection: PropTypes.object, + toggleFunction: PropTypes.func.isRequired, + collectionFunction: PropTypes.func.isRequired, + onCollection: PropTypes.bool.isRequired, + filter: PropTypes.string, +}; + export default memo(Items); diff --git a/src/components/modals/main/marketplace/Lightbox.jsx b/src/components/modals/main/marketplace/Lightbox.jsx index 07631e2c..fa9944a0 100644 --- a/src/components/modals/main/marketplace/Lightbox.jsx +++ b/src/components/modals/main/marketplace/Lightbox.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import variables from 'modules/variables'; function Lightbox({ modalClose, img }) { @@ -14,4 +15,9 @@ function Lightbox({ modalClose, img }) { ); } +Lightbox.propTypes = { + modalClose: PropTypes.func.isRequired, + img: PropTypes.string.isRequired, +}; + export default memo(Lightbox); diff --git a/src/components/modals/main/marketplace/SideloadFailedModal.jsx b/src/components/modals/main/marketplace/SideloadFailedModal.jsx index 567c6325..a561c7cd 100644 --- a/src/components/modals/main/marketplace/SideloadFailedModal.jsx +++ b/src/components/modals/main/marketplace/SideloadFailedModal.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import variables from 'modules/variables'; import { MdClose } from 'react-icons/md'; import Tooltip from 'components/helpers/tooltip/Tooltip'; @@ -22,4 +23,9 @@ function SideloadFailedModal({ modalClose, reason }) { ); } +SideloadFailedModal.propTypes = { + modalClose: PropTypes.func.isRequired, + reason: PropTypes.string.isRequired, +}; + export default memo(SideloadFailedModal); diff --git a/src/components/modals/main/marketplace/sections/Added.jsx b/src/components/modals/main/marketplace/sections/Added.jsx index a9e68638..992db415 100644 --- a/src/components/modals/main/marketplace/sections/Added.jsx +++ b/src/components/modals/main/marketplace/sections/Added.jsx @@ -13,8 +13,8 @@ import Dropdown from '../../settings/Dropdown'; import { install, uninstall, urlParser } from 'modules/helpers/marketplace'; export default class Added extends PureComponent { - constructor(props) { - super(props); + constructor() { + super(); this.state = { installed: JSON.parse(localStorage.getItem('installed')), item: {}, diff --git a/src/components/modals/main/marketplace/sections/Marketplace.jsx b/src/components/modals/main/marketplace/sections/Marketplace.jsx index 885df875..dad4f27f 100644 --- a/src/components/modals/main/marketplace/sections/Marketplace.jsx +++ b/src/components/modals/main/marketplace/sections/Marketplace.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { toast } from 'react-toastify'; import { MdWifiOff, @@ -16,7 +17,7 @@ import Dropdown from '../../settings/Dropdown'; import { install, urlParser, uninstall } from 'modules/helpers/marketplace'; -export default class Marketplace extends PureComponent { +class Marketplace extends PureComponent { constructor() { super(); this.state = { @@ -470,3 +471,9 @@ export default class Marketplace extends PureComponent { ); } } + +Marketplace.propTypes = { + type: PropTypes.string, +}; + +export default Marketplace; diff --git a/src/components/modals/main/scss/settings/modules/_material-ui.scss b/src/components/modals/main/scss/settings/modules/_material-ui.scss index e26ea70e..7db44458 100644 --- a/src/components/modals/main/scss/settings/modules/_material-ui.scss +++ b/src/components/modals/main/scss/settings/modules/_material-ui.scss @@ -98,7 +98,7 @@ legend, color: t($color); } - li{ + li { &:hover { @include themed { background-color: t($modal-sidebarActive); diff --git a/src/components/modals/main/settings/Checkbox.jsx b/src/components/modals/main/settings/Checkbox.jsx index 9dda856b..0384e0ba 100644 --- a/src/components/modals/main/settings/Checkbox.jsx +++ b/src/components/modals/main/settings/Checkbox.jsx @@ -1,10 +1,11 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { Checkbox as CheckboxUI, FormControlLabel } from '@mui/material'; import EventBus from 'modules/helpers/eventbus'; -export default class Checkbox extends PureComponent { +class Checkbox extends PureComponent { constructor(props) { super(props); this.state = { @@ -36,7 +37,7 @@ export default class Checkbox extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; render() { @@ -57,3 +58,14 @@ export default class Checkbox extends PureComponent { ); } } + +Checkbox.propTypes = { + name: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + category: PropTypes.string, + element: PropTypes.string, + onChange: PropTypes.func, + disabled: PropTypes.bool, +}; + +export default Checkbox; diff --git a/src/components/modals/main/settings/ChipSelect.jsx b/src/components/modals/main/settings/ChipSelect.jsx index ecb6f7ce..6ef2e735 100644 --- a/src/components/modals/main/settings/ChipSelect.jsx +++ b/src/components/modals/main/settings/ChipSelect.jsx @@ -1,4 +1,6 @@ import { useState, memo } from 'react'; +import PropTypes from 'prop-types'; + import Box from '@mui/material/Box'; import OutlinedInput from '@mui/material/OutlinedInput'; import InputLabel from '@mui/material/InputLabel'; @@ -53,4 +55,10 @@ function ChipSelect({ label, options, name }) { ); } +ChipSelect.propTypes = { + label: PropTypes.string, + options: PropTypes.array, + name: PropTypes.string, +}; + export default memo(ChipSelect); diff --git a/src/components/modals/main/settings/Dropdown.jsx b/src/components/modals/main/settings/Dropdown.jsx index a7eee012..14c6915d 100644 --- a/src/components/modals/main/settings/Dropdown.jsx +++ b/src/components/modals/main/settings/Dropdown.jsx @@ -1,10 +1,11 @@ import variables from 'modules/variables'; import { PureComponent, createRef } from 'react'; +import PropTypes from 'prop-types'; import { InputLabel, MenuItem, FormControl, Select } from '@mui/material'; import EventBus from 'modules/helpers/eventbus'; -export default class Dropdown extends PureComponent { +class Dropdown extends PureComponent { constructor(props) { super(props); this.state = { @@ -43,7 +44,7 @@ export default class Dropdown extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; render() { @@ -76,3 +77,17 @@ export default class Dropdown extends PureComponent { ); } } + +Dropdown.propTypes = { + name: PropTypes.string.isRequired, + label: PropTypes.string, + category: PropTypes.string, + element: PropTypes.string, + onChange: PropTypes.func, + noSetting: PropTypes.bool, + manual: PropTypes.bool, + value2: PropTypes.string, + name2: PropTypes.string, +}; + +export default Dropdown; diff --git a/src/components/modals/main/settings/FileUpload.jsx b/src/components/modals/main/settings/FileUpload.jsx index f74d2587..6d26c9cc 100644 --- a/src/components/modals/main/settings/FileUpload.jsx +++ b/src/components/modals/main/settings/FileUpload.jsx @@ -1,10 +1,11 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { toast } from 'react-toastify'; import { compressAccurately, filetoDataURL } from 'image-conversion'; import { videoCheck } from 'modules/helpers/background/widget'; -export default class FileUpload extends PureComponent { +class FileUpload extends PureComponent { componentDidMount() { document.getElementById(this.props.id).onchange = (e) => { const reader = new FileReader(); @@ -61,3 +62,12 @@ export default class FileUpload extends PureComponent { ); } } + +FileUpload.propTypes = { + id: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + loadFunction: PropTypes.func.isRequired, + accept: PropTypes.string, +}; + +export default FileUpload; diff --git a/src/components/modals/main/settings/Header.jsx b/src/components/modals/main/settings/Header.jsx index c522373b..69d5207c 100644 --- a/src/components/modals/main/settings/Header.jsx +++ b/src/components/modals/main/settings/Header.jsx @@ -1,6 +1,7 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { /*MdHelpOutline,*/ MdFlag, MdArrowBack } from 'react-icons/md'; import Slider from './Slider'; @@ -10,7 +11,7 @@ import SettingsItem from './SettingsItem'; import { values } from 'modules/helpers/settings/modals'; import Tooltip from 'components/helpers/tooltip/Tooltip'; -export default class Header extends PureComponent { +class Header extends PureComponent { render() { return ( <> @@ -89,3 +90,17 @@ export default class Header extends PureComponent { ); } } + +Header.propTypes = { + title: PropTypes.string.isRequired, + setting: PropTypes.string.isRequired, + category: PropTypes.string.isRequired, + element: PropTypes.string, + backButton: PropTypes.bool, + clickEffect: PropTypes.func, + switch: PropTypes.bool, + zoomSetting: PropTypes.string, + zoomCategory: PropTypes.string, +}; + +export default Header; diff --git a/src/components/modals/main/settings/Radio.jsx b/src/components/modals/main/settings/Radio.jsx index 53423f80..cf60a310 100644 --- a/src/components/modals/main/settings/Radio.jsx +++ b/src/components/modals/main/settings/Radio.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { Radio as RadioUI, RadioGroup, @@ -11,7 +12,7 @@ import { import EventBus from 'modules/helpers/eventbus'; import translations from 'modules/translations'; -export default class Radio extends PureComponent { +class Radio extends PureComponent { constructor(props) { super(props); this.state = { @@ -52,7 +53,7 @@ export default class Radio extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; render() { @@ -83,3 +84,20 @@ export default class Radio extends PureComponent { ); } } + +Radio.propTypes = { + name: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + options: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + }), + ).isRequired, + onChange: PropTypes.func, + category: PropTypes.string, + element: PropTypes.string, + smallTitle: PropTypes.bool, +}; + +export default Radio; diff --git a/src/components/modals/main/settings/ResetModal.jsx b/src/components/modals/main/settings/ResetModal.jsx index bc88c0da..157876ed 100644 --- a/src/components/modals/main/settings/ResetModal.jsx +++ b/src/components/modals/main/settings/ResetModal.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import variables from 'modules/variables'; import { MdClose, MdRestartAlt } from 'react-icons/md'; import { setDefaultSettings } from 'modules/helpers/settings'; @@ -45,4 +46,8 @@ function ResetModal({ modalClose }) { ); } +ResetModal.propTypes = { + modalClose: PropTypes.func.isRequired, +}; + export default memo(ResetModal); diff --git a/src/components/modals/main/settings/SettingsItem.jsx b/src/components/modals/main/settings/SettingsItem.jsx index 9b5b8a6a..7dad66f8 100644 --- a/src/components/modals/main/settings/SettingsItem.jsx +++ b/src/components/modals/main/settings/SettingsItem.jsx @@ -1,15 +1,23 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; -function SettingsItem(props) { +function SettingsItem({ final, title, subtitle, children }) { return ( -
+
- {props.title} - {props.subtitle} + {title} + {subtitle}
-
{props.children}
+
{children}
); } +SettingsItem.propTypes = { + title: PropTypes.string.isRequired, + subtitle: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, + final: PropTypes.bool, +}; + export default memo(SettingsItem); diff --git a/src/components/modals/main/settings/Slider.jsx b/src/components/modals/main/settings/Slider.jsx index ee7e728e..b3fd5fed 100644 --- a/src/components/modals/main/settings/Slider.jsx +++ b/src/components/modals/main/settings/Slider.jsx @@ -1,12 +1,13 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { toast } from 'react-toastify'; import { Slider } from '@mui/material'; import { MdRefresh } from 'react-icons/md'; import EventBus from 'modules/helpers/eventbus'; -export default class SliderComponent extends PureComponent { +class SliderComponent extends PureComponent { constructor(props) { super(props); this.state = { @@ -46,7 +47,7 @@ export default class SliderComponent extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; resetItem = () => { @@ -84,3 +85,17 @@ export default class SliderComponent extends PureComponent { ); } } + +SliderComponent.propTypes = { + name: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + default: PropTypes.number.isRequired, + min: PropTypes.number.isRequired, + max: PropTypes.number.isRequired, + step: PropTypes.number, + marks: PropTypes.array, + element: PropTypes.string, + category: PropTypes.string, +}; + +export default SliderComponent; diff --git a/src/components/modals/main/settings/Switch.jsx b/src/components/modals/main/settings/Switch.jsx index 80b72457..2692e11e 100644 --- a/src/components/modals/main/settings/Switch.jsx +++ b/src/components/modals/main/settings/Switch.jsx @@ -1,10 +1,11 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { Switch as SwitchUI, FormControlLabel } from '@mui/material'; import EventBus from 'modules/helpers/eventbus'; -export default class Switch extends PureComponent { +class Switch extends PureComponent { constructor(props) { super(props); this.state = { @@ -32,7 +33,7 @@ export default class Switch extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; render() { @@ -52,3 +53,13 @@ export default class Switch extends PureComponent { ); } } + +Switch.propTypes = { + name: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + category: PropTypes.string, + element: PropTypes.string, + header: PropTypes.bool, +}; + +export default Switch; diff --git a/src/components/modals/main/settings/Text.jsx b/src/components/modals/main/settings/Text.jsx index 34c4cf09..a38c4132 100644 --- a/src/components/modals/main/settings/Text.jsx +++ b/src/components/modals/main/settings/Text.jsx @@ -1,11 +1,12 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { toast } from 'react-toastify'; import { TextField } from '@mui/material'; import EventBus from 'modules/helpers/eventbus'; -export default class Text extends PureComponent { +class Text extends PureComponent { constructor(props) { super(props); this.state = { @@ -33,7 +34,7 @@ export default class Text extends PureComponent { } } - EventBus.dispatch('refresh', this.props.category); + EventBus.emit('refresh', this.props.category); }; resetItem = () => { @@ -77,3 +78,16 @@ export default class Text extends PureComponent { ); } } + +Text.propTypes = { + title: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + category: PropTypes.string.isRequired, + default: PropTypes.string, + element: PropTypes.string, + customcss: PropTypes.bool, + textarea: PropTypes.bool, + upperCaseFirst: PropTypes.bool, +}; + +export default Text; diff --git a/src/components/modals/main/settings/sections/Experimental.jsx b/src/components/modals/main/settings/sections/Experimental.jsx index c9391e02..3f744eac 100644 --- a/src/components/modals/main/settings/sections/Experimental.jsx +++ b/src/components/modals/main/settings/sections/Experimental.jsx @@ -51,7 +51,7 @@ function ExperimentalSettings() { varient="outlined" InputLabelProps={{ shrink: true }} /> - diff --git a/src/components/modals/main/settings/sections/Message.jsx b/src/components/modals/main/settings/sections/Message.jsx index afd72d10..0338d9ee 100644 --- a/src/components/modals/main/settings/sections/Message.jsx +++ b/src/components/modals/main/settings/sections/Message.jsx @@ -23,7 +23,7 @@ export default class Message extends PureComponent { messages: [], }); toast(variables.getMessage(this.languagecode, 'toasts.reset')); - EventBus.dispatch('refresh', 'message'); + EventBus.emit('refresh', 'message'); }; modifyMessage(type, index) { diff --git a/src/components/modals/main/settings/sections/Overview.jsx b/src/components/modals/main/settings/sections/Overview.jsx index 4b0f3520..1679eaea 100644 --- a/src/components/modals/main/settings/sections/Overview.jsx +++ b/src/components/modals/main/settings/sections/Overview.jsx @@ -124,7 +124,7 @@ export default class OrderSettings extends PureComponent { componentDidUpdate() { localStorage.setItem('order', JSON.stringify(this.state.items)); variables.stats.postEvent('setting', 'Widget order'); - EventBus.dispatch('refresh', 'widgets'); + EventBus.emit('refresh', 'widgets'); } componentDidMount() { diff --git a/src/components/modals/main/settings/sections/Quote.jsx b/src/components/modals/main/settings/sections/Quote.jsx index b2070b3f..4e5a4674 100644 --- a/src/components/modals/main/settings/sections/Quote.jsx +++ b/src/components/modals/main/settings/sections/Quote.jsx @@ -46,7 +46,7 @@ export default class QuoteSettings extends PureComponent { ], }); toast(variables.getMessage('toasts.reset')); - EventBus.dispatch('refresh', 'background'); + EventBus.emit('refresh', 'background'); }; customQuote(e, text, index, type) { diff --git a/src/components/modals/main/settings/sections/Search.jsx b/src/components/modals/main/settings/sections/Search.jsx index 405cd90b..7ec8b384 100644 --- a/src/components/modals/main/settings/sections/Search.jsx +++ b/src/components/modals/main/settings/sections/Search.jsx @@ -47,7 +47,7 @@ export default class SearchSettings extends PureComponent { localStorage.setItem('customSearchEngine', this.state.customValue); } - EventBus.dispatch('refresh', 'search'); + EventBus.emit('refresh', 'search'); } setSearchEngine(input) { @@ -64,7 +64,7 @@ export default class SearchSettings extends PureComponent { localStorage.setItem('searchEngine', input); } - EventBus.dispatch('refresh', 'search'); + EventBus.emit('refresh', 'search'); } render() { diff --git a/src/components/modals/main/settings/sections/background/Custom.jsx b/src/components/modals/main/settings/sections/background/Custom.jsx index 5ae81d1f..3cd8bea1 100644 --- a/src/components/modals/main/settings/sections/background/Custom.jsx +++ b/src/components/modals/main/settings/sections/background/Custom.jsx @@ -40,7 +40,7 @@ export default class CustomSettings extends PureComponent { customBackground: [], }); toast(variables.getMessage('toasts.reset')); - EventBus.dispatch('refresh', 'background'); + EventBus.emit('refresh', 'background'); }; customBackground(e, text, index) { diff --git a/src/components/modals/main/settings/sections/background/CustomURLModal.jsx b/src/components/modals/main/settings/sections/background/CustomURLModal.jsx index be4f4264..704f5ce5 100644 --- a/src/components/modals/main/settings/sections/background/CustomURLModal.jsx +++ b/src/components/modals/main/settings/sections/background/CustomURLModal.jsx @@ -1,6 +1,7 @@ import variables from 'modules/variables'; import { useState, memo } from 'react'; -import { MdAdd, MdClose, MdOutlineAddLink } from 'react-icons/md'; +import PropTypes from 'prop-types'; +import { MdClose, MdOutlineAddLink } from 'react-icons/md'; import Tooltip from 'components/helpers/tooltip/Tooltip'; function CustomURLModal({ modalClose, urlError, modalCloseOnly }) { @@ -20,14 +21,14 @@ function CustomURLModal({ modalClose, urlError, modalCloseOnly }) {
- setURL(e.target.value.replace(/(\r\n|\n|\r)/gm, ''))} - varient="outlined" - /> - {urlError} -
+ setURL(e.target.value.replace(/(\r\n|\n|\r)/gm, ''))} + varient="outlined" + /> + {urlError} +
-
+ ); } +CustomURLModal.propTypes = { + modalClose: PropTypes.func.isRequired, + urlError: PropTypes.string.isRequired, + modalCloseOnly: PropTypes.func.isRequired, +}; + export default memo(CustomURLModal); diff --git a/src/components/modals/main/settings/sections/quicklinks/AddModal.jsx b/src/components/modals/main/settings/sections/quicklinks/AddModal.jsx index 80e74627..0c4394de 100644 --- a/src/components/modals/main/settings/sections/quicklinks/AddModal.jsx +++ b/src/components/modals/main/settings/sections/quicklinks/AddModal.jsx @@ -1,6 +1,7 @@ import variables from 'modules/variables'; import { useState, memo } from 'react'; +import PropTypes from 'prop-types'; import { TextareaAutosize } from '@mui/material'; import { MdAddLink, MdClose } from 'react-icons/md'; import Tooltip from 'components/helpers/tooltip/Tooltip'; @@ -69,4 +70,14 @@ function AddModal({ urlError, iconError, addLink, closeModal, edit, editData, ed ); } +AddModal.propTypes = { + urlError: PropTypes.string.isRequired, + iconError: PropTypes.string.isRequired, + addLink: PropTypes.func.isRequired, + closeModal: PropTypes.func.isRequired, + edit: PropTypes.bool.isRequired, + editData: PropTypes.object.isRequired, + editLink: PropTypes.func.isRequired, +}; + export default memo(AddModal); diff --git a/src/components/modals/main/tabs/Addons.jsx b/src/components/modals/main/tabs/Addons.jsx index 9f548fda..3c7a9eca 100644 --- a/src/components/modals/main/tabs/Addons.jsx +++ b/src/components/modals/main/tabs/Addons.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { memo } from 'react'; +import PropTypes from 'prop-types'; import Tabs from './backend/Tabs'; import Added from '../marketplace/sections/Added'; @@ -18,4 +19,8 @@ function Addons(props) { ); } +Addons.propTypes = { + changeTab: PropTypes.func.isRequired, +}; + export default memo(Addons); diff --git a/src/components/modals/main/tabs/Marketplace.jsx b/src/components/modals/main/tabs/Marketplace.jsx index 301b6239..9311509c 100644 --- a/src/components/modals/main/tabs/Marketplace.jsx +++ b/src/components/modals/main/tabs/Marketplace.jsx @@ -1,8 +1,8 @@ import variables from 'modules/variables'; import { memo } from 'react'; +import PropTypes from 'prop-types'; import Tabs from './backend/Tabs'; - import MarketplaceTab from '../marketplace/sections/Marketplace'; function Marketplace(props) { @@ -30,4 +30,8 @@ function Marketplace(props) { ); } +Marketplace.propTypes = { + changeTab: PropTypes.func.isRequired, +}; + export default memo(Marketplace); diff --git a/src/components/modals/main/tabs/Settings.jsx b/src/components/modals/main/tabs/Settings.jsx index 28f3211b..f1cfed91 100644 --- a/src/components/modals/main/tabs/Settings.jsx +++ b/src/components/modals/main/tabs/Settings.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { memo } from 'react'; +import PropTypes from 'prop-types'; import Tabs from './backend/Tabs'; @@ -116,4 +117,8 @@ function Settings(props) { ); } +Settings.propTypes = { + changeTab: PropTypes.func.isRequired, +}; + export default memo(Settings); diff --git a/src/components/modals/main/tabs/backend/Tab.jsx b/src/components/modals/main/tabs/backend/Tab.jsx index 0b36cbcc..b615d863 100644 --- a/src/components/modals/main/tabs/backend/Tab.jsx +++ b/src/components/modals/main/tabs/backend/Tab.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { memo } from 'react'; +import PropTypes from 'prop-types'; import { MdSettings as Settings, MdWidgets as Addons, @@ -162,4 +163,11 @@ function Tab({ label, currentTab, onClick, navbarTab }) { ); } +Tab.propTypes = { + label: PropTypes.string.isRequired, + currentTab: PropTypes.string.isRequired, + onClick: PropTypes.func.isRequired, + navbarTab: PropTypes.bool, +}; + export default memo(Tab); diff --git a/src/components/modals/main/tabs/backend/Tabs.jsx b/src/components/modals/main/tabs/backend/Tabs.jsx index ba6773a3..416cf215 100644 --- a/src/components/modals/main/tabs/backend/Tabs.jsx +++ b/src/components/modals/main/tabs/backend/Tabs.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { MdSettings, MdOutlineShoppingBasket, @@ -10,7 +11,7 @@ import { import Tab from './Tab'; import ErrorBoundary from '../../../ErrorBoundary'; -export default class Tabs extends PureComponent { +class Tabs extends PureComponent { constructor(props) { super(props); @@ -129,3 +130,16 @@ export default class Tabs extends PureComponent { ); } } + +Tabs.propTypes = { + children: PropTypes.instanceOf(Array).isRequired, + current: PropTypes.string.isRequired, + changeTab: PropTypes.func.isRequired, + navbar: PropTypes.bool, +}; + +Tabs.defaultProps = { + navbar: false, +}; + +export default Tabs; diff --git a/src/components/modals/welcome/ProgressBar.jsx b/src/components/modals/welcome/ProgressBar.jsx index f67dcc14..801513e7 100644 --- a/src/components/modals/welcome/ProgressBar.jsx +++ b/src/components/modals/welcome/ProgressBar.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; function ProgressBar({ count, currentTab, switchTab }) { return ( @@ -17,4 +18,10 @@ function ProgressBar({ count, currentTab, switchTab }) { ); } +ProgressBar.propTypes = { + count: PropTypes.arrayOf(PropTypes.number).isRequired, + currentTab: PropTypes.number.isRequired, + switchTab: PropTypes.func.isRequired, +}; + export default memo(ProgressBar); diff --git a/src/components/modals/welcome/Welcome.jsx b/src/components/modals/welcome/Welcome.jsx index 9429170d..71f03a81 100644 --- a/src/components/modals/welcome/Welcome.jsx +++ b/src/components/modals/welcome/Welcome.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import EventBus from 'modules/helpers/eventbus'; @@ -8,7 +9,7 @@ import ProgressBar from './ProgressBar'; import './welcome.scss'; -export default class WelcomeModal extends PureComponent { +class WelcomeModal extends PureComponent { constructor() { super(); this.state = { @@ -145,3 +146,10 @@ export default class WelcomeModal extends PureComponent { ); } } + +WelcomeModal.propTypes = { + modalClose: PropTypes.func.isRequired, + modalSkip: PropTypes.func.isRequired, +}; + +export default WelcomeModal; diff --git a/src/components/modals/welcome/WelcomeSections.jsx b/src/components/modals/welcome/WelcomeSections.jsx index ce23c2b4..add037e2 100644 --- a/src/components/modals/welcome/WelcomeSections.jsx +++ b/src/components/modals/welcome/WelcomeSections.jsx @@ -1,5 +1,7 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; + import { MdCloudUpload, MdAutoAwesome, @@ -22,7 +24,7 @@ import { importSettings } from 'modules/helpers/settings/modals'; import default_settings from 'modules/default_settings.json'; import languages from 'modules/languages.json'; -export default class WelcomeSections extends PureComponent { +class WelcomeSections extends PureComponent { constructor() { super(); this.state = { @@ -420,3 +422,10 @@ export default class WelcomeSections extends PureComponent { } } } + +WelcomeSections.propTypes = { + currentTab: PropTypes.number.isRequired, + switchTab: PropTypes.func.isRequired, +}; + +export default WelcomeSections; diff --git a/src/components/widgets/background/ExcludeModal.jsx b/src/components/widgets/background/ExcludeModal.jsx index 325dae36..39c6bb99 100644 --- a/src/components/widgets/background/ExcludeModal.jsx +++ b/src/components/widgets/background/ExcludeModal.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { memo } from 'react'; +import PropTypes from 'prop-types'; import EventBus from 'modules/helpers/eventbus'; import Tooltip from 'components/helpers/tooltip/Tooltip'; import { MdClose, MdDone } from 'react-icons/md'; @@ -10,7 +11,7 @@ function ExcludeModal({ modalClose, info }) { backgroundExclude.push(info.pun); backgroundExclude = JSON.stringify(backgroundExclude); localStorage.setItem('backgroundExclude', backgroundExclude); - EventBus.dispatch('refresh', 'background'); + EventBus.emit('refresh', 'background'); modalClose(); }; @@ -45,4 +46,9 @@ function ExcludeModal({ modalClose, info }) { ); } +ExcludeModal.propTypes = { + modalClose: PropTypes.func.isRequired, + info: PropTypes.object.isRequired, +}; + export default memo(ExcludeModal); diff --git a/src/components/widgets/background/Favourite.jsx b/src/components/widgets/background/Favourite.jsx index 29b5f3a8..21944e59 100644 --- a/src/components/widgets/background/Favourite.jsx +++ b/src/components/widgets/background/Favourite.jsx @@ -1,8 +1,9 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; import { MdStar, MdStarBorder } from 'react-icons/md'; -export default class Favourite extends PureComponent { +class Favourite extends PureComponent { buttons = { favourited: this.favourite()} className="topicons" />, unfavourited: this.favourite()} className="topicons" />, @@ -103,3 +104,9 @@ export default class Favourite extends PureComponent { return this.state.favourited; } } + +Favourite.propTypes = { + credit: PropTypes.string, + offline: PropTypes.bool, + pun: PropTypes.string, +}; diff --git a/src/components/widgets/background/Maximise.jsx b/src/components/widgets/background/Maximise.jsx index bf5d1558..04fe43fa 100644 --- a/src/components/widgets/background/Maximise.jsx +++ b/src/components/widgets/background/Maximise.jsx @@ -1,10 +1,12 @@ import variables from 'modules/variables'; import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; + import { MdCropFree } from 'react-icons/md'; import Tooltip from 'components/helpers/tooltip/Tooltip'; -export default class Maximise extends PureComponent { +class Maximise extends PureComponent { constructor() { super(); this.state = { @@ -81,3 +83,9 @@ export default class Maximise extends PureComponent { ); } } + +Maximise.propTypes = { + fontSize: PropTypes.number, +}; + +export default Maximise; diff --git a/src/components/widgets/background/PhotoInformation.jsx b/src/components/widgets/background/PhotoInformation.jsx index 5d438091..022c208b 100644 --- a/src/components/widgets/background/PhotoInformation.jsx +++ b/src/components/widgets/background/PhotoInformation.jsx @@ -1,5 +1,6 @@ import variables from 'modules/variables'; import { useState, memo } from 'react'; +import PropTypes from 'prop-types'; import Favourite from './Favourite'; import { MdInfo, @@ -19,15 +20,29 @@ import Modal from 'react-modal'; import ShareModal from 'components/helpers/sharemodal/ShareModal'; import ExcludeModal from './ExcludeModal'; +/** + * It takes a URL, fetches the resource, and returns a URL to the resource. + * @param {string} url The URL to fetch. + * @returns A promise that resolves to a blob URL. + */ const toDataURL = async (url) => { const res = await fetch(url); return URL.createObjectURL(await res.blob()); }; +/** + * It takes a string, makes it lowercase, removes commas, and replaces spaces with dashes. + * @param {string} text The string to format. + * @returns A function that takes a string and returns a string. + */ const formatText = (text) => { return text.toLowerCase().replaceAll(',', '').replaceAll(' ', '-'); }; +/** + * It downloads an image from a URL and saves it to the user's computer. + * @param {object} info The photo information. + */ const downloadImage = async (info) => { const link = document.createElement('a'); link.href = await toDataURL(info.url); @@ -383,4 +398,10 @@ function PhotoInformation({ info, url, api }) { ); } +PhotoInformation.propTypes = { + info: PropTypes.object.isRequired, + url: PropTypes.string.isRequired, + api: PropTypes.string.isRequired, +}; + export default memo(PhotoInformation); diff --git a/src/components/widgets/greeting/Greeting.jsx b/src/components/widgets/greeting/Greeting.jsx index 55cb59d0..3f6c32e7 100644 --- a/src/components/widgets/greeting/Greeting.jsx +++ b/src/components/widgets/greeting/Greeting.jsx @@ -16,6 +16,13 @@ export default class Greeting extends PureComponent { this.greeting = createRef(); } + /** + * Change the greeting message for the events of Christmas, New Year and Halloween. + * If the events setting is disabled, then the greeting message will not be changed. + * @param {Date} time The current time. + * @param {String} message The current greeting message. + * @returns The message variable is being returned. + */ doEvents(time, message) { if (localStorage.getItem('events') === 'false') { return message; @@ -39,6 +46,11 @@ export default class Greeting extends PureComponent { return message; } + /** + * It takes a date object and returns the age of the person in years. + * @param {Date} date The date of birth. + * @returns The age of the person. + */ calculateAge(date) { const diff = Date.now() - date.getTime(); const birthday = new Date(diff); diff --git a/src/components/widgets/navbar/Navbar.jsx b/src/components/widgets/navbar/Navbar.jsx index 4af28485..31de2a3f 100644 --- a/src/components/widgets/navbar/Navbar.jsx +++ b/src/components/widgets/navbar/Navbar.jsx @@ -1,5 +1,7 @@ import variables from 'modules/variables'; import { PureComponent, createRef } from 'react'; +import PropTypes from 'prop-types'; + import { MdRefresh, MdSettings } from 'react-icons/md'; import Notes from './Notes'; @@ -11,7 +13,7 @@ import EventBus from 'modules/helpers/eventbus'; import './scss/index.scss'; -export default class Navbar extends PureComponent { +class Navbar extends PureComponent { constructor() { super(); this.navbarContainer = createRef(); @@ -81,12 +83,12 @@ export default class Navbar extends PureComponent { refresh() { switch (this.state.refreshOption) { case 'background': - return EventBus.dispatch('refresh', 'backgroundrefresh'); + return EventBus.emit('refresh', 'backgroundrefresh'); case 'quote': - return EventBus.dispatch('refresh', 'quoterefresh'); + return EventBus.emit('refresh', 'quoterefresh'); case 'quotebackground': - EventBus.dispatch('refresh', 'quoterefresh'); - return EventBus.dispatch('refresh', 'backgroundrefresh'); + EventBus.emit('refresh', 'quoterefresh'); + return EventBus.emit('refresh', 'backgroundrefresh'); default: window.location.reload(); } @@ -143,3 +145,9 @@ export default class Navbar extends PureComponent { ); } } + +Navbar.propTypes = { + openModal: PropTypes.func, +}; + +export default Navbar; diff --git a/src/components/widgets/navbar/Notes.jsx b/src/components/widgets/navbar/Notes.jsx index 488f79a4..eaea1b13 100644 --- a/src/components/widgets/navbar/Notes.jsx +++ b/src/components/widgets/navbar/Notes.jsx @@ -1,5 +1,7 @@ import variables from 'modules/variables'; import { PureComponent, memo } from 'react'; +import PropTypes from 'prop-types'; + import { MdContentCopy, MdAssignment, MdPushPin, MdDownload } from 'react-icons/md'; import { useFloating, shift } from '@floating-ui/react-dom'; import TextareaAutosize from '@mui/material/TextareaAutosize'; @@ -120,12 +122,12 @@ class Notes extends PureComponent { - - @@ -162,4 +164,12 @@ function NotesWrapper() { ); } +Notes.propTypes = { + notesRef: PropTypes.object, + floatRef: PropTypes.object, + position: PropTypes.string, + xPosition: PropTypes.number, + yPosition: PropTypes.number, +}; + export default memo(NotesWrapper); diff --git a/src/components/widgets/navbar/Todo.jsx b/src/components/widgets/navbar/Todo.jsx index b12d28b4..43648e93 100644 --- a/src/components/widgets/navbar/Todo.jsx +++ b/src/components/widgets/navbar/Todo.jsx @@ -1,5 +1,7 @@ import variables from 'modules/variables'; import { PureComponent, memo } from 'react'; +import PropTypes from 'prop-types'; + import { MdChecklist, MdPushPin, @@ -53,6 +55,13 @@ class Todo extends PureComponent { EventBus.off('refresh'); } + /** + * It takes an array, removes an item from it, and then inserts it at a new index. + * @param {Array} array The array to move the item in. + * @param {Number} oldIndex The index of the item to move. + * @param {Number} newIndex The index to move the item to. + * @returns The result of the splice method. + */ arrayMove(array, oldIndex, newIndex) { const result = Array.from(array); const [removed] = result.splice(oldIndex, 1); @@ -79,6 +88,12 @@ class Todo extends PureComponent { }); } + /** + * This function takes in an action, an index, and data, and then updates the todo list accordingly. + * @param {String} action The action to perform. Can be 'add', 'remove', 'set', or 'done'. + * @param {Number} index The index of the item to perform the action on. + * @param {Object} data The data to use for the action. + */ updateTodo(action, index, data) { let todo = this.state.todo; switch (action) { @@ -228,4 +243,12 @@ function TodoWrapper() { ); } +Todo.propTypes = { + todoRef: PropTypes.object, + floatRef: PropTypes.object, + position: PropTypes.string, + xPosition: PropTypes.string, + yPosition: PropTypes.string, +}; + export default memo(TodoWrapper); diff --git a/src/components/widgets/navbar/scss/_notes.scss b/src/components/widgets/navbar/scss/_notes.scss index 941e5f1e..93147de7 100644 --- a/src/components/widgets/navbar/scss/_notes.scss +++ b/src/components/widgets/navbar/scss/_notes.scss @@ -109,13 +109,13 @@ textarea { display: flex !important; gap: 10px; button { - &:disabled { - @include themed() { - background: t($modal-sidebar) !important; + &:disabled { + @include themed() { + background: t($modal-sidebar) !important; + } + cursor: not-allowed; } - cursor: not-allowed; } -} .tooltip { flex: 1 !important; diff --git a/src/components/widgets/search/Search.jsx b/src/components/widgets/search/Search.jsx index 3346fd08..7d27ff22 100644 --- a/src/components/widgets/search/Search.jsx +++ b/src/components/widgets/search/Search.jsx @@ -114,6 +114,12 @@ export default class Search extends PureComponent { }); } + /** + * If the user selects a search engine from the dropdown menu, the function will set the state of the + * search engine to the selected search engine. + * @param {string} name - The name of the search engine + * @param {boolean} custom - If the search engine is custom + */ setSearch(name, custom) { let url; let query = 'q'; @@ -166,6 +172,11 @@ export default class Search extends PureComponent { EventBus.off('refresh'); } + /** + * Gets the icon for the search engine dropdown. + * @param {string} name - The name of the search engine. + * @returns A React component. + */ getSearchDropdownicon(name) { switch (name) { case 'Google': @@ -196,7 +207,9 @@ export default class Search extends PureComponent {
{localStorage.getItem('searchDropdown') === 'true' ? ( - +
diff --git a/src/components/widgets/time/Date.jsx b/src/components/widgets/time/Date.jsx index b248cf49..123125ee 100644 --- a/src/components/widgets/time/Date.jsx +++ b/src/components/widgets/time/Date.jsx @@ -1,7 +1,7 @@ import variables from 'modules/variables'; import { PureComponent, createRef } from 'react'; -import { nth, convertTimezone } from 'modules/helpers/date'; +import { nth, convertTimezone } from '../../../modules/helpers/date'; import EventBus from 'modules/helpers/eventbus'; import './date.scss'; @@ -16,6 +16,10 @@ export default class DateWidget extends PureComponent { this.date = createRef(); } + /** + * Get the week number of the year for the given date. + * @param {Date} date + */ getWeekNumber(date) { const dateToday = new Date(date.valueOf()); const dayNumber = (dateToday.getDay() + 6) % 7; diff --git a/src/components/widgets/weather/Expanded.jsx b/src/components/widgets/weather/Expanded.jsx index 0dd09b63..119df044 100644 --- a/src/components/widgets/weather/Expanded.jsx +++ b/src/components/widgets/weather/Expanded.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import { WiHumidity, WiWindy, WiBarometer, WiCloud } from 'react-icons/wi'; import { MdDisabledVisible } from 'react-icons/md'; @@ -9,6 +10,12 @@ import WindDirectionIcon from './WindDirectionIcon'; import Tooltip from 'components/helpers/tooltip/Tooltip'; function Expanded({ state, weatherType, variables }) { + /** + * If the localStorage item is true and the weatherType is greater than or equal to 3, or if the + * weatherType is equal to 3, then return true. + * @param {string} setting - The localStorage item to check. + * @returns a boolean value. + */ const enabled = (setting) => { return (localStorage.getItem(setting) === 'true' && weatherType >= 3) || weatherType === '3'; }; @@ -107,4 +114,10 @@ function Expanded({ state, weatherType, variables }) { ); } +Expanded.propTypes = { + state: PropTypes.object.isRequired, + weatherType: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + variables: PropTypes.object.isRequired, +}; + export default memo(Expanded); diff --git a/src/components/widgets/weather/WeatherIcon.jsx b/src/components/widgets/weather/WeatherIcon.jsx index 51bcf303..16b2047d 100644 --- a/src/components/widgets/weather/WeatherIcon.jsx +++ b/src/components/widgets/weather/WeatherIcon.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import { WiDaySunny, @@ -53,4 +54,8 @@ function WeatherIcon({ name }) { } } +WeatherIcon.propTypes = { + name: PropTypes.string.isRequired, +}; + export default memo(WeatherIcon); diff --git a/src/components/widgets/weather/WindDirectionIcon.jsx b/src/components/widgets/weather/WindDirectionIcon.jsx index b767153f..5b0c5191 100644 --- a/src/components/widgets/weather/WindDirectionIcon.jsx +++ b/src/components/widgets/weather/WindDirectionIcon.jsx @@ -1,4 +1,5 @@ import { memo } from 'react'; +import PropTypes from 'prop-types'; import { WiDirectionDownLeft, @@ -54,4 +55,8 @@ function WindDirectionIcon({ degrees }) { return direction ? direction.icon : null; } +WindDirectionIcon.propTypes = { + degrees: PropTypes.number.isRequired, +}; + export default memo(WindDirectionIcon); diff --git a/src/index.jsx b/src/index.jsx index c62f44fe..78d9be16 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -2,15 +2,13 @@ import { render } from 'react-dom'; import * as Sentry from '@sentry/react'; import App from './App'; -import variables from 'modules/variables'; +import variables from './modules/variables'; import './scss/index.scss'; // the toast css is based on default so we need to import it import 'react-toastify/dist/ReactToastify.min.css'; -import Stats from 'modules/helpers/stats'; - -import translations from 'modules/translations'; +import translations from './modules/translations'; const languagecode = localStorage.getItem('language') || 'en_GB'; variables.language = translations(languagecode); @@ -20,8 +18,6 @@ document.documentElement.lang = languagecode.replace('_', '-'); variables.getMessage = (text, optional) => variables.language.getMessage(variables.languagecode, text, optional || {}); -variables.stats = Stats; - Sentry.init({ dsn: variables.constants.SENTRY_DSN, defaultIntegrations: false, diff --git a/src/modules/helpers/background/avif.js b/src/modules/helpers/background/avif.js index 6b267edc..1ea5ff35 100644 --- a/src/modules/helpers/background/avif.js +++ b/src/modules/helpers/background/avif.js @@ -1,6 +1,10 @@ const testImage = 'AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAAFCbWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAFBETmF2aWYAAAAADnBpdG0AAAAAAAEAAAAsaWxvYwAAAABEAAACAAEAAAABAAACRgAAABgAAgAAAAEAAAFqAAAA3AAAAEFpaW5mAAAAAAACAAAAGmluZmUCAAAAAAEAAGF2MDFDb2xvcgAAAAAZaW5mZQIAAAEAAgAARXhpZkV4aWYAAAAAGmlyZWYAAAAAAAAADmNkc2MAAgABAAEAAAB5aXBycAAAAFlpcGNvAAAAFGlzcGUAAAAAAAAAAQAAAAEAAAAQcGFzcAAAAAEAAAABAAAADGF2MUOBABwAAAAADnBpeGkAAAAAAQgAAAATY29scm5jbHgAAQANAAGAAAAAGGlwbWEAAAAAAAAAAQABBQECg4SFAAAA/G1kYXQAAAAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAADEBAgARAAAAZgAAAGmHBAABAAAAeAAAAAAAAAABAAAAAQAAAAEAAAABAAAAcGFpbnQubmV0IDQuMy4xMgAABQAAkAcABAAAADAyMzABoAMAAQAAAAEAAAACoAQAAQAAAAEAAAADoAQAAQAAAAEAAAAFoAQAAQAAALoAAAAAAAAAAgABAAIABAAAAFI5OAACAAcABAAAADAxMDAAAAAAEgAKBxgABpgIaA0yCxJABBEAEADG1FkX'; +/** + * It creates a new image element, sets the source to a base64 encoded AVIF image, and then resolves + * true if the image loads successfully, or false if it doesn't + */ export const supportsAVIF = () => { new Promise((resolve) => { const image = new Image(); diff --git a/src/modules/helpers/background/hexToRgb.js b/src/modules/helpers/background/hexToRgb.js index 587b4313..ad2960f3 100644 --- a/src/modules/helpers/background/hexToRgb.js +++ b/src/modules/helpers/background/hexToRgb.js @@ -4,6 +4,11 @@ import setRgba from './setRgba'; const hexRegexp = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)|(^#{0,1}[0-9A-F]{8}$)/i; const regexp = /([0-9A-F])([0-9A-F])([0-9A-F])/i; +/** + * It takes a hex color code and returns an object with the color's RGB and HSV values + * @param value - The hex value to convert to RGB. + * @returns An object with the properties red, green, blue, alpha, hue, saturation, and value. + */ export default function hexToRgb(value) { const valid = hexRegexp.test(value); diff --git a/src/modules/helpers/background/rgbToHex.js b/src/modules/helpers/background/rgbToHex.js index fb5a22d9..49b44510 100644 --- a/src/modules/helpers/background/rgbToHex.js +++ b/src/modules/helpers/background/rgbToHex.js @@ -1,3 +1,11 @@ +/** + * It takes three numbers, converts them to hexadecimal, and returns a string of the three hexadecimal + * numbers concatenated together + * @param red - The red value of the color (0-255) + * @param green - 0 + * @param blue - 0 + * @returns a string of the hexadecimal value of the rgb values passed in. + */ export default function rgbToHex(red, green, blue) { let r16 = red.toString(16); let g16 = green.toString(16); diff --git a/src/modules/helpers/background/rgbToHsv.js b/src/modules/helpers/background/rgbToHsv.js index 0bc0febb..65e7eb12 100644 --- a/src/modules/helpers/background/rgbToHsv.js +++ b/src/modules/helpers/background/rgbToHsv.js @@ -1,3 +1,10 @@ +/** + * It converts RGB values to HSV values + * @returns An object with the hue, saturation, and value of the color. + * @param red - The red value of the color. + * @param green - 0-255 + * @param blue - The blue value of the color. + */ export default function rgbToHSv({ red, green, blue }) { let rr, gg, bb, h, s; diff --git a/src/modules/helpers/background/setRgba.js b/src/modules/helpers/background/setRgba.js index 2a2b73b3..a4a0ec64 100644 --- a/src/modules/helpers/background/setRgba.js +++ b/src/modules/helpers/background/setRgba.js @@ -1,7 +1,23 @@ +/** + * It returns true if the value is a number, not NaN, and between 0 and 255. + * @param value - The value to check. + * @returns A function that takes a value and returns a boolean. + */ const isValidRGBValue = (value) => { return typeof value === 'number' && Number.isNaN(value) === false && value >= 0 && value <= 255; }; +/** + * "If the red, green, and blue values are valid, return an object with the red, green, and blue + * values, and if the alpha value is valid, add it to the object." + * + * The function is a bit more complicated than that, but that's the gist of it + * @param red - The red value of the color. + * @param green - 0-255 + * @param blue - The blue value of the color. + * @param alpha - The alpha value of the color. + * @returns An object with the properties red, green, blue, and alpha. + */ export default function setRGBA(red, green, blue, alpha) { if (isValidRGBValue(red) && isValidRGBValue(green) && isValidRGBValue(blue)) { const color = { diff --git a/src/modules/helpers/background/widget.js b/src/modules/helpers/background/widget.js index fd6e1b9b..b06d0eca 100644 --- a/src/modules/helpers/background/widget.js +++ b/src/modules/helpers/background/widget.js @@ -1,6 +1,11 @@ // since there is so much code in the component, we have moved it to a separate file import offlineImages from './offlineImages.json'; +/** + * If the URL starts with `data:video/` or ends with `.mp4`, `.webm`, or `.ogg`, then it's a video. + * @param url - The URL of the file to be checked. + * @returns A function that takes a url and returns a boolean. + */ export function videoCheck(url) { return ( url.startsWith('data:video/') || @@ -10,8 +15,19 @@ export function videoCheck(url) { ); } +/** + * It gets a random photographer from the offlineImages.json file, then gets a random image from that + * photographer, and returns an object with the image's URL, type, and photoInfo. + * + * @param type - 'background' or 'thumbnail' + * @returns An object with the following properties: + * url: A string that is the path to the image. + * type: A string that is the type of image. + * photoInfo: An object with the following properties: + * offline: A boolean that is true. + * credit: A string that is the name of the photographer. + */ export function offlineBackground(type) { - // Get all photographers from the keys in offlineImages.json const photographers = Object.keys(offlineImages); const photographer = photographers[Math.floor(Math.random() * photographers.length)]; @@ -33,6 +49,10 @@ export function offlineBackground(type) { return object; } +/** + * It takes a gradient object and returns a style object + * @returns An object with two properties: type and style. + */ function gradientStyleBuilder({ type, angle, gradient }) { // Note: Append the gradient for additional browser support. const steps = gradient?.map((v) => `${v.colour} ${v.stop}%`); @@ -44,6 +64,10 @@ function gradientStyleBuilder({ type, angle, gradient }) { }; } +/** + * It gets the gradient settings from localStorage, parses it, and returns the gradient style. + * @returns A string. + */ export function getGradient() { const customBackgroundColour = localStorage.getItem('customBackgroundColour') || { angle: '180', @@ -72,6 +96,11 @@ export function getGradient() { } } +/** + * It returns a random colour or random gradient as a style object + * @param type - The type of the style. This is used to determine which style builder to use. + * @returns An object with two properties: type and style. + */ export function randomColourStyleBuilder(type) { // randomColour based on https://stackoverflow.com/a/5092872 const randomColour = () => diff --git a/src/modules/helpers/date.js b/src/modules/helpers/date.js index 30b97381..35a5ace9 100644 --- a/src/modules/helpers/date.js +++ b/src/modules/helpers/date.js @@ -1,3 +1,9 @@ +/** + * If the number is between 3 and 20, return the number with the suffix "th". Otherwise, return the + * number with the suffix "st", "nd", "rd", or "th" depending on the last digit of the number + * @param d - The day of the month. + * @returns the day of the month with the appropriate suffix. + */ export function nth(d) { if (d > 3 && d < 21) { return d + 'th'; @@ -15,6 +21,12 @@ export function nth(d) { } } +/** + * It takes a date and a timezone and returns a new date object with the timezone applied. + * @param date - The date you want to convert. + * @param tz - The timezone you want to convert to. + * @returns A new Date object with the timezone set to the timezone passed in. + */ export function convertTimezone(date, tz) { return new Date( (typeof date === 'string' ? new Date(date) : date).toLocaleString('en-US', { diff --git a/src/modules/helpers/eventbus.js b/src/modules/helpers/eventbus.js index 1d402f4e..05d72fb8 100644 --- a/src/modules/helpers/eventbus.js +++ b/src/modules/helpers/eventbus.js @@ -1,13 +1,28 @@ -// one day it might be a good idea to replace all this with redux, but it'd take -// a lot of rewriting export default class EventBus { + static listeners = {}; + + /** + * The on function adds an event listener to the document, and then pushes the callback function into + * the listeners array. + * @param event - The event name + * @param callback - The function to be called when the event is triggered. + */ static on(event, callback) { document.addEventListener(event, (e) => { callback(e.detail); }); + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].push(callback); } - static dispatch(event, data) { + /** + * It creates a new custom event, and dispatches it + * @param event - The name of the event you want to emit. + * @param data - The data you want to pass to the event. + */ + static emit(event, data) { document.dispatchEvent( new CustomEvent(event, { detail: data, @@ -15,7 +30,107 @@ export default class EventBus { ); } + /** + * It removes an event listener from the document and removes the callback from the listeners array + * @param event - The event to listen for. + * @param callback - The function to be called when the event is triggered. + */ static off(event, callback) { document.removeEventListener(event, callback); + if (this.listeners[event]) { + this.listeners[event] = this.listeners[event].filter((listener) => listener !== callback); + } + } + + /** + * The once function takes an event and a callback, and then adds a listener to the event that calls + * the callback with the event's detail, and then removes the listener. + * @param event - The event name + * @param callback - The function to be called when the event is triggered. + */ + static once(event, callback) { + const listener = (e) => { + callback(e.detail); + this.off(event, listener); + }; + document.addEventListener(event, listener); + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].push({ callback, listener }); + } + + /** + * It adds a listener to the beginning of the event listener queue. + * @param event - The name of the event to listen for. + * @param callback - The function to be called when the event is triggered. + */ + static prepend(event, callback) { + const listener = (e) => { + callback(e.detail); + }; + document.addEventListener( + event, + listener, + true, // set `useCapture` to `true` to insert the listener at the beginning + ); + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].unshift({ callback, listener }); + } + + /** + * It adds an event listener to the document that will be called before any other event listeners for + * the same event + * @param event - The name of the event to listen for. + * @param callback - The function to be called when the event is triggered. + */ + static prependOnce(event, callback) { + const listener = (e) => { + callback(e.detail); + this.off(event, listener); + }; + document.addEventListener( + event, + listener, + true, // set `useCapture` to `true` to insert the listener at the beginning + ); + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].unshift({ callback, listener }); + } + + /** + * If the event exists, return the listeners for that event, otherwise return an empty array. + * @param event - The event name. + * @returns An array of listeners for the event. + */ + static getListeners(event) { + if (this.listeners[event]) { + return this.listeners[event]; + } + return []; + } + + /** + * It returns an array of all the event names that have listeners attached to them. + * @returns An array of the keys of the listeners object. + */ + static eventNames() { + return Object.keys(this.listeners); + } + + /** + * It removes all event listeners from the document. + */ + static removeAllListeners() { + Object.keys(this.listeners).forEach((event) => { + this.listeners[event].forEach(({ listener }) => { + document.removeEventListener(event, listener); + }); + }); + this.listeners = {}; } } diff --git a/src/modules/helpers/marketplace.js b/src/modules/helpers/marketplace.js index 0ffbb600..74bd4b70 100644 --- a/src/modules/helpers/marketplace.js +++ b/src/modules/helpers/marketplace.js @@ -48,7 +48,7 @@ export function install(type, input, sideload) { } localStorage.setItem('backgroundType', 'photo_pack'); localStorage.removeItem('backgroundchange'); - EventBus.dispatch('refresh', 'background'); + EventBus.emit('refresh', 'background'); // TODO: make this legitimately good and work without a reload - currently we just refresh sleep(4000); window.location.reload(); @@ -66,7 +66,7 @@ export function install(type, input, sideload) { } localStorage.setItem('quoteType', 'quote_pack'); localStorage.removeItem('quotechange'); - EventBus.dispatch('refresh', 'quote'); + EventBus.emit('refresh', 'quote'); break; default: @@ -121,7 +121,7 @@ export function uninstall(type, name) { localStorage.removeItem('quote_packs'); } localStorage.removeItem('quotechange'); - EventBus.dispatch('refresh', 'marketplacequoteuninstall'); + EventBus.emit('refresh', 'marketplacequoteuninstall'); break; case 'photos': @@ -142,7 +142,7 @@ export function uninstall(type, name) { localStorage.removeItem('photo_packs'); } localStorage.removeItem('backgroundchange'); - EventBus.dispatch('refresh', 'marketplacebackgrounduninstall'); + EventBus.emit('refresh', 'marketplacebackgrounduninstall'); break; default: diff --git a/src/modules/helpers/settings/index.js b/src/modules/helpers/settings/index.js index ef475078..fba29f91 100644 --- a/src/modules/helpers/settings/index.js +++ b/src/modules/helpers/settings/index.js @@ -4,6 +4,10 @@ import experimentalInit from '../experimental'; import defaultSettings from 'modules/default_settings.json'; import languages from 'modules/languages.json'; +/** + * It sets the default settings for the extension + * @param reset - boolean + */ export function setDefaultSettings(reset) { localStorage.clear(); defaultSettings.forEach((element) => localStorage.setItem(element.name, element.value)); @@ -31,6 +35,10 @@ export function setDefaultSettings(reset) { localStorage.setItem('firstRun', true); } +/** + * It loads the settings from localStorage and applies them to the page. + * @param hotreload - boolean + */ export function loadSettings(hotreload) { switch (localStorage.getItem('theme')) { case 'dark': @@ -157,8 +165,11 @@ export function loadSettings(hotreload) { `); } -// in a nutshell, this function saves all of the current settings, resets them, sets the defaults and then overrides -// the new settings with the old saved messages where they exist +/** + * Saves all of the current settings, resets them, sets the defaults and then overrides + * the new settings with the old saved messages where they exist. + * @returns the result of the setDefaultSettings() function. + */ export function moveSettings() { const currentSettings = Object.keys(localStorage); if (currentSettings.length === 0) { diff --git a/src/modules/helpers/settings/modals.js b/src/modules/helpers/settings/modals.js index 3bfdba11..1fc0db63 100644 --- a/src/modules/helpers/settings/modals.js +++ b/src/modules/helpers/settings/modals.js @@ -1,6 +1,12 @@ import variables from 'modules/variables'; import { toast } from 'react-toastify'; +/** + * It creates a link to a file, and then clicks it + * @param data - the data you want to save + * @param [filename=file] - the name of the file to be saved + * @param [type=text/json] - the type of file you want to save. + */ export function saveFile(data, filename = 'file', type = 'text/json') { if (typeof data === 'object') { data = JSON.stringify(data, undefined, 4); @@ -36,6 +42,9 @@ export function saveFile(data, filename = 'file', type = 'text/json') { a.dispatchEvent(event); } +/** + * It takes all the settings from localStorage and saves them to a file + */ export function exportSettings() { const settings = {}; @@ -49,6 +58,11 @@ export function exportSettings() { variables.stats.postEvent('tab', 'Settings exported'); } +/** + * It takes a JSON file of Mue settings, parses it, and then sets the localStorage values to the values in the + * file. + * @param e - The JSON settings string to import + */ export function importSettings(e) { const content = JSON.parse(e); @@ -60,6 +74,11 @@ export function importSettings(e) { variables.stats.postEvent('tab', 'Settings imported'); } +/** + * It returns an array of objects with a value and label property for the Mue sliders. + * @param type - The type of slider you want to use. + * @returns An object with keys of either zoom, toast, background or experimental. + */ export function values(type) { const marks = { zoom: [ @@ -98,5 +117,5 @@ export function values(type) { ], }; - return marks[type]; + return marks[type] || []; } diff --git a/src/modules/helpers/stats.js b/src/modules/helpers/stats.js index 813ef567..bbd43c49 100644 --- a/src/modules/helpers/stats.js +++ b/src/modules/helpers/stats.js @@ -1,4 +1,11 @@ export default class Stats { + /** + * It takes two arguments, a type and a name, and then it increments the value of the name in the type + * object in localStorage + * @param type - The type of event you want to track. This can be anything you want, but I recommend + * using something like "click" or "hover" + * @param name - The name of the event. + */ static async postEvent(type, name) { const value = name.toLowerCase().replaceAll(' ', '-'); @@ -19,6 +26,9 @@ export default class Stats { localStorage.setItem('statsData', JSON.stringify(data)); } + /** + * It increments the value of the key 'tabs-opened' in the object stored in localStorage by 1. + */ static async tabLoad() { const data = JSON.parse(localStorage.getItem('statsData')); data['tabs-opened'] = data['tabs-opened'] + 1 || 1; diff --git a/src/modules/translations.js b/src/modules/translations.js index 52e3ec15..f3d8e5b0 100644 --- a/src/modules/translations.js +++ b/src/modules/translations.js @@ -1,34 +1,26 @@ import I18n from '@eartharoid/i18n'; -import * as de_DE from '../translations/de_DE.json'; -import * as en_GB from '../translations/en_GB.json'; -import * as en_US from '../translations/en_US.json'; -import * as es from '../translations/es.json'; -import * as es_419 from '../translations/es_419.json'; -import * as fr from '../translations/fr.json'; -import * as nl from '../translations/nl.json'; -import * as no from '../translations/no.json'; -import * as ru from '../translations/ru.json'; -import * as zh_CN from '../translations/zh_CN.json'; -import * as id_ID from '../translations/id_ID.json'; -import * as tr_TR from '../translations/tr_TR.json'; -import * as pt_BR from '../translations/pt_BR.json'; - +/** + * Initialise the i18n object. + * The i18n object is then returned. + * @param locale - The locale to use. + * @returns The i18n object. + */ export default function initTranslations(locale) { const i18n = new I18n(locale, { - de_DE, - en_GB, - en_US, - es, - es_419, - fr, - nl, - no, - ru, - zh_CN, - id_ID, - tr_TR, - pt_BR, + de_DE: import('../translations/de_DE.json'), + en_GB: import('../translations/en_GB.json'), + en_US: import('../translations/en_US.json'), + es: import('../translations/es.json'), + es_419: import('../translations/es_419.json'), + fr: import('../translations/fr.json'), + nl: import('../translations/nl.json'), + no: import('../translations/no.json'), + ru: import('../translations/ru.json'), + zh_CN: import('../translations/zh_CN.json'), + id_ID: import('../translations/id_ID.json'), + tr_TR: import('../translations/tr_TR.json'), + pt_BR: import('../translations/pt_BR.json'), }); return i18n; diff --git a/src/modules/variables.js b/src/modules/variables.js index a5c5a3c8..d2c3aa57 100644 --- a/src/modules/variables.js +++ b/src/modules/variables.js @@ -1,12 +1,10 @@ import * as constants from 'modules/constants'; +import Stats from 'modules/helpers/stats'; const variables = { language: {}, languagecode: '', - stats: { - tabLoad: () => '', - postEvent: () => '', - }, + stats: Stats, constants, }; diff --git a/vite.config.js b/vite.config.js index d8c74e72..a94f3a04 100644 --- a/vite.config.js +++ b/vite.config.js @@ -61,11 +61,7 @@ const prepareBuilds = () => ({ }); export default defineConfig({ - plugins: [ - react(), - prepareBuilds(), - progress(), - ], + plugins: [react(), prepareBuilds(), progress()], server: { open: true, hmr: {