Skip to content

Commit afe5e1d

Browse files
committed
first commit
1 parent fded516 commit afe5e1d

36 files changed

+1193
-163
lines changed

app/components/LangSwitch.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default function LangSwitch() {
3838
<div className="lang-dropdown">
3939

4040
<button ref={btnRef} className="btn btn-outline btn-inline" aria-haspopup="menu" aria-expanded={open} onClick={() => setOpen(v => !v)}>
41-
<Image src="/language-svgrepo-com.svg" alt="Cogling-AI Lab" width={20} height={20} />
41+
<Image src="/language-svgrepo-com.svg" alt="CogNLP Lab" width={20} height={20} />
4242
{currentLabel}
4343
</button>
4444
{open && (

app/components/SideToc.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export default function SideToc({ items }: { items: TocItem[] }) {
88
const [active, setActive] = useState<string | null>(null);
99

1010
useEffect(() => {
11+
if (!active && items.length > 0) {
12+
setActive(items[0].id);
13+
}
1114
const observers: IntersectionObserver[] = [];
1215
items.forEach(({ id }) => {
1316
const el = document.getElementById(id);
@@ -24,7 +27,7 @@ export default function SideToc({ items }: { items: TocItem[] }) {
2427
observers.push(ob);
2528
});
2629
return () => observers.forEach(o => o.disconnect());
27-
}, [items]);
30+
}, [items, active]);
2831

2932
return (
3033
<nav className="side-toc" aria-label="Section Navigation">

app/en/page.tsx

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default function HomePageEN() {
1313
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
1414
<nav className="nav">
1515
<a href="#home">{t.nav.home}</a>
16-
<a href="#publications">{t.nav.publications}</a>
16+
<Link href="/en/publication">{t.nav.publications}</Link>
1717
<a href="#research">{t.nav.research}</a>
1818
<a href="#courses">{t.nav.courses}</a>
1919
</nav>
@@ -30,31 +30,33 @@ export default function HomePageEN() {
3030
<a className="btn btn-primary" href="#about">{t.hero.ctaLearn}</a>
3131
<a className="btn btn-outline" href={`mailto:${t.contact.email}`}>{t.hero.ctaEmail}</a>
3232
</div>
33-
<div className="profile-card">
34-
<h2>{t.profile.name}</h2>
35-
<div className="lines">
36-
{t.profile.lines.map((line: string, idx: number) => (<div key={idx}>{line}</div>))}
37-
</div>
38-
</div>
39-
</div>
40-
</section>
4133

42-
<section id="publications" className="section">
43-
<div className="container">
44-
<h2 className="section-title">{t.publications.title}</h2>
45-
<ul className="list">
46-
{t.publications.list.map((p: any, idx: number) => (
47-
<li key={idx}>
48-
{p.href ? (<a href={p.href} target="_blank" rel="noopener noreferrer">{p.text}</a>) : p.text}
49-
</li>
50-
))}
51-
</ul>
5234
</div>
5335
</section>
5436

37+
{/* Publications moved to /en/publication */}
38+
5539
<section id="about" className="section">
5640
<div className="container">
5741
<h2 className="section-title">{t.about.title}</h2>
42+
<div className="about-grid">
43+
<div className="about-photo">
44+
<img src="/wang_hao.jpeg" alt="Hao WANG" />
45+
</div>
46+
<div>
47+
{t.profile && t.profile.name && Array.isArray(t.profile.lines) && (
48+
<div className="profile-card">
49+
<h2>{t.profile.name}</h2>
50+
<div className="lines">
51+
{t.profile.lines.map((line: string, idx: number) => (<div key={idx}>{line}</div>))}
52+
</div>
53+
<div className="contact-email">
54+
<a href={`mailto:${t.contact.email}`}>{t.contact.email}</a>
55+
</div>
56+
</div>
57+
)}
58+
</div>
59+
</div>
5860
<p>{t.about.p1}</p>
5961
<p>{t.about.p2}</p>
6062
</div>
@@ -145,7 +147,15 @@ export default function HomePageEN() {
145147
<tbody>
146148
{t.alumni.rows.map((r, idx) => (
147149
<tr key={idx}>
148-
{r.map((cell, cidx) => (<td key={cidx}>{cell}</td>))}
150+
{r.map((cell: any, cidx: number) => (
151+
<td key={cidx}>
152+
{cell && typeof cell === 'object' && 'href' in cell ? (
153+
<a href={cell.href} target="_blank" rel="noopener noreferrer">{cell.text}</a>
154+
) : (
155+
cell
156+
)}
157+
</td>
158+
))}
149159
</tr>
150160
))}
151161
</tbody>
@@ -171,9 +181,13 @@ export default function HomePageEN() {
171181

172182
<SideToc items={[
173183
{ id: 'home', label: t.nav.home },
174-
{ id: 'publications', label: t.nav.publications },
184+
{ id: 'courses', label: t.nav.courses },
175185
{ id: 'research', label: t.nav.research },
176-
{ id: 'courses', label: t.nav.courses }
186+
{ id: 'expectations', label: t.nav.expectations },
187+
{ id: 'insights', label: t.nav.insights },
188+
{ id: 'students', label: t.nav.students },
189+
{ id: 'alumni', label: t.nav.alumni },
190+
{ id: 'contact', label: t.nav.contact }
177191
]} />
178192
</main>
179193
);

app/en/publication/page.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Link from 'next/link';
2+
import pubs from '../../../data/publications.json';
3+
4+
type Pub = typeof pubs[number];
5+
6+
export default function PublicationEN() {
7+
return (
8+
<main>
9+
<section className="section">
10+
<div className="container">
11+
<h1 className="section-title">Publications</h1>
12+
{(() => {
13+
const byYear: Record<string, Pub[]> = {};
14+
pubs.forEach((e: Pub) => {
15+
const y = String(e.year || 'Others');
16+
(byYear[y] ||= []).push(e);
17+
});
18+
const years = Object.keys(byYear).sort((a, b) => Number(b) - Number(a));
19+
return years.map((year) => (
20+
<div key={year} style={{ marginBottom: 24 }}>
21+
<h2 className="section-title">{year}</h2>
22+
<ul className="list">
23+
{byYear[year].map((e) => (
24+
<li key={e.id}>
25+
<strong>{e.abbr ? `[${e.abbr}] ` : ''}{e.title}</strong>
26+
<div style={{ color: '#6b7280' }}>
27+
{Array.isArray(e.authors) ? e.authors.join(', ') : ''} · {(e as any).journal || (e as any).booktitle || ''}
28+
{e.pages ? ` · ${e.pages}` : ''}
29+
</div>
30+
{(e as any).html ? (
31+
<div><a href={(e as any).html} target="_blank" rel="noopener noreferrer">PDF</a></div>
32+
) : (e as any).url ? (
33+
<div><a href={(e as any).url} target="_blank" rel="noopener noreferrer">Link</a></div>
34+
) : e.doi ? (
35+
<div><a href={e.doi} target="_blank" rel="noopener noreferrer">DOI</a></div>
36+
) : null}
37+
</li>
38+
))}
39+
</ul>
40+
</div>
41+
));
42+
})()}
43+
<p style={{ marginTop: 16 }}><Link href="/en">Back to Home</Link></p>
44+
</div>
45+
</section>
46+
</main>
47+
);
48+
}
49+
50+

app/globals.css

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ a {
127127
padding: 40px 0;
128128
}
129129

130+
.hero,
131+
.section {
132+
scroll-margin-top: 88px;
133+
}
134+
130135
.section:nth-of-type(even) {
131136
background: rgba(13, 71, 161, 0.03);
132137
}
@@ -198,30 +203,85 @@ a {
198203
border: 1.5px solid var(--color-border);
199204
border-radius: 10px;
200205
padding: 10px;
206+
z-index: 1000;
207+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
201208
}
209+
202210
.side-toc a {
203211
padding: 6px 8px;
204212
border-radius: 6px;
205213
color: var(--color-primary);
206214
}
215+
207216
.side-toc a[aria-current="page"] {
208217
background: rgba(13, 71, 161, 0.08);
209218
}
210-
@media (max-width: 1024px) {
211-
.side-toc { display: none; }
219+
220+
@media (max-width: 768px) {
221+
.side-toc {
222+
display: none;
223+
}
212224
}
213225

214226
/* Profile card */
215227
.profile-card {
216228
margin-top: 20px;
217-
border: 1.5px solid var(--color-border);
218-
border-radius: 12px;
219-
padding: 16px;
220-
max-width: 640px;
229+
padding: 18px;
230+
max-width: 720px;
231+
background: linear-gradient(180deg, rgba(13, 71, 161, .03), rgba(13, 71, 161, .01));
232+
}
233+
234+
.profile-card h2 {
235+
margin: 0 0 8px;
236+
font-size: 22px;
237+
}
238+
239+
.profile-card .lines {
240+
color: var(--color-muted);
241+
}
242+
243+
.profile-card .contact-email {
244+
margin-top: 8px;
245+
}
246+
247+
.profile-card .contact-email a {
248+
color: var(--color-primary);
249+
font-weight: 600;
250+
}
251+
252+
/* About grid */
253+
.about-grid {
254+
display: grid;
255+
grid-template-columns: 300px 1fr;
256+
gap: 20px;
257+
align-items: start;
258+
}
259+
260+
.about-grid>* {
261+
align-self: start;
262+
}
263+
264+
.about-grid .profile-card {
265+
margin-top: 0;
266+
}
267+
268+
.about-photo {
269+
border-radius: 14px;
270+
overflow: hidden;
221271
background: #fff;
222272
}
223-
.profile-card h2 { margin: 0 0 8px; font-size: 22px; }
224-
.profile-card .lines { color: var(--color-muted); }
273+
274+
.about-photo img {
275+
display: block;
276+
width: 100%;
277+
height: auto;
278+
}
279+
280+
@media (max-width: 900px) {
281+
.about-grid {
282+
grid-template-columns: 1fr;
283+
}
284+
}
225285

226286
@media (max-width: 720px) {
227287
.nav {

app/ja/page.tsx

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import LangSwitch from '../components/LangSwitch';
22
import Link from 'next/link';
3+
import SideToc from '../components/SideToc';
34
import { getDict } from '../lib/i18n';
45

56
export default function HomePageJA() {
@@ -11,21 +12,17 @@ export default function HomePageJA() {
1112
<div className="brand"><Link href="/">{t.brand}</Link></div>
1213
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
1314
<nav className="nav">
14-
<a href="#about">{t.nav.about}</a>
15-
<a href="#courses">{t.nav.courses}</a>
15+
<a href="#home">{t.nav.home}</a>
16+
<Link href="/ja/publication">{t.nav.publications}</Link>
1617
<a href="#research">{t.nav.research}</a>
17-
<a href="#expectations">{t.nav.expectations}</a>
18-
<a href="#insights">{t.nav.insights}</a>
19-
<a href="#students">{t.nav.students}</a>
20-
<a href="#alumni">{t.nav.alumni}</a>
21-
<a href="#contact">{t.nav.contact}</a>
18+
<a href="#courses">{t.nav.courses}</a>
2219
</nav>
2320
<LangSwitch />
2421
</div>
2522
</div>
2623
</header>
2724

28-
<section className="hero">
25+
<section id="home" className="hero">
2926
<div className="container">
3027
<h1 className="title">{t.hero.title}</h1>
3128
<p className="subtitle">{t.hero.subtitle}</p>
@@ -36,8 +33,28 @@ export default function HomePageJA() {
3633
</div>
3734
</section>
3835

36+
{/* Publications moved to /ja/publication */}
37+
3938
<section id="about" className="section">
4039
<div className="container">
40+
41+
<div className="about-grid ">
42+
<div className="about-photo">
43+
<img src="/wang_hao.jpeg" alt="Hao WANG" />
44+
</div>
45+
<div>
46+
{t.profile && t.profile.name && Array.isArray(t.profile.lines) && (
47+
<div className="profile-card">
48+
<div className="lines">
49+
{t.profile.lines.map((line: string, idx: number) => (<div key={idx}>{line}</div>))}
50+
</div>
51+
<div className="contact-email">
52+
<a href={`mailto:${t.contact.email}`}>{t.contact.email}</a>
53+
</div>
54+
</div>
55+
)}
56+
</div>
57+
</div>
4158
<h2 className="section-title">{t.about.title}</h2>
4259
<p>{t.about.p1}</p>
4360
<p>{t.about.p2}</p>
@@ -130,7 +147,15 @@ export default function HomePageJA() {
130147
<tbody>
131148
{t.alumni.rows.map((r, idx) => (
132149
<tr key={idx}>
133-
{r.map((cell, cidx) => (<td key={cidx}>{cell}</td>))}
150+
{r.map((cell: any, cidx: number) => (
151+
<td key={cidx}>
152+
{cell && typeof cell === 'object' && 'href' in cell ? (
153+
<a href={cell.href} target="_blank" rel="noopener noreferrer">{cell.text}</a>
154+
) : (
155+
cell
156+
)}
157+
</td>
158+
))}
134159
</tr>
135160
))}
136161
</tbody>
@@ -153,6 +178,17 @@ export default function HomePageJA() {
153178
<p>{t.footer.replace('{year}', String(new Date().getFullYear()))}</p>
154179
</div>
155180
</footer>
181+
182+
<SideToc items={[
183+
{ id: 'home', label: t.nav.home },
184+
{ id: 'courses', label: t.nav.courses },
185+
{ id: 'research', label: t.nav.research },
186+
{ id: 'expectations', label: t.nav.expectations },
187+
{ id: 'insights', label: t.nav.insights },
188+
{ id: 'students', label: t.nav.students },
189+
{ id: 'alumni', label: t.nav.alumni },
190+
{ id: 'contact', label: t.nav.contact }
191+
]} />
156192
</main>
157193
);
158194
}

0 commit comments

Comments
 (0)