feat: Add smooth connection animation to MCP dropdown

Adds a pulse animation when WebMCP connection is established.
The animation triggers regardless of dropdown state.
This commit is contained in:
2026-02-13 21:27:44 -06:00
parent 8118356999
commit 2c0ece71b2

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue' import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useCanvasStore } from '../stores/canvas' import { useCanvasStore } from '../stores/canvas'
import { connectWithToken, getConnectionInfo } from '../services/webmcp' import { connectWithToken, getConnectionInfo } from '../services/webmcp'
@@ -10,6 +10,18 @@ const { isConnected, isReconnecting, connectionStatus, connectionInfo } = storeT
const isOpen = ref(false) const isOpen = ref(false)
const tokenInput = ref('') const tokenInput = ref('')
const isConnecting = ref(false) const isConnecting = ref(false)
const justConnected = ref(false)
// Watch for connection changes and trigger animation
watch(isConnected, (newValue, oldValue) => {
if (newValue && !oldValue) {
// Just connected - trigger animation
justConnected.value = true
setTimeout(() => {
justConnected.value = false
}, 2500) // Animation duration
}
})
const statusText = computed(() => { const statusText = computed(() => {
if (isReconnecting.value) return 'Reconnecting...' if (isReconnecting.value) return 'Reconnecting...'
@@ -73,7 +85,7 @@ onUnmounted(() => {
<template> <template>
<div class="connection-dropdown-container"> <div class="connection-dropdown-container">
<button class="dropdown-trigger" @click.stop="toggleDropdown" title="WebMCP Connection"> <button class="dropdown-trigger" :class="{ 'just-connected': justConnected }" @click.stop="toggleDropdown" title="WebMCP Connection">
<span class="status-dot" :class="statusClass"></span> <span class="status-dot" :class="statusClass"></span>
<span>MCP</span> <span>MCP</span>
<svg class="chevron" :class="{ open: isOpen }" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg class="chevron" :class="{ open: isOpen }" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -141,6 +153,7 @@ onUnmounted(() => {
<style scoped> <style scoped>
.connection-dropdown-container { .connection-dropdown-container {
position: relative; position: relative;
overflow: visible;
} }
.dropdown-trigger { .dropdown-trigger {
@@ -360,4 +373,39 @@ onUnmounted(() => {
text-align: center; text-align: center;
padding: 0.5rem 0; padding: 0.5rem 0;
} }
/* Connection animation - Smooth effect */
.dropdown-trigger.just-connected {
animation: connectionPulse 2s ease-in-out;
}
@keyframes connectionPulse {
0% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
border-color: var(--border-color);
}
15% {
transform: scale(1.05);
box-shadow: 0 0 8px rgba(16, 185, 129, 0.4),
0 0 20px rgba(16, 185, 129, 0.2);
border-color: #10b981;
}
30% {
transform: scale(1);
box-shadow: 0 0 12px rgba(16, 185, 129, 0.5),
0 0 30px rgba(16, 185, 129, 0.25);
border-color: #34d399;
}
50% {
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4),
0 0 35px rgba(16, 185, 129, 0.2);
border-color: #10b981;
}
100% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
border-color: var(--border-color);
}
}
</style> </style>