Skip to content

Commit 7bb5bf3

Browse files
CopilotTechQuery
andauthored
[add] Hackathon Project page & components (#45)
Co-authored-by: TechQuery <[email protected]>
1 parent 8fb2f78 commit 7bb5bf3

File tree

12 files changed

+603
-125
lines changed

12 files changed

+603
-125
lines changed

components/Activity/CommentBox.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Giscus from '@giscus/react';
2+
import { observer } from 'mobx-react';
3+
import { useContext } from 'react';
4+
5+
import { I18nContext } from '../../models/Translation';
6+
7+
export const CommentBox = observer(() => {
8+
const { currentLanguage } = useContext(I18nContext);
9+
10+
return (
11+
<Giscus
12+
repo="Open-Source-Bazaar/Open-Source-Bazaar.github.io"
13+
repoId="R_kgDOGzCrLg"
14+
category="Comments"
15+
categoryId="DIC_kwDOGzCrLs4C0g_6"
16+
mapping="pathname"
17+
strict="0"
18+
reactionsEnabled="1"
19+
emitMetadata="0"
20+
inputPosition="bottom"
21+
theme="preferred_color_scheme"
22+
lang={currentLanguage.startsWith('zh-') ? currentLanguage : currentLanguage.split('-')[0]}
23+
/>
24+
);
25+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { observer } from 'mobx-react';
2+
import { FilePreview } from 'mobx-restful-table';
3+
import { FC } from 'react';
4+
import { CardProps, Card, Button } from 'react-bootstrap';
5+
import { formatDate } from 'web-utility';
6+
7+
import { Product } from '../../models/Hackathon';
8+
import styles from '../../styles/Hackathon.module.less';
9+
10+
export type ProductCardProps = Product & Omit<CardProps, 'id' | 'title'>;
11+
12+
export const ProductCard: FC<ProductCardProps> = observer(
13+
({ className = '', id, createdAt, name, sourceLink, link = sourceLink, summary, ...props }) => (
14+
<Card className={`${styles.projectCard} ${className}`} {...props}>
15+
<Card.Body className="d-flex flex-column">
16+
<Card.Title
17+
as="a"
18+
className="text-dark fw-bold"
19+
title={name as string}
20+
target="_blank"
21+
href={link as string}
22+
>
23+
{(name || link) as string}
24+
</Card.Title>
25+
<p className="text-dark opacity-75 mb-3">{summary as string}</p>
26+
<div className="flex-fill mb-3">
27+
<FilePreview className="w-100" path={link as string} />
28+
</div>
29+
30+
{sourceLink && (
31+
<div className="d-flex flex-wrap gap-2 mb-3">
32+
<Button
33+
variant="dark"
34+
size="sm"
35+
href={sourceLink as string}
36+
target="_blank"
37+
rel="noreferrer"
38+
>
39+
GitHub
40+
</Button>
41+
<Button
42+
variant="primary"
43+
size="sm"
44+
href={`https://github.dev/${(sourceLink as string).replace('https://github.com/', '')}`}
45+
target="_blank"
46+
rel="noreferrer"
47+
>
48+
GitHub.dev
49+
</Button>
50+
<Button
51+
variant="dark"
52+
size="sm"
53+
href={`https://codespaces.new/${(sourceLink as string).replace('https://github.com/', '')}`}
54+
target="_blank"
55+
rel="noreferrer"
56+
>
57+
Codespaces
58+
</Button>
59+
<Button
60+
variant="warning"
61+
size="sm"
62+
href={`https://gitpod.io/#${sourceLink as string}`}
63+
target="_blank"
64+
rel="noreferrer"
65+
>
66+
GitPod
67+
</Button>
68+
</div>
69+
)}
70+
71+
<time className="text-dark opacity-75 small" dateTime={new Date(createdAt as number).toJSON()}>
72+
📅 {formatDate(createdAt as number)}
73+
</time>
74+
</Card.Body>
75+
</Card>
76+
),
77+
);

components/Navigator/MainNavigator.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { textJoin } from 'mobx-i18n';
12
import { observer } from 'mobx-react';
23
import dynamic from 'next/dynamic';
34
import { useRouter } from 'next/router';
@@ -39,11 +40,24 @@ const topNavBarMenu = ({ t }: typeof i18n): MenuItem[] => [
3940
subs: [
4041
{ href: '/project', title: t('open_source_projects') },
4142
{ href: '/issue', title: 'GitHub issues' },
43+
{ href: '/license-filter', title: t('license_filter') },
44+
],
45+
},
46+
{
47+
title: t('hackathon'),
48+
subs: [
4249
{
4350
href: 'https://github.com/Open-Source-Bazaar/Git-Hackathon-scaffold',
44-
title: t('hackathon'),
51+
title: textJoin('GitHub', t('hackathon')),
52+
},
53+
{
54+
href: '/search/activity?keywords=Hackathon',
55+
title: textJoin('Lark', t('hackathon')),
56+
},
57+
{
58+
href: 'https://test.hackathon.fcc-cd.dev/open-source',
59+
title: textJoin(t('hackathon'), t('open_source_projects')),
4560
},
46-
{ href: '/license-filter', title: t('license_filter') },
4761
],
4862
},
4963
{

models/Activity.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
BiDataQueryOptions,
33
BiDataTable,
44
BiSearch,
5+
BiTableSchema,
56
LarkPageData,
67
makeSimpleFilter,
78
normalizeText,
@@ -34,7 +35,9 @@ export type Activity = LarkBase &
3435
| 'liveLink'
3536
| `database${'' | 'Schema'}`,
3637
TableCellValue
37-
>;
38+
> & {
39+
databaseSchema: BiTableSchema;
40+
};
3841

3942
export class ActivityModel extends BiDataTable<Activity>() {
4043
client = larkClient;

models/Hackathon.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
normalizeText,
77
TableCellRelation,
88
TableCellText,
9+
TableCellUser,
910
TableCellValue,
1011
TableRecord,
1112
} from 'mobx-lark';
@@ -24,7 +25,7 @@ export class AgendaModel extends BiDataTable<Agenda>() {
2425
return {
2526
...meta,
2627
...fields,
27-
summary: normalizeText(summary as TableCellText),
28+
summary: (summary as TableCellText[])!.map(normalizeText),
2829
};
2930
}
3031
}
@@ -140,3 +141,47 @@ export class ProjectModel extends BiDataTable<Project>() {
140141
};
141142
}
142143
}
144+
145+
export type Member = LarkBase &
146+
Record<'summary' | 'person' | 'skills' | 'githubAccount' | 'project' | 'status', TableCellValue>;
147+
148+
export class MemberModel extends BiDataTable<Member>() {
149+
client = larkClient;
150+
151+
queryOptions: BiDataQueryOptions = { text_field_as_array: false };
152+
153+
extractFields({
154+
fields: { summary, person, skills, githubAccount, ...fields },
155+
...meta
156+
}: TableRecord<Member>) {
157+
return {
158+
...meta,
159+
...fields,
160+
person: (person as TableCellUser[])?.[0],
161+
summary: (summary as TableCellText[])!.map(normalizeText),
162+
skills: skills?.toString().split(/\s*,\s*/) || [],
163+
githubAccount: normalizeText(githubAccount as TableCellText),
164+
};
165+
}
166+
}
167+
168+
export type Product = LarkBase &
169+
Record<
170+
'name' | 'project' | 'template' | 'link' | 'sourceLink' | 'file' | 'summary',
171+
TableCellValue
172+
>;
173+
174+
export class ProductModel extends BiDataTable<Product>() {
175+
client = larkClient;
176+
177+
queryOptions: BiDataQueryOptions = { text_field_as_array: false };
178+
179+
extractFields({ fields: { link, sourceLink, ...fields }, ...meta }: TableRecord<Product>) {
180+
return {
181+
...meta,
182+
...fields,
183+
link: normalizeText(link as TableCellText),
184+
sourceLink: normalizeText(sourceLink as TableCellText),
185+
};
186+
}
187+
}

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
"test": "lint-staged && tsc --noEmit"
1515
},
1616
"dependencies": {
17-
"@koa/router": "^15.1.1",
17+
"@giscus/react": "^3.1.0",
18+
"@koa/router": "^15.2.0",
1819
"@mdx-js/loader": "^3.1.1",
1920
"@mdx-js/react": "^3.1.1",
2021
"@next/mdx": "^16.1.1",
2122
"core-js": "^3.47.0",
2223
"echarts-jsx": "^0.6.0",
23-
"file-type": "^21.2.0",
24+
"file-type": "^21.3.0",
2425
"idea-react": "^2.0.0-rc.13",
2526
"jsonwebtoken": "^9.0.3",
2627
"koa": "^3.1.1",
@@ -32,7 +33,7 @@
3233
"mobx": "^6.15.0",
3334
"mobx-github": "^0.6.2",
3435
"mobx-i18n": "^0.7.2",
35-
"mobx-lark": "^2.6.3",
36+
"mobx-lark": "^2.6.4",
3637
"mobx-react": "^9.2.1",
3738
"mobx-react-helper": "^0.5.1",
3839
"mobx-restful": "^2.1.4",
@@ -81,7 +82,7 @@
8182
"lint-staged": "^16.2.7",
8283
"next-with-less": "^3.0.1",
8384
"prettier": "^3.7.4",
84-
"prettier-plugin-css-order": "^2.1.2",
85+
"prettier-plugin-css-order": "^2.2.0",
8586
"sass": "^1.97.1",
8687
"typescript": "~5.9.3",
8788
"typescript-eslint": "^8.51.0"

pages/hackathon/[id].tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BiTableSchema, TableCellLocation, TableCellUser } from 'mobx-lark';
22
import { observer } from 'mobx-react';
3+
import Link from 'next/link';
34
import { cache, compose, errorLogger } from 'next-ssr-middleware';
45
import { FC, useContext } from 'react';
56
import { Badge, Card, Col, Container, Row } from 'react-bootstrap';
@@ -34,7 +35,6 @@ export const getServerSideProps = compose<{ id: string }>(
3435
async ({ params }) => {
3536
const activity = await new ActivityModel().getOne(params!.id);
3637

37-
// @ts-expect-error Upstream compatibility
3838
const { appId, tableIdMap } = activity.databaseSchema as BiTableSchema;
3939

4040
const [people, organizations, agenda, prizes, templates, projects] = await Promise.all([
@@ -199,11 +199,18 @@ const HackathonDetail: FC<HackathonDetailProps> = observer(({ activity, hackatho
199199
<h2 className={styles.sectionTitle}>💡 {t('projects')}</h2>
200200

201201
<Row as="ul" className="list-unstyled mt-4 g-3" md={2} lg={3} xl={4}>
202-
{projects.map(({ name, score, summary, createdBy, members }) => (
202+
{projects.map(({ id, name, score, summary, createdBy, members }) => (
203203
<Col as="li" key={name as string}>
204204
<Card className={styles.projectCard} body>
205205
<div className="d-flex justify-content-between align-items-start mb-3">
206-
<h6 className="text-white flex-grow-1">{name as string}</h6>
206+
<h6 className="text-white flex-grow-1">
207+
<Link
208+
className="stretched-link"
209+
href={`${ActivityModel.getLink(activity)}/team/${id}`}
210+
>
211+
{name as string}
212+
</Link>
213+
</h6>
207214
<div className={styles.scoreCircle}>{score as number}</div>
208215
</div>
209216
<p className="text-white-50 small mb-3">{summary as string}</p>

0 commit comments

Comments
 (0)