forked from npmx-dev/npmx.dev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConnectorStatus.client.vue
More file actions
104 lines (95 loc) · 3.21 KB
/
ConnectorStatus.client.vue
File metadata and controls
104 lines (95 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<script setup lang="ts">
const {
isConnected,
isConnecting,
npmUser,
avatar,
error,
activeOperations,
hasPendingOperations,
} = useConnector()
const showModal = shallowRef(false)
const showTooltip = shallowRef(false)
const tooltipText = computed(() => {
if (isConnecting.value) return $t('connector.status.connecting')
if (isConnected.value) return $t('connector.status.connected')
return $t('connector.status.connect_cli')
})
const statusColor = computed(() => {
if (isConnecting.value) return 'bg-yellow-500'
if (isConnected.value) return 'bg-green-500'
return 'bg-fg-subtle'
})
/** Only show count of active (pending/approved/running) operations */
const operationCount = computed(() => activeOperations.value.length)
const ariaLabel = computed(() => {
if (error.value) return error.value
if (isConnecting.value) return $t('connector.status.aria_connecting')
if (isConnected.value) return $t('connector.status.aria_connected')
return $t('connector.status.aria_click_to_connect')
})
</script>
<template>
<div class="relative flex items-center gap-2">
<!-- Username link (when connected) -->
<NuxtLink
v-if="isConnected && npmUser"
:to="`/~${npmUser}`"
class="link-subtle font-mono text-sm hidden sm:inline"
>
@{{ npmUser }}
</NuxtLink>
<button
type="button"
class="relative flex items-center justify-center w-8 h-8 rounded-md transition-colors duration-200 hover:bg-bg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
:aria-label="ariaLabel"
@click="showModal = true"
@mouseenter="showTooltip = true"
@mouseleave="showTooltip = false"
@focus="showTooltip = true"
@blur="showTooltip = false"
>
<!-- Avatar (when connected with avatar) -->
<img
v-if="isConnected && avatar"
:src="avatar"
:alt="$t('connector.status.avatar_alt', { user: npmUser })"
width="24"
height="24"
class="w-6 h-6 rounded-full"
/>
<!-- Status dot (when not connected or no avatar) -->
<span
v-else
class="w-2.5 h-2.5 rounded-full transition-colors duration-200"
:class="statusColor"
aria-hidden="true"
/>
<!-- Operation count badge (overlaid) -->
<span
v-if="isConnected && operationCount > 0"
class="absolute -top-0.5 -inset-ie-0.5 min-w-[1rem] h-4 px-1 flex items-center justify-center font-mono text-[10px] rounded-full"
:class="hasPendingOperations ? 'bg-yellow-500 text-black' : 'bg-blue-500 text-white'"
aria-hidden="true"
>
{{ operationCount }}
</span>
</button>
<!-- Tooltip -->
<Transition
enter-active-class="transition-opacity duration-150"
leave-active-class="transition-opacity duration-100"
enter-from-class="opacity-0"
leave-to-class="opacity-0"
>
<div
v-if="showTooltip"
role="tooltip"
class="absolute inset-ie-0 top-full mt-2 px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-nowrap z-50"
>
{{ tooltipText }}
</div>
</Transition>
<ConnectorModal v-model:open="showModal" />
</div>
</template>