Skip to content

Commit 6255857

Browse files
committed
feat(site): add team page
1 parent 064da66 commit 6255857

File tree

18 files changed

+257
-17
lines changed

18 files changed

+257
-17
lines changed

.knosys/sites/default/src/content/config.ts

+37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,42 @@
11
import { defineCollection, z } from 'astro:content';
22
import { docsSchema } from '@astrojs/starlight/schema';
33

4+
const i18nSchema = z.object({
5+
en: z.string(),
6+
zh: z.string(),
7+
});
8+
9+
const contributors = defineCollection({
10+
type: 'data',
11+
schema: z.object({
12+
nickname: i18nSchema,
13+
avatar: z.string().url(),
14+
github: z.union([
15+
z.string(),
16+
z.object({
17+
id: z.number(),
18+
username: z.string(),
19+
}),
20+
]),
21+
twitter: z.union([
22+
z.string(),
23+
i18nSchema,
24+
]).optional(),
25+
homepage: z.union([
26+
z.string().url(),
27+
i18nSchema,
28+
]).optional(),
29+
title: z.string(),
30+
org: z.union([
31+
z.string(),
32+
z.object({
33+
name: z.string(),
34+
homepage: z.string().url().optional(),
35+
}),
36+
]).optional(),
37+
}),
38+
});
39+
440
const docs = defineCollection({ schema: docsSchema() });
541

642
const postSchema = z.object({
@@ -19,6 +55,7 @@ const posts = defineCollection({
1955
});
2056

2157
export const collections = {
58+
contributors,
2259
docs,
2360
posts,
2461
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
nickname:
2+
en: Ourai L.
3+
zh: 欧雷
4+
avatar: https://avatars.githubusercontent.com/u/562589
5+
github: ourai
6+
twitter:
7+
en: ntksol
8+
zh: fxxkol
9+
homepage:
10+
en: https://ourai.github.io
11+
zh: https://linxoid.com/ourai
12+
title: Front-end Engineer & DevRel
13+
org: OpenBuild
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { SupportedLocale } from '@/types';
2+
import { unwrapLocalValue } from '@/utils';
3+
4+
import type { InternalContributor, Contributor, ContributorMap } from './typing';
5+
6+
function getGitHubHandler(c: InternalContributor): string {
7+
return typeof c.github === 'string' ? c.github : c.github.username;
8+
}
9+
10+
function resolveContributor({ avatar, title, ...others }: InternalContributor, locale: SupportedLocale): Contributor {
11+
return {
12+
nickname: unwrapLocalValue(others.nickname, locale),
13+
avatar,
14+
github: getGitHubHandler(others as InternalContributor),
15+
twitter: typeof others.twitter === 'object' ? unwrapLocalValue(others.twitter, locale) : others.twitter,
16+
homepage: typeof others.homepage === 'object' ? unwrapLocalValue(others.homepage, locale) : others.homepage,
17+
title,
18+
org: typeof others.org === 'string' ? { name: others.org } : (others.org || { name: '' }),
19+
};
20+
}
21+
22+
function resolveContributorList(githubHandlers: string[], contributorMap: ContributorMap, locale: SupportedLocale) {
23+
return githubHandlers.map(githubHandler => resolveContributor(contributorMap[githubHandler], locale));
24+
}
25+
26+
export { getGitHubHandler, resolveContributorList };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as CoreMemberListView } from './views/core-member-list';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { SupportedLocale } from '@/types';
2+
import { getCollection } from '@/utils';
3+
4+
import type { InternalContributor, Contributor, ContributorMap } from './typing';
5+
import { getGitHubHandler, resolveContributorList } from './helper';
6+
7+
const contributors: InternalContributor[] = await getCollection('contributors');
8+
const contributorMap: ContributorMap = contributors.reduce((p, c) => ({
9+
...p,
10+
[getGitHubHandler(c)]: c,
11+
}), {});
12+
13+
function getList(locale: SupportedLocale): Contributor[] {
14+
return [];
15+
}
16+
17+
function getCoreTeamMemberList(locale: SupportedLocale) {
18+
return resolveContributorList(['ourai'], contributorMap, locale);
19+
}
20+
21+
export { getList, getCoreTeamMemberList };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { PickCollectionData } from '@/types';
2+
3+
type InternalContributor = PickCollectionData<'contributors'>;
4+
type ComplexKey = 'nickname' | 'github' | 'twitter' | 'homepage' | 'org';
5+
6+
type Contributor = Omit<InternalContributor, ComplexKey> & {
7+
nickname: string;
8+
github: string;
9+
twitter?: string;
10+
homepage?: string;
11+
org: {
12+
name: string;
13+
homepage?: string;
14+
};
15+
};
16+
17+
type ContributorMap = Record<string, InternalContributor>;
18+
19+
export type { InternalContributor, Contributor, ContributorMap };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
import type { SupportedLocale } from '@/types';
3+
4+
import { getCoreTeamMemberList } from '../../repository';
5+
import MemberCardWidget from '../../widgets/member-card';
6+
7+
const members = getCoreTeamMemberList(Astro.currentLocale as SupportedLocale);
8+
---
9+
10+
<ul class="list-none pl-0 grid grid-cols-1 gap-4 md:grid-cols-2">
11+
{members.map(m => (
12+
<li class="!m-0">
13+
<MemberCardWidget contributor={m} />
14+
</li>
15+
))}
16+
</ul>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './CoreMemberList.astro';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
import clsx from 'clsx';
3+
4+
import AstroLink from '@/controls/astro-link';
5+
6+
import type { Contributor } from '../../typing';
7+
import SocialList from './SocialList.astro';
8+
9+
interface Props {
10+
contributor: Contributor;
11+
class?: string;
12+
}
13+
14+
const { contributor, ...others } = Astro.props;
15+
---
16+
17+
<div class={clsx('flex !m-0 py-4 border rounded-lg shadow-sm text-sm', others.class)}>
18+
<div class="flex-shrink-0 px-4">
19+
<img class="!size-20 border rounded-full" src={contributor.avatar} alt={contributor.nickname} />
20+
</div>
21+
<div class="flex-grow !mt-0 pr-4">
22+
<h3 class="!text-xl">{contributor.homepage ? (<AstroLink class="no-underline" url={contributor.homepage}>{contributor.nickname}</AstroLink>) : contributor.nickname}</h3>
23+
<p class="!mt-1 text-neutral-500">{contributor.title}{contributor.org && (<> @ {contributor.org.name}</>)}</p>
24+
<SocialList class="!mt-4" contributor={contributor} />
25+
</div>
26+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
import clsx from 'clsx';
3+
import { Icon } from '@astrojs/starlight/components';
4+
5+
import AstroLink from '@/controls/astro-link';
6+
7+
import type { Contributor } from '../../typing';
8+
9+
interface Props {
10+
contributor: Contributor;
11+
class?: string;
12+
}
13+
14+
const { contributor: { github, twitter }, ...others } = Astro.props;
15+
---
16+
17+
<div class={clsx('flex items-center gap-4', others.class)}>
18+
<AstroLink class="inline-flex gap-1 no-underline" url={`https://github.com/${github}`}><Icon name="github" />{github}</AstroLink>{twitter && (
19+
<AstroLink class="inline-flex gap-1 no-underline" url={`https://x.com/${twitter}`}><Icon name="x.com" />{twitter}</AstroLink>
20+
)}
21+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './MemberCard.astro';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { StarlightPageProps } from '@astrojs/starlight/components/StarlightPage.astro';
2+
3+
type SidebarKey = 'about';
4+
type SidebarItems = StarlightPageProps['sidebar'];
5+
6+
const sidebarMap: Record<SidebarKey, SidebarItems> = {
7+
about: [
8+
{
9+
label: '关于',
10+
items: [
11+
{ label: '社区', link: '/community/' },
12+
{ label: '团队', link: '/team/' },
13+
],
14+
}
15+
],
16+
};
17+
18+
function getSidebar(key: SidebarKey) {
19+
return sidebarMap[key] || [];
20+
}
21+
22+
export { getSidebar };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './helper';
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
---
22
import StarlightLayout from '@astrojs/starlight/components/StarlightPage.astro';
33
4-
const title = '社区';
5-
const sidebar = [
6-
{
7-
label: '关于',
8-
items: [
9-
{ label: title, link: '/community/' },
10-
],
11-
}
12-
];
4+
import AstroLink from '@/controls/astro-link';
5+
import { getSidebar } from '#/layouts/guide';
6+
137
const headings = [
148
{ depth: 2, slug: '行为规范', text: '行为规范' },
159
{ depth: 2, slug: '获取新闻', text: '获取新闻' },
1610
{ depth: 2, slug: '讨论交流', text: '讨论交流' },
1711
];
1812
---
1913

20-
<StarlightLayout frontmatter={{ title }} sidebar={sidebar} headings={headings}>
21-
<p>OpenBuild 官网是一个社区驱动的 <a href="https://openbuildxyz.github.io/eco/zh/" target="_blank" rel="external">OpenBuild 生态</a>项目,在 2023 年由 OpenBuild 核心团队创建并研发了初始版本,<a href="https://openbuildxyz.github.io/eco/zh/posts/the-openbuild-official-website-frontend-codebase-is-open-now/" target="_blank" rel="external">于 2024 年 12 月开放源码</a>后引入社区力量协同共建。</p>
22-
<p>现如今,该项目由 OpenBuild 核心团队成员与来自世界各地的志愿者共同推进,并由<a href="https://x.com/fxxkol" target="_blank" rel="external">欧雷</a>担当项目负责人。</p>
14+
<StarlightLayout frontmatter={{ title: '社区' }} sidebar={getSidebar('about')} headings={headings}>
15+
<p>OpenBuild 官网是一个社区驱动的 <AstroLink url="https://openbuildxyz.github.io/eco/zh/">OpenBuild 生态</AstroLink>项目,在 2023 年由 OpenBuild 核心团队创建并研发了初始版本,<AstroLink url="https://openbuildxyz.github.io/eco/zh/posts/the-openbuild-official-website-frontend-codebase-is-open-now/">于 2024 年 12 月开放源码</AstroLink>后引入社区力量协同共建。</p>
16+
<p>现如今,该项目由 <AstroLink url="/team/">OpenBuild 核心团队成员与来自世界各地的志愿者</AstroLink>共同推进,并由<AstroLink url="https://x.com/fxxkol">欧雷</AstroLink>担当项目负责人。</p>
2317
<h2 id={headings[0].slug}>{headings[0].text}</h2>
24-
<p>作为由 OpenBuild 核心团队发起的项目,沿用 <a href="https://github.com/openbuildxyz/.github/blob/main/.github/CODE_OF_CONDUCT.md" target="_blank" rel="external">OpenBuild 官方统一的行为规范</a>;强烈建议在参与社区活动前仔细阅读,我们希望所有社区成员都能遵守其中的准则。</p>
18+
<p>作为由 OpenBuild 核心团队发起的项目,沿用 <AstroLink url="https://github.com/openbuildxyz/.github/blob/main/.github/CODE_OF_CONDUCT.md">OpenBuild 官方统一的行为规范</AstroLink>;强烈建议在参与社区活动前仔细阅读,我们希望所有社区成员都能遵守其中的准则。</p>
2519
<h2 id={headings[1].slug}>{headings[1].text}</h2>
2620
<p>在下列地点能取得有关 OpenBuild 官网的最新动态:</p>
2721
<ul>
28-
<li>关注微信公众号「<a href="https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzU4Mjk1MTI2NA==" target="_blank" rel="external">OpenBuild</a>」;</li>
29-
<li>关注<a href="https://x.com/OpenBuildxyz" target="_blank" rel="external">官方推特账号</a>。</li>
22+
<li>关注<AstroLink url="https://linktr.ee/openbuild">官方社交媒体账号</AstroLink>。</li>
3023
</ul>
3124
<h2 id={headings[2].slug}>{headings[2].text}</h2>
3225
<p>可通过以下渠道与他人讨论 OpenBuild 官网相关话题及获得帮助等:</p>
3326
<ul>
3427
<li>微信群——专门的开源共建兴趣组微信群,可加微信 <code>fxxkol</code> 申请进群;</li>
35-
<li><a href="https://github.com/openbuildxyz/openbuild-frontend" target="_blank" rel="external">GitHub</a>——借由 issue 报告缺陷或提出想法,也十分欢迎 pull request。</li>
28+
<li><AstroLink url="https://github.com/openbuildxyz/openbuild-frontend">GitHub</AstroLink>——借由 issue 报告缺陷或提出想法,也十分欢迎 pull request。</li>
3629
</ul>
3730
</StarlightLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
import StarlightLayout from '@astrojs/starlight/components/StarlightPage.astro';
3+
4+
import { CoreMemberListView } from '~/contributor';
5+
import { getSidebar } from '#/layouts/guide';
6+
7+
const headings = [
8+
{ depth: 2, slug: '核心团队成员', text: '核心团队成员' },
9+
];
10+
---
11+
12+
<StarlightLayout frontmatter={{ title: '认识团队' }} sidebar={getSidebar('about')} headings={headings}>
13+
<p>本页面所展示的是由以「社区共建者」身份参与 OpenBuild 官网项目研发的人员所组成的团队,与 OpenBuild 核心团队不同。</p>
14+
<h2 id={headings[0].slug}>{headings[0].text}</h2>
15+
<p>这些是积极参与维护 OpenBuild 官网及关联项目的人,他们做出了重大贡献,并对项目及其用户的成功做出了长期的承诺。</p>
16+
<CoreMemberListView />
17+
</StarlightLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
import { getRelativeLocaleUrl } from 'astro:i18n';
3+
4+
import type { SupportedLocale } from '../../types';
5+
6+
interface Props {
7+
url: string;
8+
external?: boolean;
9+
class?: string;
10+
}
11+
12+
const { url, external, ...others } = Astro.props;
13+
const locale = (Astro.currentLocale || 'en') as SupportedLocale;
14+
const linkExternal = url.toLowerCase().startsWith('http');
15+
16+
const resolvedExternal = typeof external === 'boolean' ? external : linkExternal;
17+
const resolvedUrl = linkExternal ? url : getRelativeLocaleUrl(locale, url);
18+
---
19+
20+
{resolvedExternal ? (
21+
<a class={others.class} href={resolvedUrl} target="_blank" rel="external"><slot /></a>
22+
) : (
23+
<a class={others.class} href={resolvedUrl}><slot /></a>
24+
)}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './Link.astro';

.knosys/sites/default/src/shared/types/content.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CollectionEntry } from 'astro:content';
22

3-
type DataCollectionKey = 'posts';
3+
type DataCollectionKey = 'contributors' | 'posts';
44

55
type PickCollectionData<K extends DataCollectionKey> = CollectionEntry<K>['data'];
66

0 commit comments

Comments
 (0)