diff --git a/.env b/.env
new file mode 100644
index 00000000..83c60e7c
--- /dev/null
+++ b/.env
@@ -0,0 +1,28 @@
+// API URLs
+API_URL=https://api.muetab.com/v2
+SPONSORS_URL=https://sponsors.muetab.com
+GITHUB_URL=https://api.github.com
+DDG_IMAGE_PROXY=https://external-content.duckduckgo.com/iu/?u=
+OPENSTREETMAP_URL=https://www.openstreetmap.org
+
+// Mue URLs
+WEBSITE_URL=https://muetab.com
+PRIVACY_URL=https://muetab.com/privacy
+BLOG_POST=https://blog.muetab.com/posts/version-7-0
+TRANSLATIONS_URL=https://docs.muetab.com/translations/
+WEBLATE_URL=https://hosted.weblate.org/projects/mue/mue-tab/
+REPORT_ITEM =https://github.com/mue/marketplace/issues/new?assignees=&labels=item+report&template=item-report.md&title=%5BItem+Report%5D+
+BUG_REPORT =https://github.com/mue/mue/issues/new?assignees=&labels=issue+report&template=bug-report.md&title=%5BBug%5D+
+DONATE_LINK=https://muetab.com/donate
+SENTRY_DSN =https://430352fd4b174d688ebd82fc85c22c58@o1217438.ingest.sentry.io/6359480
+KNOWLEDGEBASE=https://support.muetab.com
+
+// Mue Info
+ORG_NAME=mue
+REPO_NAME=mue
+EMAIL=hello@muetab.com
+TWITTER_HANDLE=getmue
+DISCORD_SERVER=zv8C9F8
+OPENCOLLECTIVE_USERNAME=mue
+
+VERSION=7.0.1
diff --git a/src/ErrorBoundary.jsx b/src/ErrorBoundary.jsx
index 202f4e85..cc78ba43 100644
--- a/src/ErrorBoundary.jsx
+++ b/src/ErrorBoundary.jsx
@@ -1,19 +1,51 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
-class ErrorBoundary extends Component {
+import { captureException } from '@sentry/react';
+
+class ErrorBoundary extends PureComponent {
constructor(props) {
super(props);
- this.state = { hasError: false };
+ this.state = {
+ error: false,
+ errorData: '',
+ showReport: true,
+ };
}
componentDidCatch(error, errorInfo) {
- this.setState({ hasError: true });
+ this.setState({ error: true, errorData: errorInfo });
console.error('Error boundary caught an error:', error, errorInfo);
}
+ reportError() {
+ captureException(this.state.errorData);
+ this.setState({
+ showReport: false,
+ });
+ }
+
render() {
- if (this.state.hasError) {
- return
Mue has broken horribly
;
+ if (this.state.error) {
+ return (
+
+
+
A critical error has occurred
+
+ The new tab page could not be loaded. Please uninstall the extension and try again.
+
+
+ {this.state.showReport ? (
+
+ ) : (
+
Sent Successfully
+ )}
+
+ Support Discord
+
+
+
+
+ );
}
return this.props.children;
diff --git a/src/components/modals/main/scss/settings/_main.scss b/src/components/modals/main/scss/settings/_main.scss
index 0209ff85..615ebde4 100644
--- a/src/components/modals/main/scss/settings/_main.scss
+++ b/src/components/modals/main/scss/settings/_main.scss
@@ -3,6 +3,7 @@
@import 'modules/tabs/about';
@import 'modules/tabs/changelog';
@import 'modules/tabs/order';
+@import 'modules/tabs/stats';
input {
/* colour picker */
@@ -127,102 +128,18 @@ h4 {
}
}
-.stats {
- display: flex;
- flex-flow: column;
- gap: 30px;
- width: 100%;
-
- .rightPanel {
- .statIcon {
- display: flex;
- justify-content: center;
- margin-bottom: 30px;
- }
-
- .statGrid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- grid-gap: 10px;
-
- div {
- display: flex;
- flex-flow: column;
- }
- }
-
- .subtitle {
- text-transform: capitalize;
- }
-
- span {
- font-size: 20px;
- }
- }
-}
-
-.achievements {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
- grid-gap: 10px;
-}
-
-.achievement {
- padding: 20px 10px;
- display: flex;
- flex-flow: row !important;
- align-items: center;
-
- @include themed {
- background: t($modal-secondaryColour);
- border: 1px solid t($modal-sidebarActive);
- border-radius: t($borderRadius);
- gap: 10px;
- }
-
- svg {
- font-size: 20px !important;
- padding: 15px;
- border-radius: 100%;
-
- @include themed {
- background: t($modal-sidebarActive);
- }
- }
-}
-
-.statSection.rightPanel {
- padding: 25px;
-
- @include themed {
- border-radius: t($borderRadius);
- background: t($modal-secondaryColour);
- box-shadow: 0 0 0 1px t($modal-sidebarActive);
-
- svg {
- font-size: 50px;
- color: t($subColor);
- }
- }
-}
-
-.achievementContent {
- display: flex;
- flex-flow: column;
- gap: 2px;
-
- span:first-child {
- font-weight: bold;
- font-size: 15px;
- }
-
- .subtitle {
- font-size: 13px !important;
- }
-}
-
.customcss textarea {
font-family: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter',
'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco,
'Courier New', Courier, monospace !important;
}
+
+.preferences {
+ transition: 0.4s ease-in-out;
+}
+
+.preferencesInactive {
+ opacity: 0.5;
+ pointer-events: none;
+ transition: 0.4s ease-in-out;
+}
diff --git a/src/components/modals/main/scss/settings/modules/tabs/_stats.scss b/src/components/modals/main/scss/settings/modules/tabs/_stats.scss
new file mode 100644
index 00000000..23826c5b
--- /dev/null
+++ b/src/components/modals/main/scss/settings/modules/tabs/_stats.scss
@@ -0,0 +1,106 @@
+.stats {
+ display: flex;
+ flex-flow: column;
+ gap: 30px;
+ width: 100%;
+
+ .rightPanel {
+ .statIcon {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 30px;
+ }
+
+ .statGrid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ grid-gap: 10px;
+
+ div {
+ display: flex;
+ flex-flow: column;
+ }
+ }
+
+ .subtitle {
+ text-transform: capitalize;
+ }
+
+ span {
+ font-size: 20px;
+ }
+ }
+}
+
+.achievements {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ grid-gap: 10px;
+}
+
+.achievement {
+ padding: 20px 10px;
+ display: flex;
+ flex-flow: row !important;
+ align-items: center;
+
+ @include themed {
+ background: t($modal-secondaryColour);
+ border: 1px solid t($modal-sidebarActive);
+ border-radius: t($borderRadius);
+ gap: 10px;
+ }
+
+ svg {
+ font-size: 20px !important;
+ padding: 15px;
+ border-radius: 100%;
+
+ @include themed {
+ background: t($modal-sidebarActive);
+ }
+ }
+}
+
+.statSection.rightPanel {
+ padding: 25px;
+
+ @include themed {
+ border-radius: t($borderRadius);
+ background: t($modal-secondaryColour);
+ box-shadow: 0 0 0 1px t($modal-sidebarActive);
+
+ svg {
+ font-size: 50px;
+ color: t($subColor);
+ }
+ }
+}
+
+.achievementContent {
+ display: flex;
+ flex-flow: column;
+ gap: 2px;
+
+ span:first-child {
+ font-weight: bold;
+ font-size: 15px;
+ }
+
+ .subtitle {
+ font-size: 13px !important;
+ }
+}
+
+.statsTopBar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ button {
+ margin-bottom: 15px;
+ flex-flow: row !important;
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+}
diff --git a/src/components/modals/main/tabs/backend/Tabs.jsx b/src/components/modals/main/tabs/backend/Tabs.jsx
index 84d44d35..9814b853 100644
--- a/src/components/modals/main/tabs/backend/Tabs.jsx
+++ b/src/components/modals/main/tabs/backend/Tabs.jsx
@@ -99,6 +99,7 @@ class Tabs extends PureComponent {
icon={icon}
label={variables.getMessage(`modals.main.navbar.${tab}`)}
active={this.props.current === tab}
+ key={tab}
/>
))}
diff --git a/src/modules/constants.js b/src/modules/constants.js
index 39e20d43..f69cb60b 100644
--- a/src/modules/constants.js
+++ b/src/modules/constants.js
@@ -28,6 +28,4 @@ export const TWITTER_HANDLE = 'getmue';
export const DISCORD_SERVER = 'zv8C9F8';
export const OPENCOLLECTIVE_USERNAME = 'mue';
-export const OFFLINE_IMAGES = 20;
-
export const VERSION = '7.0.1';
diff --git a/src/modules/translations.js b/src/modules/translations.js
index f762bbff..f9651c78 100644
--- a/src/modules/translations.js
+++ b/src/modules/translations.js
@@ -1,19 +1,21 @@
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';
-import * as bn from '../translations/bn.json';
+export const translations = {
+ 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'),
+ bn: import('../translations/bn.json'),
+};
/**
* Initialise the i18n object.
@@ -22,39 +24,6 @@ import * as bn from '../translations/bn.json';
* @returns The i18n object.
*/
export 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,
- bn,
- });
-
+ const i18n = new I18n(locale, translations);
return i18n;
}
-
-export const translations = {
- de_DE,
- en_GB,
- en_US,
- es,
- es_419,
- fr,
- nl,
- no,
- ru,
- zh_CN,
- id_ID,
- tr_TR,
- pt_BR,
- bn,
-};
diff --git a/src/scss/_error.scss b/src/scss/_error.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/scss/index.scss b/src/scss/index.scss
index 298edf18..d42e224c 100644
--- a/src/scss/index.scss
+++ b/src/scss/index.scss
@@ -116,25 +116,45 @@ body {
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
-.statsTopBar {
- display: flex;
- justify-content: space-between;
- align-items: center;
+/* error */
+.criticalError {
+ display: grid;
+ place-items: center;
+ width: 100vw;
+ height: 100vh;
+ .criticalError-message {
+ color: #fff;
+ }
+ p {
+ color: #ffffffc0;
+ }
- button {
- margin-bottom: 15px;
- flex-flow: row !important;
- padding-left: 20px;
- padding-right: 20px;
+ .criticalError-actions {
+ display: flex;
+ flex-flow: row;
+ gap: 20px;
+ }
+
+ button,
+ a {
+ background: #0e1013;
+ box-shadow: 0 0 0 1px #484848;
+ border: 0;
+ color: #fff;
+ border-radius: 12px;
+ padding: 10px 30px 10px 30px;
+ font-size: 1rem;
+ display: flex;
+ align-items: center;
+ flex-flow: row;
+ justify-content: center;
+ gap: 20px;
+ transition: 0.5s;
+ cursor: pointer;
+ text-decoration: none;
+
+ &:hover {
+ background: #1e1e1e;
+ }
}
}
-
-.preferences {
- transition: 0.4s ease-in-out;
-}
-
-.preferencesInactive {
- opacity: 0.5;
- pointer-events: none;
- transition: 0.4s ease-in-out;
-}