Xu Lab

Xu Lab Website

A bilingual (English/Chinese) research group website built with Hugo and the theme-research-group theme. Deployed to xulab.pages.dev via Cloudflare Pages.


⚠️ GUIDING PRINCIPLE

Keep the code and the content base minimal.

Resist the urge to add features, pages, customizations, or dependencies unless strictly necessary. Every addition has a maintenance cost. When in doubt, leave it out.


Local Preview

For local development and testing changes before pushing to github:

Prerequisites

Run the development server

python update_publications.py --local   # reads the running Zotero app; or set ZOTERO_API_KEY and omit --local
academic import --bibtex "Exported Items.bib" content/en/publication/ --overwrite --compact
academic import --bibtex "Exported Items.bib" content/zh/publication/ --overwrite --compact
hugo server

Open http://localhost:1313 in your browser. The server auto-reloads on file changes.

To customize theme templates, vendor the theme first:

hugo mod vendor

Then copy templates from _vendor/github.com/HugoBlox/hugo-blox-builder/modules/blox-bootstrap/v5/layouts/ into layouts/ and edit there. Prefer CSS over custom layout overrides — only copy a theme template if CSS cannot achieve the same result.


Architecture

Bilingual Content

All content exists in parallel under content/en/ and content/zh/. Changes to one language usually need a matching change in the other. Language config is in config/_default/languages.yaml.

The layouts/partials/blocks/people.html template implements a fallback mechanism: the Chinese site uses English author profiles as fallback, so only authors with actual Chinese translations need a content/zh/authors/<name>/ directory.

Configuration Files

Content Types

Custom Layouts (theme overrides)

Styling


Managing Content

Publications

The publication list lives in Zotero, not in this repo: the Publications collection of the xu-research-lab Zotero group. Every build fetches it fresh (update_publications.py → Exported Items.bib, untracked) and generates the pages under content/*/publication/ — do not edit those files manually.

When the site picks up changes:

To show/hide authors on the publications page, edit config/_default/hugo.yaml:

taxonomies:
  author: authors  # comment out to hide authors

Lab Members

成员自助更新指南(无需编程)

你可以直接在 GitHub 网页上修改自己的资料,不需要安装软件。修改后提交给网站管理员审核,审核通过并合并后,网站会自动更新。所有成员都应提交英文资料,填写在 content/en/authors/。

1. 找到自己的资料

登录 GitHub,打开成员资料文件夹。找到自己姓名对应的文件夹(如 bingyue-hu),点击其中的 _index.md。如果没有自己的文件夹,可以自行创建,见下方“新成员:创建自己的资料”。

2. 修改文字

点击文件右上角的铅笔按钮(Edit this file)。如果提示 Fork this repository,点击确认:这会在你的账号下创建一份副本,供你提交修改,不会直接改动网站。

文件开头两行 --- 之间是资料设置;第二行 --- 后面可以填写较详细的个人简介。这里是英文资料,简介正文也请用英文填写。 常见字段如下:

字段 含义 如何修改
title 显示姓名 填写姓名的英文写法,如 Bingyue Hu
role 身份 如 M.S. student(硕士生)、Ph.D. student(博士生)
bio 简短介绍 如 bio: 'I study the gut microbiome and host health.'
interests 研究兴趣 每行填写一项,见下方示例
social 公开联系方式、学术主页 按文件中的示例填写;邮箱链接以 mailto: 开头
no_link 是否关闭个人详情页入口 有个人简介时改为 false,让访客可以点击进入

请保留英文冒号、缩进和每行开头的 -。行首的 # 表示这一行暂不生效;需要启用某项时,去掉该项及其下属行开头的 #,保留缩进。例如,把原来的研究兴趣注释行替换为:

interests:
  - Gut microbiome
  - Bioinformatics

不要重复添加已有字段。authors、superuser、weight 和 user_groups 请保持原样;身份变更或毕业时,请在提交说明中告知管理员,让管理员同步调整分组和排序。邮箱和简介会公开展示,只填写愿意公开的信息。

3. 提交给管理员审核

点击 Commit changes… 或 Propose changes,填写说明,例如“更新胡冰月的个人简介”。如果可以选择提交位置,请选择 Create a new branch … and start a pull request,不要直接提交到 master。

接着按页面提示点击 Compare & pull request 或 Create pull request,检查修改内容,再点击 Create pull request 完成提交。Pull request(简称 PR)就是一份“请管理员审核这些修改”的申请。若页面显示目标仓库和分支,请确认是 xu-research-lab/xu-research-lab.github.io 的 master 分支。

提交后,把申请页面的链接发给网站管理员。管理员可能会在页面上留言,请按意见修改;合并且自动发布成功后,刷新网站即可看到更新。

更换照片

准备一张竖版个人照片,保存为真正的 JPG 格式,文件名为 avatar.jpg(不要只把 PNG 的扩展名改成 JPG)。在 GitHub 上打开自己的资料文件夹,选择 Add file → Upload files,上传同名照片并按上述流程提交审核。如果文字修改已经提交,请在自己的副本中切换到该申请所用的分支,再上传照片,这样照片会加入同一份申请;不确定时可单独提交,并把两个链接发给管理员。

新成员:创建自己的资料

新成员可以自己创建文件夹并提交审核,无需等待管理员代建:

  1. 打开仓库首页,点击右上角 Fork → Create fork,在自己账号下创建副本;已有副本则直接打开,并在需要时点击 Sync fork → Update branch 同步最新内容。
  2. 在自己的副本中,打开 content/en/authors/ 下同身份成员的 _index.md,点击 Raw 查看原文,复制全部内容作为模板。
  3. 回到自己副本的 content/en/authors/,选择 Add file → Create new file。在文件名输入框填写 你的姓名拼音/_index.md,例如 xiaoming-zhang/_index.md。输入 / 后 GitHub 会自动创建文件夹。文件夹名使用小写字母和连字符,不能与已有成员重复。
  4. 粘贴模板,将 title 和 authors 列表中的姓名都改成自己的英文姓名,填写自己的英文资料及简介。删除或替换从模板复制来的他人联系方式、教育经历和介绍;保留原有注释示例。填写了简介后,将 no_link 设为 false。
  5. 新建资料时,role 和 user_groups 都要匹配自己的身份:硕士生用 M.S. student,博士生用 Ph.D. student,博士后用 Postdoctoral Researchers。superuser 保持 false。weight 是排序数字:硕士生为 10 加入学年份(如 102026),博士生为 20 加入学年份(如 202026),博士后为 30 加入站年份(如 302026)。不确定时在申请中说明,请管理员核对。
  6. 点击 Commit changes…,选择创建新分支(如 add-xiaoming-zhang)并保存。记住这个分支名,接下来保持在该分支,打开新建的姓名文件夹,按“更换照片”的步骤上传自己的 avatar.jpg,保存到同一分支。
  7. 按上方第 3 步创建 pull request,目标选择实验室原仓库的 master 分支,来源选择自己副本中刚才的分支。确认申请包含自己的 _index.md 和 avatar.jpg,然后将申请链接发给网站管理员。

如果同时提供中文翻译,在同一分支下回到副本首页,选择 Add file → Create new file,填写 content/zh/authors/xiaoming-zhang/_index.md(换成自己的文件夹名),粘贴并翻译自己的资料,再保存到该分支,即可一起提交审核。

Each member is defined by a folder under content/en/authors/<name>/ containing:

Author profiles follow a consistent Hugo Blox template format with these sections (commented out when empty): bio, interests, education, social.

The user_groups field determines which section the member appears in:

Set no_link: false to enable links to the member’s profile page, or no_link: true to disable.

Only create content/zh/authors/<name>/ if you have an actual Chinese translation (the English profile is used as fallback).

To remove a member: delete their folder from content/en/authors/ (and from content/zh/authors/ if a Chinese version exists).

To sort members: within each group, members are ordered by weight defined in their profiles. The weight value combines role priority (Postdoc = 30, Ph.D. = 20, M.S. = 10) with year. Use graduation year for alumni, or start year for current members, e.g., 102021. The sorting is configured in content/en/people/index.md.

Blog Posts

Each post is a folder under content/en/post/<slug>/ containing index.md.

To add a post: create the folder and index.md. Set draft: true to hide it from the live site. Mirror under content/zh/post/<slug>/ if a Chinese version is needed.

To remove a post: delete the folder from both language directories.

Activity Page (Photo Slider)

The slider is configured in content/en/activity/index.md and content/zh/activity/index.md.

To add a photo:

  1. Put the image file in assets/media/ (e.g. assets/media/group3.jpg)
  2. Add a slide entry in both activity files:
- title: "2025.9"
  content: Lab retreat
  align: end
  background:
    image:
      filename: group3.jpg
      filters:
        brightness: 1.0

To remove a photo: delete its slide entry from both files (and optionally delete the image from assets/media/).

Events

Events are listed at /event/. Each event is a folder under content/en/event/<slug>/ containing index.md.

A minimal event file:

---
title: "Talk: Title of the Talk"
event: Conference or Seminar Name
location: Room 503, Building X
date: 2025-09-01T14:00:00
date_end: 2025-09-01T15:00:00
all_day: false
abstract: "Brief description of the talk."
---

Mirror the file under content/zh/event/<slug>/ with a Chinese version.

Links are defined in content/en/_index.md and content/zh/_index.md as a markdown block:

- block: markdown
  content:
    title: Useful Links
    text: |
      - [**Link Name**](https://example.com)
        Brief description
  design:
    columns: '1'
    css_class: section-useful-links

Add, remove, or reorder items in the markdown list. Mirror the change in content/zh/_index.md.

Contact Page

Edit content/en/contact/index.md and content/zh/contact/index.md. The address, coordinates, and office details are set in the front matter of those files.

Edit config/_default/menus.en.yaml (English) and config/_default/menus.zh.yaml (Chinese). Each entry under main has a name, url, and weight (lower weight = appears first).

The navigation contains Home, People, Publications, Activities, and Contact, with matching Chinese entries. Events / 学术活动 and Posts / 博客 are hidden from both menus; their content and URLs remain available. Removing a menu entry does not unpublish a page.

To restore a hidden tab, add its entry back to both menu files:

Tab (English / Chinese) English URL Chinese URL Weight
Events / 学术活动 /event/ /zh/event/ 43
Posts / 博客 /post/ /zh/post/ 50

Homepage Background

Replace assets/media/true.jpg, or edit the design.background.image.filename field in content/en/_index.md and content/zh/_index.md.

Site Icon

Replace assets/media/icon.png (keep the filename).

Recruiting Information

Edit content/en/authors/we-want-you/_index.md (and content/zh/authors/we-want-you/_index.md) to reflect current open positions.


Password-Protected Posts

Specific posts are encrypted after the Hugo build using StaticCrypt. The encrypted HTML is what gets deployed — the plaintext is never served to the browser.

The CI step:

staticrypt public/en/post/lab-nas-guide/index.html -p "$HUGO_SITE_PASSWORD" -d public/en/post/lab-nas-guide/ --short

The --short flag suppresses the interactive confirmation prompt in non-interactive CI environments.

To protect an additional post, add a line in the same form to the “Encrypt protected pages” step in .github/workflows/publish.yaml.

The password is stored as a GitHub secret named HUGO_SITE_PASSWORD. To set or update it:

  1. Go to Settings → Secrets and variables → Actions in the GitHub repository.
  2. Click New repository secret.
  3. Set Name to HUGO_SITE_PASSWORD and Value to your chosen password.

CI/CD Workflow

Pushes to the master branch, a daily schedule, or a manual run trigger .github/workflows/publish.yaml, which:

  1. Runs update_publications.py to fetch the Zotero group’s “Publications” collection into Exported Items.bib.
  2. Runs academic import "Exported Items.bib" content/*/publication/ --compact to regenerate publication pages.
  3. Builds the site with Hugo (--minify --baseURL "https://xulab.pages.dev/").
  4. Encrypts password-protected pages with StaticCrypt.
  5. Deploys to Cloudflare Pages using wrangler pages deploy.

Cloudflare Pages Setup (one-time)

1. Create the Pages project

  1. Log in to the Cloudflare dashboard.
  2. Go to Workers & Pages → Create → Pages → Direct Upload.
  3. Name the project xulab and complete the wizard.

2. Find your Account ID

Navigate to Workers & Pages. The Account ID is the hex string in the dashboard URL:

https://dash.cloudflare.com/<ACCOUNT_ID>/workers-and-pages

3. Create an API Token

Go to My Profile → API Tokens → Create Token. Use the “Edit Cloudflare Workers” template, or create a custom token with the “Cloudflare Pages: Edit” permission.

4. Add GitHub Secrets

Go to Settings → Secrets and variables → Actions in the GitHub repository and add:

Secret name Value
CLOUDFLARE_API_TOKEN The API token from step 3
CLOUDFLARE_ACCOUNT_ID The Account ID from step 2
HUGO_SITE_PASSWORD The site password for protected posts
ZOTERO_API_KEY A read-only Zotero API key with access to the xu-research-lab group (zotero.org/settings/keys)

SEO & Search Engine Verification

The site’s search-engine verification and SEO signals live in four places:

Both verification files sit in static/ (not the repo root or public/) because Hugo copies static/ verbatim to the site root — that is the Hugo equivalent of “upload the file to your site root.”


Dependencies