127 lines
3.0 KiB
Vue
127 lines
3.0 KiB
Vue
<template>
|
|
<div class="grid grid-cols-[1fr_1.25fr] gap-2 p-2 h-screen grid-rows-[auto_1fr]">
|
|
<div
|
|
class="flex items-center justify-between gap-2 rounded-xl p-3 bg-surface-950"
|
|
>
|
|
<div class="inline-flex items-center gap-3">
|
|
<PrimeBadge v-if="isTauri" class="opacity-50" severity="secondary" :value="version" size="small" />
|
|
<PrimeBadge :severity="connected ? 'success' : 'danger' " />
|
|
</div>
|
|
|
|
<PrimeButtonGroup class="ml-auto">
|
|
<PrimeButton :severity="inputMuted ? 'info' : undefined" outlined @click="toggleInput">
|
|
<template #icon>
|
|
<Component :is="inputMuted ? MicOff : Mic" />
|
|
</template>
|
|
</PrimeButton>
|
|
<PrimeButton :severity="outputMuted ? 'info' : undefined" outlined @click="toggleOutput">
|
|
<template #icon>
|
|
<Component :is="outputMuted ? VolumeOff : Volume2" />
|
|
</template>
|
|
</PrimeButton>
|
|
</PrimeButtonGroup>
|
|
|
|
<PrimeButton :severity="sharingEnabled ? 'success' : undefined" outlined @click="toggleShare">
|
|
<template #icon>
|
|
<Component :is="sharingEnabled ? ScreenShareOff : ScreenShare" />
|
|
</template>
|
|
</PrimeButton>
|
|
</div>
|
|
|
|
<div
|
|
class="flex items-center justify-center rounded-xl p-3 bg-surface-950"
|
|
>
|
|
<PrimeSelectButton
|
|
v-model="activeTab"
|
|
:options="tabs"
|
|
data-key="id"
|
|
:allow-empty="false"
|
|
style="--p-togglebutton-content-padding: 0.25rem 0.5rem"
|
|
>
|
|
<template #option="{ option }">
|
|
<Component :is="option.icon" size="24" />
|
|
</template>
|
|
</PrimeSelectButton>
|
|
</div>
|
|
|
|
<PrimeScrollPanel class="bg-surface-900 rounded-xl" style="min-height: 0">
|
|
<div v-auto-animate class="p-3 space-y-1">
|
|
<ClientRow v-for="client of clients" :key="client.userId" :client="client" />
|
|
</div>
|
|
</PrimeScrollPanel>
|
|
|
|
<PrimeScrollPanel class="bg-surface-900 rounded-xl" style="min-height: 0">
|
|
<div class="p-3">
|
|
<slot />
|
|
</div>
|
|
</PrimeScrollPanel>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
MessageCircle,
|
|
Mic,
|
|
MicOff,
|
|
ScreenShare,
|
|
ScreenShareOff,
|
|
Settings,
|
|
UserPen,
|
|
Volume2,
|
|
VolumeOff,
|
|
} from 'lucide-vue-next'
|
|
|
|
const {
|
|
isTauri,
|
|
version,
|
|
clients,
|
|
inputMuted,
|
|
outputMuted,
|
|
sharingEnabled,
|
|
toggleInput,
|
|
toggleOutput,
|
|
toggleShare,
|
|
} = useApp()
|
|
const { connect, connected } = useSignaling()
|
|
|
|
interface Tab {
|
|
id: string
|
|
icon: Component
|
|
onClick: () => void | Promise<void>
|
|
}
|
|
|
|
const route = useRoute()
|
|
|
|
const tabs: Tab[] = [
|
|
{
|
|
id: 'Index',
|
|
icon: MessageCircle,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Index' })
|
|
},
|
|
},
|
|
{
|
|
id: 'Profile',
|
|
icon: UserPen,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Profile' })
|
|
},
|
|
},
|
|
{
|
|
id: 'Preferences',
|
|
icon: Settings,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Preferences' })
|
|
},
|
|
},
|
|
]
|
|
|
|
const activeTab = ref<Tab>(tabs.find(tab => tab.id === route.name) ?? tabs[0]!)
|
|
|
|
watch(activeTab, (activeTab) => {
|
|
activeTab.onClick()
|
|
})
|
|
|
|
connect()
|
|
</script>
|