mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-08-08 18:56:03 +02:00
feat(add toast):
This commit is contained in:
@@ -63,6 +63,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
<div class="fixed top-6 right-6 z-50 space-y-3">
|
||||||
|
<transition-group name="toast">
|
||||||
|
<div
|
||||||
|
v-for="toast in toasts"
|
||||||
|
:key="toast.id"
|
||||||
|
class="flex items-center p-3 rounded-xl shadow-xl text-white max-w-md animate-toast-in border border-opacity-30"
|
||||||
|
:class="{
|
||||||
|
'bg-success-toast border-accent-green': toast.type === 'success',
|
||||||
|
'bg-error-toast border-accent-red': toast.type === 'error',
|
||||||
|
'bg-info-toast border-accent-orange': toast.type === 'info'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="flex-1 font-medium tracking-wide text-sm">{{ toast.message }}</span>
|
||||||
|
<button
|
||||||
|
@click="removeToast(toast.id)"
|
||||||
|
class="ml-3 focus:outline-none hover:opacity-80 transition-opacity"
|
||||||
|
>
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<main class="max-w-6xl mx-auto space-y-8">
|
<main class="max-w-6xl mx-auto space-y-8">
|
||||||
<section class="bg-dark-card rounded-lg p-6 shadow-lg" v-show="false">
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg" v-show="false">
|
||||||
<h2 class="text-2xl font-bold mb-4">Select a Config</h2>
|
<h2 class="text-2xl font-bold mb-4">Select a Config</h2>
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ var app = new Vue({
|
|||||||
showModules: false,
|
showModules: false,
|
||||||
showLogs: false,
|
showLogs: false,
|
||||||
showConsentModal: true,
|
showConsentModal: true,
|
||||||
|
toasts: [], // Array to store toast notifications
|
||||||
|
toastTimeout: 3000, // Duration in milliseconds (3 seconds)
|
||||||
statusDotClass: 'bg-gray-500', // Default status dot class
|
statusDotClass: 'bg-gray-500', // Default status dot class
|
||||||
statusText: 'Verified', // Default status text
|
statusText: 'Verified', // Default status text
|
||||||
statusClass: 'bg-green-500 text-dark-bg', // Default status class
|
statusClass: 'bg-green-500 text-dark-bg', // Default status class
|
||||||
@@ -93,6 +95,19 @@ var app = new Vue({
|
|||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showToast(message, type = 'success') {
|
||||||
|
const id = Date.now(); // Unique ID for each toast
|
||||||
|
this.toasts.push({ id, message, type });
|
||||||
|
|
||||||
|
// Automatically remove toast after timeout
|
||||||
|
setTimeout(() => {
|
||||||
|
this.removeToast(id);
|
||||||
|
}, this.toastTimeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeToast(id) {
|
||||||
|
this.toasts = this.toasts.filter(toast => toast.id !== id);
|
||||||
|
},
|
||||||
focusTextarea() {
|
focusTextarea() {
|
||||||
this.isFocused = true;
|
this.isFocused = true;
|
||||||
self = this.$refs;
|
self = this.$refs;
|
||||||
@@ -210,10 +225,12 @@ var app = new Vue({
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
this.updateStatusDot(false);
|
this.updateStatusDot(false);
|
||||||
this.errorMsg = 'Integration verification failed:' + JSON.stringify(r);
|
this.errorMsg = 'Integration verification failed:' + JSON.stringify(r);
|
||||||
|
this.showToast('Integration verification failed', 'error');
|
||||||
} else {
|
} else {
|
||||||
this.errorMsg = '';
|
this.errorMsg = '';
|
||||||
this.updateStatusDot(true);
|
this.updateStatusDot(true);
|
||||||
this.okMsg = 'Integration verified';
|
this.okMsg = 'Integration verified';
|
||||||
|
this.showToast('Integration verified successfully', 'success');
|
||||||
this.integrationVerified = true;
|
this.integrationVerified = true;
|
||||||
// console.log('Integration verified', this.integrationVerified);
|
// console.log('Integration verified', this.integrationVerified);
|
||||||
// this.$forceUpdate();
|
// this.$forceUpdate();
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.scrollbar-hide::-webkit-scrollbar {
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -96,4 +97,55 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
/* Toast-specific colors */
|
||||||
|
.bg-success-toast {
|
||||||
|
background: #1C3F74
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-error-toast {
|
||||||
|
background: #85144B
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-info-toast {
|
||||||
|
background: #FFC300
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-accent-green, .border-accent-red, .border-accent-orange {
|
||||||
|
border-color: rgba(255, 255, 255, 0.1); /* Subtle white border for depth */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animation */
|
||||||
|
.animate-toast-in {
|
||||||
|
animation: tSlideIn 0.4s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes tSlideIn {
|
||||||
|
from {
|
||||||
|
transform: translateX(120%) scale(0.95);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0) scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast-enter-active,
|
||||||
|
.toast-leave-active {
|
||||||
|
transition: all 0.4s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast-enter-from,
|
||||||
|
.toast-leave-to {
|
||||||
|
transform: translateX(120%) scale(0.95);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effect */
|
||||||
|
[toast-type]:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
Reference in New Issue
Block a user