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 { routes } from "@/router.js";
|
||||||
import Vinlottis from "@/Vinlottis";
|
import Vinlottis from "@/Vinlottis";
|
||||||
|
|
||||||
|
import Toast from "@/plugins/Toast";
|
||||||
|
|
||||||
import * as Sentry from "@sentry/browser";
|
import * as Sentry from "@sentry/browser";
|
||||||
import { Vue as VueIntegration } from "@sentry/integrations";
|
import { Vue as VueIntegration } from "@sentry/integrations";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
Vue.use(Toast);
|
||||||
|
|
||||||
const ENV = window.location.href.includes("localhost") ? "development" : "production";
|
const ENV = window.location.href.includes("localhost") ? "development" : "production";
|
||||||
if (ENV !== "development") {
|
if (ENV !== "development") {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
|
|||||||
Reference in New Issue
Block a user