Contributing to the PPGCosmo Website
This is a Quarto website rendered to static HTML and deployed automatically to ppgcosmo.github.io on every push to main.
Repository structure
ppgcosmo-website/
├── _quarto.yml # Site config: navbar, footer, theme
├── styles.css # Custom CSS overrides
├── index.qmd # Home page
├── people.qmd # People page
├── applications.qmd # Applications page
├── _data/ # JSON data files — the main place to edit content
│ ├── news.json # News/highlights feed shown on the home page
│ ├── faculty_brazil.json # Faculty members based in Brazil
│ ├── collaborators.json # International collaborators
│ ├── phd_students.json # Current PhD students
│ ├── postdocs.json # Current postdoctoral researchers
│ ├── postdocs_previous.json# Previous postdocs
│ ├── alumni.json # Alumni
│ ├── institutions.json # Partner institutions
│ └── organization.json # Coordinator and deputy coordinator
├── images/
│ ├── people/ # Profile photos (see naming convention below)
│ └── ... # Logos and banner images
└── .github/workflows/
└── publish.yml # CI/CD: renders and deploys to GitHub Pages
The .qmd pages read from the _data/ JSON files using embedded Python. In most cases, only the JSON files need to be edited — no Python or Quarto knowledge required.
Common edits
Adding a news item
Edit _data/news.json. Insert the new entry at the top of the array. There are three kinds of entries.
1. Person achievement — highlights something done by a member of the program:
{
"date": "2026-05-15",
"people": [{"name": "Full Name", "role": "fac"}],
"text": "One or two sentences describing the achievement or event.",
"urls": [{"label": "Link text", "url": "https://..."}]
}2. Call / announcement — a program-wide notice (e.g. a fellowship call). Uses type and title instead of people:
{
"date": "2026-05-15",
"type": "call",
"title": "Short headline shown in bold",
"text": "One or two sentences of detail (may be empty: \"\").",
"urls": [{"label": "Link text", "url": "https://..."}]
}3. Qualification exam — announces a student’s qualification exam. Uses type together with a student name (no role: the tag already says it is a qualification exam), plus three fields of its own:
{
"date": "2026-08-13",
"type": "qualification",
"student": "Full Name",
"title": "Title of the exam",
"when": "14 August 2026, 16:00 BRT",
"committee": [
{"name": "Committee Member", "affiliation": "Institution"},
{"name": "Another Member"}
],
"text": "",
"urls": [{"label": "Zoom link", "url": "https://..."}]
}The student’s name heads the card, followed by a teal (qualification exam) tag; the title, the date/time and the examining committee follow underneath. date is the date of the announcement (the exam date belongs in when). when is free text — keep the house style 14 August 2026, 16:00 BRT. affiliation may be omitted for a member, and text may be "" or hold an extra sentence, shown above the title.
| Field | Notes |
|---|---|
date |
ISO date ("2026-05-15") or year-only ("2026"). Items are sorted newest-first; within the same date, order follows the JSON file. |
type |
call or announcement (with title), or qualification (with student). Shown as a colored tag; qualification is displayed as qualification exam. |
role |
Only on person entries: fac (faculty) · pd (postdoc) · s (PhD student) · a (alumnus/a) |
urls |
Can be [] (empty) or contain one or more {"label": "...", "url": "..."} objects. |
The home page feed shows only items from the current and previous calendar year.
Adding or updating a person
PhD students — _data/phd_students.json:
{
"name": "Full Name",
"photo": "images/people/firstname_lastname.jpg",
"e-mail": "name@edu.ufes.br",
"orcid": "https://orcid.org/0000-0000-0000-0000",
"cv_lattes": "http://lattes.cnpq.br/0000000000000000",
"website": "https://...",
"country": "Brazil",
"fellowship": "CAPES",
"enrolment": "2026-08",
"advisor": "Advisor Name",
"coadvisor": "Co-advisor Name",
"qualifying": "2025-04",
"grad_institution": "UFES",
"grad_country": "Brazil",
"masters_institution": "UFES",
"masters_country": "Brazil"
}Only name and photo are required — keep the other fields when editing an existing entry, they are not decoration. Five of them appear on the People page as small icons under the student’s name:
| Field | Shown as |
|---|---|
e-mail |
envelope icon (address is assembled in the browser, never plain in the HTML) |
cv_lattes |
Lattes icon — full URL |
orcid |
ORCID icon — store the full URL, not the bare id |
website |
globe icon — full URL, including https:// |
qualifying |
check mark for the qualifying exam — see below |
Any of these may be left out or empty; the icon is simply omitted.
The qualifying check mark
qualifying holds the date of the exam, "YYYY-MM", or "" if it has not happened. The page turns that into one of three states, using enrolment to tell the two empty cases apart:
- Green check — a date is filled in. Hovering shows it, e.g. Qualifying exam passed (Apr 2025).
- Grey check — no date, and
enrolmentis 2023-01 or later, so the exam is still ahead of the student. Hover reads Qualifying to be done. - No mark — no date, and
enrolmentis before 2023-01. Qualifying dates were not recorded back then, so an empty field means “unrecorded” rather than “pending”.
That 2023-01 boundary is QUALIFYING_RECORDS_FROM in people.qmd — the date from which qualifying dates started being recorded. It should not normally change. Everything else is worked out from the JSON at render time, so adding a student or filling in a qualifying date is the only edit ever needed — the marks update by themselves on the next publish.
The public page deliberately shows only “done” or “to be done”, never how late a student is. For that, the coordination runs python3 tools/qualifying_report.py locally — see Coordinator tools below.
Set "student_representative": true to also list a student under Student Representatives.
Faculty in Brazil — _data/faculty_brazil.json:
{"name": "Full Name", "affiliation": "Institution", "url": "https://...", "orcid": "0000-0000-0000-0000"}Current postdocs — _data/postdocs.json (same structure as PhD students).
Previous postdocs — _data/postdocs_previous.json.
Alumni — _data/alumni.json.
International collaborators — _data/collaborators.json.
Profile photos
- Place the file in
images/people/using the formatfirstname_lastname.jpg(lowercase, no accents, no spaces). - Any common format works (jpg, jpeg, png). Photos are displayed as 90×90 px circles.
Updating the applications page
Edit applications.qmd directly. It is plain Markdown with a short YAML header.
Updating the coordination
Edit _data/organization.json.
Coordinator tools
python3 tools/qualifying_report.pyLists every PhD student by qualifying status — overdue, due soon, on track, no record, passed — with each one’s deadline (enrolment + 24 months), how many months are left or overdue, and their advisor. It reads _data/phd_students.json, prints to the terminal and writes no files.
Keep it a script, not a page. The People page intentionally shows only “done” or “to be done”; ranking named students by lateness is for the coordination, not for the public site. Because quarto render only walks .qmd files, and _quarto.yml copies just images/** and CNAME, a .py here cannot end up in _site/ by accident.
Local preview
Install Quarto and Python with Jupyter:
pip install jupyter
quarto preview # live preview with auto-reload at localhost:4200To do a full build without serving:
quarto render # output goes to _site/Deployment
Pushing to main triggers the GitHub Actions workflow in .github/workflows/publish.yml, which renders the site and publishes it to GitHub Pages. No manual step is needed. All contributors who commit to the repository will appear in the contributors graph.