Friendship (request/accept/decline/remove, self-request and crossing-request handling, DB-level pair uniqueness via a hand-written expression index), ChatRoom/ChatMessage/ChatReadState backed by Nitro's built-in websocket (server/api/v1/community/ws.get.ts) behind a ChatTransport seam (server/internal/community/chatTransport.ts) with a REST send fallback. Mid-milestone product redirect: chat's primary job is coordinating the persistent-world servers (EQEmu/WoW/DAoC), not per-title discussion -- ChatRoomKind gets a first-class `server` case and chatService.ts ships a static KNOWN_SERVERS registry keyed the same way M4's GameServer will be, once that lands (gameServerId reserved for that wiring-up pass). Presence has no new table -- "online" is a live websocket registry (presenceRuntime.ts), "playing X" reads through an isolated query module (presenceService.ts) that degrades to an empty, clearly-labeled result if PlaySession's shape doesn't match what it expects. Pages: /community/friends, /community/chat, plus a friends/servers strip on /community itself. Migration 20260803120000_m3_friends_chat.
176 lines
6.2 KiB
Vue
176 lines
6.2 KiB
Vue
<template>
|
|
<footer class="bg-zinc-950" aria-labelledby="footer-heading">
|
|
<h2 id="footer-heading" class="sr-only">{{ $t("footer.footer") }}</h2>
|
|
<div class="mx-auto max-w-7xl px-6 py-16 sm:py-24 lg:px-8">
|
|
<!-- Drop Info -->
|
|
<div class="xl:grid xl:grid-cols-3 xl:gap-8">
|
|
<div class="space-y-8">
|
|
<DropWordmark class="h-10" />
|
|
<p class="text-sm leading-6 text-zinc-300">
|
|
{{ $t("drop.desc") }}
|
|
</p>
|
|
|
|
<SelectorLanguage />
|
|
|
|
<div class="flex space-x-6">
|
|
<NuxtLink
|
|
v-for="item in navigation.social"
|
|
:key="item.name"
|
|
:to="item.href"
|
|
target="_blank"
|
|
class="text-zinc-400 hover:text-zinc-400"
|
|
>
|
|
<span class="sr-only">{{ item.name }}</span>
|
|
<component :is="item.icon" class="h-6 w-6" aria-hidden="true" />
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Foot links -->
|
|
<div class="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
|
|
<div class="md:grid md:grid-cols-2 md:gap-8">
|
|
<div>
|
|
<h3 class="text-sm font-semibold leading-6 text-white">
|
|
{{ $t("footer.games") }}
|
|
</h3>
|
|
<ul role="list" class="mt-6 space-y-4">
|
|
<li v-for="item in navigation.games" :key="item.name">
|
|
<NuxtLink
|
|
:to="item.href"
|
|
class="text-sm leading-6 text-zinc-300 hover:text-white"
|
|
>{{ item.name }}</NuxtLink
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="mt-10 md:mt-0">
|
|
<h3 class="text-sm font-semibold leading-6 text-white">
|
|
{{ $t("userHeader.links.community") }}
|
|
</h3>
|
|
<ul role="list" class="mt-6 space-y-4">
|
|
<li v-for="item in navigation.community" :key="item.name">
|
|
<NuxtLink
|
|
:to="item.href"
|
|
class="text-sm leading-6 text-zinc-300 hover:text-white"
|
|
>{{ item.name }}</NuxtLink
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="md:grid md:grid-cols-2 md:gap-8">
|
|
<div>
|
|
<h3 class="text-sm font-semibold leading-6 text-white">
|
|
{{ $t("footer.documentation") }}
|
|
</h3>
|
|
<ul role="list" class="mt-6 space-y-4">
|
|
<li v-for="item in navigation.documentation" :key="item.name">
|
|
<NuxtLink
|
|
:to="item.href"
|
|
class="text-sm leading-6 text-zinc-300 hover:text-white"
|
|
>{{ item.name }}</NuxtLink
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="mt-10 md:mt-0">
|
|
<h3 class="text-sm font-semibold leading-6 text-white">
|
|
{{ $t("footer.about") }}
|
|
</h3>
|
|
<ul role="list" class="mt-6 space-y-4">
|
|
<li v-for="item in navigation.about" :key="item.name">
|
|
<NuxtLink
|
|
:to="item.href"
|
|
class="text-sm leading-6 text-zinc-300 hover:text-white"
|
|
>{{ item.name }}</NuxtLink
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-center xl:col-span-3 mt-8">
|
|
<NuxtLink
|
|
:to="`https://devops.quasarke.net/drop-oss/drop/releases/tag/${versionInfo.version}`"
|
|
class="text-xs text-zinc-700 hover:text-zinc-400 transition-colors duration-200 cursor-default select-none"
|
|
>
|
|
<i18n-t keypath="footer.version" tag="span" scope="global">
|
|
<template #version>
|
|
<span>{{ versionInfo.version }}</span>
|
|
</template>
|
|
<template #gitRef>
|
|
<span>{{ versionInfo.gitRef }}</span>
|
|
</template>
|
|
</i18n-t>
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { IconsDiscordLogo, IconsGithubLogo } from "#components";
|
|
|
|
const { t } = useI18n();
|
|
|
|
const versionInfo = await $dropFetch("/api/v1");
|
|
|
|
// Every upstream Drop-OSS URL below is retargeted at our own infrastructure
|
|
// -- we took over the dead upstream project and run the fork at
|
|
// devops.quasarke.net/drop-oss/drop (see the README's "Quasarke Edition"
|
|
// history). Previously done as a post-build patch across four compiled
|
|
// artifacts (see the now-removed homelab-compose
|
|
// drop-stack/patch-footer-links.js); folded into source now that the fork
|
|
// builds from source.
|
|
//
|
|
// The Discord/social link used to point at community.quasarke.net, a
|
|
// separate sidecar service. That service has been retired -- community
|
|
// features now live at /community, inside Drop itself -- so the link
|
|
// points there directly instead of out to another vhost.
|
|
const navigation = computed(() => ({
|
|
games: [
|
|
{ name: t("store.recentlyAdded"), href: "#" },
|
|
{ name: t("store.recentlyReleased"), href: "#" },
|
|
{ name: t("footer.topSellers"), href: "#" },
|
|
{ name: t("footer.findGame"), href: "#" },
|
|
],
|
|
community: [
|
|
{ name: t("common.friends"), href: "/community/friends" },
|
|
{ name: t("common.groups"), href: "/community" },
|
|
{ name: t("common.servers"), href: "/community/chat" },
|
|
],
|
|
documentation: [
|
|
// TODO: public API docs
|
|
// { name: t("footer.api"), href: "https://api.droposs.org/" },
|
|
{
|
|
name: t("footer.docs.server"),
|
|
href: "https://drop-docs.quasarke.net/docs/admin/quickstart",
|
|
},
|
|
{
|
|
name: t("footer.docs.client"),
|
|
href: "https://drop-docs.quasarke.net/docs/user",
|
|
},
|
|
],
|
|
about: [
|
|
{ name: t("footer.aboutDrop"), href: "https://drop-docs.quasarke.net/" },
|
|
{
|
|
name: t("footer.comparison"),
|
|
href: "https://drop-docs.quasarke.net/",
|
|
},
|
|
],
|
|
social: [
|
|
{
|
|
name: t("footer.social.github"),
|
|
href: "https://devops.quasarke.net/drop-oss",
|
|
icon: IconsGithubLogo,
|
|
},
|
|
{
|
|
name: t("footer.social.discord"),
|
|
href: "/community",
|
|
icon: IconsDiscordLogo,
|
|
},
|
|
],
|
|
}));
|
|
</script>
|