Skip to content

Commit ae197d6

Browse files
authored
Use forwards theme (#11)
1 parent 2f81f13 commit ae197d6

9 files changed

Lines changed: 701 additions & 13 deletions

File tree

_freeze/site_libs/clipboard/clipboard.min.js

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_freeze/site_libs/quarto-listing/list.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
const kProgressiveAttr = "data-src";
2+
let categoriesLoaded = false;
3+
4+
window.quartoListingCategory = (category) => {
5+
// category is URI encoded in EJS template for UTF-8 support
6+
category = decodeURIComponent(atob(category));
7+
if (categoriesLoaded) {
8+
activateCategory(category);
9+
setCategoryHash(category);
10+
}
11+
};
12+
13+
window["quarto-listing-loaded"] = () => {
14+
// Process any existing hash
15+
const hash = getHash();
16+
17+
if (hash) {
18+
// If there is a category, switch to that
19+
if (hash.category) {
20+
// category hash are URI encoded so we need to decode it before processing
21+
// so that we can match it with the category element processed in JS
22+
activateCategory(decodeURIComponent(hash.category));
23+
}
24+
// Paginate a specific listing
25+
const listingIds = Object.keys(window["quarto-listings"]);
26+
for (const listingId of listingIds) {
27+
const page = hash[getListingPageKey(listingId)];
28+
if (page) {
29+
showPage(listingId, page);
30+
}
31+
}
32+
}
33+
34+
const listingIds = Object.keys(window["quarto-listings"]);
35+
for (const listingId of listingIds) {
36+
// The actual list
37+
const list = window["quarto-listings"][listingId];
38+
39+
// Update the handlers for pagination events
40+
refreshPaginationHandlers(listingId);
41+
42+
// Render any visible items that need it
43+
renderVisibleProgressiveImages(list);
44+
45+
// Whenever the list is updated, we also need to
46+
// attach handlers to the new pagination elements
47+
// and refresh any newly visible items.
48+
list.on("updated", function () {
49+
renderVisibleProgressiveImages(list);
50+
setTimeout(() => refreshPaginationHandlers(listingId));
51+
52+
// Show or hide the no matching message
53+
toggleNoMatchingMessage(list);
54+
});
55+
}
56+
};
57+
58+
window.document.addEventListener("DOMContentLoaded", function (_event) {
59+
// Attach click handlers to categories
60+
const categoryEls = window.document.querySelectorAll(
61+
".quarto-listing-category .category"
62+
);
63+
64+
for (const categoryEl of categoryEls) {
65+
// category needs to support non ASCII characters
66+
const category = decodeURIComponent(
67+
atob(categoryEl.getAttribute("data-category"))
68+
);
69+
categoryEl.onclick = () => {
70+
activateCategory(category);
71+
setCategoryHash(category);
72+
};
73+
}
74+
75+
// Attach a click handler to the category title
76+
// (there should be only one, but since it is a class name, handle N)
77+
const categoryTitleEls = window.document.querySelectorAll(
78+
".quarto-listing-category-title"
79+
);
80+
for (const categoryTitleEl of categoryTitleEls) {
81+
categoryTitleEl.onclick = () => {
82+
activateCategory("");
83+
setCategoryHash("");
84+
};
85+
}
86+
87+
categoriesLoaded = true;
88+
});
89+
90+
function toggleNoMatchingMessage(list) {
91+
const selector = `#${list.listContainer.id} .listing-no-matching`;
92+
const noMatchingEl = window.document.querySelector(selector);
93+
if (noMatchingEl) {
94+
if (list.visibleItems.length === 0) {
95+
noMatchingEl.classList.remove("d-none");
96+
} else {
97+
if (!noMatchingEl.classList.contains("d-none")) {
98+
noMatchingEl.classList.add("d-none");
99+
}
100+
}
101+
}
102+
}
103+
104+
function setCategoryHash(category) {
105+
setHash({ category });
106+
}
107+
108+
function setPageHash(listingId, page) {
109+
const currentHash = getHash() || {};
110+
currentHash[getListingPageKey(listingId)] = page;
111+
setHash(currentHash);
112+
}
113+
114+
function getListingPageKey(listingId) {
115+
return `${listingId}-page`;
116+
}
117+
118+
function refreshPaginationHandlers(listingId) {
119+
const listingEl = window.document.getElementById(listingId);
120+
const paginationEls = listingEl.querySelectorAll(
121+
".pagination li.page-item:not(.disabled) .page.page-link"
122+
);
123+
for (const paginationEl of paginationEls) {
124+
paginationEl.onclick = (sender) => {
125+
setPageHash(listingId, sender.target.getAttribute("data-i"));
126+
showPage(listingId, sender.target.getAttribute("data-i"));
127+
return false;
128+
};
129+
}
130+
}
131+
132+
function renderVisibleProgressiveImages(list) {
133+
// Run through the visible items and render any progressive images
134+
for (const item of list.visibleItems) {
135+
const itemEl = item.elm;
136+
if (itemEl) {
137+
const progressiveImgs = itemEl.querySelectorAll(
138+
`img[${kProgressiveAttr}]`
139+
);
140+
for (const progressiveImg of progressiveImgs) {
141+
const srcValue = progressiveImg.getAttribute(kProgressiveAttr);
142+
if (srcValue) {
143+
progressiveImg.setAttribute("src", srcValue);
144+
}
145+
progressiveImg.removeAttribute(kProgressiveAttr);
146+
}
147+
}
148+
}
149+
}
150+
151+
function getHash() {
152+
// Hashes are of the form
153+
// #name:value|name1:value1|name2:value2
154+
const currentUrl = new URL(window.location);
155+
const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined;
156+
return parseHash(hashRaw);
157+
}
158+
159+
const kAnd = "&";
160+
const kEquals = "=";
161+
162+
function parseHash(hash) {
163+
if (!hash) {
164+
return undefined;
165+
}
166+
const hasValuesStrs = hash.split(kAnd);
167+
const hashValues = hasValuesStrs
168+
.map((hashValueStr) => {
169+
const vals = hashValueStr.split(kEquals);
170+
if (vals.length === 2) {
171+
return { name: vals[0], value: vals[1] };
172+
} else {
173+
return undefined;
174+
}
175+
})
176+
.filter((value) => {
177+
return value !== undefined;
178+
});
179+
180+
const hashObj = {};
181+
hashValues.forEach((hashValue) => {
182+
hashObj[hashValue.name] = decodeURIComponent(hashValue.value);
183+
});
184+
return hashObj;
185+
}
186+
187+
function makeHash(obj) {
188+
return Object.keys(obj)
189+
.map((key) => {
190+
return `${key}${kEquals}${obj[key]}`;
191+
})
192+
.join(kAnd);
193+
}
194+
195+
function setHash(obj) {
196+
const hash = makeHash(obj);
197+
window.history.pushState(null, null, `#${hash}`);
198+
}
199+
200+
function showPage(listingId, page) {
201+
const list = window["quarto-listings"][listingId];
202+
if (list) {
203+
list.show((page - 1) * list.page + 1, list.page);
204+
}
205+
}
206+
207+
function activateCategory(category) {
208+
// Deactivate existing categories
209+
const activeEls = window.document.querySelectorAll(
210+
".quarto-listing-category .category.active"
211+
);
212+
for (const activeEl of activeEls) {
213+
activeEl.classList.remove("active");
214+
}
215+
216+
// Activate this category
217+
const categoryEl = window.document.querySelector(
218+
`.quarto-listing-category .category[data-category='${btoa(
219+
encodeURIComponent(category)
220+
)}']`
221+
);
222+
if (categoryEl) {
223+
categoryEl.classList.add("active");
224+
}
225+
226+
// Filter the listings to this category
227+
filterListingCategory(category);
228+
}
229+
230+
function filterListingCategory(category) {
231+
const listingIds = Object.keys(window["quarto-listings"]);
232+
for (const listingId of listingIds) {
233+
const list = window["quarto-listings"][listingId];
234+
if (list) {
235+
if (category === "") {
236+
// resets the filter
237+
list.filter();
238+
} else {
239+
// filter to this category
240+
list.filter(function (item) {
241+
const itemValues = item.values();
242+
if (itemValues.categories !== null) {
243+
const categories = decodeURIComponent(
244+
atob(itemValues.categories)
245+
).split(",");
246+
return categories.includes(category);
247+
} else {
248+
return false;
249+
}
250+
});
251+
}
252+
}
253+
}
254+
}

_quarto.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ website:
2626
© 2024 Forwards, under [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) license.<br>
2727
2828
navbar:
29-
logo: /images/forwards.svg
29+
logo: /images/forwards_hex_solid_border.png
3030
logo-href: /index.html
3131
left:
3232
# - menu:
@@ -79,8 +79,9 @@ website:
7979
format:
8080
html:
8181
theme:
82-
light: cosmo
83-
dark: [darkly, theme-dark.scss] #cosmo
82+
light: forwards-light.scss
83+
dark: forwards-dark.scss
84+
highlight-style: forwards.theme
8485
css: styles.css
8586
toc: true
8687
email-obfuscation: references

forwards-dark.scss

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*-- scss:defaults --*/
2+
// Forwards colours
3+
$darkpurple: #200F48;
4+
$darkpurple30: #bcb7c8;
5+
$verydarkpurple: #0C0721;
6+
7+
$plum: #A5317D;
8+
$pink: #D2436F;
9+
$red: #E95A61;
10+
$orange: #FD9567;
11+
$peach: #FDC88D;
12+
$yellow: #FEE4A7;
13+
14+
$blue: #3143A5;
15+
$green: #31A559;
16+
$purple: #5931A5;
17+
18+
$blue_dark: #222f73;
19+
$green_dark: #22733e;
20+
$red_dark: #a33f44;
21+
$orange_dark: #b16848;
22+
$peach_dark: #b18c63;
23+
$darkpurple_light: $darkpurple30;
24+
25+
$gray: #58595B;
26+
$gray_dark: #383838; // this is text colour used on main Warwick site
27+
$black: #000000;
28+
$gray20: #cccccc; // % of black
29+
$gray10: #e6e6e6; // % of black
30+
$gray05: #f2f2f2; // % of black
31+
$white: #ffffff;
32+
33+
$primary: $pink !default;
34+
35+
$body-color: $white;
36+
$body-bg: $verydarkpurple;
37+
$link-color: $pink;
38+
$code-color: $orange;
39+
$navbar-bg: $darkpurple;
40+
$navbar-fg: $yellow;
41+
42+
// Code blocks
43+
$code-block-bg: $white;
44+
45+
// Callouts
46+
$callout-color-note: $blue;
47+
$callout-color-caution: $peach;
48+
$callout-color-tip: $green;
49+
$callout-color-warning: $orange;
50+
$callout-color-important: $red;
51+
52+
div.callout.callout-style-default.callout-note.callout-titled > div.callout-header {
53+
background-color: $blue_dark !important;
54+
}
55+
56+
div.callout.callout-style-default.callout-warning.callout-titled > div.callout-header {
57+
background-color: $orange_dark !important;
58+
}
59+
60+
div.callout.callout-style-default.callout-important.callout-titled > div.callout-header {
61+
background-color: $red_dark !important;
62+
}
63+
64+
div.callout.callout-style-default.callout-tip.callout-titled > div.callout-header {
65+
background-color: $green_dark !important;
66+
}
67+
68+
div.callout.callout-style-default.callout-caution.callout-titled > div.callout-header {
69+
background-color: $peach_dark !important;
70+
}
71+
72+
// white icons in inverse mode
73+
.callout-icon::before {
74+
filter: brightness(0) invert(1);
75+
}
76+
77+
.callout-title p {
78+
color: $white !important;
79+
}

0 commit comments

Comments
 (0)