web-app/src/components/ConnectionStatus.vue
padreug 69d0a23848 fix typescript errors
fix typescript errors
2025-02-16 11:00:41 +01:00

120 lines
No EOL
3.3 KiB
Vue

<script setup lang="ts">
import { useNostrStore } from '@/stores/nostr'
import { useRouter, useRoute } from 'vue-router'
import { computed } from 'vue'
const nostrStore = useNostrStore()
const router = useRouter()
const route = useRoute()
const status = computed(() => nostrStore.connectionStatus)
const hasUnread = computed(() => nostrStore.hasUnreadMessages)
const isOnSupportChat = computed(() => route.path === '/support')
// Compute theme-specific classes
const indicatorClasses = computed(() => ({
'bg-primary/20 dark:bg-primary/30': true,
'shadow-[0_0_8px_rgba(var(--primary),0.3)] dark:shadow-[0_0_12px_rgba(var(--primary),0.4)]': true
}))
const breatheClasses = computed(() => ({
'bg-primary/10 dark:bg-primary/20': true,
'shadow-[0_0_12px_rgba(var(--primary),0.2)] dark:shadow-[0_0_16px_rgba(var(--primary),0.3)]': true
}))
async function handleIndicatorClick() {
if (isOnSupportChat.value) {
return // Do nothing if already on support chat
}
if (status.value === 'connected') {
// Navigate to support chat if connected
router.push('/support')
} else {
// Attempt to reconnect if not connected
try {
await nostrStore.init() // Use init instead of reconnectToRelays
} catch (err) {
console.error('Failed to reconnect:', err)
}
}
}
</script>
<template>
<div class="flex items-center gap-2">
<div class="relative">
<div
class="relative h-4 w-4 flex items-center justify-center cursor-pointer hover:scale-110 transition-transform duration-200"
@click="handleIndicatorClick"
:title="isOnSupportChat
? status
: status === 'connected'
? 'Click to open support chat'
: 'Click to reconnect'"
>
<!-- Base connection dot -->
<div
class="h-2 w-2 rounded-full z-20 relative transition-colors duration-300"
:class="{
'bg-green-500 shadow-green-500/30': status === 'connected',
'bg-yellow-500 shadow-yellow-500/30': status === 'connecting',
'bg-red-500 shadow-red-500/30': status === 'disconnected'
}"
/>
<!-- Message indicator -->
<div
v-if="hasUnread"
class="absolute inset-0 message-indicator"
>
<div
class="absolute inset-0 rounded-full transition-colors duration-300"
:class="indicatorClasses"
></div>
<div
class="absolute inset-0 rounded-full transition-colors duration-300 animate-breathe"
:class="breatheClasses"
></div>
</div>
</div>
</div>
<span class="text-sm text-muted-foreground hidden md:inline">
{{ status }}
<span v-if="hasUnread" class="text-primary font-medium ml-1">
(1)
</span>
</span>
</div>
</template>
<style scoped>
.message-indicator {
transform-origin: center;
animation: gentle-pulse 2s ease-in-out infinite;
}
@keyframes gentle-pulse {
0% { transform: scale(0.95); }
50% { transform: scale(1.1); }
100% { transform: scale(0.95); }
}
.animate-breathe {
animation: breathe 2s ease-in-out infinite;
}
@keyframes breathe {
0% {
transform: scale(1);
opacity: 0.3;
}
50% {
transform: scale(1.5);
opacity: 0.6;
}
100% {
transform: scale(1);
opacity: 0.3;
}
}
</style>