New toast plugin, replacing ui/TextToast.vue.
Globally register toast plugin allows us to call this.$toast.info({})
from anywhere for a toast.
Currently styled types:
- error
- info
This commit is contained in:
188
frontend/plugins/Toast/Toast.vue
Normal file
188
frontend/plugins/Toast/Toast.vue
Normal file
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<transition name="slide">
|
||||
<div class="toast" :class="type" v-if="show" ref="toast">
|
||||
<div class="message">
|
||||
<span v-html="title"></span>
|
||||
<span class="description" v-if="description">
|
||||
{{ description }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<button @click="dismiss">Lukk</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
type: this.$root.type || "info",
|
||||
title: this.$root.title || undefined,
|
||||
description: this.$root.description || undefined,
|
||||
image: this.$root.image || undefined,
|
||||
link: this.$root.link || undefined,
|
||||
timeout: this.$root.timeout || 4500,
|
||||
show: false,
|
||||
mouseover: false,
|
||||
timedOut: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// Here we set show when mounted in-order to get the transition animation to be displayed correctly
|
||||
this.show = true;
|
||||
const timeout = setTimeout(() => {
|
||||
console.log("Your toast time is up 👋");
|
||||
if (this.mouseover !== true) {
|
||||
this.show = false;
|
||||
}
|
||||
}, this.timeout);
|
||||
|
||||
setTimeout(() => {
|
||||
const { toast } = this.$refs;
|
||||
|
||||
if (toast) {
|
||||
toast.addEventListener("mouseenter", _ => {
|
||||
if (timeout != null) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
this.mouseover = true;
|
||||
});
|
||||
|
||||
toast.addEventListener("mouseleave", _ => {
|
||||
console.log("leaving", timeout, this.timeout);
|
||||
this.show = false;
|
||||
});
|
||||
}
|
||||
}, 400);
|
||||
},
|
||||
methods: {
|
||||
clicked() {
|
||||
if (this.link) {
|
||||
let resolved = this.$root.router.resolve(this.link);
|
||||
|
||||
if (resolved && resolved.route.name !== "404") {
|
||||
this.$root.router.push(this.link);
|
||||
} else {
|
||||
console.error("Found a link but it resolved to 404. Link:", this.link);
|
||||
}
|
||||
} else {
|
||||
this.show = false;
|
||||
}
|
||||
},
|
||||
dismiss() {
|
||||
this.show = false;
|
||||
},
|
||||
move(e) {
|
||||
console.log("moving", e);
|
||||
let target = e.target;
|
||||
|
||||
console.log("target", target);
|
||||
|
||||
var div = document.getElementById("target");
|
||||
div.style.position = "absolute";
|
||||
div.style.top = e.clientY + "px";
|
||||
div.style.left = e.clientX + "px";
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/media-queries.scss";
|
||||
|
||||
.slide-enter-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.slide-enter,
|
||||
.slide-leave-to {
|
||||
transform: translateY(100vh);
|
||||
opacity: 0;
|
||||
}
|
||||
.slide-leave-active {
|
||||
transition: all 2s ease;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: 1.3rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
background: #2d2d2d;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 80vw;
|
||||
|
||||
@include mobile {
|
||||
width: 85vw;
|
||||
}
|
||||
|
||||
.message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
& span {
|
||||
color: white;
|
||||
|
||||
&.description {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
& .button-container {
|
||||
& button {
|
||||
color: #2d2d2d;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin: 0 3px;
|
||||
font-size: 0.8rem;
|
||||
height: max-content;
|
||||
border: 0;
|
||||
font-size: 0.9rem;
|
||||
|
||||
&:active {
|
||||
background: #2d2d2d;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
background-color: #5bc2a1;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.info {
|
||||
background: #2d2d2d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
border-left: 6px solid #f6993f;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: var(--red);
|
||||
|
||||
button {
|
||||
color: var(--dark-red);
|
||||
|
||||
&:active {
|
||||
background-color: var(--dark-red);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
51
frontend/plugins/Toast/index.js
Normal file
51
frontend/plugins/Toast/index.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import Vue from "vue";
|
||||
import ToastComponent from "./Toast";
|
||||
|
||||
const optionsDefaults = {
|
||||
data: {
|
||||
type: "info",
|
||||
show: true,
|
||||
timeout: 4500,
|
||||
|
||||
onCreate(created = null) {},
|
||||
onEdit(editted = null) {},
|
||||
onRemove(removed = null) {}
|
||||
}
|
||||
};
|
||||
|
||||
function toast(options) {
|
||||
// merge the default options with the passed options.
|
||||
const root = new Vue({
|
||||
data: {
|
||||
...optionsDefaults.data,
|
||||
...options
|
||||
},
|
||||
render: createElement => createElement(ToastComponent)
|
||||
});
|
||||
|
||||
root.$mount(document.body.appendChild(document.createElement("div")));
|
||||
}
|
||||
|
||||
export default {
|
||||
install(vue) {
|
||||
console.log("Installing toast plugin!");
|
||||
|
||||
Vue.prototype.$toast = {
|
||||
info(options) {
|
||||
toast({ type: "info", ...options });
|
||||
},
|
||||
success(options) {
|
||||
toast({ type: "success", ...options });
|
||||
},
|
||||
warning(options) {
|
||||
toast({ type: "warning", ...options });
|
||||
},
|
||||
error(options) {
|
||||
toast({ type: "error", ...options });
|
||||
},
|
||||
simple(options) {
|
||||
toast({ type: "simple", ...options });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<div class="update-toast" :class="showClass">
|
||||
<span v-html="text"></span>
|
||||
<div class="button-container">
|
||||
<button @click="closeToast">Lukk</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
text: { type: String, required: true },
|
||||
refreshButton: { type: Boolean, required: false }
|
||||
},
|
||||
data() {
|
||||
return { showClass: null };
|
||||
},
|
||||
created() {
|
||||
this.showClass = "show";
|
||||
},
|
||||
mounted() {
|
||||
if (this.refreshButton) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.$emit("closeToast");
|
||||
}, 5000);
|
||||
},
|
||||
methods: {
|
||||
refresh: function() {
|
||||
location.reload();
|
||||
},
|
||||
closeToast: function() {
|
||||
this.$emit("closeToast");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../styles/media-queries.scss";
|
||||
|
||||
.update-toast {
|
||||
position: fixed;
|
||||
bottom: 1.3rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
background: #2d2d2d;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 80vw;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
&.show {
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
-webkit-transition: opacity 0.5s ease-in-out;
|
||||
-moz-transition: opacity 0.5s ease-in-out;
|
||||
-ms-transition: opacity 0.5s ease-in-out;
|
||||
-o-transition: opacity 0.5s ease-in-out;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
|
||||
@include mobile {
|
||||
width: 85vw;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
|
||||
& span {
|
||||
color: white;
|
||||
}
|
||||
|
||||
& .button-container {
|
||||
& button {
|
||||
color: #2d2d2d;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin: 0 3px;
|
||||
font-size: 0.8rem;
|
||||
height: max-content;
|
||||
|
||||
&:active {
|
||||
background: #2d2d2d;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -3,11 +3,16 @@ import VueRouter from "vue-router";
|
||||
import { routes } from "@/router.js";
|
||||
import Vinlottis from "@/Vinlottis";
|
||||
|
||||
import Toast from "@/plugins/Toast";
|
||||
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { Vue as VueIntegration } from "@sentry/integrations";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
// Plugins
|
||||
Vue.use(Toast);
|
||||
|
||||
const ENV = window.location.href.includes("localhost") ? "development" : "production";
|
||||
if (ENV !== "development") {
|
||||
Sentry.init({
|
||||
|
||||
Reference in New Issue
Block a user