Skip to content

Commit fae5000

Browse files
committed
optimise: SEO optimised, add robot.txt, xml file etc.
1 parent 02057ed commit fae5000

10 files changed

Lines changed: 569 additions & 352 deletions

File tree

public/_redirects

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://www.j1ml1.github.io/* https://j1ml1.github.io/:splat 301!

public/robots.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
User-agent: *
2+
Allow: /
3+
4+
Sitemap: https://j1ml1.github.io/sitemap.xml

public/sitemap.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3+
<url>
4+
<loc>https://j1ml1.github.io/</loc>
5+
</url>
6+
<url>
7+
<loc>https://j1ml1.github.io/about</loc>
8+
</url>
9+
<url>
10+
<loc>https://j1ml1.github.io/contact</loc>
11+
</url>
12+
<url>
13+
<loc>https://j1ml1.github.io/projects</loc>
14+
</url>
15+
<url>
16+
<loc>https://j1ml1.github.io/projects/project_docmmir</loc>
17+
</url>
18+
<url>
19+
<loc>https://j1ml1.github.io/blog</loc>
20+
</url>
21+
<url>
22+
<loc>https://j1ml1.github.io/plog</loc>
23+
</url>
24+
</urlset>

src/content/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ const projectsCollection = defineCollection({
88
date: z.string(),
99
thumbnail: image(),
1010
id: z.string(),
11+
links: z.array(z.object({
12+
label: z.string(),
13+
href: z.string().url(),
14+
badge: z.string().url(),
15+
})).optional(),
1116
})
1217
});
1318

src/content/projects/docmmir.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ tags: ["Multimodal", "Information Retrieval", "Deep Learning", "Computer Vision"
55
date: "2025-05-19"
66
thumbnail: "./docmmir_illustrate.png"
77
id: "project_docmmir"
8+
links:
9+
- label: "arXiv"
10+
href: "https://arxiv.org/abs/2505.19312"
11+
badge: "https://img.shields.io/badge/arXiv-2505.19312-b31b1b.svg"
12+
- label: "ACL Anthology"
13+
href: "https://aclanthology.org/2025.findings-emnlp.705/"
14+
badge: "https://img.shields.io/badge/ACL%20Anthology-2025.findings--emnlp.705-9cf.svg"
15+
- label: "HF Dataset"
16+
href: "https://huggingface.co/datasets/Lord-Jim/DocMMIR"
17+
badge: "https://img.shields.io/badge/HF%20Dataset-Lord--Jim%2FDocMMIR-yellow"
18+
- label: "License: MIT"
19+
href: "https://opensource.org/licenses/MIT"
20+
badge: "https://img.shields.io/badge/License-MIT-green.svg"
821
---
922

1023
# DocMMIR: Cross-Domain Document Multimodal Retrieval Framework

src/pages/about.astro

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import "../styles/pages/about.css";
66
import { Image } from "astro:assets";
77
import avatarImage from "../assets/avatar.jpg";
88
9-
const pageTitle = "About Zirui Li | Multimodal LLM Researcher";
10-
const pageDescription = "Learn about Zirui Li, a Computer Science PhD student driven by multimodal large language models, interpretability, and AI reasoning research.";
9+
const pageTitle = "About Zirui Li | Computer Science Ph.D candidate at HITSZ ";
10+
const pageDescription = "Learn about Zirui Li, a Computer Science Ph.D candidate at HITSZ, exploring multimodal large language models, interpretability, and AI reasoning.";
1111
const pageKeywords = [
12-
"Zirui Li biography",
13-
"Zirui Li research",
14-
"Jim Li PhD student",
12+
"Zirui Li",
13+
"Jim Li",
14+
"Li Zirui",
1515
"multimodal LLM researcher",
16-
"AI interpretability researcher"
16+
"NLP PhD student",
17+
"AI interpretability",
1718
];
1819
const siteOrigin = Astro.site ? Astro.site.origin : "https://j1ml1.github.io";
1920
const canonicalUrl = `${siteOrigin.replace(/\/$/, "")}${Astro.url.pathname}`;
@@ -47,7 +48,7 @@ const structuredData = [
4748
"alternateName": "Jim Li",
4849
"url": canonicalUrl,
4950
"image": `${siteOrigin}/images/avatar.jpg`,
50-
"jobTitle": "Computer Science PhD Student",
51+
"jobTitle": "Ph.D candidate in Computer Science",
5152
"affiliation": {
5253
"@type": "CollegeOrUniversity",
5354
"name": "Harbin Institute of Technology, Shenzhen"
@@ -91,16 +92,16 @@ const heroImage = avatarImage;
9192
<span class="hero-badge">LLM reasoning</span>
9293
</div>
9394
<div class="hero-meta">
94-
<div class="hero-meta-item hero-meta-item--location">
95-
<span class="meta-label">Location</span>
96-
<span class="meta-value">Shenzhen, China</span>
97-
</div>
98-
<div class="hero-meta-item hero-meta-item--email">
99-
<span class="meta-label">Email</span>
100-
<span class="meta-value">
101-
zirui[dot]li[at]stu[dot]hit[dot]edu[dot]cn
102-
</span>
103-
</div>
95+
<div class="hero-meta-item hero-meta-item--location">
96+
<span class="meta-label">Location</span>
97+
<span class="meta-value">Shenzhen, China</span>
98+
</div>
99+
<div class="hero-meta-item hero-meta-item--email">
100+
<span class="meta-label">Email</span>
101+
<span class="meta-value">
102+
zirui[dot]li[at]stu[dot]hit[dot]edu[dot]cn
103+
</span>
104+
</div>
104105
</div>
105106
</div>
106107
<div class="hero-pane">

src/pages/index.astro

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import Layout from '../layouts/Layout.astro';
33
import NeumorphicCard from '../components/NeumorphicCard.astro';
44
import '../styles/main.css';
55
6-
const pageTitle = "Zirui Li | Multimodal LLM & NLP Researcher";
7-
const pageDescription = "Discover the research, projects, and photography of Zirui Li, a Computer Science PhD student exploring multimodal large language models, interpretability, and reasoning.";
6+
const pageTitle = "Zirui Li | AI Research, Multimodal LLM Projects & Photography";
7+
const pageDescription = "Explore Zirui Li's AI research, multimodal LLM projects, and photography portfolio focused on NLP and model interpretability.";
88
const pageKeywords = [
99
"Zirui Li",
10-
"Jim Li",
11-
"Li Zirui",
12-
"multimodal LLM researcher",
10+
"AI research",
11+
"multimodal LLM projects",
1312
"NLP PhD student",
14-
"AI interpretability",
13+
"model interpretability",
14+
"photography portfolio",
1515
];
1616
const siteOrigin = Astro.site ? Astro.site.origin : "https://j1ml1.github.io";
1717
const canonicalUrl = `${siteOrigin.replace(/\/$/, "")}${Astro.url.pathname}`;
@@ -23,7 +23,7 @@ const personSchema = {
2323
"alternateName": "Jim Li",
2424
"url": canonicalUrl,
2525
"image": `${siteOrigin}/images/avatar.jpg`,
26-
"jobTitle": "Computer Science PhD Student",
26+
"jobTitle": "Ph.D candidate in Computer Science",
2727
"affiliation": {
2828
"@type": "CollegeOrUniversity",
2929
"name": "Harbin Institute of Technology, Shenzhen"
@@ -62,9 +62,9 @@ const personSchema = {
6262
>
6363
<div class="layout-stack layout-stack--lg">
6464
<NeumorphicCard class="mb-8">
65-
<h1 class="page-heading text-center">Welcome to <span class="text-gradient">Zirui Li's Corner</span></h1>
65+
<h1 class="page-heading text-center">Zirui Li's <span class="text-gradient">AI Research & Projects Hub</span></h1>
6666
<p class="page-subheading text-center">
67-
Hello! I'm <strong>Zirui Li</strong>, you can call me <strong>Jim</strong>. I'm a computer science PhD student passionate about Natural Language Processing, especially in multimodal LLM research, mechanism interpretability, and LLM reasoning. This is where I document my projects, life insights, and photographic works 📝
67+
I am <strong>Zirui Li</strong> (you can also call me <strong>Jim</strong>), a computer science PhD candidate exploring multimodal large language models, NLP interpretability, and creative storytelling through photography. Dive into my latest AI research, hands-on projects, and visual work.
6868
</p>
6969
</NeumorphicCard>
7070

src/pages/projects.astro

Lines changed: 119 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@ import { getCollection, type CollectionEntry } from 'astro:content';
66
import type { ImageMetadata } from 'astro';
77
import { Image } from 'astro:assets';
88
9-
const pageTitle = "My Projects";
9+
const pageTitle = "Project Portfolio | Zirui Li";
10+
const pageDescription = "Discover AI and NLP projects by Zirui Li, featuring multimodal retrieval research, interpretability work, and creative technology experiments.";
11+
const pageKeywords = [
12+
'Zirui Li projects',
13+
'AI portfolio',
14+
'NLP research',
15+
'multimodal LLM',
16+
'model interpretability',
17+
'research showcase',
18+
];
1019
const projectsData = await getCollection('projects');
1120
// Sort by date, newest first
1221
projectsData.sort((a: CollectionEntry<'projects'>, b: CollectionEntry<'projects'>) =>
@@ -26,31 +35,48 @@ const resolveThumbnail = (project: CollectionEntry<'projects'>): ImageMetadata |
2635
return thumbnailModules[key];
2736
};
2837
29-
const projects = projectsData.map((project) => ({
30-
entry: project,
31-
thumbnail: resolveThumbnail(project),
32-
}));
33-
---
38+
const projects = projectsData.map((entry) => {
39+
const links = Array.isArray(entry.data.links) ? entry.data.links : [];
40+
41+
return {
42+
entry,
43+
thumbnail: resolveThumbnail(entry),
44+
href: `/projects/${entry.data.id}`,
45+
links,
46+
};
47+
});
48+
49+
const tagKeywords = Array.from(new Set(projectsData.flatMap((project) => project.data.tags)));
3450
35-
<Layout title={pageTitle}>
51+
const combinedKeywords = Array.from(new Set([...pageKeywords, ...tagKeywords]));
52+
---
53+
<Layout title={pageTitle} description={pageDescription} keywords={combinedKeywords}>
3654
<div class="projects-layout layout-stack layout-stack--lg">
3755
<NeumorphicCard class="projects-hero text-center mb-8">
38-
<h1 class="page-heading">My <span class="text-gradient">Project</span> Collection</h1>
56+
<h1 class="page-heading">Zirui Li's <span class="text-gradient">Project Portfolio</span></h1>
3957
<p class="page-subheading">
40-
Here are some of my recent projects. Click to view details.
58+
Explore AI and NLP projects covering multimodal retrieval, model interpretability, and creative applications built during my PhD journey.
4159
</p>
4260
</NeumorphicCard>
4361

4462
<div class="projects-list">
45-
{projects.map(({ entry: project, thumbnail }, index) => (
46-
<NeumorphicCard class="project-card hover:shadow-neu-lg transition-all duration-300">
47-
<a href={`/projects/${project.data.id}`} class="block link-plain">
63+
{projects.map(({ entry, thumbnail, href, links }, index) => {
64+
const { title, description, tags, date } = entry.data;
65+
66+
return (
67+
<NeumorphicCard
68+
class="project-card hover:shadow-neu-lg transition-all duration-300"
69+
data-href={href}
70+
role="link"
71+
tabindex="0"
72+
aria-label={`View project ${title}`}
73+
>
4874
<div class="project-content">
4975
<div class="project-image-container">
5076
{thumbnail ? (
5177
<Image
5278
src={thumbnail}
53-
alt={project.data.title}
79+
alt={title}
5480
class="project-image rounded-lg"
5581
loading={index === 0 ? 'eager' : 'lazy'}
5682
fetchpriority={index === 0 ? 'high' : 'auto'}
@@ -59,7 +85,7 @@ const projects = projectsData.map((project) => ({
5985
) : (
6086
<img
6187
src="/images/placeholder.svg"
62-
alt={`${project.data.title} placeholder`}
88+
alt={`${title} placeholder`}
6389
class="project-image rounded-lg"
6490
loading={index === 0 ? 'eager' : 'lazy'}
6591
fetchpriority={index === 0 ? 'high' : 'auto'}
@@ -71,53 +97,98 @@ const projects = projectsData.map((project) => ({
7197
</div>
7298
</div>
7399
<div class="project-details">
74-
<h2 class="project-title">{project.data.title}</h2>
75-
<p class="project-desc">{project.data.description}</p>
76-
<div class="project-meta">
77-
<div class="project-tags">
78-
{project.data.tags.map((tag: string) => (
79-
<span class="project-tag">{tag}</span>
100+
<h2 class="project-title">{title}</h2>
101+
{links.length > 0 && (
102+
<div class="project-links" aria-label={`${title} resource links`}>
103+
{links.map((link) => (
104+
<a
105+
href={link.href}
106+
target="_blank"
107+
rel="noopener"
108+
aria-label={`Visit ${link.label}`}
109+
on:click={(event) => event.stopPropagation()}
110+
>
111+
<img src={link.badge} alt={`${link.label} badge`} loading="lazy" decoding="async" />
112+
</a>
80113
))}
81114
</div>
82-
<div class="project-date">{project.data.date}</div>
83-
</div>
115+
)}
116+
<p class="project-desc">{description}</p>
84117
</div>
85118
</div>
86-
</a>
87-
</NeumorphicCard>
88-
))}
119+
<div class="project-meta project-meta--footer">
120+
<div class="project-tags">
121+
{tags.map((tag: string) => (
122+
<span class="project-tag">{tag}</span>
123+
))}
124+
</div>
125+
<div class="project-date">{date}</div>
126+
</div>
127+
</NeumorphicCard>
128+
);
129+
})}
89130
</div>
90131
</div>
91132
</Layout>
92133

93134
<script>
94-
document.addEventListener('DOMContentLoaded', () => {
95-
const images = document.querySelectorAll<HTMLImageElement>('.project-image');
96-
images.forEach(img => {
97-
const container = img.closest('.project-image-container');
98-
const loadingDiv = container?.querySelector<HTMLElement>('.project-loading');
99-
100-
const markLoaded = () => {
101-
img.classList.add('loaded');
102-
if (loadingDiv) (loadingDiv as HTMLElement).style.opacity = '0';
135+
const handleImageLoading = (img: HTMLImageElement) => {
136+
const container = img.closest('.project-image-container');
137+
const loadingOverlay = container?.querySelector<HTMLElement>('.project-loading');
138+
139+
const markLoaded = () => {
140+
img.classList.add('loaded');
141+
if (loadingOverlay) loadingOverlay.style.opacity = '0';
142+
};
143+
144+
if (img.complete) {
145+
if (img.naturalWidth === 0) {
146+
img.removeAttribute('srcset');
147+
img.src = '/images/placeholder.svg';
148+
}
149+
markLoaded();
150+
return;
151+
}
152+
153+
img.addEventListener('load', markLoaded, { once: true });
154+
img.addEventListener('error', () => {
155+
img.removeAttribute('srcset');
156+
container?.querySelectorAll('source').forEach((el) => el.remove());
157+
img.src = '/images/placeholder.svg';
158+
markLoaded();
159+
}, { once: true });
160+
};
161+
162+
const enhanceProjectCards = () => {
163+
const projectCards = document.querySelectorAll<HTMLElement>('.project-card[data-href]');
164+
projectCards.forEach((card) => {
165+
const href = card.dataset.href;
166+
if (!href) return;
167+
168+
const navigate = () => {
169+
window.location.href = href;
103170
};
104171

105-
if (img.complete) {
106-
if (img.naturalWidth === 0) {
107-
img.removeAttribute('srcset');
108-
img.src = '/images/placeholder.svg';
172+
card.addEventListener('click', (event) => {
173+
const target = event.target as HTMLElement;
174+
if (target.closest('.project-links a')) {
175+
event.stopPropagation();
176+
return;
109177
}
110-
markLoaded();
111-
} else {
112-
img.addEventListener('load', markLoaded, { once: true });
113-
img.addEventListener('error', () => {
114-
img.removeAttribute('srcset');
115-
container?.querySelectorAll('source').forEach(el => el.remove());
116-
img.src = '/images/placeholder.svg';
117-
markLoaded();
118-
}, { once: true });
119-
}
178+
navigate();
179+
});
180+
181+
card.addEventListener('keydown', (event) => {
182+
if (event.key === 'Enter' || event.key === ' ') {
183+
event.preventDefault();
184+
navigate();
185+
}
186+
});
120187
});
188+
};
121189

190+
document.addEventListener('DOMContentLoaded', () => {
191+
document.querySelectorAll<HTMLImageElement>('.project-image').forEach(handleImageLoading);
192+
enhanceProjectCards();
122193
});
123194
</script>

0 commit comments

Comments
 (0)