Add course schedule feature to teaching page (#2258) (#3147)

Implements the course schedule feature requested in issue
#[2258](https://github.com/alshedivat/al-folio/issues/2258).

This PR adds a new course schedule feature to the al-folio theme,
allowing academics to easily create and display structured course
information.

**Changes:**
- Added a `courses` collection to organize and display academic courses
- Created course layout and display templates with responsive design
- Implemented organization by year and term with automatic sorting
- Added support for weekly schedule with topics and course materials
- Simplified documentation with a README for course creation

This feature makes it easier for academics to showcase their teaching
materials with a consistent, organized display of course schedules,
helping users create professional teaching pages without custom
implementation.

---------

Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
This commit is contained in:
Jiahao Zhang 2026-01-17 15:43:47 -06:00 committed by GitHub
parent 5be5124eb2
commit 0fe3c84636
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 549 additions and 15 deletions

View File

@ -409,6 +409,67 @@ Then in your landing page template:
{% endif %}
```
### Creating a teachings collection
The al-folio theme includes a pre-configured `_teachings/` collection for course pages. Each course is represented by a markdown file with frontmatter metadata. Here's how to add or modify courses:
#### Course file format
Create markdown files in `_teachings/` with the following structure:
```yaml
---
layout: course
title: Course Title
description: Course description
instructor: Your Name
year: 2023
term: Fall
location: Room 101
time: MWF 10:00-11:00
course_id: course-id # This should be unique
schedule:
- week: 1
date: Jan 10
topic: Introduction
description: Overview of course content and objectives
materials:
- name: Slides
url: /assets/pdf/example_pdf.pdf
- name: Reading
url: https://example.com/reading
- week: 2
date: Jan 17
topic: Topic 2
description: Description of this week's content
---
Additional course content, information, or resources can be added here as markdown.
```
#### Important course collection notes
1. Each course file must have a unique `course_id` in the frontmatter
2. Course files will be grouped by `year` on the teaching page
3. Within each year, courses are sorted by `term`
4. The content below the frontmatter (written in markdown) will appear on the individual course page
5. The schedule section will be automatically formatted into a table
#### Required fields
- `layout: course` — Must be set to use the course layout
- `title` — The course title
- `year` — The year the course was/will be taught (used for sorting)
- `course_id` — A unique identifier for the course
#### Optional fields
- `description` — A brief description of the course
- `instructor` — The course instructor's name
- `term` — The academic term (e.g., Fall, Spring, Summer)
- `location` — The course location
- `time` — The course meeting time
- `schedule` — A list of course sessions with details
### Collections with categories and tags
If you want to add category and tag support (like the blog posts have), you need to configure the `jekyll-archives` section in [\_config.yml](_config.yml). See how this is done with the `books` collection for reference. For more details, check the [jekyll-archives-v2 documentation](https://george-gca.github.io/jekyll-archives-v2/).

View File

@ -164,6 +164,8 @@ collections:
output: true
projects:
output: true
teachings:
output: true
# -----------------------------------------------------------------------------
# Jekyll settings

View File

@ -0,0 +1,71 @@
{% assign course = site.teachings | where: 'course_id', include.course_id | first %}
{% if course %}
<div class="course-schedule">
<h2>{{ course.title }}</h2>
{% if course.description %}
<div class="course-description">
{{ course.description | markdownify }}
</div>
{% endif %}
{% if course.instructor %}
<p><strong>Instructor:</strong> {{ course.instructor }}</p>
{% endif %}
{% if course.term %}
<p><strong>Term:</strong> {{ course.term }}</p>
{% endif %}
{% if course.schedule %}
<table class="table table-sm table-responsive">
<thead>
<tr>
<th>Week</th>
<th>Date</th>
<th>Topic</th>
<th>Materials</th>
</tr>
</thead>
<tbody>
{% for entry in course.schedule %}
<tr>
<td>{{ entry.week }}</td>
<td>{{ entry.date }}</td>
<td>
{% if entry.topic %}
<strong>{{ entry.topic }}</strong>
{% endif %}
{% if entry.description %}
<div class="schedule-description">{{ entry.description | markdownify }}</div>
{% endif %}
</td>
<td>
{% if entry.materials %}
<ul class="schedule-materials">
{% for material in entry.materials %}
<li>
{% if material.url %}
{% if material.url contains '://' %}
<a href="{{ material.url }}" target="_blank">{{ material.name }}</a>
{% else %}
<a href="{{ material.url | relative_url }}" target="_blank">{{ material.name }}</a>
{% endif %}
{% else %}
{{ material.name }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No schedule available for this course.</p>
{% endif %}
</div>
{% endif %}

37
_includes/courses.liquid Normal file
View File

@ -0,0 +1,37 @@
{% if site.teachings %}
<div class="courses">
{% assign courses_by_year = site.teachings | sort: 'year' | reverse | group_by: 'year' %}
{% for year_group in courses_by_year %}
<h2 class="year">{{ year_group.name }}</h2>
<div class="course-list">
{% assign year_courses = year_group.items | sort: 'term' %}
{% for course in year_courses %}
<div class="course-item">
<h3 class="course-title">
<a href="{{ course.url | relative_url }}">{{ course.title }}</a>
</h3>
<div class="course-meta">
{% if course.term %}
<span class="course-term">{{ course.term }}</span>
{% endif %}
{% if course.instructor %}
<span class="course-instructor">{{ course.instructor }}</span>
{% endif %}
</div>
{% if course.description %}
<div class="course-description">
{{ course.description | markdownify }}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% else %}
<p>No courses available yet.</p>
{% endif %}

75
_layouts/course.liquid Normal file
View File

@ -0,0 +1,75 @@
---
layout: page
---
<div class="course">
{% if page.instructor or page.term or page.location or page.time %}
<div class="course-info">
{% if page.instructor %}
<p><strong>Instructor:</strong> {{ page.instructor }}</p>
{% endif %}
{% if page.term %}
<p><strong>Term:</strong> {{ page.term }}</p>
{% endif %}
{% if page.location %}
<p><strong>Location:</strong> {{ page.location }}</p>
{% endif %}
{% if page.time %}
<p><strong>Time:</strong> {{ page.time }}</p>
{% endif %}
</div>
{% endif %}
{{ content }}
{% if page.schedule %}
<h2>Schedule</h2>
<table class="table table-sm table-responsive">
<thead>
<tr>
<th>Week</th>
<th>Date</th>
<th>Topic</th>
<th>Materials</th>
</tr>
</thead>
<tbody>
{% for entry in page.schedule %}
<tr>
<td>{{ entry.week }}</td>
<td>{{ entry.date }}</td>
<td>
{% if entry.topic %}
<strong>{{ entry.topic }}</strong>
{% endif %}
{% if entry.description %}
<div class="schedule-description">{{ entry.description | markdownify }}</div>
{% endif %}
</td>
<td>
{% if entry.materials %}
<ul class="schedule-materials">
{% for material in entry.materials %}
<li>
{% if material.url %}
{% if material.url contains '://' %}
<a href="{{ material.url }}" target="_blank">{{ material.name }}</a>
{% else %}
<a href="{{ material.url | relative_url }}" target="_blank">{{ material.name }}</a>
{% endif %}
{% else %}
{{ material.name }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>

View File

@ -11,7 +11,7 @@ layout: default
{% if page.cv_pdf contains '://' %}
href="{{ page.cv_pdf }}"
{% else %}
href="{{ page.cv_pdf | prepend: 'assets/pdf/' | relative_url }}"
href="{{ page.cv_pdf | relative_url }}"
{% endif %}
target="_blank"
rel="noopener noreferrer"
@ -62,7 +62,7 @@ layout: default
{% if page.cv_pdf contains '://' %}
href="{{ page.cv_pdf }}"
{% else %}
href="{{ page.cv_pdf | prepend: 'assets/pdf/' | relative_url }}"
href="{{ page.cv_pdf | relative_url }}"
{% endif %}
target="_blank"
rel="noopener noreferrer"

View File

@ -4,7 +4,7 @@ permalink: /cv/
title: cv
nav: true
nav_order: 5
cv_pdf: example_pdf.pdf # you can also use external links here
cv_pdf: /assets/pdf/example_pdf.pdf # you can also use external links here
description: This is a description of the page. You can modify it in '_pages/cv.md'. You can also change or remove the top pdf download button.
toc:
sidebar: left

View File

@ -2,11 +2,11 @@
layout: page
permalink: /teaching/
title: teaching
description: Materials for courses you taught. Replace this text with your description.
description: Course materials, schedules, and resources for classes taught.
nav: true
nav_order: 6
---
For now, this page is assumed to be a static description of your courses. You can convert it to a collection similar to `_projects/` so that you can have a dedicated page for each course.
This page displays a collection of courses with detailed schedules, materials, and resources. You can organize your courses by years, terms, or topics.
Organize your courses by years, topics, or universities, however you like!
{% include courses.liquid %}

77
_sass/_teachings.scss Normal file
View File

@ -0,0 +1,77 @@
/*****************************
* Teachings/Courses styles
*****************************/
.courses {
margin-top: 30px;
}
.year {
margin-top: 40px;
margin-bottom: 20px;
border-bottom: 1px solid var(--global-divider-color);
padding-bottom: 10px;
}
.course-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.course-item {
border: 1px solid var(--global-divider-color);
border-radius: 5px;
padding: 15px;
background-color: var(--global-bg-color);
transition: transform 0.2s ease-in-out;
&:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.05);
}
}
.course-title {
margin-top: 0;
margin-bottom: 10px;
}
.course-meta {
font-size: 0.9rem;
color: var(--global-text-color-light);
margin-bottom: 10px;
}
.course-term,
.course-instructor {
margin-right: 15px;
}
.course-description {
font-size: 0.9rem;
margin-bottom: 15px;
p {
margin-bottom: 0;
}
}
.course-info {
margin-bottom: 30px;
}
.course-schedule {
margin-bottom: 30px;
}
.schedule-description {
p {
margin-bottom: 0;
}
}
.schedule-materials {
padding-left: 18px;
margin-bottom: 0;
}

View File

@ -0,0 +1,97 @@
---
layout: course
title: Data Science Fundamentals
description: This course covers the foundational aspects of data science, including data collection, cleaning, analysis, and visualization. Students will learn practical skills for working with real-world datasets.
instructor: Prof. Data
year: 2024
term: Spring
location: Science Building, Room 202
time: Mondays and Wednesdays, 2:00-3:30 PM
course_id: data-science-fundamentals
schedule:
- week: 1
date: Feb 5
topic: Introduction to Data Science
description: Overview of the data science workflow and key concepts.
materials:
- name: Syllabus
url: /assets/pdf/example_pdf.pdf
- name: Slides
url: /assets/pdf/example_pdf.pdf
- week: 2
date: Feb 12
topic: Data Collection and APIs
description: Methods for collecting data through APIs, web scraping, and databases.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 1
url: /assets/pdf/example_pdf.pdf
- week: 3
date: Feb 19
topic: Data Cleaning and Preprocessing
description: Techniques for handling missing values, outliers, and data transformation.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Coding Lab
url: https://github.com/
- week: 4
date: Feb 26
topic: Exploratory Data Analysis
description: Descriptive statistics, visualization, and pattern discovery.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 2
url: /assets/pdf/example_pdf.pdf
- week: 5
date: Mar 4
topic: Statistical Analysis
description: Hypothesis testing, confidence intervals, and statistical inference.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Review Materials
url: /assets/pdf/example_pdf.pdf
- week: 6
date: Mar 11
topic: Data Visualization
description: Principles and tools for effective data visualization.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 3
url: /assets/pdf/example_pdf.pdf
---
## Course Overview
This course provides a comprehensive introduction to data science principles and practices. Students will:
- Learn the end-to-end data science workflow
- Gain practical experience with data manipulation tools
- Develop skills in data visualization and communication
- Apply statistical methods to derive insights from data
## Prerequisites
- Basic programming knowledge (preferably in Python)
- Introductory statistics
- Comfort with basic algebra
## Textbooks
- "Python for Data Analysis" by Wes McKinney
- "Data Science from Scratch" by Joel Grus
## Grading
- Assignments: 50%
- Project: 40%
- Participation: 10%

View File

@ -0,0 +1,113 @@
---
layout: course
title: Introduction to Machine Learning
description: This course provides an introduction to machine learning concepts, algorithms, and applications. Students will learn about supervised and unsupervised learning, model evaluation, and practical implementations.
instructor: Prof. Example
year: 2023
term: Fall
location: Main Campus, Room 301
time: Tuesdays and Thursdays, 10:00-11:30 AM
course_id: intro-machine-learning
schedule:
- week: 1
date: Sept 5
topic: Course Introduction
description: Overview of machine learning, course structure, and expectations.
materials:
- name: Syllabus
url: /assets/pdf/example_pdf.pdf
- name: Slides
url: /assets/pdf/example_pdf.pdf
- week: 2
date: Sept 12
topic: Linear Regression
description: Introduction to linear regression, gradient descent, and model evaluation.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 1
url: /assets/pdf/example_pdf.pdf
- week: 3
date: Sept 19
topic: Classification
description: Logistic regression, decision boundaries, and multi-class classification.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Coding Lab
url: https://github.com/
- week: 4
date: Sept 26
topic: Decision Trees and Random Forests
description: Tree-based methods, ensemble learning, and feature importance.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 2
url: /assets/pdf/example_pdf.pdf
- week: 5
date: Oct 3
topic: Support Vector Machines
description: Margin maximization, kernel methods, and support vectors.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Review Materials
url: /assets/pdf/example_pdf.pdf
- week: 6
date: Oct 10
topic: Midterm Exam
description: Covers weeks 1-5.
- week: 7
date: Oct 17
topic: Neural Networks Fundamentals
description: Perceptrons, multilayer networks, and backpropagation.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Assignment 3
url: /assets/pdf/example_pdf.pdf
- week: 8
date: Oct 24
topic: Deep Learning
description: Convolutional neural networks, recurrent neural networks, and applications.
materials:
- name: Lecture Notes
url: /assets/pdf/example_pdf.pdf
- name: Coding Lab
url: https://github.com/
---
## Course Overview
This introductory course on machine learning covers fundamental concepts and algorithms in the field. By the end of this course, students will be able to:
- Understand key machine learning paradigms and concepts
- Implement basic machine learning algorithms
- Evaluate and compare model performance
- Apply machine learning techniques to real-world problems
## Prerequisites
- Basic knowledge of linear algebra and calculus
- Programming experience in Python
- Probability and statistics fundamentals
## Textbooks
- Primary: "Machine Learning: A Probabilistic Perspective" by Kevin Murphy
- Reference: "Pattern Recognition and Machine Learning" by Christopher Bishop
## Grading
- Assignments: 40%
- Midterm Exam: 20%
- Final Project: 30%
- Participation: 10%

View File

@ -14,6 +14,7 @@ $max-content-width: {{ site.max_width }};
"distill",
"cv",
"tabs",
"teachings",
"typograms",
"font-awesome/fontawesome",
"font-awesome/brands",

18
package-lock.json generated
View File

@ -5,8 +5,8 @@
"packages": {
"": {
"devDependencies": {
"@shopify/prettier-plugin-liquid": "1.4.0",
"prettier": "^3.1.1"
"@shopify/prettier-plugin-liquid": "1.10.0",
"prettier": "^3.7.4"
}
},
"node_modules/@shopify/liquid-html-parser": {
@ -21,13 +21,13 @@
}
},
"node_modules/@shopify/prettier-plugin-liquid": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@shopify/prettier-plugin-liquid/-/prettier-plugin-liquid-1.4.0.tgz",
"integrity": "sha512-Fd0QiPi0bpSapUG0plri1+bLew9j//Q0MFKkBjkIG4RTJC76dycVysf5Dy7JvbvIjSJ4YFxaT0PBW5v9O7JItQ==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@shopify/prettier-plugin-liquid/-/prettier-plugin-liquid-1.10.0.tgz",
"integrity": "sha512-csHYjwuT34o8ja6EY0dUBYQS5UVwsKwRYxGiuG816Ov0B8lVd8FUjOwWUk2SnrNx3cGgL0no7z+Byapp7sC1Uw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@shopify/liquid-html-parser": "^2.0.0",
"@shopify/liquid-html-parser": "^2.9.0",
"html-styles": "^1.0.0"
},
"peerDependencies": {
@ -83,9 +83,9 @@
}
},
"node_modules/prettier": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.0.tgz",
"integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==",
"dev": true,
"license": "MIT",
"bin": {