diff --git a/src/renderer/App.js b/src/renderer/App.js
index 4930836f..f7d45d8f 100644
--- a/src/renderer/App.js
+++ b/src/renderer/App.js
@@ -1,6 +1,7 @@
import Vue from 'vue'
import TopNav from './components/top-nav/top-nav.vue'
import SideNav from './components/side-nav/side-nav.vue'
+import FtToast from './components/ft-toast/ft-toast.vue'
import $ from 'jquery'
let useElectron
@@ -18,7 +19,8 @@ export default Vue.extend({
name: 'App',
components: {
TopNav,
- SideNav
+ SideNav,
+ FtToast,
},
computed: {
isOpen: function () {
diff --git a/src/renderer/App.vue b/src/renderer/App.vue
index 187e4b0d..2bb16c04 100644
--- a/src/renderer/App.vue
+++ b/src/renderer/App.vue
@@ -14,6 +14,7 @@
/>
+
diff --git a/src/renderer/components/ft-share-button/ft-share-button.js b/src/renderer/components/ft-share-button/ft-share-button.js
index ac9799c0..8da6f680 100644
--- a/src/renderer/components/ft-share-button/ft-share-button.js
+++ b/src/renderer/components/ft-share-button/ft-share-button.js
@@ -2,6 +2,7 @@ import Vue from 'vue'
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
import FtButton from '../ft-button/ft-button.vue'
+import { mapActions } from 'vuex'
export default Vue.extend({
name: 'FtShareButton',
@@ -59,6 +60,7 @@ export default Vue.extend({
},
copyInvidious() {
+ this.showToast('Invidious URL copied to clipboard')
this.copy(this.invidiousURL)
this.$refs.iconButton.toggleDropdown()
},
@@ -69,6 +71,7 @@ export default Vue.extend({
},
copyYoutube() {
+ this.showToast('YouTube URL copied to clipboard')
this.copy(this.youtubeURL)
this.$refs.iconButton.toggleDropdown()
},
@@ -79,6 +82,7 @@ export default Vue.extend({
},
copyYoutubeEmbed() {
+ this.showToast('YouTube Embed URL copied to clipboard')
this.copy(this.youtubeEmbedURL)
this.$refs.iconButton.toggleDropdown()
},
@@ -89,8 +93,13 @@ export default Vue.extend({
},
copyInvidiousEmbed() {
+ this.showToast('Invidious Embed URL copied to clipboard')
this.copy(this.invidiousEmbedURL)
this.$refs.iconButton.toggleDropdown()
},
+
+ ...mapActions([
+ 'showToast'
+ ])
}
})
diff --git a/src/renderer/components/ft-toast/ft-toast-events.js b/src/renderer/components/ft-toast/ft-toast-events.js
new file mode 100644
index 00000000..c32b0e13
--- /dev/null
+++ b/src/renderer/components/ft-toast/ft-toast-events.js
@@ -0,0 +1,4 @@
+import Vue from 'vue'
+
+const events = new Vue()
+export default events
diff --git a/src/renderer/components/ft-toast/ft-toast.css b/src/renderer/components/ft-toast/ft-toast.css
new file mode 100644
index 00000000..79ce9f80
--- /dev/null
+++ b/src/renderer/components/ft-toast/ft-toast.css
@@ -0,0 +1,37 @@
+.toast-holder {
+ position: fixed;
+ left: 50vw;
+ transform: translate(-50%, 0);
+ bottom: 50px;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.toast {
+ padding: 10px;
+ margin: 5px;
+ overflow-y: auto;
+ background-color: rgba(0, 0, 0, 0.7);
+ color: white;
+ opacity: 0;
+ border-radius: 20px;
+ cursor: pointer;
+}
+
+.message {
+ margin: auto;
+}
+
+.open {
+ visibility: visible;
+ opacity: 1;
+ transition: visibility 0s linear 0s, opacity 300ms;
+}
+
+.closed {
+ visibility: hidden;
+ opacity: 0;
+ transition: visibility 0s linear 300ms, opacity 300ms;
+}
diff --git a/src/renderer/components/ft-toast/ft-toast.js b/src/renderer/components/ft-toast/ft-toast.js
new file mode 100644
index 00000000..79a49c50
--- /dev/null
+++ b/src/renderer/components/ft-toast/ft-toast.js
@@ -0,0 +1,42 @@
+import Vue from 'vue'
+import FtToastEvents from './ft-toast-events.js'
+
+export default Vue.extend({
+ name: 'FtToast',
+ data: function () {
+ return {
+ toasts: [],
+ }
+ },
+ mounted: function () {
+ FtToastEvents.$on('toast.open', this.open)
+ },
+ beforeDestroy: function () {
+ FtToastEvents.$off('toast.open', this.open)
+ },
+ methods: {
+ performAction: function (index) {
+ this.toasts[index].action()
+ this.remove(index)
+ },
+ close: function (toast) {
+ // Wait for fade-out to finish
+ setTimeout(this.remove, 300, 0)
+
+ toast.isOpen = false
+ },
+ open: function (message, action, time) {
+ const toast = { message: message, action: action || (() => { }), isOpen: false, timeout: null }
+ toast.timeout = setTimeout(this.close, time || 3000, toast)
+ setImmediate(() => { toast.isOpen = true })
+ if (this.toasts.length > 4) {
+ this.remove(0)
+ }
+ this.toasts.push(toast)
+ },
+ remove: function(index) {
+ const removed = this.toasts.splice(index, 1)
+ clearTimeout(removed[0].timeout)
+ }
+ },
+})
diff --git a/src/renderer/components/ft-toast/ft-toast.vue b/src/renderer/components/ft-toast/ft-toast.vue
new file mode 100644
index 00000000..efcd91a8
--- /dev/null
+++ b/src/renderer/components/ft-toast/ft-toast.vue
@@ -0,0 +1,18 @@
+
+
+
+
+ {{ toast.message }}
+
+
+
+
+
+
+
diff --git a/src/renderer/store/modules/utils.js b/src/renderer/store/modules/utils.js
index 680fb7c8..19243798 100644
--- a/src/renderer/store/modules/utils.js
+++ b/src/renderer/store/modules/utils.js
@@ -1,5 +1,5 @@
import IsEqual from 'lodash.isequal'
-
+import FtToastEvents from '../../components/ft-toast/ft-toast-events'
const state = {
isSideNavOpen: false,
sessionSearchHistory: [],
@@ -84,6 +84,10 @@ const actions = {
]
return extractors.reduce((a, c) => a || c(), null) || false
+ },
+
+ showToast (_, message, action, time) {
+ FtToastEvents.$emit('toast.open', message, action, time)
}
}