From a4bc00de9b1b478a9183c759e654921f6be219cc Mon Sep 17 00:00:00 2001 From: TechQuery Date: Wed, 16 Jul 2025 23:20:44 +0800 Subject: [PATCH] [add] GitHub Volunteer page based on Section Title & Person Card components --- components/Layout/SectionTitle.tsx | 15 +++++ components/Navigator/MainNavigator.tsx | 1 + components/PersonCard.tsx | 35 ++++++++++ models/Translation.ts | 12 +--- package.json | 1 + pages/volunteer.tsx | 90 ++++++++++++++++++++++++++ translation/en-US.ts | 4 ++ translation/zh-CN.ts | 4 ++ translation/zh-TW.ts | 4 ++ 9 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 components/Layout/SectionTitle.tsx create mode 100644 components/PersonCard.tsx create mode 100644 pages/volunteer.tsx diff --git a/components/Layout/SectionTitle.tsx b/components/Layout/SectionTitle.tsx new file mode 100644 index 0000000..69c44c4 --- /dev/null +++ b/components/Layout/SectionTitle.tsx @@ -0,0 +1,15 @@ +import { FC, HTMLAttributes, PropsWithChildren } from 'react'; +import { Badge } from 'react-bootstrap'; + +export type SectionTitleProps = PropsWithChildren< + HTMLAttributes & { count?: number } +>; + +export const SectionTitle: FC = ({ className = '', count, children }) => ( +

+ {children} + + {count} + +

+); diff --git a/components/Navigator/MainNavigator.tsx b/components/Navigator/MainNavigator.tsx index 90acec7..15c57c8 100644 --- a/components/Navigator/MainNavigator.tsx +++ b/components/Navigator/MainNavigator.tsx @@ -19,6 +19,7 @@ const topNavBarMenu = ({ t }: typeof i18n): MenuItem[] => [ href: '/article/open-collaborator-award', name: t('open_collaborator_award'), }, + { href: '/volunteer', name: t('volunteer') }, { href: '/project', name: t('open_source_projects') }, { href: '/issue', name: 'GitHub issues' }, { diff --git a/components/PersonCard.tsx b/components/PersonCard.tsx new file mode 100644 index 0000000..35f8c0d --- /dev/null +++ b/components/PersonCard.tsx @@ -0,0 +1,35 @@ +import { FC } from 'react'; +import { Badge, Card, Col } from 'react-bootstrap'; + +export interface PersonCardProps { + avatar: string; + name: string; + link?: string; + position?: string; + count?: number; +} + +export const PersonCard: FC = ({ avatar, name, link, position, count }) => ( + + + {count != null && ( + + {count} + + )} + + + + {name} + + {position} + + + +); diff --git a/models/Translation.ts b/models/Translation.ts index 91df3b8..90c22cf 100644 --- a/models/Translation.ts +++ b/models/Translation.ts @@ -1,9 +1,4 @@ -import { - loadLanguageMapFrom, - parseCookie, - TranslationMap, - TranslationModel, -} from 'mobx-i18n'; +import { loadLanguageMapFrom, parseCookie, TranslationMap, TranslationModel } from 'mobx-i18n'; import { DataObject } from 'mobx-restful'; import { NextPageContext } from 'next'; import { createContext } from 'react'; @@ -32,6 +27,7 @@ export const createI18nStore = ( }); if (language) store.currentLanguage = language; + if (data) store.currentMap = data as TranslationMap; return store; }; @@ -53,9 +49,7 @@ export const parseSSRContext = ( const cookie = parseCookie(req?.headers.cookie || '') as T; for (const key of queryKeys) - cookie[key] = - (query[key as string]?.toString().split(',')[0] as T[keyof T]) || - cookie[key]; + cookie[key] = (query[key as string]?.toString().split(',')[0] as T[keyof T]) || cookie[key]; return cookie; }; diff --git a/package.json b/package.json index a947350..0a7807c 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "singleQuote": true, "trailingComma": "all", "arrowParens": "avoid", + "printWidth": 100, "plugins": [ "prettier-plugin-css-order", "@softonus/prettier-plugin-duplicate-remover" diff --git a/pages/volunteer.tsx b/pages/volunteer.tsx new file mode 100644 index 0000000..ff4f72b --- /dev/null +++ b/pages/volunteer.tsx @@ -0,0 +1,90 @@ +import { Contributor } from 'mobx-github'; +import { observer } from 'mobx-react'; +import { cache, compose, errorLogger } from 'next-ssr-middleware'; +import { FC, useContext } from 'react'; +import { Container, Row } from 'react-bootstrap'; + +import { PageHead } from '../components/Layout/PageHead'; +import { SectionTitle } from '../components/Layout/SectionTitle'; +import { PersonCard } from '../components/PersonCard'; +import { repositoryStore } from '../models/Repository'; +import { I18nContext } from '../models/Translation'; + +export const getServerSideProps = compose(cache(), errorLogger, async () => { + const contributors: Contributor[] = await repositoryStore.getAllContributors(); + + return { props: { contributors } }; +}); + +const Organizer: FC<{ contributors: Contributor[] }> = observer(({ contributors }) => { + const { t } = useContext(I18nContext); + + return ( + + +

{t('volunteer')}

+ +
+ + + + Participants roles of Open Source Bazaar + + + + + + Most engaged people of Open Source Bazaar + + +
+ + {t('online_volunteer')} + + {contributors.map(({ login, html_url, contributions }) => ( + + ))} + +
+ ); +}); + +export default Organizer; diff --git a/translation/en-US.ts b/translation/en-US.ts index 6d663f9..6453bf0 100644 --- a/translation/en-US.ts +++ b/translation/en-US.ts @@ -17,4 +17,8 @@ export default { // Scroll List load_more: 'Load more...', no_more: 'No more', + + // Volunteer page + volunteer: 'Volunteer', + online_volunteer: 'Online Volunteer', }; diff --git a/translation/zh-CN.ts b/translation/zh-CN.ts index 13d7027..5929e1e 100644 --- a/translation/zh-CN.ts +++ b/translation/zh-CN.ts @@ -17,4 +17,8 @@ export default { // Scroll List load_more: '加载更多……', no_more: '没有更多', + + // Volunteer page + volunteer: '志愿者', + online_volunteer: '线上志愿者', }; diff --git a/translation/zh-TW.ts b/translation/zh-TW.ts index 586319c..0a13d6f 100644 --- a/translation/zh-TW.ts +++ b/translation/zh-TW.ts @@ -17,4 +17,8 @@ export default { // Scroll List load_more: '加載更多……', no_more: '沒有更多', + + // Volunteer page + volunteer: '志工', + online_volunteer: '線上志工', };