233 lines
7.6 KiB
Vue

<script setup lang="ts">
import { useNuxtApp, useAsyncData } from 'nuxt/app';
import useConfig from '../composables/useConfig.ts';
import useSimpleHead from '../composables/useSimpleHead.ts';
import useSpelling from '../composables/useSpelling.ts';
import { random } from '#shared/helpers.ts';
import type { Admin } from '#shared/user.ts';
import { getUrlForLocale } from '~/src/domain.ts';
import type { LocaleCode } from '~~/locale/locales.ts';
definePageMeta({
translatedPaths: (config) => {
if (!config.contact.enabled) {
return [];
}
return translatedPathByConfigModule(config.contact.team);
},
});
const { $translator: translator } = useNuxtApp();
const config = useConfig();
useSimpleHead({
title: translator.translate('contact.team.name'),
description: translator.translate('contact.team.description'),
}, translator);
const { convertName } = useSpelling();
const teamAsyncData = useAsyncData(async () => {
const membersByLocaleRaw = await $fetch('/api/admin/list');
const membersByLocale: Partial<Record<LocaleCode | '', Admin[]>> = Object.fromEntries(Object.entries(membersByLocaleRaw)
.filter(([_, members]) => {
return members.length > 0;
}));
const credentials = (membersByLocale[config.locale] ?? [])
.filter((member) => member.credentials !== null)
.toSorted((a, b) => {
if (a.credentialsLevel! > b.credentialsLevel!) {
return -1;
}
if (a.credentialsLevel! < b.credentialsLevel!) {
return 1;
}
return random() > 0.5 ? 1 : -1;
});
return { membersByLocale, credentials };
}, {
lazy: true,
});
const membersByLocale = computed(() => teamAsyncData.data.value?.membersByLocale);
const credentials = computed(() => teamAsyncData.data.value?.credentials);
</script>
<template>
<Page>
<CommunityNav />
<h2>
<Icon v="collective-logo.svg" class="invertible" />
<T>contact.team.name</T>
</h2>
<figure class="float-end border rounded m-3">
<img :src="`/img/${config.locale}/logo/logo-full-path.svg`" alt="" class="invertible">
<hr>
<figcaption>
<p><T>contact.team.logo</T></p>
<p class="text-center bigger mb-0">
<Icon v="transgender-alt" />
+
<Icon v="comment" />
=
<Icon v="collective-logo.svg" class="invertible" />
</p>
<nuxt-link to="/design" class="mt-3 btn btn-outline-primary btn-sm w-100">
<Icon v="palette" />
<T>contact.contribute.design.header</T>
</nuxt-link>
</figcaption>
</figure>
<section>
<p><T>contact.team.description</T></p>
<ul v-if="$te('contact.team.extra')">
<li v-for="item in $t('contact.team.extra')">
<LinkedText :text="item" />
</li>
</ul>
</section>
<Mission />
<section v-if="$te('contact.team.credentials')">
<h3>
<Icon v="graduation-cap" />
<T>contact.team.credentials.header</T>
</h3>
<T>contact.team.credentials.description</T>
<ul>
<li v-for="credential in credentials" :key="credential.username">
<Spelling :text="convertName(credential.credentialsName || credential.teamName)" />
<a :href="`${getUrlForLocale('_')}/@${credential.username}`" class="badge bg-light text-dark border">
@{{ credential.username }}
</a>
<ul>
<li v-for="item in credential.credentials" :key="item">
<ProfileLink v-if="item.startsWith('https://') || item.startsWith('http://')" :link="item" />
<LinkedText v-else :text="item" />
</li>
</ul>
</li>
</ul>
</section>
<section>
<Contribute id="contribute" />
</section>
<section v-if="false && $te('contact.team.join')">
<h3>
<Icon v="user-plus" />
<T>contact.team.join.header</T>
</h3>
<p><T>contact.team.join.encouragement</T></p>
<p><T>contact.team.join.areasIntro</T></p>
<ul>
<li v-for="item in $t('contact.team.join.areas')">
<Spelling :text="item" />
</li>
</ul>
<p><T>contact.team.join.allies</T></p>
<div v-if="$te('contact.team.join.warning')" class="alert alert-warning">
<p class="mb-0">
<Icon v="exclamation-triangle" />
<T>contact.team.join.warning</T>
</p>
</div>
<p><T>contact.team.join.how</T></p>
<ul>
<li v-for="item in $t('contact.team.join.application')">
<Spelling :text="item" />
</li>
</ul>
</section>
<AdPlaceholder :phkey="['content-0', 'content-mobile-0']" />
<Loading :value="membersByLocale">
<template #header>
<h3>
<Icon v="user-friends" />
<T>contact.team.members</T>
</h3>
</template>
<template v-for="(members, locale) in membersByLocale">
<h4 class="mt-4">
<template v-if="locale === ''">
<T>contact.team.upcoming</T>
</template>
<template v-else-if="locale === config.locale">
{{ $locales[locale].fullName }}
</template>
<a v-else :href="getUrlForLocale(locale)">
{{ $locales[locale].fullName }}
</a>
</h4>
<ul class="list-unstyled member-list">
<li v-for="member in members" class="mb-3 d-flex">
<a :href="`${getUrlForLocale('_')}/@${member.username}`">
<Avatar :user="member" dsize="4rem" />
</a>
<span class="ms-2">
<Spelling :text="convertName(member.teamName)" />
<br>
<a :href="`${getUrlForLocale('_')}/@${member.username}`" class="badge bg-light text-dark border">
@{{ member.username }}
</a>
</span>
</li>
</ul>
</template>
</Loading>
<AdPlaceholder :phkey="['content-1', 'content-mobile-1']" />
</Page>
</template>
<style lang="scss" scoped>
@import "~/assets/variables";
img {
max-width: 100%;
}
figure {
width: 100%;
max-width: 18rem;
padding: $spacer;
> img {
width: 100%;
}
figcaption {
font-size: $small-font-size;
}
}
@include media-breakpoint-down('md', $grid-breakpoints) {
figure {
float: none !important;
margin: 0 auto;
}
}
.bigger {
font-size: 2rem;
}
@include media-breakpoint-up('md', $grid-breakpoints) {
.member-list {
column-count: 3;
column-width: 16rem;
}
}
</style>