datalog-theme 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +26 -19
  5. data/_data/cdn-integrity.yml +0 -30
  6. data/_includes/analytics/dashboard.html +3 -1
  7. data/_includes/components/api-function.html +20 -1
  8. data/_includes/components/author-bio.html +2 -2
  9. data/_includes/components/enhanced-code-block.html +1 -1
  10. data/_includes/components/hero.html +19 -1
  11. data/_includes/csp-meta.html +115 -11
  12. data/_includes/footer.html +19 -20
  13. data/_includes/head.html +61 -29
  14. data/_includes/header/navigation.html +12 -15
  15. data/_includes/header.html +29 -20
  16. data/_includes/layouts/default/article.html +5 -1
  17. data/_includes/meta/math-config.html +27 -1
  18. data/_includes/meta/schema.html +5 -2
  19. data/_includes/meta/scripts-loader.html +16 -31
  20. data/_includes/post/related-posts.html +4 -7
  21. data/_includes/scripts.html +1 -9
  22. data/_includes/search/index-data.json +131 -0
  23. data/_includes/search/page.html +136 -0
  24. data/_layouts/dataset.html +1 -0
  25. data/_layouts/default.html +16 -8
  26. data/_layouts/home.html +6 -0
  27. data/_layouts/notebook.html +1 -0
  28. data/_layouts/package.html +1 -0
  29. data/_layouts/portfolio.html +1 -0
  30. data/_layouts/post.html +20 -5
  31. data/_layouts/project.html +2 -1
  32. data/_plugins/analytics_dashboard.rb +9 -3
  33. data/_plugins/config_validator.rb +12 -7
  34. data/_plugins/csp_generator.rb +18 -28
  35. data/_plugins/datalog_bibliography.rb +9 -7
  36. data/_plugins/datalog_comments.rb +8 -5
  37. data/_plugins/datalog_slides.rb +9 -8
  38. data/_plugins/i18n.rb +7 -8
  39. data/_plugins/image_optimizer.rb +17 -6
  40. data/_plugins/math_preprocessor.rb +36 -3
  41. data/_plugins/notebook_converter.rb +23 -43
  42. data/_plugins/plugin_loader.rb +3 -1
  43. data/_plugins/publications_generator.rb +8 -2
  44. data/_plugins/rouge_highlight_filter.rb +42 -0
  45. data/_plugins/search_code_blocks.rb +30 -0
  46. data/_plugins/search_normalizer.rb +15 -53
  47. data/_plugins/search_pages.rb +72 -0
  48. data/_sass/_academic-dashboard.scss +262 -0
  49. data/_sass/_base.scss +19 -1
  50. data/_sass/_components.scss +77 -1144
  51. data/_sass/_features.scss +17 -0
  52. data/_sass/_font-fallbacks.scss +43 -0
  53. data/_sass/_header.scss +10 -0
  54. data/_sass/_layout.scss +18 -12
  55. data/_sass/_mathematical.scss +1 -1
  56. data/_sass/_notebooks.scss +322 -0
  57. data/_sass/_open-science-badges.scss +56 -0
  58. data/_sass/{_phase1-enhancements.scss → _post-components.scss} +46 -1
  59. data/_sass/_search-page.scss +530 -0
  60. data/_sass/_search.scss +47 -1
  61. data/_sass/_syntax-highlighting.scss +212 -97
  62. data/_sass/_theme.scss +42 -18
  63. data/_sass/_typography.scss +14 -0
  64. data/_sass/_variables.scss +7 -4
  65. data/assets/css/main.scss +14 -0
  66. data/assets/img/hero-detail-640.webp +0 -0
  67. data/assets/img/hero-detail.webp +0 -0
  68. data/assets/img/social-card.png +0 -0
  69. data/assets/js/dist/academic.js +1 -0
  70. data/assets/js/dist/analytics-dashboard.js +1 -0
  71. data/assets/js/dist/chunks/chunk-225H5YXE.js +1 -0
  72. data/assets/js/dist/core.js +1 -0
  73. data/assets/js/dist/loader.js +1 -0
  74. data/assets/js/dist/math.js +1 -0
  75. data/assets/js/dist/notebook.js +1 -0
  76. data/assets/js/dist/search.js +1 -0
  77. data/assets/js/dist/visualizations.js +11 -0
  78. data/assets/js/loader.js +3 -1
  79. data/datalog-theme.gemspec +43 -22
  80. data/lib/datalog/cli.rb +53 -15
  81. data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
  82. data/lib/datalog/theme/package.rb +57 -0
  83. data/lib/datalog/theme/repository_checkout.rb +90 -0
  84. data/lib/datalog/theme/version.rb +1 -1
  85. data/lib/datalog/warning_filter.rb +5 -11
  86. data/lib/datalog-theme.rb +21 -0
  87. metadata +75 -146
  88. data/_data/academic.yml +0 -217
  89. data/_data/config/author.yml +0 -121
  90. data/_data/config/features.yml +0 -262
  91. data/_data/config/site.yml +0 -42
  92. data/_data/config/theme.yml +0 -181
  93. data/_data/datasets.yml +0 -28
  94. data/_data/js_meta.json +0 -371
  95. data/_data/navigation.yml +0 -145
  96. data/_data/projects.yml +0 -41
  97. data/_data/publications.yml +0 -28
  98. data/_data/social.yml +0 -73
  99. data/_data/visualizations.yml +0 -51
  100. data/_includes/components/advanced-search.html +0 -682
  101. data/_includes/components/bookmark-system.html +0 -96
  102. data/_includes/components/comments.html +0 -244
  103. data/_includes/components/content-recommendations.html +0 -228
  104. data/_includes/components/email-preferences.html +0 -200
  105. data/_includes/components/enhanced-metadata.html +0 -228
  106. data/_includes/components/language-switcher.html +0 -396
  107. data/_includes/components/navigation-enhancements.html +0 -454
  108. data/_includes/components/newsletter-signup.html +0 -178
  109. data/_includes/components/popular-posts.html +0 -233
  110. data/_includes/components/reading-progress.html +0 -133
  111. data/_includes/components/reading-time.html +0 -121
  112. data/_includes/components/series-navigation.html +0 -124
  113. data/_includes/components/social-proof.html +0 -34
  114. data/_includes/components/user-preferences.html +0 -566
  115. data/_layouts/archive.html +0 -282
  116. data/_layouts/post-sidebar.html +0 -183
  117. data/_sass/_phase3-enhancements.scss +0 -874
  118. data/_sass/_phase4-enhancements.scss +0 -1214
  119. data/_sass/_phase5-enhancements.scss +0 -414
  120. data/assets/img/20220607123041_detail.001.png +0 -0
  121. data/assets/js/academic.js +0 -262
  122. data/assets/js/analytics-dashboard.js +0 -382
  123. data/assets/js/core/dark-mode.js +0 -79
  124. data/assets/js/core/github-cards.js +0 -123
  125. data/assets/js/core/language-filter.js +0 -69
  126. data/assets/js/core/navigation.js +0 -184
  127. data/assets/js/core/scroll-progress.js +0 -45
  128. data/assets/js/core/search-hotkeys.js +0 -62
  129. data/assets/js/core/skip-links.js +0 -62
  130. data/assets/js/main.js +0 -23
  131. data/assets/js/math.js +0 -818
  132. data/assets/js/notebook.js +0 -158
  133. data/assets/js/search/analytics.js +0 -91
  134. data/assets/js/search/app.js +0 -271
  135. data/assets/js/search/autocomplete.js +0 -120
  136. data/assets/js/search/engine.js +0 -260
  137. data/assets/js/search/filters.js +0 -38
  138. data/assets/js/search/render.js +0 -217
  139. data/assets/js/search/utils.js +0 -99
  140. data/assets/js/search.js +0 -354
  141. data/assets/js/visualizations.js +0 -816
  142. data/assets/publications/datalog-publications.bib +0 -8
  143. data/assets/publications/datalog-publications.ris +0 -9
  144. data/assets/publications/publications.bib +0 -30
  145. data/assets/templates/diogo-ribeiro-cv.md +0 -31
  146. data/assets/templates/diogo-ribeiro-cv.tex +0 -32
  147. data/lib/datalog/theme/theme.rb +0 -18
data/assets/js/search.js DELETED
@@ -1,354 +0,0 @@
1
- import { initializeSearchApp } from "./search/app.js";
2
-
3
- const DEBOUNCE_DELAY = 300;
4
- const RESULT_ID_PREFIX = "search-result-";
5
- const MIN_LOADING_VISIBLE_MS = 500;
6
-
7
- function debounce(callback, delay = DEBOUNCE_DELAY) {
8
- let timerId;
9
- const debounced = (...args) => {
10
- if (timerId) {
11
- window.clearTimeout(timerId);
12
- }
13
- timerId = window.setTimeout(() => {
14
- timerId = undefined;
15
- callback.apply(null, args);
16
- }, delay);
17
- };
18
-
19
- debounced.cancel = () => {
20
- if (timerId) {
21
- window.clearTimeout(timerId);
22
- timerId = undefined;
23
- }
24
- };
25
-
26
- return debounced;
27
- }
28
-
29
- function updateLiveRegion(region, message) {
30
- if (!region) {
31
- return;
32
- }
33
- const text = String(message || "");
34
- if (region.textContent === text) {
35
- region.textContent = `${text}\u00A0`;
36
- } else {
37
- region.textContent = text;
38
- }
39
- if (text.trim()) {
40
- region.removeAttribute("hidden");
41
- } else {
42
- region.setAttribute("hidden", "");
43
- }
44
- }
45
-
46
- function setupSearchEnhancements() {
47
- const app = document.querySelector("[data-search-app]");
48
- if (!app) {
49
- return;
50
- }
51
-
52
- const form = app.querySelector("[data-search-form]");
53
- const input = app.querySelector("[data-search-input]");
54
- const resultsList = app.querySelector("[data-search-results]");
55
- const emptyState = app.querySelector("[data-search-empty]");
56
- const loadingIndicator = app.querySelector("[data-search-loading]");
57
- const resultsRegion = app.querySelector("[data-search-region]");
58
- const liveCount = app.querySelector('[data-search-live="count"]');
59
- const liveSelection = app.querySelector('[data-search-live="selection"]');
60
- const liveStatus = app.querySelector('[data-search-live="status"]');
61
- const filtersContainer = app.querySelector("[data-search-filters]");
62
- const tagContainer = app.querySelector("[data-filter-tags]");
63
-
64
- if (!input || !resultsList) {
65
- return;
66
- }
67
-
68
- let activeIndex = -1;
69
- let resultIdCounter = 0;
70
- let resultItems = [];
71
- let pendingSearch = false;
72
- let filterControls = [];
73
- let loadingStartedAt = 0;
74
- let loadingHideTimer = null;
75
-
76
- const debouncedSubmit = debounce(() => {
77
- if (!form) {
78
- return;
79
- }
80
- pendingSearch = true;
81
- showLoading();
82
- updateLiveRegion(liveStatus, "Loading results…");
83
- form.dispatchEvent(new Event("submit", { cancelable: true }));
84
- });
85
-
86
- const observer = new MutationObserver(() => {
87
- refreshResultItems();
88
- });
89
- observer.observe(resultsList, { childList: true });
90
-
91
- refreshResultItems();
92
- refreshFilterControls();
93
-
94
- if (tagContainer) {
95
- const tagObserver = new MutationObserver(() => {
96
- refreshFilterControls();
97
- });
98
- tagObserver.observe(tagContainer, { childList: true });
99
- }
100
-
101
- input.addEventListener("input", () => {
102
- clearActiveResult(false);
103
- debouncedSubmit();
104
- });
105
-
106
- input.addEventListener("keydown", (event) => {
107
- if (handleInputNavigation(event)) {
108
- return;
109
- }
110
- if (event.key === "Tab" && filterControls.length > 0) {
111
- event.preventDefault();
112
- const nextIndex = event.shiftKey ? filterControls.length - 1 : 0;
113
- filterControls[nextIndex].focus();
114
- }
115
- });
116
-
117
- function handleFilterKeydown(event) {
118
- if (event.key !== "Tab" || filterControls.length === 0) {
119
- return;
120
- }
121
- event.preventDefault();
122
- const currentIndex = filterControls.indexOf(event.currentTarget);
123
- if (currentIndex === -1) {
124
- return;
125
- }
126
- const direction = event.shiftKey ? -1 : 1;
127
- const nextIndex = (currentIndex + direction + filterControls.length) % filterControls.length;
128
- filterControls[nextIndex].focus();
129
- }
130
-
131
- function refreshFilterControls() {
132
- if (!filtersContainer) {
133
- return;
134
- }
135
- const selects = Array.from(filtersContainer.querySelectorAll("select"));
136
- const tags = tagContainer ? Array.from(tagContainer.querySelectorAll("[data-filter-tag]")) : [];
137
- filterControls = [...selects, ...tags];
138
- filterControls.forEach((control) => {
139
- control.removeEventListener("keydown", handleFilterKeydown);
140
- control.addEventListener("keydown", handleFilterKeydown);
141
- });
142
- }
143
-
144
- function handleInputNavigation(event) {
145
- if (!resultItems.length && ["ArrowDown", "ArrowUp", "Enter"].includes(event.key)) {
146
- return false;
147
- }
148
- switch (event.key) {
149
- case "ArrowDown":
150
- event.preventDefault();
151
- moveActive(1);
152
- return true;
153
- case "ArrowUp":
154
- event.preventDefault();
155
- moveActive(-1);
156
- return true;
157
- case "Enter":
158
- if (activeIndex >= 0) {
159
- event.preventDefault();
160
- openActiveResult();
161
- return true;
162
- }
163
- return false;
164
- case "Escape":
165
- event.preventDefault();
166
- clearSearch();
167
- return true;
168
- default:
169
- return false;
170
- }
171
- }
172
-
173
- function moveActive(delta) {
174
- if (!resultItems.length) {
175
- return;
176
- }
177
- const nextIndex = activeIndex === -1 ? (delta > 0 ? 0 : resultItems.length - 1) : (activeIndex + delta + resultItems.length) % resultItems.length;
178
- setActiveResult(nextIndex);
179
- }
180
-
181
- function setActiveResult(index) {
182
- if (index < -1 || index >= resultItems.length) {
183
- return;
184
- }
185
- if (activeIndex === index) {
186
- return;
187
- }
188
- if (activeIndex >= 0 && resultItems[activeIndex]) {
189
- resultItems[activeIndex].classList.remove("is-active");
190
- }
191
- activeIndex = index;
192
- if (activeIndex >= 0) {
193
- const item = resultItems[activeIndex];
194
- if (!item) {
195
- return;
196
- }
197
- item.classList.add("is-active");
198
- const id = ensureResultId(item);
199
- input.setAttribute("aria-activedescendant", id);
200
- const title = getResultTitle(item);
201
- updateLiveRegion(liveSelection, `Result ${activeIndex + 1} of ${resultItems.length}: ${title}`);
202
- item.scrollIntoView({ block: "nearest" });
203
- } else {
204
- input.removeAttribute("aria-activedescendant");
205
- updateLiveRegion(liveSelection, "Search results selection cleared.");
206
- }
207
- }
208
-
209
- function clearActiveResult(announce = true) {
210
- if (activeIndex >= 0 && resultItems[activeIndex]) {
211
- resultItems[activeIndex].classList.remove("is-active");
212
- }
213
- activeIndex = -1;
214
- input.removeAttribute("aria-activedescendant");
215
- if (announce) {
216
- updateLiveRegion(liveSelection, "Search results selection cleared.");
217
- }
218
- }
219
-
220
- function ensureResultId(item) {
221
- if (item.id) {
222
- return item.id;
223
- }
224
- resultIdCounter += 1;
225
- const id = `${RESULT_ID_PREFIX}${resultIdCounter}`;
226
- item.id = id;
227
- return id;
228
- }
229
-
230
- function refreshResultItems() {
231
- resultItems = Array.from(resultsList.querySelectorAll(".search-result"));
232
- resultItems.forEach((item) => {
233
- ensureResultId(item);
234
- item.setAttribute("role", "option");
235
- item.setAttribute("tabindex", "-1");
236
- });
237
- if (activeIndex >= resultItems.length) {
238
- clearActiveResult(false);
239
- }
240
- if (pendingSearch) {
241
- pendingSearch = false;
242
- updateLiveRegion(liveStatus, "Results updated.");
243
- }
244
- hideLoading();
245
- announceCount();
246
- }
247
-
248
- function announceCount() {
249
- if (!liveCount) {
250
- return;
251
- }
252
- const query = input.value.trim();
253
- if (!query) {
254
- updateLiveRegion(liveCount, "Enter a query to begin.");
255
- return;
256
- }
257
- if (emptyState && !emptyState.hidden && resultItems.length === 0) {
258
- updateLiveRegion(liveCount, `No results found for “${query}”.`);
259
- return;
260
- }
261
- updateLiveRegion(liveCount, `${resultItems.length} result${resultItems.length === 1 ? "" : "s"} found for “${query}”.`);
262
- }
263
-
264
- function showLoading() {
265
- if (resultsRegion) {
266
- resultsRegion.setAttribute("aria-busy", "true");
267
- }
268
- if (loadingIndicator) {
269
- if (loadingHideTimer) {
270
- window.clearTimeout(loadingHideTimer);
271
- loadingHideTimer = null;
272
- }
273
- loadingStartedAt = Date.now();
274
- loadingIndicator.hidden = false;
275
- loadingIndicator.removeAttribute("hidden");
276
- }
277
- }
278
-
279
- function hideLoading() {
280
- if (resultsRegion) {
281
- resultsRegion.setAttribute("aria-busy", "false");
282
- }
283
- if (loadingIndicator) {
284
- const finalize = () => {
285
- loadingIndicator.hidden = true;
286
- loadingIndicator.setAttribute("hidden", "");
287
- loadingHideTimer = null;
288
- loadingStartedAt = 0;
289
- };
290
- const elapsed = loadingStartedAt ? Date.now() - loadingStartedAt : MIN_LOADING_VISIBLE_MS;
291
- if (elapsed < MIN_LOADING_VISIBLE_MS) {
292
- const remaining = MIN_LOADING_VISIBLE_MS - elapsed;
293
- if (loadingHideTimer) {
294
- window.clearTimeout(loadingHideTimer);
295
- }
296
- loadingHideTimer = window.setTimeout(finalize, remaining);
297
- } else {
298
- finalize();
299
- }
300
- }
301
- }
302
-
303
- function openActiveResult() {
304
- const item = activeIndex >= 0 ? resultItems[activeIndex] : null;
305
- if (!item) {
306
- return;
307
- }
308
- const link = item.querySelector("[data-result-link]");
309
- if (link && link.href) {
310
- window.location.assign(link.href);
311
- }
312
- }
313
-
314
- function clearSearch() {
315
- debouncedSubmit.cancel();
316
- input.value = "";
317
- clearActiveResult();
318
- updateLiveRegion(liveStatus, "Search cleared.");
319
- if (form) {
320
- pendingSearch = true;
321
- showLoading();
322
- form.dispatchEvent(new Event("submit", { cancelable: true }));
323
- }
324
- }
325
-
326
- function getResultTitle(item) {
327
- const link = item.querySelector("[data-result-link]");
328
- if (link && link.textContent) {
329
- return link.textContent.trim();
330
- }
331
- const heading = item.querySelector(".search-result__title");
332
- return heading && heading.textContent ? heading.textContent.trim() : "Result";
333
- }
334
- }
335
-
336
- const isTestEnvironment =
337
- typeof process !== "undefined" &&
338
- process.env &&
339
- (process.env.NODE_ENV === "test" || process.env.VITEST === "true");
340
-
341
- function onReady() {
342
- initializeSearchApp();
343
- setupSearchEnhancements();
344
- }
345
-
346
- if (!isTestEnvironment) {
347
- if (document.readyState === "loading") {
348
- document.addEventListener("DOMContentLoaded", onReady);
349
- } else {
350
- onReady();
351
- }
352
- }
353
-
354
- export { debounce, updateLiveRegion, setupSearchEnhancements };