Skip to content

Commit f2f4a95

Browse files
committed
Add Jobs recruitment page and nav link
1 parent 54c2387 commit f2f4a95

3 files changed

Lines changed: 316 additions & 19 deletions

File tree

src/app/jobs/page.tsx

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import type { Metadata } from "next";
2+
import type { ReactNode } from "react";
3+
4+
export const metadata: Metadata = {
5+
title: "Jobs",
6+
description:
7+
"TaskBeacon recruitment notice for psychology-background interns, presented in Chinese and English."
8+
};
9+
10+
const CONTACT_EMAIL = "braintrace@yeah.net";
11+
12+
type NumberedItem = {
13+
number: string;
14+
text: string;
15+
};
16+
17+
type CopySection = {
18+
lang: "zh-CN" | "en";
19+
badge: string;
20+
title: string;
21+
summary: string;
22+
aboutTitle: string;
23+
aboutText: string;
24+
responsibilitiesTitle: string;
25+
responsibilities: NumberedItem[];
26+
requirementsTitle: string;
27+
requirements: NumberedItem[];
28+
benefitsTitle: string;
29+
benefits: string[];
30+
workModeTitle: string;
31+
workModeText: string;
32+
contactTitle: string;
33+
contactText: string;
34+
templateTitle: string;
35+
templateText: string;
36+
};
37+
38+
function Panel({
39+
title,
40+
children,
41+
className = ""
42+
}: {
43+
title: string;
44+
children: ReactNode;
45+
className?: string;
46+
}) {
47+
return (
48+
<article className={`tb-frame-soft bg-[#fffdf9] p-5 sm:p-6 ${className}`}>
49+
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">
50+
{title}
51+
</div>
52+
<div className="mt-3">{children}</div>
53+
</article>
54+
);
55+
}
56+
57+
function NumberedList({ items }: { items: NumberedItem[] }) {
58+
return (
59+
<div className="space-y-3">
60+
{items.map((item) => (
61+
<div key={`${item.number}-${item.text.slice(0, 20)}`} className="flex gap-3">
62+
<div className="mt-0.5 shrink-0 rounded-full border-2 border-[#25314d] bg-white px-2 py-0.5 text-xs font-bold text-[#25314d] shadow-[0_3px_0_#25314d]">
63+
{item.number}
64+
</div>
65+
<p className="text-sm leading-7 text-slate-700">{item.text}</p>
66+
</div>
67+
))}
68+
</div>
69+
);
70+
}
71+
72+
function BulletList({ items }: { items: string[] }) {
73+
return (
74+
<div className="space-y-3">
75+
{items.map((item) => (
76+
<div key={item} className="flex gap-3">
77+
<span className="mt-2 size-2 shrink-0 rounded-full bg-[#39d95d]" aria-hidden="true" />
78+
<p className="text-sm leading-7 text-slate-700">{item}</p>
79+
</div>
80+
))}
81+
</div>
82+
);
83+
}
84+
85+
function RecruitmentSection(copy: CopySection) {
86+
const aboutTone = copy.lang === "zh-CN" ? "bg-[#eef8ff]" : "bg-[#fff8f0]";
87+
const chipTone = copy.lang === "zh-CN" ? "bg-[#f5c1b5]" : "bg-[#b9dceb]";
88+
89+
return (
90+
<section lang={copy.lang} className="tb-frame bg-[#fffdf9] p-6 sm:p-8">
91+
<div className="flex flex-wrap items-start justify-between gap-4">
92+
<div className="max-w-3xl">
93+
<div className={`tb-section-chip ${chipTone}`}>{copy.badge}</div>
94+
<h2 className="mt-4 font-heading text-3xl font-bold leading-tight text-[#25314d] sm:text-4xl">
95+
{copy.title}
96+
</h2>
97+
<p className="mt-4 text-base leading-8 text-slate-700">{copy.summary}</p>
98+
</div>
99+
100+
<a
101+
className="tb-focus-ring tb-button-secondary w-full sm:w-auto"
102+
href={`mailto:${CONTACT_EMAIL}`}
103+
>
104+
{CONTACT_EMAIL}
105+
</a>
106+
</div>
107+
108+
<div className="mt-6 grid gap-4 md:grid-cols-2">
109+
<Panel title={copy.aboutTitle} className={`md:col-span-2 ${aboutTone}`}>
110+
<p className="text-sm leading-7 text-slate-700">{copy.aboutText}</p>
111+
</Panel>
112+
113+
<Panel title={copy.responsibilitiesTitle}>
114+
<NumberedList items={copy.responsibilities} />
115+
</Panel>
116+
117+
<Panel title={copy.requirementsTitle}>
118+
<NumberedList items={copy.requirements} />
119+
</Panel>
120+
121+
<Panel title={copy.benefitsTitle}>
122+
<BulletList items={copy.benefits} />
123+
</Panel>
124+
125+
<Panel title={copy.workModeTitle}>
126+
<p className="text-sm leading-7 text-slate-700">{copy.workModeText}</p>
127+
</Panel>
128+
129+
<Panel title={copy.contactTitle}>
130+
<p className="text-sm leading-7 text-slate-700">{copy.contactText}</p>
131+
<a
132+
className="tb-focus-ring mt-4 inline-flex rounded-full border-2 border-[#25314d] bg-white px-4 py-2 text-sm font-bold text-[#25314d] shadow-[0_4px_0_#25314d] transition-transform hover:-translate-y-px"
133+
href={`mailto:${CONTACT_EMAIL}`}
134+
>
135+
{CONTACT_EMAIL}
136+
</a>
137+
</Panel>
138+
139+
<Panel title={copy.templateTitle} className="md:col-span-2">
140+
<pre className="whitespace-pre-wrap rounded-[18px] border-2 border-[#25314d] bg-white p-4 text-sm leading-7 text-slate-700">
141+
{copy.templateText}
142+
</pre>
143+
</Panel>
144+
</div>
145+
</section>
146+
);
147+
}
148+
149+
const chineseCopy: CopySection = {
150+
lang: "zh-CN",
151+
badge: "中文招募",
152+
title: "TaskBeacon招募心理学背景实习生",
153+
summary:
154+
"面向认知任务开发、验证和文档整理的线上协作岗位,中文和英文版本都展示在本页中,方便直接查看与转发。",
155+
aboutTitle: "关于 TaskBeacon",
156+
aboutText:
157+
"TaskBeacon(https://taskbeacon.github.io/) 是一个面向认知任务开发与整理的平台,聚合了经典任务目录、任务包标准(TAPS)、PsyFlow 本地开发框架、psyflow-web 网页预览,以及相关 Agent 自动化技能(Skills)与文档资源,目标是让认知任务的设计、实现、预览、文档和复核更加标准、清晰、可审计。当前网站已整理 35 个任务,目标是 99 个,并强调以统一结构组织任务逻辑、参数配置、参考文献和说明文档。",
158+
responsibilitiesTitle: "工作内容",
159+
responsibilities: [
160+
{
161+
number: "1",
162+
text:
163+
"任务校验与测试:参与人工校验任务参数、任务流程、任务输出、任务流程图,以及网页版任务的测试与实际执行,确保任务设计与实现一致、结果可靠。"
164+
},
165+
{
166+
number: "2",
167+
text:
168+
"文献调研与参数确认:查阅相关文献,整理并确认任务所使用的刺激材料、流程设计及关键参数,为任务标准化提供依据。"
169+
},
170+
{
171+
number: "3",
172+
text:
173+
"网站建设与文档撰写:参与网站内容建设,补充和撰写任务说明、使用文档及相关介绍材料,提升平台的清晰度与可用性。"
174+
}
175+
],
176+
requirementsTitle: "希望你",
177+
requirements: [
178+
{
179+
number: "0",
180+
text: "对本项目感兴趣。"
181+
},
182+
{
183+
number: "1",
184+
text:
185+
"心理学背景,做事认真细致,对心理学实验、认知任务或科研工具建设有兴趣,具备基本的英文文献阅读能力。"
186+
},
187+
{
188+
number: "2",
189+
text: "有行为实验、PsychoPy、jsPsych(非必须)、GitHub、文档整理经验。"
190+
},
191+
{
192+
number: "3",
193+
text: "有 Python 以及 Vibe Coding 经验。"
194+
}
195+
],
196+
benefitsTitle: "你将获得",
197+
benefits: [
198+
"将在项目页面中以贡献者身份进行展示。",
199+
"根据实际贡献,有机会获得后续论文署名。",
200+
"有机会进一步参与其他项目及后续合作。",
201+
"可根据经验、能力及实际投入确定是否提供报酬。"
202+
],
203+
workModeTitle: "工作形式",
204+
workModeText: "线上协作。",
205+
contactTitle: "联系方式",
206+
contactText: "邮箱:braintrace@yeah.net",
207+
templateTitle: "申请模板",
208+
templateText:
209+
"您好,我想应聘实习生岗位。{自我介绍},我已阅读网站内容,并对项目整体架构有基本了解。我的专业 / 背景是 ______,相关经验包括 ______。我对该岗位感兴趣,主要原因是______,希望参与 ______ 相关工作。目前预计每周可投入 ______ 小时,可持续投入 ______ 周/月。"
210+
};
211+
212+
const englishCopy: CopySection = {
213+
lang: "en",
214+
badge: "English Recruitment",
215+
title: "TaskBeacon is recruiting psychology-background interns",
216+
summary:
217+
"An online collaboration role focused on cognitive task development, validation, and documentation. The Chinese version appears above; this section provides the matching English notice.",
218+
aboutTitle: "About TaskBeacon",
219+
aboutText:
220+
"TaskBeacon (https://taskbeacon.github.io/) is a platform for cognitive task development and organization. It brings together a canonical task catalog, the TAPS task package standard, the PsyFlow local development framework, psyflow-web browser previews, and related agent automation skills (Skills) and documentation resources. The goal is to make cognitive task design, implementation, previewing, documentation, and review more standardized, clearer, and auditable. The site currently organizes 35 tasks and aims to reach 99, while emphasizing a unified structure for task logic, parameter configuration, references, and documentation.",
221+
responsibilitiesTitle: "Responsibilities",
222+
responsibilities: [
223+
{
224+
number: "1",
225+
text:
226+
"Task validation and testing: participate in manual checks of task parameters, task flow, task outputs, task flowcharts, and browser-based task testing and execution to ensure the design and implementation stay aligned and results remain reliable."
227+
},
228+
{
229+
number: "2",
230+
text:
231+
"Literature review and parameter confirmation: review relevant literature, organize and confirm the stimuli, procedure design, and key parameters used by the tasks, and help establish the basis for standardization."
232+
},
233+
{
234+
number: "3",
235+
text:
236+
"Website build-out and documentation: help improve the website content, write task instructions, usage guides, and related introduction materials, and make the platform clearer and easier to use."
237+
}
238+
],
239+
requirementsTitle: "Desired Qualifications",
240+
requirements: [
241+
{
242+
number: "0",
243+
text: "Interested in this project."
244+
},
245+
{
246+
number: "1",
247+
text:
248+
"Psychology background, careful and detail-oriented work habits, interest in psychological experiments, cognitive tasks, or research tooling, and basic English reading ability."
249+
},
250+
{
251+
number: "2",
252+
text: "Experience with behavioral experiments, PsychoPy, jsPsych (optional), GitHub, and documentation organization."
253+
},
254+
{
255+
number: "3",
256+
text: "Python and Vibe Coding experience."
257+
}
258+
],
259+
benefitsTitle: "What You Will Get",
260+
benefits: [
261+
"You will be shown as a contributor on the project page.",
262+
"Depending on actual contributions, there may be opportunities for future paper authorship.",
263+
"You may be able to join other projects and future collaborations.",
264+
"Compensation may be provided depending on experience, ability, and actual time commitment."
265+
],
266+
workModeTitle: "Work Mode",
267+
workModeText: "Online collaboration.",
268+
contactTitle: "Contact",
269+
contactText: "Email: braintrace@yeah.net",
270+
templateTitle: "Application Template",
271+
templateText:
272+
"Hello, I would like to apply for the internship position. {Self-introduction}. I have read the website content and have a basic understanding of the overall project structure. My major/background is ______, and related experience includes ______. I am interested in this role mainly because ______, and I hope to work on ______ related tasks. I can currently commit ______ hours per week and can continue for ______ weeks/months."
273+
};
274+
275+
export default function JobsPage() {
276+
return (
277+
<div className="space-y-8 lg:pt-6">
278+
<section className="tb-frame bg-[#fffdf9] p-6 sm:p-8">
279+
<div className="flex flex-wrap items-start justify-between gap-4">
280+
<div className="max-w-3xl">
281+
<div className="tb-section-chip bg-[#f5c1b5]">Jobs</div>
282+
<h1 className="mt-4 font-heading text-4xl font-bold leading-[0.95] text-[#25314d] sm:text-5xl">
283+
TaskBeacon recruitment, in Chinese and English.
284+
</h1>
285+
<p className="mt-4 max-w-3xl text-base leading-8 text-slate-700">
286+
The notice below is shown in Chinese first and English second, with the same role
287+
scope, benefits, contact path, and application template in both sections.
288+
</p>
289+
</div>
290+
291+
<div className="grid gap-3 sm:justify-items-end">
292+
<span className="tb-badge">35 tasks organized</span>
293+
<span className="tb-badge">Target: 99 tasks</span>
294+
<a
295+
className="tb-focus-ring tb-button-secondary w-full sm:w-auto"
296+
href={`mailto:${CONTACT_EMAIL}`}
297+
>
298+
{CONTACT_EMAIL}
299+
</a>
300+
</div>
301+
</div>
302+
</section>
303+
304+
<RecruitmentSection {...chineseCopy} />
305+
<RecruitmentSection {...englishCopy} />
306+
</div>
307+
);
308+
}

src/components/site-header.tsx

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ import Link from "next/link";
44
import { useState } from "react";
55
import { IconClose, IconMenu } from "@/components/icons";
66
import { TaskBeaconLogo } from "@/components/taskbeacon-logo";
7-
import { tasksPageHref } from "@/lib/routes";
7+
import { jobsPageHref, tasksPageHref } from "@/lib/routes";
88

99
const PRIMARY_LINKS = [
1010
{ label: "Home", href: "/" },
1111
{ label: "Tasks", href: tasksPageHref() },
1212
{ label: "Tutorial", href: "/tutorial/" },
1313
{ label: "Framework", href: "/framework/" },
1414
{ label: "Contribute", href: "/contribute/" },
15-
{ label: "Teams", href: "/teams/" }
15+
{ label: "Teams", href: "/teams/" },
16+
{ label: "Jobs", href: jobsPageHref() }
1617
] as const;
1718

1819
function NavLink({
@@ -61,14 +62,6 @@ export function SiteHeader() {
6162
{PRIMARY_LINKS.map((link) => (
6263
<NavLink key={link.href} {...link} />
6364
))}
64-
<a
65-
className="tb-focus-ring rounded-full px-3 py-2 text-sm font-medium text-slate-600 transition-colors hover:text-[#25314d]"
66-
href="https://github.com/TaskBeacon"
67-
target="_blank"
68-
rel="noreferrer"
69-
>
70-
GitHub
71-
</a>
7265
<a
7366
className="tb-focus-ring tb-button-primary px-5 py-3 text-sm"
7467
href="https://taskbeacon.github.io/psyflow-web"
@@ -97,15 +90,7 @@ export function SiteHeader() {
9790
<NavLink key={link.href} {...link} mobile onNavigate={() => setOpen(false)} />
9891
))}
9992
</div>
100-
<div className="mt-3 grid gap-2">
101-
<a
102-
className="tb-focus-ring tb-button-secondary w-full text-sm"
103-
href="https://github.com/TaskBeacon"
104-
target="_blank"
105-
rel="noreferrer"
106-
>
107-
GitHub Org
108-
</a>
93+
<div className="mt-3 grid gap-2">
10994
<a
11095
className="tb-focus-ring tb-button-primary w-full text-sm"
11196
href="https://taskbeacon.github.io/psyflow-web"

src/lib/routes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ export function tasksPageHref(): string {
22
return "/tasks/";
33
}
44

5+
export function jobsPageHref(): string {
6+
return "/jobs/";
7+
}
8+
59
export function taskDetailHref(repo: string): string {
610
return `/tasks/${encodeURIComponent(repo)}/index.html`;
711
}

0 commit comments

Comments
 (0)