Skip to content

Commit 6df3619

Browse files
committed
Add static hackathon fallback for niuma 2026
1 parent babc91a commit 6df3619

4 files changed

Lines changed: 353 additions & 4 deletions

File tree

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import type { FC } from 'react';
2+
import { Badge, Button, Card, Col, Container, Row } from 'react-bootstrap';
3+
4+
import type { StaticHackathonProfile } from '../../constants/staticHackathons';
5+
import styles from '../../styles/Hackathon.module.less';
6+
7+
const AgendaTypeLabel: Record<StaticHackathonProfile['agenda'][number]['type'], string> = {
8+
enrollment: '报名',
9+
formation: '组队',
10+
competition: '比赛',
11+
evaluation: '评审',
12+
break: '展示',
13+
};
14+
15+
export interface StaticHackathonDetailProps {
16+
profile: StaticHackathonProfile;
17+
}
18+
19+
export const StaticHackathonDetail: FC<StaticHackathonDetailProps> = ({ profile }) => (
20+
<>
21+
<section className={styles.hero}>
22+
<Container>
23+
<div className="text-center mb-3">
24+
<Badge bg="light" text="dark">
25+
{profile.theme}
26+
</Badge>
27+
</div>
28+
<h1 className={`text-center ${styles.title}`}>{profile.name}</h1>
29+
<p className={`text-center ${styles.description}`}>{profile.summary}</p>
30+
31+
<Row className="mt-4 justify-content-center">
32+
<Col md={4}>
33+
<Card className={styles.infoCard}>
34+
<Card.Body>
35+
<h5 className="text-white mb-2">📍 活动形式</h5>
36+
<p className="text-white-50 mb-0">{profile.location}</p>
37+
</Card.Body>
38+
</Card>
39+
</Col>
40+
<Col md={4}>
41+
<Card className={styles.infoCard}>
42+
<Card.Body>
43+
<h5 className="text-white mb-2">⏰ 活动时间</h5>
44+
<p className="text-white-50 mb-0">{profile.timeline}</p>
45+
</Card.Body>
46+
</Card>
47+
</Col>
48+
</Row>
49+
50+
<Row className="mt-4 g-3 justify-content-center">
51+
{profile.entryLinks.slice(0, 2).map(({ href, label }) => (
52+
<Col key={label} md="auto">
53+
<Button href={href} target="_blank" rel="noreferrer" size="lg">
54+
{label}
55+
</Button>
56+
</Col>
57+
))}
58+
</Row>
59+
</Container>
60+
</section>
61+
62+
<Container className="my-5">
63+
<section className={styles.section}>
64+
<h2 className={styles.sectionTitle}>🔗 报名与入口</h2>
65+
<Row className="mt-4 g-3" md={2} xl={3}>
66+
{profile.entryLinks.map(({ href, label, note }) => (
67+
<Col key={label}>
68+
<Card className={styles.darkCard} body>
69+
<h3 className="h5 text-white">{label}</h3>
70+
<p className="text-white-50 mb-3">{note}</p>
71+
<Button href={href} target="_blank" rel="noreferrer" variant="light">
72+
打开链接
73+
</Button>
74+
</Card>
75+
</Col>
76+
))}
77+
</Row>
78+
</section>
79+
80+
<section className={styles.section}>
81+
<h2 className={styles.sectionTitle}>📅 活动日程</h2>
82+
<ol className="list-unstyled mt-4">
83+
{profile.agenda.map(({ endedAt, name, startedAt, summary, type }) => (
84+
<li key={`${name}-${startedAt}`} className={`${styles.agendaItem} ${styles[type]}`}>
85+
<h3 className="h5 text-white mb-2">{name}</h3>
86+
<p className="text-white-50 small mb-2">{summary}</p>
87+
<div className="d-flex justify-content-between align-items-center gap-3 flex-wrap">
88+
<Badge bg="dark">{AgendaTypeLabel[type]}</Badge>
89+
<div className="text-white-50 small">
90+
{startedAt} - {endedAt}
91+
</div>
92+
</div>
93+
</li>
94+
))}
95+
</ol>
96+
</section>
97+
98+
<section className={`${styles.section} ${styles.prizeSection}`}>
99+
<h2 className={styles.sectionTitle}>🏆 奖项设置</h2>
100+
<Row className="mt-4 g-3" md={2} xl={3}>
101+
{profile.awards.map(({ name, quota, summary }) => (
102+
<Col key={name}>
103+
<Card className={styles.lightCard} body>
104+
<div className="d-flex justify-content-between align-items-start gap-3">
105+
<h3 className="h5 mb-2">{name}</h3>
106+
<Badge bg="dark">{quota}</Badge>
107+
</div>
108+
<p className="mb-0">{summary}</p>
109+
</Card>
110+
</Col>
111+
))}
112+
</Row>
113+
</section>
114+
115+
<section className={styles.section}>
116+
<h2 className={styles.sectionTitle}>🧾 参赛说明</h2>
117+
<Row className="mt-4 g-3" md={2}>
118+
{profile.notes.map(note => (
119+
<Col key={note}>
120+
<Card className={styles.darkCard} body>
121+
<p className="text-white-50 mb-0">{note}</p>
122+
</Card>
123+
</Col>
124+
))}
125+
</Row>
126+
</section>
127+
128+
<section className={styles.section}>
129+
<h2 className={styles.sectionTitle}>❓ FAQ</h2>
130+
<Row className="mt-4 g-3" md={2}>
131+
{profile.faq.map(({ answer, question }) => (
132+
<Col key={question}>
133+
<Card className={styles.darkCard} body>
134+
<h3 className="h5 text-white">{question}</h3>
135+
<p className="text-white-50 mb-0">{answer}</p>
136+
</Card>
137+
</Col>
138+
))}
139+
</Row>
140+
</section>
141+
</Container>
142+
</>
143+
);

constants/staticHackathons.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
export interface StaticHackathonLink {
2+
href: string;
3+
label: string;
4+
note: string;
5+
}
6+
7+
export interface StaticHackathonAgendaItem {
8+
endedAt: string;
9+
name: string;
10+
startedAt: string;
11+
summary: string;
12+
type: 'break' | 'competition' | 'enrollment' | 'evaluation' | 'formation';
13+
}
14+
15+
export interface StaticHackathonPrize {
16+
name: string;
17+
quota: string;
18+
summary: string;
19+
}
20+
21+
export interface StaticHackathonFAQ {
22+
answer: string;
23+
question: string;
24+
}
25+
26+
export interface StaticHackathonProfile {
27+
agenda: StaticHackathonAgendaItem[];
28+
awards: StaticHackathonPrize[];
29+
entryLinks: StaticHackathonLink[];
30+
faq: StaticHackathonFAQ[];
31+
id: string;
32+
location: string;
33+
name: string;
34+
notes: string[];
35+
summary: string;
36+
theme: string;
37+
timeline: string;
38+
}
39+
40+
export const staticHackathons: Record<string, StaticHackathonProfile> = {
41+
'niuma-hackathon-2026': {
42+
id: 'niuma-hackathon-2026',
43+
name: '2026 五一牛马 AI 黑客松',
44+
summary:
45+
'劳动节,用 AI 把自己从重复劳动中解放出来。报名一个月拉满人,组队只给 7 天做决策,比赛压缩为 3 天核心冲刺,再用 Demo Day 做集中展示。',
46+
theme: 'AI 解放牛马',
47+
location: '线上 + 线下同步',
48+
timeline: '2026-03-25 00:00 - 2026-05-06 晚上(UTC+8)',
49+
entryLinks: [
50+
{
51+
label: '队员注册',
52+
href: 'https://open-source-bazaar.feishu.cn/share/base/shrcnZAJd1yhqHYRmQXmAwlXjkc',
53+
note: '所有参赛者先完成报名,进入组队池与官方群。',
54+
},
55+
{
56+
label: '项目注册',
57+
href: 'https://open-source-bazaar.feishu.cn/share/base/shrcnKsgpHpBXcwh4W6GDg2G7Nc',
58+
note: '组队阶段由队长登记项目、成员、赛道和一句话介绍。',
59+
},
60+
{
61+
label: '代码库创建',
62+
href: 'https://open-source-bazaar.feishu.cn/share/base/shrcnc1mbGsxMm8mS69au3B7uzf',
63+
note: '需要官方统一协助建库时使用,不是所有队伍都必须填写。',
64+
},
65+
{
66+
label: '产品提交',
67+
href: 'https://open-source-bazaar.feishu.cn/share/base/shrcnkrO7EMQlXYR1I41w26Ioyf',
68+
note: '比赛截止前由队长或指定提交人统一提交最终作品。',
69+
},
70+
{
71+
label: '活动官网',
72+
href: 'https://hack.digitalvio.shop/',
73+
note: '查看当前活动主页、时间线和最新说明。',
74+
},
75+
],
76+
agenda: [
77+
{
78+
name: '报名阶段',
79+
summary: '所有队员完成注册,开始找人、找方向、进入官方群。',
80+
startedAt: '2026-03-25 00:00',
81+
endedAt: '2026-04-20 23:59',
82+
type: 'enrollment',
83+
},
84+
{
85+
name: '组队 / 项目注册',
86+
summary: '队长完成项目注册,锁定队伍、赛道和项目介绍。',
87+
startedAt: '2026-04-21 00:00',
88+
endedAt: '2026-04-28 23:59',
89+
type: 'formation',
90+
},
91+
{
92+
name: '比赛冲刺',
93+
summary: '3 天核心开发冲刺,围绕 AI Agents、开发者工具、创意娱乐与社会影响展开。',
94+
startedAt: '2026-05-01 10:00',
95+
endedAt: '2026-05-03 20:00',
96+
type: 'competition',
97+
},
98+
{
99+
name: '评审阶段',
100+
summary: '评委完成打分与复核,筛出进入 Demo Day 的队伍。',
101+
startedAt: '2026-05-03 20:00',
102+
endedAt: '2026-05-05 18:00',
103+
type: 'evaluation',
104+
},
105+
{
106+
name: 'Demo Day',
107+
summary: '集中展示项目成果,并公布最终结果。',
108+
startedAt: '2026-05-06 晚上',
109+
endedAt: '2026-05-06 晚上',
110+
type: 'break',
111+
},
112+
],
113+
awards: [
114+
{
115+
name: '一等奖',
116+
quota: '1 队',
117+
summary: '首页展示 + 资源连接 + 一等奖数字徽章',
118+
},
119+
{
120+
name: '二等奖',
121+
quota: '2 队',
122+
summary: '社区展示 + 官方收录 + 二等奖数字徽章',
123+
},
124+
{
125+
name: '三等奖',
126+
quota: '3 队',
127+
summary: '荣誉名单 + 项目合集收录 + 三等奖数字徽章',
128+
},
129+
{
130+
name: '最佳创意奖',
131+
quota: '1 队',
132+
summary: '专题推荐 + 最佳创意数字徽章',
133+
},
134+
{
135+
name: '最佳牛马精神奖',
136+
quota: '1 队',
137+
summary: '社区荣誉 + 最佳牛马精神数字徽章',
138+
},
139+
{
140+
name: 'Demo Day 入选',
141+
quota: '若干',
142+
summary: 'Demo Day 展示资格 + 入选数字徽章',
143+
},
144+
],
145+
notes: [
146+
'每队 1-4 人,支持跨城市、跨公司组队。',
147+
'作品需在本次黑客松期间完成核心创作,并包含 AI 核心能力或 AI 驱动体验。',
148+
'最终提交建议包含 GitHub 仓库链接、Demo 视频、产品说明和 AI 技术栈说明。',
149+
'奖项以数字徽章 + 展示 / 资源连接为主,不承诺实体奖章或现金奖励。',
150+
],
151+
faq: [
152+
{
153+
question: '可以一个人参赛吗?',
154+
answer: '可以,单人队伍有效参赛,也可以在官方群里继续找队友。',
155+
},
156+
{
157+
question: '活动鼓励哪些方向?',
158+
answer: '鼓励 AI Agents、开发者工具、创意娱乐、社会影响等方向,也支持自由赛道。',
159+
},
160+
{
161+
question: '什么时候截止报名?',
162+
answer: '报名截止时间是 2026-04-20 23:59(UTC+8)。',
163+
},
164+
{
165+
question: '什么时候开始比赛?',
166+
answer: '比赛将在 2026-05-01 10:00(UTC+8)正式开始。',
167+
},
168+
],
169+
},
170+
};
171+
172+
export const getStaticHackathonProfile = (id: string) => staticHackathons[id];

0 commit comments

Comments
 (0)