Skip to content

Commit 8044ff1

Browse files
Copilotcycomachead
andauthored
feat: add archive banner based on semester date range
Agent-Logs-Url: https://github.com/berkeley-cdss/berkeley-class-site/sessions/b541e009-643e-4e51-a543-e291bb28f017 Co-authored-by: cycomachead <1505907+cycomachead@users.noreply.github.com>
1 parent 2087a8d commit 8044ff1

5 files changed

Lines changed: 149 additions & 5 deletions

File tree

_config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ gradescope_course_id: 123456 # you can find this in the Gradescope URL after /co
3636
bcourses_course_id: 123456 # Same as above, but for bCourses. Leave blank if not in use...
3737
ed_course_id: 123456 # Again, same as above.
3838
sememster: spYY | suYY | faYY # set for the current seemester
39+
semester_start_date: '2025-01-21' # Required for the archive banner logic (YYYY-MM-DD)
40+
semester_end_date: '2025-05-09' # Required for the archive banner logic (YYYY-MM-DD)
3941
# TODO(setup): Set this to the file path of your course logo image, or leave it blank to display your course name.
4042
# To edit the size and positioning of the logo/course name, see _sass/custom/course_overrides.scss
4143
logo: /assets/images/berkeley_walking_bear.png
@@ -45,6 +47,7 @@ course_department: dsus
4547
# This should be the page of all class archives
4648
# Typically just / for DS courses (with a visible index page), or /archives if you're hosting your own, or a link to the inst.eecs page
4749
# If you have no archive page, comment this line out or leave blank.
50+
# We recommend listing archived offerings as "Archive" or "Not Updated" in course listings.
4851
class_archive_path: /
4952

5053
# TODO(setup): Remove this line if your favicon is named favicon.ico and is in the root directory,

_includes/header_custom.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<div id="archive-banner" class="archive-banner" role="status">
2+
This site is archived. Please check:
3+
<a id="archive-banner-link" class="archive-banner-link" href="#"></a>
4+
</div>
5+
6+
<script>
7+
(() => {
8+
const semesterStart = {{ site.semester_start_date | jsonify }};
9+
const semesterEnd = {{ site.semester_end_date | jsonify }};
10+
const archivePath = {{ site.class_archive_path | jsonify }};
11+
12+
if (!semesterStart || !semesterEnd || !archivePath) {
13+
return;
14+
}
15+
16+
const parseDate = (value) => {
17+
const parsed = new Date(value);
18+
return Number.isNaN(parsed.getTime()) ? null : parsed;
19+
};
20+
21+
const startDate = parseDate(semesterStart);
22+
const endDate = parseDate(semesterEnd);
23+
if (!startDate || !endDate) {
24+
return;
25+
}
26+
27+
endDate.setHours(23, 59, 59, 999);
28+
const currentDate = new Date();
29+
const isOutsideSemester = currentDate < startDate || currentDate > endDate;
30+
if (!isOutsideSemester) {
31+
return;
32+
}
33+
34+
const archiveUrl = new URL(archivePath, window.location.origin).toString();
35+
const banner = document.getElementById('archive-banner');
36+
const archiveLink = document.getElementById('archive-banner-link');
37+
if (!banner || !archiveLink) {
38+
return;
39+
}
40+
41+
archiveLink.href = archiveUrl;
42+
archiveLink.textContent = archiveUrl;
43+
banner.style.display = 'block';
44+
document.body.classList.add('archive-banner-visible');
45+
})();
46+
</script>

_plugins/config_validator.rb

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'date'
4+
35
# A UC Berkeley-specific validator for Jekyll sites
46
# This class validates the following options:
57
# 1) Ensures required attributes are present in the config file.
@@ -44,7 +46,9 @@ class ConfigValidator
4446
url: :validate_clean_url,
4547
baseurl: :validate_semester_format,
4648
course_department: :inclusion_validator,
47-
color_scheme: :inclusion_validator
49+
color_scheme: :inclusion_validator,
50+
semester_start_date: :validate_iso8601_date,
51+
semester_end_date: :validate_iso8601_date
4852
}.freeze
4953

5054
attr_accessor :config, :errors
@@ -61,13 +65,15 @@ def validate
6165
send(validator, key, config[key.to_s]) if @config.key?(key.to_s)
6266
end
6367

68+
validate_semester_date_range
69+
6470
raise ConfigValidationError, errors if errors.length.positive?
6571

6672
puts 'Passed Berkeley YAML Config Validations'
6773
end
6874

6975
def validate_keys!
70-
required_keys = %i[baseurl course_department]
76+
required_keys = %i[baseurl course_department semester_start_date semester_end_date]
7177
required_keys.each do |key|
7278
errors << "#{key} is missing from site config" unless @config.key?(key.to_s)
7379
end
@@ -95,6 +101,27 @@ def inclusion_validator(key, value)
95101
allowed = self.class.const_get("VALID_#{key.upcase}")
96102
errors << "`#{key}` must be one of #{allowed} (not '#{value}')" unless allowed.include?(value)
97103
end
104+
105+
def validate_iso8601_date(key, value)
106+
return if parse_iso8601_date(value)
107+
108+
errors << "`#{key}` must be a valid ISO-8601 date string (YYYY-MM-DD), not '#{value}'"
109+
end
110+
111+
def validate_semester_date_range
112+
start_date = parse_iso8601_date(config['semester_start_date'])
113+
end_date = parse_iso8601_date(config['semester_end_date'])
114+
return unless start_date && end_date
115+
return unless start_date > end_date
116+
117+
errors << '`semester_start_date` must be on or before `semester_end_date`'
118+
end
119+
120+
def parse_iso8601_date(value)
121+
Date.iso8601(value.to_s)
122+
rescue Date::Error
123+
nil
124+
end
98125
end
99126
end
100127

_sass/custom/custom.scss

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,34 @@ p.note::before {
137137
@include btn-color($white, #6929c4);
138138
}
139139

140-
.btn-officehours{
141-
@include btn-color($white, #009d9a);
142-
}
140+
.btn-officehours{
141+
@include btn-color($white, #009d9a);
142+
}
143+
144+
.archive-banner {
145+
display: none;
146+
position: fixed;
147+
top: 0;
148+
right: 0;
149+
left: 0;
150+
z-index: 999;
151+
padding: 0.75rem 1rem;
152+
background-color: #d02670;
153+
color: #fff;
154+
font-weight: 700;
155+
text-align: center;
156+
}
157+
158+
.archive-banner-link,
159+
.archive-banner-link:visited {
160+
color: #fff;
161+
font-weight: 700;
162+
text-decoration: underline;
163+
}
164+
165+
body.archive-banner-visible {
166+
padding-top: 3rem;
167+
}
143168

144169
@if $color-scheme == dark {
145170
@include dark-mode-overrides;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require_relative '../../_plugins/config_validator'
5+
6+
RSpec.describe Jekyll::ConfigValidator do
7+
let(:base_config) do
8+
{
9+
'baseurl' => '/sp26',
10+
'course_department' => 'dsus',
11+
'semester_start_date' => '2026-01-21',
12+
'semester_end_date' => '2026-05-09'
13+
}
14+
end
15+
16+
it 'validates with required semester dates present' do
17+
validator = described_class.new(base_config)
18+
19+
expect { validator.validate }.not_to raise_error
20+
end
21+
22+
it 'requires semester_start_date and semester_end_date' do
23+
config = base_config.except('semester_start_date', 'semester_end_date')
24+
validator = described_class.new(config)
25+
26+
expect { validator.validate }
27+
.to raise_error(ConfigValidationError, /semester_start_date is missing.*semester_end_date is missing/m)
28+
end
29+
30+
it 'validates ISO-8601 semester dates' do
31+
validator = described_class.new(base_config.merge('semester_start_date' => 'spring-2026'))
32+
33+
expect { validator.validate }
34+
.to raise_error(ConfigValidationError, /`semester_start_date` must be a valid ISO-8601 date string/)
35+
end
36+
37+
it 'requires the start date to be on or before the end date' do
38+
validator = described_class.new(base_config.merge('semester_start_date' => '2026-06-01'))
39+
40+
expect { validator.validate }
41+
.to raise_error(ConfigValidationError, /`semester_start_date` must be on or before `semester_end_date`/)
42+
end
43+
end

0 commit comments

Comments
 (0)