diff --git a/scripts/updatetranslations.js b/scripts/updatetranslations.js index d33a49cf..e0e54624 100644 --- a/scripts/updatetranslations.js +++ b/scripts/updatetranslations.js @@ -37,3 +37,32 @@ fs.readdirSync('../src/i18n/locales').forEach((file) => { // add new line fs.appendFileSync('../src/i18n/locales/' + file, '\n'); }); + + +// do the same with achievements +fs.readdirSync('../src/i18n/achievements').forEach((file) => { + if (file === 'en_GB.json') { + return; + } + + const en = require('../src/i18n/achievements/en_GB.json'); + const newdata = merge(en, require('../src/i18n/achievements/' + file)); + + // remove strings not in english file + compareAndRemoveKeys(newdata, en); + + // write new file + fs.writeFileSync('../src/i18n/achievements/' + file, JSON.stringify(newdata, null, 2)); + + // add new line + fs.appendFileSync('../src/i18n/achievements/' + file, '\n'); + + // if missing translations from locales/ add them to achievements/ + const locales = fs.readdirSync('../src/i18n/locales'); + locales.forEach((locale) => { + if (!fs.existsSync('../src/i18n/achievements/' + locale)) { + fs.writeFileSync('../src/i18n/achievements/' + locale, JSON.stringify(en, null, 2)); + fs.appendFileSync('../src/i18n/achievements/' + locale, '\n'); + } + }); +}); \ No newline at end of file diff --git a/src/features/modals/main/marketplace/components/Collection/Collection.jsx b/src/features/modals/main/marketplace/components/Collection/Collection.jsx new file mode 100644 index 00000000..ffc2fe03 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Collection/Collection.jsx @@ -0,0 +1,53 @@ +import { MdOutlineArrowForward, MdOutlineOpenInNew } from 'react-icons/md'; +import { Button } from 'components/Elements'; +import variables from 'config/variables'; + +const Collection = ({ collection, toggle, collectionFunction }) => { + const { news, background_colour, img, display_name, description, name } = collection; + + const getStyle = () => { + if (news) { + return { backgroundColor: background_colour }; + } + return { + backgroundImage: `linear-gradient(to left, #000, transparent, #000), url('${variables.constants.DDG_IMAGE_PROXY + img}')`, + }; + }; + + return ( +
+
+ {display_name} using component + {description} +
+ {collection.news === true ? ( + + {variables.getMessage('modals.main.marketplace.learn_more')} + + ) : ( +
+ ); +}; + +export default Collection; +export { Collection }; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/components/Collection/index.jsx b/src/features/modals/main/marketplace/components/Collection/index.jsx new file mode 100644 index 00000000..b9d8ea40 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Collection/index.jsx @@ -0,0 +1 @@ +export * from './Collection'; \ No newline at end of file diff --git a/src/features/helpers/carousel/Carousel.jsx b/src/features/modals/main/marketplace/components/Elements/Carousel/Carousel.jsx similarity index 96% rename from src/features/helpers/carousel/Carousel.jsx rename to src/features/modals/main/marketplace/components/Elements/Carousel/Carousel.jsx index c73083f4..a9962ffe 100644 --- a/src/features/helpers/carousel/Carousel.jsx +++ b/src/features/modals/main/marketplace/components/Elements/Carousel/Carousel.jsx @@ -86,4 +86,6 @@ function EmblaCarousel({ data }) { ); } -export default memo(EmblaCarousel); +const Carousel = memo(EmblaCarousel); + +export { Carousel as default, Carousel }; diff --git a/src/features/helpers/carousel/carousel.scss b/src/features/modals/main/marketplace/components/Elements/Carousel/carousel.scss similarity index 97% rename from src/features/helpers/carousel/carousel.scss rename to src/features/modals/main/marketplace/components/Elements/Carousel/carousel.scss index 46edb938..98b55939 100644 --- a/src/features/helpers/carousel/carousel.scss +++ b/src/features/modals/main/marketplace/components/Elements/Carousel/carousel.scss @@ -22,6 +22,7 @@ .carousel_container { display: flex; -webkit-touch-callout: none; + -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; margin-left: -10px; diff --git a/src/features/modals/main/marketplace/components/Elements/Carousel/index.jsx b/src/features/modals/main/marketplace/components/Elements/Carousel/index.jsx new file mode 100644 index 00000000..7837b1c9 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Elements/Carousel/index.jsx @@ -0,0 +1 @@ +export * from './Carousel'; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/Lightbox.jsx b/src/features/modals/main/marketplace/components/Elements/Lightbox/Lightbox.jsx similarity index 76% rename from src/features/modals/main/marketplace/Lightbox.jsx rename to src/features/modals/main/marketplace/components/Elements/Lightbox/Lightbox.jsx index d6601a77..59afca97 100644 --- a/src/features/modals/main/marketplace/Lightbox.jsx +++ b/src/features/modals/main/marketplace/components/Elements/Lightbox/Lightbox.jsx @@ -14,4 +14,6 @@ function Lightbox({ modalClose, img }) { ); } -export default memo(Lightbox); +const MemoizedLightbox = memo(Lightbox); +export default MemoizedLightbox; +export { MemoizedLightbox as Lightbox }; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/components/Elements/Lightbox/index.jsx b/src/features/modals/main/marketplace/components/Elements/Lightbox/index.jsx new file mode 100644 index 00000000..be6f8581 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Elements/Lightbox/index.jsx @@ -0,0 +1 @@ +export * from './Lightbox'; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/SideloadFailedModal.jsx b/src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/SideloadFailedModal.jsx similarity index 82% rename from src/features/modals/main/marketplace/SideloadFailedModal.jsx rename to src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/SideloadFailedModal.jsx index c4526f10..182a14c5 100644 --- a/src/features/modals/main/marketplace/SideloadFailedModal.jsx +++ b/src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/SideloadFailedModal.jsx @@ -2,6 +2,7 @@ import { memo } from 'react'; import variables from 'config/variables'; import { MdClose } from 'react-icons/md'; import { Tooltip } from 'components/Elements'; + function SideloadFailedModal({ modalClose, reason }) { return (
@@ -21,4 +22,7 @@ function SideloadFailedModal({ modalClose, reason }) { ); } -export default memo(SideloadFailedModal); +const MemoizedSideloadFailedModal = memo(SideloadFailedModal); + +export default MemoizedSideloadFailedModal; +export { MemoizedSideloadFailedModal as SideloadFailedModal }; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/index.jsx b/src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/index.jsx new file mode 100644 index 00000000..7b7ea247 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Elements/SideloadFailedModal/index.jsx @@ -0,0 +1 @@ +export * from './SideloadFailedModal'; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/components/Elements/index.jsx b/src/features/modals/main/marketplace/components/Elements/index.jsx new file mode 100644 index 00000000..63a1a581 --- /dev/null +++ b/src/features/modals/main/marketplace/components/Elements/index.jsx @@ -0,0 +1,3 @@ +export * from './Carousel'; +export * from './SideloadFailedModal'; +export * from './Lightbox'; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/Item.jsx b/src/features/modals/main/marketplace/components/Items/Item.jsx similarity index 98% rename from src/features/modals/main/marketplace/Item.jsx rename to src/features/modals/main/marketplace/components/Items/Item.jsx index ef1ea9d0..2eb95161 100644 --- a/src/features/modals/main/marketplace/Item.jsx +++ b/src/features/modals/main/marketplace/components/Items/Item.jsx @@ -1,7 +1,5 @@ import variables from 'config/variables'; import { PureComponent, Fragment } from 'react'; -import { Tooltip } from 'components/Elements'; -import ImageCarousel from 'features/helpers/carousel/Carousel'; import { toast } from 'react-toastify'; import { MdIosShare, @@ -21,7 +19,7 @@ import { Header } from 'components/Layout/Settings'; import { Button } from 'components/Elements'; import { install, uninstall } from 'utils/marketplace'; - +import { Carousel } from '../Elements/Carousel'; import { ShareModal } from 'components/Elements'; class Item extends PureComponent { @@ -124,7 +122,7 @@ class Item extends PureComponent { {this.props.data.data.photos && (
- +
)} @@ -306,4 +304,4 @@ class Item extends PureComponent { } } -export default Item; +export { Item as default, Item }; diff --git a/src/features/modals/main/marketplace/Items.jsx b/src/features/modals/main/marketplace/components/Items/Items.jsx similarity index 96% rename from src/features/modals/main/marketplace/Items.jsx rename to src/features/modals/main/marketplace/components/Items/Items.jsx index ec0502ea..bccc6758 100644 --- a/src/features/modals/main/marketplace/Items.jsx +++ b/src/features/modals/main/marketplace/components/Items/Items.jsx @@ -3,6 +3,7 @@ import React, { memo } from 'react'; import { MdAutoFixHigh, MdOutlineArrowForward, MdOutlineOpenInNew } from 'react-icons/md'; import { Button } from 'components/Elements'; +import MemoizedLightbox from '../Elements/Lightbox/Lightbox'; function Items({ type, @@ -114,4 +115,5 @@ function Items({ ); } -export default memo(Items); +const MemoizedItems = memo(Items); +export { MemoizedItems as default, MemoizedItems as Items }; diff --git a/src/features/modals/main/marketplace/components/index.jsx b/src/features/modals/main/marketplace/components/index.jsx new file mode 100644 index 00000000..1f5d55b4 --- /dev/null +++ b/src/features/modals/main/marketplace/components/index.jsx @@ -0,0 +1,2 @@ +export * from './Elements'; +export * from './Items'; \ No newline at end of file diff --git a/src/features/modals/main/marketplace/sections/Added.jsx b/src/features/modals/main/marketplace/views/Added.jsx similarity index 96% rename from src/features/modals/main/marketplace/sections/Added.jsx rename to src/features/modals/main/marketplace/views/Added.jsx index c111de34..8449f736 100644 --- a/src/features/modals/main/marketplace/sections/Added.jsx +++ b/src/features/modals/main/marketplace/views/Added.jsx @@ -4,11 +4,10 @@ import { MdUpdate, MdOutlineExtensionOff, MdSendTimeExtension } from 'react-icon import { toast } from 'react-toastify'; import Modal from 'react-modal'; -import SideloadFailedModal from '../SideloadFailedModal'; -import FileUpload from '../../../../../components/Form/Settings/FileUpload/FileUpload'; -import Item from '../Item'; -import Items from '../Items'; -import Dropdown from '../../../../../components/Form/Settings/Dropdown/Dropdown'; +import { SideloadFailedModal } from '../components/Elements/SideloadFailedModal/SideloadFailedModal'; +import Item from '../components/Items/Item'; +import Items from '../components/Items/Items'; +import { Dropdown, FileUpload } from 'components/Form/Settings'; import { Header, CustomActions } from 'components/Layout/Settings'; import { Button } from 'components/Elements'; diff --git a/src/features/modals/main/marketplace/sections/Marketplace.jsx b/src/features/modals/main/marketplace/views/Browse.jsx similarity index 99% rename from src/features/modals/main/marketplace/sections/Marketplace.jsx rename to src/features/modals/main/marketplace/views/Browse.jsx index 8ab60438..4e26e14e 100644 --- a/src/features/modals/main/marketplace/sections/Marketplace.jsx +++ b/src/features/modals/main/marketplace/views/Browse.jsx @@ -10,8 +10,8 @@ import { MdLibraryAdd, } from 'react-icons/md'; -import Item from '../Item'; -import Items from '../Items'; +import Item from '../components/Items/Item'; +import Items from '../components/Items/Items'; import Dropdown from '../../../../../components/Form/Settings/Dropdown/Dropdown'; import { Header } from 'components/Layout/Settings'; import { Button } from 'components/Elements'; diff --git a/src/features/modals/main/marketplace/sections/Create.jsx b/src/features/modals/main/marketplace/views/Create.jsx similarity index 100% rename from src/features/modals/main/marketplace/sections/Create.jsx rename to src/features/modals/main/marketplace/views/Create.jsx diff --git a/src/features/modals/main/settings/sections/Changelog.jsx b/src/features/modals/main/settings/sections/Changelog.jsx index 658bde63..95d4df2b 100644 --- a/src/features/modals/main/settings/sections/Changelog.jsx +++ b/src/features/modals/main/settings/sections/Changelog.jsx @@ -3,7 +3,7 @@ import { PureComponent, createRef } from 'react'; import { MdOutlineWifiOff } from 'react-icons/md'; import Modal from 'react-modal'; -import Lightbox from '../../marketplace/Lightbox'; +import Lightbox from '../../marketplace/components/Elements/Lightbox/Lightbox'; export default class Changelog extends PureComponent { constructor() { diff --git a/src/features/modals/main/settings/sections/Stats.jsx b/src/features/modals/main/settings/sections/Stats.jsx index fffaac60..b9c93b54 100644 --- a/src/features/modals/main/settings/sections/Stats.jsx +++ b/src/features/modals/main/settings/sections/Stats.jsx @@ -10,31 +10,14 @@ import { Header, CustomActions } from 'components/Layout/Settings'; import { saveFile } from 'utils/saveFile'; -import achievementsData from 'utils/data/achievements.json'; -import translations from 'i18n/locales/achievements/index'; - -const achievementLanguage = { - de_DE: translations.de_DE, - en_GB: translations.en_GB, - en_US: translations.en_US, - es: translations.es, - fr: translations.fr, - nl: translations.nl, - no: translations.no, - ru: translations.ru, - zh_CN: translations.zh_CN, - id_ID: translations.id_ID, - tr_TR: translations.tr_TR, - bn: translations.bn, - pt_BR: translations.pt_BR, -}; +import { translations, achievements } from 'utils/achievements'; export default class Stats extends PureComponent { constructor() { super(); this.state = { stats: JSON.parse(localStorage.getItem('statsData')) || {}, - achievements: achievementsData.achievements, + achievements, }; } @@ -79,7 +62,7 @@ export default class Stats extends PureComponent { this.setState({ stats: {}, }); - toast('Stats reset'); + toast(variables.getMessage('toasts.stats_reset')); this.getAchievements(); this.forceUpdate(); } @@ -92,23 +75,35 @@ export default class Stats extends PureComponent { saveFile(JSON.stringify(this.state.stats, null, 2), filename); } + getLocalisedAchievementData(id) { + const localised = translations[variables.languagecode][id] || + translations.en_GB[id] || { name: id, description: '' }; + + return { + name: localised.name, + description: localised.description, + }; + } + componentDidMount() { this.getAchievements(); this.forceUpdate(); } render() { - const achievementElement = (key, name, achieved) => ( -
- -
- {name} - - {achievementLanguage[localStorage.getItem('language')][key]} - + const achievementElement = (key, id, achieved) => { + const { name, description } = this.getLocalisedAchievementData(id); + + return ( +
+ +
+ {name} + {description} +
-
- ); + ); + }; const STATS_SECTION = 'modals.main.settings.sections.stats'; @@ -220,7 +215,7 @@ export default class Stats extends PureComponent {
{this.state.achievements.map((achievement, index) => { if (achievement.achieved) { - return achievementElement(index, achievement.name, achievement.achieved); + return achievementElement(index, achievement.id, achievement.achieved); } })}
diff --git a/src/features/modals/main/tabs/Addons.jsx b/src/features/modals/main/tabs/Addons.jsx index 2c42d393..3af185ec 100644 --- a/src/features/modals/main/tabs/Addons.jsx +++ b/src/features/modals/main/tabs/Addons.jsx @@ -2,8 +2,8 @@ import variables from 'config/variables'; import { memo } from 'react'; import Tabs from './backend/Tabs'; -import Added from '../marketplace/sections/Added'; -import Create from '../marketplace/sections/Create'; +import Added from '../marketplace/views/Added'; +import Create from '../marketplace/views/Create'; function Addons(props) { return ( diff --git a/src/features/modals/main/tabs/Marketplace.jsx b/src/features/modals/main/tabs/Marketplace.jsx index a158c562..cd87863a 100644 --- a/src/features/modals/main/tabs/Marketplace.jsx +++ b/src/features/modals/main/tabs/Marketplace.jsx @@ -2,7 +2,7 @@ import variables from 'config/variables'; import { memo } from 'react'; import Tabs from './backend/Tabs'; -import MarketplaceTab from '../marketplace/sections/Marketplace'; +import MarketplaceTab from '../marketplace/views/Browse'; function Marketplace(props) { return ( diff --git a/src/i18n/locales/achievements/en_GB.json b/src/i18n/locales/achievements/en_GB.json index 8dcc1526..4d63ede3 100644 --- a/src/i18n/locales/achievements/en_GB.json +++ b/src/i18n/locales/achievements/en_GB.json @@ -1,8 +1,50 @@ -[ - "Opened 10 tabs", - "Opened 39 tabs", - "Opened 100 tabs", - "Opened 305 tabs", - "Installed an add-on", - "Installed 5 add-ons" -] +{ + "10tabs": { + "name": "10/10 IGN", + "description": "Opened 10 tabs" + }, + "thankyou": { + "name": "Thank You", + "description": "Opened 39 tabs" + }, + "seasoning": { + "name": "Seasoning", + "description": "Opened 100 tabs" + }, + "mrworldwide": { + "name": "Mr. Worldwide", + "description": "Opened 305 tabs" + }, + "tabaholic": { + "name": "Tabaholic", + "description": "Opened 500 tabs" + }, + "727": { + "name": "When You See It", + "description": "Opened 727 tabs" + }, + "808s": { + "name": "808s & Tab Breaks", + "description": "Opened 808 tabs" + }, + "1337": { + "name": "MU3T4B", + "description": "Opened 1337 tabs" + }, + "averagelinuxuser": { + "name": "Average Linux User", + "description": "Installed an add-on" + }, + "fullyriced": { + "name": "Fully Riced", + "description": "Installed 5 add-ons" + }, + "21addons": { + "name": "They installed 21 add-ons? Whaaat?", + "description": "Installed 21 add-ons" + }, + "overload": { + "name": "System Overload", + "description": "Installed 50 add-ons" + } +} \ No newline at end of file diff --git a/src/i18n/locales/achievements/index.js b/src/i18n/locales/achievements/index.js deleted file mode 100644 index 562c6219..00000000 --- a/src/i18n/locales/achievements/index.js +++ /dev/null @@ -1,31 +0,0 @@ -import de_DE from './de_DE.json'; -import en_GB from './en_GB.json'; -import en_US from './en_US.json'; -import es from './es.json'; -import fr from './fr.json'; -import nl from './nl.json'; -import no from './no.json'; -import ru from './ru.json'; -import zh_CN from './zh_CN.json'; -import id_ID from './id_ID.json'; -import tr_TR from './tr_TR.json'; -import bn from './bn.json'; -import pt_BR from './pt_BR.json'; - -const translations = { - de_DE, - en_GB, - en_US, - es, - fr, - nl, - no, - ru, - zh_CN, - id_ID, - tr_TR, - bn, - pt_BR, -}; - -export default translations; diff --git a/src/i18n/locales/en_GB.json b/src/i18n/locales/en_GB.json index 735ab71a..24c7c909 100644 --- a/src/i18n/locales/en_GB.json +++ b/src/i18n/locales/en_GB.json @@ -676,6 +676,7 @@ "error": "Something went wrong", "imported": "Successfully imported", "no_storage": "Not enough storage", - "link_copied": "Link copied" + "link_copied": "Link copied", + "stats_reset": "Stats reset" } } diff --git a/src/utils/achievements/index.js b/src/utils/achievements/index.js new file mode 100644 index 00000000..9e49e634 --- /dev/null +++ b/src/utils/achievements/index.js @@ -0,0 +1,36 @@ +import de_DE from 'i18n/locales/achievements/de_DE.json'; +import en_GB from 'i18n/locales/achievements/en_GB.json'; +import en_US from 'i18n/locales/achievements/en_US.json'; +import es from 'i18n/locales/achievements/es.json'; +import fr from 'i18n/locales/achievements/fr.json'; +import nl from 'i18n/locales/achievements/nl.json'; +import no from 'i18n/locales/achievements/no.json'; +import ru from 'i18n/locales/achievements/ru.json'; +import zh_CN from 'i18n/locales/achievements/zh_CN.json'; +import id_ID from 'i18n/locales/achievements/id_ID.json'; +import tr_TR from 'i18n/locales/achievements/tr_TR.json'; +import bn from 'i18n/locales/achievements/bn.json'; +import pt_BR from 'i18n/locales/achievements/pt_BR.json'; + +import achievements from 'utils/data/achievements.json'; + +const translations = { + de_DE, + en_GB, + en_US, + es, + fr, + nl, + no, + ru, + zh_CN, + id_ID, + tr_TR, + bn, + pt_BR, +}; + +export { + achievements, + translations +}; \ No newline at end of file diff --git a/src/utils/data/achievements.json b/src/utils/data/achievements.json index ddd6b44d..18a1cc75 100644 --- a/src/utils/data/achievements.json +++ b/src/utils/data/achievements.json @@ -1,52 +1,86 @@ -{ - "achievements": [ - { - "name": "10/10 IGN", - "description": "Opened 10 tabs", - "condition": { - "type": "tabsOpened", - "amount": 10 - } - }, - { - "name": "Thank you", - "description": "Opened 39 tabs", - "condition": { - "type": "tabsOpened", - "amount": 39 - } - }, - { - "name": "Seasoning", - "description": "Opened 100 tabs", - "condition": { - "type": "tabsOpened", - "amount": 100 - } - }, - { - "name": "Mr Worldwide", - "description": "Opened 305 tabs", - "condition": { - "type": "tabsOpened", - "amount": 305 - } - }, - { - "name": "Average Linux user", - "description": "Installed an add-on", - "condition": { - "type": "addonInstall", - "amount": 1 - } - }, - { - "name": "Fully riced", - "description": "Installed 5 add-ons", - "condition": { - "type": "addonInstall", - "amount": 5 - } +[ + { + "id": "10tabs", + "condition": { + "type": "tabsOpened", + "amount": 10 } - ] -} + }, + { + "id": "thankyou", + "condition": { + "type": "tabsOpened", + "amount": 39 + } + }, + { + "id": "seasoning", + "condition": { + "type": "tabsOpened", + "amount": 100 + } + }, + { + "id": "mrworldwide", + "condition": { + "type": "tabsOpened", + "amount": 305 + } + }, + { + "id": "tabaholic", + "condition": { + "type": "tabsOpened", + "amount": 500 + } + }, + { + "id": "727", + "condition": { + "type": "tabsOpened", + "amount": 727 + } + }, + { + "id": "808sandtabs", + "condition": { + "type": "tabsOpened", + "amount": 808 + } + }, + { + "id": "1337", + "condition": { + "type": "tabsOpened", + "amount": 1337 + } + }, + { + "id": "averagelinuxuser", + "condition": { + "type": "addonInstall", + "amount": 1 + } + }, + { + "id": "fullyriced", + "condition": { + "type": "addonInstall", + "amount": 5 + } + }, + { + "id": "21addons", + "condition": { + "type": "addonInstall", + "amount": 21 + } + }, + { + "id": "overload", + "condition": { + "type": "addonInstall", + "amount": 50 + } + } +]