From ef12ba449f0555dbb45eaeec47065d31c3bfc1ce Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 21:00:10 +0000 Subject: [PATCH] feat(team): roster refresh, application FAQ, role chips Roster - Tag developers (joltra, theShadowsDust, mcmdev, Random) as Entwicklung, Pega as Bau-Team, weltspielt as Content & Konzepte; promote Alex M. to Teamassistenz and move BavarianKingdom into Moderation with their real MC name (morelia0815) so the head render resolves correctly - Add permanent open positions for Social Media (Media rank) and the donation-funded Lite rank; the Lite card links to OpenCollective and uses a heart icon via a new `applyVia` field on the team schema - Extend the rank enum to cover teamassist/media/lite FAQ - New `team_faq` content collection (DE/EN markdown) with five entries covering how to apply, the process, per-rank requirements, the Lite rank, and speculative applications - Repository contract gains `listTeamFaqEntries`; `useTeamFaqContent` composable + `TeamFaqSection` accordion mounted below the roster, with its own FAQPage schema.org block UI - Sub-roles render as outlined chips under each team member name (TeamMemberCard), reusing the shared Chip component Copy - Strip em-dashes from team titles/subtitles and the profile page; lean on the existing "| OneLiteFeather.net" title template instead --- components/OgImage/TeamMember.satori.vue | 83 ++++++++++++++++ .../blog/page/FeaturedTeamMembers.vue | 3 +- .../features/home/team/TeamMemberCard.vue | 19 +++- components/features/home/team/TeamMembers.vue | 8 +- components/features/team/OpenPositionCard.vue | 28 ++++-- components/features/team/TeamFaqSection.vue | 85 ++++++++++++++++ components/features/team/TeamRankSection.vue | 1 + composables/useTeamFaqContent.ts | 24 +++++ composables/useTeamProfile.ts | 11 ++- content.config.ts | 17 +++- content/team-faq/de/apply.md | 11 +++ content/team-faq/de/lite.md | 14 +++ content/team-faq/de/no-position.md | 9 ++ content/team-faq/de/process.md | 13 +++ content/team-faq/de/requirements.md | 25 +++++ content/team-faq/en/apply.md | 11 +++ content/team-faq/en/lite.md | 15 +++ content/team-faq/en/no-position.md | 9 ++ content/team-faq/en/process.md | 14 +++ content/team-faq/en/requirements.md | 25 +++++ content/team/de/home.json | 96 ++++++++++++------- content/team/en/home.json | 96 ++++++++++++------- i18n/locales/de.json | 16 +++- i18n/locales/en.json | 16 +++- nuxt.config.ts | 6 ++ pages/team/[slug].vue | 92 ++++++++++++++++-- pages/team/index.vue | 3 + server/api/__sitemap__/team.ts | 30 ++++++ types/faq.ts | 7 ++ utils/content/nuxtContentAdapter.ts | 9 +- utils/content/repository.ts | 4 +- utils/teamRoles.ts | 32 +++++++ 32 files changed, 728 insertions(+), 104 deletions(-) create mode 100644 components/OgImage/TeamMember.satori.vue create mode 100644 components/features/team/TeamFaqSection.vue create mode 100644 composables/useTeamFaqContent.ts create mode 100644 content/team-faq/de/apply.md create mode 100644 content/team-faq/de/lite.md create mode 100644 content/team-faq/de/no-position.md create mode 100644 content/team-faq/de/process.md create mode 100644 content/team-faq/de/requirements.md create mode 100644 content/team-faq/en/apply.md create mode 100644 content/team-faq/en/lite.md create mode 100644 content/team-faq/en/no-position.md create mode 100644 content/team-faq/en/process.md create mode 100644 content/team-faq/en/requirements.md create mode 100644 server/api/__sitemap__/team.ts create mode 100644 utils/teamRoles.ts diff --git a/components/OgImage/TeamMember.satori.vue b/components/OgImage/TeamMember.satori.vue new file mode 100644 index 0000000..3d3ceb0 --- /dev/null +++ b/components/OgImage/TeamMember.satori.vue @@ -0,0 +1,83 @@ + + + diff --git a/components/features/blog/page/FeaturedTeamMembers.vue b/components/features/blog/page/FeaturedTeamMembers.vue index 866163e..6d97b88 100644 --- a/components/features/blog/page/FeaturedTeamMembers.vue +++ b/components/features/blog/page/FeaturedTeamMembers.vue @@ -2,6 +2,7 @@ import { useI18n } from 'vue-i18n' import { NuxtLink } from '#components' import { teamAvatarUrl } from '~/utils/teamAvatar' +import { toRoleString } from '~/utils/teamRoles' const props = defineProps<{ slugs: string[] }>() @@ -46,7 +47,7 @@ const members = computed(() => props.slugs /> {{ m.name }} - {{ m.role }} + {{ toRoleString(m.role) }} diff --git a/components/features/home/team/TeamMemberCard.vue b/components/features/home/team/TeamMemberCard.vue index f612af9..cbb432e 100644 --- a/components/features/home/team/TeamMemberCard.vue +++ b/components/features/home/team/TeamMemberCard.vue @@ -3,11 +3,13 @@ import { useI18n } from 'vue-i18n' import { NuxtLink } from '#components' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons' +import UiChip from '~/components/base/Chip.vue' import { teamAvatarUrl } from '~/utils/teamAvatar' +import { toRoleList, toRoleString } from '~/utils/teamRoles' type Props = { name: string - role: string + role?: string | string[] slogan?: string mcName?: string slug?: string @@ -16,6 +18,7 @@ type Props = { } const props = withDefaults(defineProps(), { + role: undefined, slogan: undefined, mcName: undefined, slug: undefined, @@ -35,7 +38,9 @@ const avatarSrc = computed(() => teamAvatarUrl({ avatarUrl: props.avatarUrl }, 128)) -const ariaLabel = computed(() => t('team.card_aria', { name: props.name, role: props.role })) +const roleChips = computed(() => toRoleList(props.role)) +const roleAriaText = computed(() => toRoleString(props.role)) +const ariaLabel = computed(() => t('team.card_aria', { name: props.name, role: roleAriaText.value }))