156 lines
3.7 KiB
Vue
156 lines
3.7 KiB
Vue
<template>
|
|
<div class="grid grid-cols-[360px_1fr] gap-2 p-2 h-screen grid-rows-[auto_1fr] max-w-full">
|
|
<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 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="videoEnabled ? 'success' : undefined" outlined @click="toggleVideo">
|
|
<template #icon>
|
|
<Component :is="videoEnabled ? CameraOff : Camera" />
|
|
</template>
|
|
</PrimeButton>
|
|
|
|
<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"
|
|
option-label="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 overflow-hidden" 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 overflow-hidden" style="min-height: 0">
|
|
<div class="p-3">
|
|
<slot />
|
|
</div>
|
|
</PrimeScrollPanel>
|
|
</div>
|
|
|
|
<FullscreenGallery />
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
Camera,
|
|
CameraOff,
|
|
MessageCircle,
|
|
Mic,
|
|
MicOff,
|
|
ScreenShare,
|
|
ScreenShareOff,
|
|
Settings,
|
|
TvMinimalPlay,
|
|
UserPen,
|
|
Volume2,
|
|
VolumeOff,
|
|
} from 'lucide-vue-next'
|
|
|
|
const {
|
|
version,
|
|
clients,
|
|
inputMuted,
|
|
outputMuted,
|
|
videoEnabled,
|
|
sharingEnabled,
|
|
somebodyStreamingVideo,
|
|
toggleInput,
|
|
toggleOutput,
|
|
toggleVideo,
|
|
toggleShare,
|
|
} = useApp()
|
|
const { connect, connected } = useSignaling()
|
|
|
|
interface Tab {
|
|
id: string
|
|
icon: Component
|
|
onClick: () => void | Promise<void>
|
|
}
|
|
|
|
const route = useRoute()
|
|
|
|
const tabs = computed<Tab[]>(() => {
|
|
const result = []
|
|
|
|
if (somebodyStreamingVideo.value) {
|
|
result.push({
|
|
id: 'Gallery',
|
|
icon: TvMinimalPlay,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Gallery' })
|
|
},
|
|
})
|
|
}
|
|
|
|
result.push(
|
|
{
|
|
id: 'Index',
|
|
icon: MessageCircle,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Index' })
|
|
},
|
|
},
|
|
{
|
|
id: 'Profile',
|
|
icon: UserPen,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Profile' })
|
|
},
|
|
},
|
|
{
|
|
id: 'Preferences',
|
|
icon: Settings,
|
|
onClick: () => {
|
|
navigateTo({ name: 'Preferences' })
|
|
},
|
|
},
|
|
)
|
|
|
|
return result
|
|
})
|
|
|
|
const activeTab = ref<Tab>(tabs.value.find(tab => tab.id === route.name) ?? tabs.value.find(tab => tab.id === 'Index')!)
|
|
|
|
watch(activeTab, (activeTab) => {
|
|
activeTab.onClick()
|
|
})
|
|
|
|
connect()
|
|
</script>
|