+
+
+
diff --git a/client/src/ui/components/common/MaterialIcon.js b/client/src/ui/components/common/MaterialIcon.js
index 94c2c27c..a6991924 100644
--- a/client/src/ui/components/common/MaterialIcon.js
+++ b/client/src/ui/components/common/MaterialIcon.js
@@ -14,3 +14,6 @@ export { default as MiExtension } from './materialicons/Extension.vue';
export { default as MiError } from './materialicons/Error.vue';
export { default as MiDiscord } from './materialicons/Discord.vue';
export { default as MiStar } from './materialicons/Star.vue';
+export { default as MiInfo } from './materialicons/Info.vue';
+export { default as MiWarning } from './materialicons/Warning.vue';
+export { default as MiSuccess } from './materialicons/Success.vue';
diff --git a/client/src/ui/components/common/Toast.vue b/client/src/ui/components/common/Toast.vue
new file mode 100644
index 00000000..cf93ad70
--- /dev/null
+++ b/client/src/ui/components/common/Toast.vue
@@ -0,0 +1,46 @@
+/**
+ * BetterDiscord Toast Component
+ * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
+ * All rights reserved.
+ * https://betterdiscord.net
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+*/
+
+
+
+
+
+
+
+
+
+
+
+ {{message}}
+
+
+
+
+
diff --git a/client/src/ui/components/common/index.js b/client/src/ui/components/common/index.js
index 74fce6b4..c0241497 100644
--- a/client/src/ui/components/common/index.js
+++ b/client/src/ui/components/common/index.js
@@ -4,6 +4,7 @@ export { default as FormButton } from './FormButton.vue';
export { default as ButtonGroup } from './ButtonGroup.vue';
export { default as Button } from './Button.vue';
export { default as Modal } from './Modal.vue';
+export { default as Toast } from './Toast.vue';
export * from './MaterialIcon';
export { default as RefreshBtn } from './RefreshBtn.vue';
diff --git a/client/src/ui/components/common/materialicons/Info.vue b/client/src/ui/components/common/materialicons/Info.vue
new file mode 100644
index 00000000..c5cd80af
--- /dev/null
+++ b/client/src/ui/components/common/materialicons/Info.vue
@@ -0,0 +1,28 @@
+/**
+ * BetterDiscord Material Design Icon
+ * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
+ * All rights reserved.
+ * https://betterdiscord.net
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * Material Design Icons
+ * Copyright (c) 2014 Google
+ * Apache 2.0 LICENSE
+ * https://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+
+
+
+
+
+
+
diff --git a/client/src/ui/components/common/materialicons/Success.vue b/client/src/ui/components/common/materialicons/Success.vue
new file mode 100644
index 00000000..15d5548e
--- /dev/null
+++ b/client/src/ui/components/common/materialicons/Success.vue
@@ -0,0 +1,28 @@
+/**
+ * BetterDiscord Material Design Icon
+ * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
+ * All rights reserved.
+ * https://betterdiscord.net
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * Material Design Icons
+ * Copyright (c) 2014 Google
+ * Apache 2.0 LICENSE
+ * https://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+
+
+
+
+
+
+
diff --git a/client/src/ui/components/common/materialicons/Warning.vue b/client/src/ui/components/common/materialicons/Warning.vue
new file mode 100644
index 00000000..7660ec27
--- /dev/null
+++ b/client/src/ui/components/common/materialicons/Warning.vue
@@ -0,0 +1,28 @@
+/**
+ * BetterDiscord Material Design Icon
+ * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
+ * All rights reserved.
+ * https://betterdiscord.net
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * Material Design Icons
+ * Copyright (c) 2014 Google
+ * Apache 2.0 LICENSE
+ * https://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+
+
+
+
+
+
+
diff --git a/client/src/ui/components/index.js b/client/src/ui/components/index.js
index 8f8e4a8c..3a22b4d8 100644
--- a/client/src/ui/components/index.js
+++ b/client/src/ui/components/index.js
@@ -1,3 +1,4 @@
export { default as BdSettingsWrapper } from './BdSettingsWrapper.vue';
export { default as BdSettings } from './BdSettings.vue';
export { default as BdModals } from './BdModals.vue';
+export { default as BdToasts } from './BdToasts.vue';
diff --git a/client/src/ui/dom.js b/client/src/ui/dom.js
index 23f16424..6646a3f7 100644
--- a/client/src/ui/dom.js
+++ b/client/src/ui/dom.js
@@ -184,6 +184,9 @@ export default class DOM {
static get bdThemes() { return this.getElement('bd-themes') || this.createElement('bd-themes').appendTo(this.bdHead) }
static get bdTooltips() { return this.getElement('bd-tooltips') || this.createElement('bd-tooltips').appendTo(this.bdBody) }
static get bdModals() { return this.getElement('bd-modals') || this.createElement('bd-modals').appendTo(this.bdBody) }
+ static get bdToasts() {
+ return this.getElement('bd-toasts') || this.createElement('bd-toasts').appendTo(this.bdBody);
+ }
static getElement(e) {
if (e instanceof BdNode) return e.element;
diff --git a/client/src/ui/toasts.js b/client/src/ui/toasts.js
new file mode 100644
index 00000000..1b572a54
--- /dev/null
+++ b/client/src/ui/toasts.js
@@ -0,0 +1,75 @@
+/**
+ * BetterDiscord Toasts
+ * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
+ * All rights reserved.
+ * https://betterdiscord.net
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+*/
+
+let toasts = 0;
+
+export default class Toasts {
+
+ /**
+ * This shows a popup message at the bottom of the screen similar to Android Toasts. This is useful for small user feedback.
+ *
+ * @param {string} message The message to be displayed in the toast
+ * @param {Object} options Options object. Optional parameter.
+ * @param {string} options.type Changes the type of the toast stylistically and semantically. Choices: "basic", "info", "success", "error", "warning". Default: "basic"
+ * @param {string} options.icon URL to custom icon to show in the toast. Having this overrides the default icon for the toast type.
+ * @param {string|Object|Array} options.additionalClasses Additional classes to add to the toast element. Can be used to style it. Optional.
+ * @param {number} options.timeout Adjusts the time (in ms) the toast should be shown for before disappearing automatically. Default: 3000
+ * @returns {Promise} This promise resolves when the toast is removed from the DOM.
+ */
+ static async push(message, options = {}) {
+ const {type = 'basic', icon, additionalClasses, timeout = 3000} = options;
+ const toast = {id: toasts++, message, type, icon, additionalClasses, closing: false};
+ this.stack.push(toast);
+ await new Promise(resolve => setTimeout(resolve, timeout));
+ toast.closing = true;
+ await new Promise(resolve => setTimeout(resolve, 300));
+ this.stack.splice(this.stack.indexOf(toast), 1);
+ }
+
+ /**
+ * This is a shortcut for `type = "success"` in {@link Toasts#push}. The parameters and options are the same.
+ */
+ static async success(message, options = {}) {
+ options.type = 'success';
+ return this.push(message, options);
+ }
+
+ /**
+ * This is a shortcut for `type = "error"` in {@link Toasts#push}. The parameters and options are the same.
+ */
+ static async error(message, options = {}) {
+ options.type = 'error';
+ return this.push(message, options);
+ }
+
+ /**
+ * This is a shortcut for `type = "info"` in {@link Toasts#push}. The parameters and options are the same.
+ */
+ static async info(message, options = {}) {
+ options.type = 'info';
+ return this.push(message, options);
+ }
+
+ /**
+ * This is a shortcut for `type = "warning"` in {@link Toasts#push}. The parameters and options are the same.
+ */
+ static async warning(message, options = {}) {
+ options.type = 'warning';
+ return this.push(message, options);
+ }
+
+ /**
+ * An array of active toasts.
+ */
+ static get stack() {
+ return this._stack || (this._stack = []);
+ }
+
+}
diff --git a/client/src/ui/ui.js b/client/src/ui/ui.js
index 90892da4..95cb30ed 100644
--- a/client/src/ui/ui.js
+++ b/client/src/ui/ui.js
@@ -2,6 +2,7 @@ export { default as DOM, DOMObserver, DOMManip } from './dom';
export { default as BdUI } from './bdui';
export { default as BdMenu, BdMenuItems } from './bdmenu';
export { default as Modals } from './modals';
+export { default as Toasts } from './toasts';
export { default as VueInjector } from './vueinjector';
export { default as Reflection } from './reflection';