Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions components/Layout/SectionTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FC, HTMLAttributes, PropsWithChildren } from 'react';
import { Badge } from 'react-bootstrap';

export type SectionTitleProps = PropsWithChildren<
HTMLAttributes<HTMLHeadingElement> & { count?: number }
>;

export const SectionTitle: FC<SectionTitleProps> = ({ className = '', count, children }) => (
<h2 className={`d-flex align-items-center gap-2 ${className}`}>
{children}
<Badge className="fs-6" pill bg="danger">
{count}
</Badge>
</h2>
);
1 change: 1 addition & 0 deletions components/Navigator/MainNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
{
Expand Down
35 changes: 35 additions & 0 deletions components/PersonCard.tsx
Original file line number Diff line number Diff line change
@@ -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<PersonCardProps> = ({ avatar, name, link, position, count }) => (
<Col as="li" className="my-3 d-flex justify-content-center">
<Card className="border-0 align-items-center position-relative">
{count != null && (
<Badge className="fs-6 position-absolute top-0 end-0" pill bg="danger">
{count}
</Badge>
)}
<Card.Img
className="rounded-circle"
style={{ width: '8rem' }}
variant="top"
src={avatar}
alt={name}
/>
<Card.Body>
<Card.Title as="a" className="fs-6 text-decoration-none stretched-link" href={link || '#'}>
{name}
</Card.Title>
<Card.Subtitle className="fw-light mt-2">{position}</Card.Subtitle>
</Card.Body>
</Card>
</Col>
);
12 changes: 3 additions & 9 deletions models/Translation.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -32,6 +27,7 @@ export const createI18nStore = <N extends LanguageCode, K extends string>(
});

if (language) store.currentLanguage = language;
if (data) store.currentMap = data as TranslationMap<keyof (typeof i18nData)['zh-CN']>;

return store;
};
Expand All @@ -53,9 +49,7 @@ export const parseSSRContext = <T extends DataObject = DataObject>(
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;
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"printWidth": 100,
"plugins": [
"prettier-plugin-css-order",
"@softonus/prettier-plugin-duplicate-remover"
Expand Down
90 changes: 90 additions & 0 deletions pages/volunteer.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Container>
<PageHead title={t('volunteer')} />
<h1 className="py-5 text-center text-md-start ps-md-4">{t('volunteer')}</h1>

<section className="d-flex justify-content-around align-items-center gap-3 flex-wrap mb-5">
<a
className="d-block"
href="https://next.ossinsight.io/widgets/official/compose-org-participants-roles-ratio?owner_id=73477979&period=past_28_days"
target="_blank"
rel="noreferrer"
>
<picture>
<source
media="(prefers-color-scheme: dark)"
srcSet="https://next.ossinsight.io/widgets/official/compose-org-participants-roles-ratio/thumbnail.png?owner_id=73477979&period=past_28_days&image_size=5x5&color_scheme=dark"
width="465"
/>
<img
alt="Participants roles of Open Source Bazaar"
src="https://next.ossinsight.io/widgets/official/compose-org-participants-roles-ratio/thumbnail.png?owner_id=73477979&period=past_28_days&image_size=5x5&color_scheme=light"
width="465"
/>
</picture>
</a>
<a
className="d-block"
href="https://next.ossinsight.io/widgets/official/compose-org-engagement-scatter?owner_id=73477979&period=past_28_days"
target="_blank"
rel="noreferrer"
>
<picture>
<source
media="(prefers-color-scheme: dark)"
srcSet="https://next.ossinsight.io/widgets/official/compose-org-engagement-scatter/thumbnail.png?owner_id=73477979&period=past_28_days&image_size=5x5&color_scheme=dark"
width="465"
/>
<img
alt="Most engaged people of Open Source Bazaar"
src="https://next.ossinsight.io/widgets/official/compose-org-engagement-scatter/thumbnail.png?owner_id=73477979&period=past_28_days&image_size=5x5&color_scheme=light"
width="465"
/>
</picture>
</a>
</section>

<SectionTitle count={contributors.length}>{t('online_volunteer')}</SectionTitle>
<Row
as="ul"
className="list-unstyled justify-content-center text-center"
xs={2}
sm={5}
md={6}
>
{contributors.map(({ login, html_url, contributions }) => (
<PersonCard
key={login}
name={login!}
avatar={`https://github.com/${login}.png`}
link={html_url}
count={contributions}
/>
))}
</Row>
</Container>
);
});

export default Organizer;
4 changes: 4 additions & 0 deletions translation/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ export default {
// Scroll List
load_more: 'Load more...',
no_more: 'No more',

// Volunteer page
volunteer: 'Volunteer',
online_volunteer: 'Online Volunteer',
};
4 changes: 4 additions & 0 deletions translation/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ export default {
// Scroll List
load_more: '加载更多……',
no_more: '没有更多',

// Volunteer page
volunteer: '志愿者',
online_volunteer: '线上志愿者',
};
4 changes: 4 additions & 0 deletions translation/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ export default {
// Scroll List
load_more: '加載更多……',
no_more: '沒有更多',

// Volunteer page
volunteer: '志工',
online_volunteer: '線上志工',
};