new message indicator
This commit is contained in:
parent
2bbb9ae938
commit
074a1fc534
3 changed files with 160 additions and 22 deletions
|
|
@ -1,21 +1,122 @@
|
|||
<script setup lang="ts">
|
||||
import { useNostrStore } from '@/stores/nostr'
|
||||
import { useTheme } from '@/components/theme-provider'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const nostrStore = useNostrStore()
|
||||
const { theme } = useTheme()
|
||||
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.reconnectToRelays()
|
||||
} catch (err) {
|
||||
console.error('Failed to reconnect:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="h-2 w-2 rounded-full"
|
||||
:class="{
|
||||
'bg-green-500 animate-pulse': status === 'connected',
|
||||
'bg-yellow-500': status === 'connecting',
|
||||
'bg-red-500': status === 'disconnected'
|
||||
}"
|
||||
/>
|
||||
<span class="text-sm text-muted-foreground hidden md:inline">{{ status }}</span>
|
||||
<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>
|
||||
</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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue