110 lines
3.1 KiB
Vue
110 lines
3.1 KiB
Vue
|
|
<template>
|
||
|
|
<div class="rounded-lg bg-zinc-800/50 p-4 flex flex-col gap-y-3">
|
||
|
|
<div class="flex items-center justify-between">
|
||
|
|
<h2 class="text-sm font-semibold font-display text-zinc-100 uppercase">
|
||
|
|
{{ $t("community.servers.panelTitle") }}
|
||
|
|
</h2>
|
||
|
|
<NuxtLink
|
||
|
|
to="/community/servers"
|
||
|
|
class="text-xs text-zinc-500 hover:text-zinc-300 duration-200"
|
||
|
|
>
|
||
|
|
{{ $t("community.servers.viewAll") }}
|
||
|
|
</NuxtLink>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div v-if="loading" class="text-sm text-zinc-500">
|
||
|
|
{{ $t("common.srLoading") }}
|
||
|
|
</div>
|
||
|
|
<div v-else-if="servers.length === 0" class="text-sm text-zinc-500">
|
||
|
|
{{ $t("community.servers.noneFeatured") }}
|
||
|
|
</div>
|
||
|
|
<ul v-else class="flex flex-col divide-y divide-zinc-700/50">
|
||
|
|
<li
|
||
|
|
v-for="server in servers"
|
||
|
|
:key="server.id"
|
||
|
|
class="py-2.5 first:pt-0 last:pb-0 flex items-start gap-x-3"
|
||
|
|
>
|
||
|
|
<span
|
||
|
|
class="mt-1 size-2.5 rounded-full shrink-0"
|
||
|
|
:class="statusDotClass(server.status)"
|
||
|
|
:title="server.status"
|
||
|
|
/>
|
||
|
|
<div class="flex flex-col gap-y-0.5 min-w-0 flex-1">
|
||
|
|
<div class="flex items-center gap-x-2">
|
||
|
|
<NuxtLink
|
||
|
|
:to="`/community/servers/${server.id}`"
|
||
|
|
class="text-sm font-semibold font-display text-zinc-100 hover:text-white truncate"
|
||
|
|
>
|
||
|
|
{{ server.name }}
|
||
|
|
</NuxtLink>
|
||
|
|
<span class="text-xs text-zinc-500 shrink-0">{{
|
||
|
|
statusLabel(server.status)
|
||
|
|
}}</span>
|
||
|
|
</div>
|
||
|
|
<div class="text-xs text-zinc-400 flex items-center gap-x-2">
|
||
|
|
<span>{{ server.host }}:{{ server.port }}</span>
|
||
|
|
<span v-if="server.playersOnline !== null" class="text-zinc-300">
|
||
|
|
{{
|
||
|
|
$t("community.servers.playersOnline", [server.playersOnline])
|
||
|
|
}}
|
||
|
|
</span>
|
||
|
|
<span
|
||
|
|
v-else-if="server.status === 'up'"
|
||
|
|
class="text-zinc-500 italic"
|
||
|
|
>
|
||
|
|
{{ $t("community.servers.playersUnavailable") }}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
interface PanelServer {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
host: string;
|
||
|
|
port: number;
|
||
|
|
status: "up" | "down" | "degraded" | "unknown";
|
||
|
|
playersOnline: number | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const loading = ref(true);
|
||
|
|
const servers = ref<PanelServer[]>([]);
|
||
|
|
const statusLabel = useServerStatusLabel();
|
||
|
|
|
||
|
|
function statusDotClass(status: PanelServer["status"]) {
|
||
|
|
switch (status) {
|
||
|
|
case "up":
|
||
|
|
return "bg-emerald-500";
|
||
|
|
case "down":
|
||
|
|
return "bg-red-500";
|
||
|
|
case "degraded":
|
||
|
|
return "bg-amber-500";
|
||
|
|
default:
|
||
|
|
return "bg-zinc-500";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function load() {
|
||
|
|
loading.value = true;
|
||
|
|
try {
|
||
|
|
servers.value = await $dropFetch<PanelServer[]>(
|
||
|
|
"/api/v1/community/servers",
|
||
|
|
{
|
||
|
|
params: { featured: "true" },
|
||
|
|
},
|
||
|
|
);
|
||
|
|
} catch (e) {
|
||
|
|
console.error("[community] failed to load featured servers", e);
|
||
|
|
servers.value = [];
|
||
|
|
} finally {
|
||
|
|
loading.value = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
await load();
|
||
|
|
</script>
|