datalog-theme 0.6.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 (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +162 -0
  3. data/CITATION.cff +29 -0
  4. data/LICENSE +21 -0
  5. data/README.md +257 -0
  6. data/_data/academic.yml +217 -0
  7. data/_data/cdn-integrity.yml +51 -0
  8. data/_data/config/author.yml +121 -0
  9. data/_data/config/features.yml +262 -0
  10. data/_data/config/site.yml +42 -0
  11. data/_data/config/theme.yml +181 -0
  12. data/_data/datasets.yml +28 -0
  13. data/_data/i18n/en.yml +438 -0
  14. data/_data/i18n/es.yml +438 -0
  15. data/_data/i18n/pt.yml +438 -0
  16. data/_data/js_manifest.json +22 -0
  17. data/_data/js_meta.json +371 -0
  18. data/_data/navigation.yml +145 -0
  19. data/_data/projects.yml +41 -0
  20. data/_data/publications.yml +28 -0
  21. data/_data/social.yml +73 -0
  22. data/_data/visualizations.yml +51 -0
  23. data/_includes/analytics/dashboard.html +149 -0
  24. data/_includes/analytics.html +9 -0
  25. data/_includes/components/academic-dashboard.html +347 -0
  26. data/_includes/components/advanced-search.html +682 -0
  27. data/_includes/components/api-function.html +94 -0
  28. data/_includes/components/author-bio.html +166 -0
  29. data/_includes/components/bookmark-system.html +96 -0
  30. data/_includes/components/breadcrumbs.html +89 -0
  31. data/_includes/components/citation-tools.html +94 -0
  32. data/_includes/components/comments.html +244 -0
  33. data/_includes/components/content-provenance.html +43 -0
  34. data/_includes/components/content-recommendations.html +228 -0
  35. data/_includes/components/difficulty-badge.html +84 -0
  36. data/_includes/components/email-preferences.html +200 -0
  37. data/_includes/components/enhanced-code-block.html +212 -0
  38. data/_includes/components/enhanced-metadata.html +228 -0
  39. data/_includes/components/enhanced-toc.html +209 -0
  40. data/_includes/components/hero.html +15 -0
  41. data/_includes/components/language-switcher.html +396 -0
  42. data/_includes/components/math-fallback.html +19 -0
  43. data/_includes/components/navigation-enhancements.html +454 -0
  44. data/_includes/components/newsletter-signup.html +178 -0
  45. data/_includes/components/open-science-badges.html +16 -0
  46. data/_includes/components/package-install.html +194 -0
  47. data/_includes/components/performance-monitor.html +170 -0
  48. data/_includes/components/popular-posts.html +233 -0
  49. data/_includes/components/post-hero.html +62 -0
  50. data/_includes/components/reading-progress.html +133 -0
  51. data/_includes/components/reading-time.html +121 -0
  52. data/_includes/components/responsive-image.html +63 -0
  53. data/_includes/components/search-facets.html +307 -0
  54. data/_includes/components/series-navigation.html +124 -0
  55. data/_includes/components/social-proof.html +34 -0
  56. data/_includes/components/social-share.html +119 -0
  57. data/_includes/components/user-preferences.html +566 -0
  58. data/_includes/components/visualization-card.html +24 -0
  59. data/_includes/components/viz-table-fallback.html +19 -0
  60. data/_includes/critical-css/default.html +0 -0
  61. data/_includes/critical-css/home.html +0 -0
  62. data/_includes/critical-css/post.html +0 -0
  63. data/_includes/csp-meta.html +17 -0
  64. data/_includes/footer/nav-column.html +31 -0
  65. data/_includes/footer.html +76 -0
  66. data/_includes/head.html +337 -0
  67. data/_includes/header/navigation.html +48 -0
  68. data/_includes/header.html +70 -0
  69. data/_includes/helpers/array-to-sentence.html +21 -0
  70. data/_includes/helpers/date-format.html +16 -0
  71. data/_includes/helpers/link-with-icon.html +26 -0
  72. data/_includes/layouts/default/article.html +67 -0
  73. data/_includes/meta/language-attributes.html +25 -0
  74. data/_includes/meta/math-config.html +21 -0
  75. data/_includes/meta/schema.html +153 -0
  76. data/_includes/meta/scripts-loader.html +52 -0
  77. data/_includes/post/related-posts.html +63 -0
  78. data/_includes/scripts.html +72 -0
  79. data/_includes/skip-link.html +1 -0
  80. data/_includes/toc.html +2 -0
  81. data/_layouts/archive.html +282 -0
  82. data/_layouts/dataset.html +52 -0
  83. data/_layouts/default.html +33 -0
  84. data/_layouts/home.html +48 -0
  85. data/_layouts/notebook.html +173 -0
  86. data/_layouts/package.html +238 -0
  87. data/_layouts/page.html +16 -0
  88. data/_layouts/portfolio.html +41 -0
  89. data/_layouts/post-sidebar.html +183 -0
  90. data/_layouts/post.html +338 -0
  91. data/_layouts/project.html +252 -0
  92. data/_layouts/research.html +504 -0
  93. data/_plugins/analytics_dashboard.rb +315 -0
  94. data/_plugins/config_validator.rb +397 -0
  95. data/_plugins/csp_generator.rb +115 -0
  96. data/_plugins/datalog_bibliography.rb +19 -0
  97. data/_plugins/datalog_comments.rb +18 -0
  98. data/_plugins/datalog_slides.rb +20 -0
  99. data/_plugins/front_matter_compat.rb +109 -0
  100. data/_plugins/i18n.rb +160 -0
  101. data/_plugins/image_optimizer.rb +445 -0
  102. data/_plugins/math_preprocessor.rb +185 -0
  103. data/_plugins/notebook_converter.rb +1107 -0
  104. data/_plugins/plugin_loader.rb +185 -0
  105. data/_plugins/publications_generator.rb +234 -0
  106. data/_plugins/reading_time.rb +15 -0
  107. data/_plugins/search_normalizer.rb +74 -0
  108. data/_plugins/sri_filter.rb +18 -0
  109. data/_plugins/toc_filter.rb +68 -0
  110. data/_plugins/warning_filter.rb +3 -0
  111. data/_sass/_base.scss +142 -0
  112. data/_sass/_components.scss +2380 -0
  113. data/_sass/_header.scss +470 -0
  114. data/_sass/_interactive.scss +344 -0
  115. data/_sass/_layout.scss +1760 -0
  116. data/_sass/_mathematical.scss +368 -0
  117. data/_sass/_mixins.scss +99 -0
  118. data/_sass/_package-docs.scss +715 -0
  119. data/_sass/_phase1-enhancements.scss +721 -0
  120. data/_sass/_phase3-enhancements.scss +874 -0
  121. data/_sass/_phase4-enhancements.scss +1214 -0
  122. data/_sass/_phase5-enhancements.scss +414 -0
  123. data/_sass/_search.scss +654 -0
  124. data/_sass/_syntax-highlighting.scss +128 -0
  125. data/_sass/_theme.scss +79 -0
  126. data/_sass/_typography.scss +148 -0
  127. data/_sass/_utilities.scss +334 -0
  128. data/_sass/_variables.scss +153 -0
  129. data/_sass/_visualizations.scss +242 -0
  130. data/assets/css/main.scss +4 -0
  131. data/assets/img/20220607123041_detail.001.png +0 -0
  132. data/assets/img/favicons/android-chrome-192x192.png +0 -0
  133. data/assets/img/favicons/android-chrome-512x512.png +0 -0
  134. data/assets/img/favicons/apple-touch-icon.png +0 -0
  135. data/assets/img/favicons/favicon-16x16.png +0 -0
  136. data/assets/img/favicons/favicon-32x32.png +0 -0
  137. data/assets/img/favicons/favicon.ico +0 -0
  138. data/assets/img/favicons/site.webmanifest +21 -0
  139. data/assets/img/portfolio-placeholder.svg +20 -0
  140. data/assets/js/academic.js +262 -0
  141. data/assets/js/analytics-dashboard.js +382 -0
  142. data/assets/js/core/dark-mode.js +79 -0
  143. data/assets/js/core/github-cards.js +123 -0
  144. data/assets/js/core/language-filter.js +69 -0
  145. data/assets/js/core/navigation.js +184 -0
  146. data/assets/js/core/scroll-progress.js +45 -0
  147. data/assets/js/core/search-hotkeys.js +62 -0
  148. data/assets/js/core/skip-links.js +62 -0
  149. data/assets/js/loader.js +163 -0
  150. data/assets/js/main.js +23 -0
  151. data/assets/js/math.js +818 -0
  152. data/assets/js/notebook.js +158 -0
  153. data/assets/js/search/analytics.js +91 -0
  154. data/assets/js/search/app.js +271 -0
  155. data/assets/js/search/autocomplete.js +120 -0
  156. data/assets/js/search/engine.js +260 -0
  157. data/assets/js/search/filters.js +38 -0
  158. data/assets/js/search/render.js +217 -0
  159. data/assets/js/search/utils.js +99 -0
  160. data/assets/js/search.js +354 -0
  161. data/assets/js/visualizations.js +816 -0
  162. data/assets/publications/datalog-publications.bib +8 -0
  163. data/assets/publications/datalog-publications.ris +9 -0
  164. data/assets/publications/publications.bib +30 -0
  165. data/assets/templates/diogo-ribeiro-cv.md +31 -0
  166. data/assets/templates/diogo-ribeiro-cv.tex +32 -0
  167. data/bin/datalog +26 -0
  168. data/datalog-theme.gemspec +72 -0
  169. data/lib/datalog/cli.rb +563 -0
  170. data/lib/datalog/plugin_system/dependency_resolver.rb +223 -0
  171. data/lib/datalog/plugin_system.rb +237 -0
  172. data/lib/datalog/plugins/citations.rb +182 -0
  173. data/lib/datalog/plugins/comments.rb +183 -0
  174. data/lib/datalog/plugins/search.rb +45 -0
  175. data/lib/datalog/plugins/slides.rb +121 -0
  176. data/lib/datalog/theme/theme.rb +18 -0
  177. data/lib/datalog/theme/version.rb +7 -0
  178. data/lib/datalog/warning_filter.rb +28 -0
  179. data/lib/datalog-theme.rb +17 -0
  180. metadata +555 -0
@@ -0,0 +1,76 @@
1
+ {% assign footer_site_name = site.title | default: site.name %}
2
+ {% assign footer_year = site.time | date: '%Y' %}
3
+ {% assign navigation_data = site.data.navigation %}
4
+ {% assign social_data = site.data.social %}
5
+ <footer class="site-footer" role="contentinfo">
6
+ <div class="container footer-container">
7
+ <section class="footer-about">
8
+ <h3>{{ site.name | default: 'DataLog' }}</h3>
9
+ <p class="footer-description">{{ site.description | strip_html | truncate: 160 }}</p>
10
+ <p class="footer-author">
11
+ <strong>{{ site.author.name }}</strong>
12
+ {% if site.author.affiliation %}
13
+ <span class="footer-affiliation">{{ site.author.affiliation }}</span>
14
+ {% endif %}
15
+ </p>
16
+ {% if site.author.orcid %}
17
+ <p class="footer-orcid">
18
+ <a href="{{ site.author.orcid }}" rel="me noopener" target="_blank">ORCID {{ site.author.orcid | replace: 'https://orcid.org/', '' }}</a>
19
+ </p>
20
+ {% endif %}
21
+ </section>
22
+
23
+ <nav class="footer-navigation">
24
+ <h3>Explore</h3>
25
+ {%- comment -%} `footer:` in _data/navigation.yml drives this column; the demo's sections are the fallback. {%- endcomment -%}
26
+ {% assign footer_links = navigation_data.footer %}
27
+ <ul class="footer-link-list">
28
+ {% if footer_links and footer_links.size > 0 %}
29
+ {% for item in footer_links %}
30
+ <li><a href="{{ item.url | relative_url }}">{{ item.title }}</a></li>
31
+ {% endfor %}
32
+ {% else %}
33
+ <li><a href="{{ '/blog/' | relative_url }}">Blog</a></li>
34
+ <li><a href="{{ '/research/' | relative_url }}">Research</a></li>
35
+ <li><a href="{{ '/portfolio/' | relative_url }}">Projects</a></li>
36
+ <li><a href="{{ '/datasets/' | relative_url }}">Datasets</a></li>
37
+ <li><a href="{{ '/visualizations/' | relative_url }}">Visualizations</a></li>
38
+ <li><a href="{{ '/about/' | relative_url }}">About</a></li>
39
+ {% endif %}
40
+ </ul>
41
+ </nav>
42
+
43
+ <section class="footer-connect">
44
+ <h3>Connect</h3>
45
+ {% assign primary_social = social_data.primary %}
46
+ {% if primary_social %}
47
+ <ul class="footer-link-list">
48
+ {% for profile in primary_social %}
49
+ <li><a href="{{ profile.url }}" target="_blank" rel="{{ profile.rel | default: 'noopener' }}">{{ profile.label }}</a></li>
50
+ {% endfor %}
51
+ </ul>
52
+ {% endif %}
53
+ {% if site.author.email %}
54
+ <p class="footer-contact">
55
+ <a href="mailto:{{ site.author.email }}">{{ site.author.email }}</a>
56
+ </p>
57
+ {% endif %}
58
+ </section>
59
+
60
+ <section class="footer-subscribe">
61
+ <h3>Stay updated</h3>
62
+ <p>Follow via RSS or check back for new research and tutorials.</p>
63
+ {% assign rss_links = social_data.rss %}
64
+ {% if rss_links %}
65
+ <ul class="footer-link-list">
66
+ {% for feed in rss_links %}
67
+ <li><a href="{{ feed.url | relative_url }}">{{ feed.label }}</a></li>
68
+ {% endfor %}
69
+ </ul>
70
+ {% endif %}
71
+ </section>
72
+ </div>
73
+ <div class="container footer-bottom">
74
+ <p>&copy; {{ footer_year }} {{ site.author.name }}. Built with the DataLog theme.</p>
75
+ </div>
76
+ </footer>
@@ -0,0 +1,337 @@
1
+ {% assign page_title = page.seo_title | default: page.title | default: site.title %}
2
+ {% assign page_description = page.seo_description | default: page.description | default: page.excerpt | default: site.description %}
3
+ {% assign canonical_url = page.url | default: page.permalink | default: '/' | absolute_url %}
4
+ {% assign raw_keywords = page.keywords | default: page.tags | default: site.keywords %}
5
+ {% assign localization_config = site.theme_options.localization %}
6
+ {% assign current_locale = page.lang | default: site.locale | default: localization_config.default_locale | default: 'en' %}
7
+ {% capture raw_keywords_json %}{{ raw_keywords | jsonify }}{% endcapture %}
8
+ {% if raw_keywords_json | slice: 0, 1 == '[' %}
9
+ {% assign keyword_list = raw_keywords %}
10
+ {% elsif raw_keywords %}
11
+ {% assign keyword_list = raw_keywords | replace: ';', ',' | split: ',' %}
12
+ {% endif %}
13
+ {% assign math_settings = site.theme_options.math %}
14
+ {% assign math_engine = page.math_engine | default: math_settings.engine | default: 'mathjax' %}
15
+ {% assign math_enabled = page.mathjax %}
16
+ {% if math_enabled == nil %}
17
+ {% assign math_enabled = page.math %}
18
+ {% endif %}
19
+ {% if math_enabled == nil %}
20
+ {% assign math_enabled = math_settings.render_on_load | default: site.features.mathjax %}
21
+ {% endif %}
22
+ {% assign js_manifest = site.data.js_manifest %}
23
+ {% assign syntax_config = site.theme_options.syntax_highlighting %}
24
+ {% assign prism_cdn = syntax_config.cdn | default: 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0' %}
25
+ {% assign prism_theme = syntax_config.themes.dark | default: syntax_config.themes.light | default: 'prism-tomorrow' %}
26
+ {% assign prism_theme_url = prism_cdn | append: '/themes/' | append: prism_theme | append: '.css' %}
27
+ {% assign prism_line_numbers_url = prism_cdn | append: '/plugins/line-numbers/prism-line-numbers.min.css' %}
28
+ <meta charset="utf-8" />
29
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
30
+ {% include csp-meta.html %}
31
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
32
+ <meta name="theme-color" content="#0b1d3d" />
33
+ <meta name="description" content="{{ page_description | strip_html | normalize_whitespace }}" />
34
+ <meta name="author" content="{{ page.author | default: site.author.name }}" />
35
+ {% if keyword_list %}
36
+ <meta name="keywords" content="{{ keyword_list | join: ', ' | strip }}" />
37
+ {% endif %}
38
+ <meta name="generator" content="Jekyll" />
39
+ <meta name="referrer" content="no-referrer-when-downgrade" />
40
+ <meta name="robots" content="index,follow" />
41
+ <meta name="format-detection" content="telephone=no" />
42
+ <meta name="application-name" content="{{ site.title }}" />
43
+ <meta property="og:site_name" content="{{ site.title }}" />
44
+ {% if page.layout == 'post' or page.collection == 'posts' %}
45
+ <meta property="og:type" content="article" />
46
+ {% else %}
47
+ <meta property="og:type" content="website" />
48
+ {% endif %}
49
+ <meta property="og:title" content="{{ page_title | strip_html | normalize_whitespace }}" />
50
+ <meta property="og:description" content="{{ page_description | strip_html | normalize_whitespace }}" />
51
+ <meta property="og:url" content="{{ canonical_url }}" />
52
+ {% if page.og_image or page.image %}
53
+ <meta property="og:image" content="{{ page.og_image | default: page.image | absolute_url }}" />
54
+ {% elsif site.social.default_image %}
55
+ <meta property="og:image" content="{{ site.social.default_image | absolute_url }}" />
56
+ {% endif %}
57
+ <meta property="og:locale" content="{{ site.locale | default: 'en_US' }}" />
58
+ <meta property="og:see_also" content="{{ site.url }}" />
59
+ <meta name="twitter:card" content="summary_large_image" />
60
+ <meta name="twitter:site" content="{{ site.social.twitter | default: site.twitter_username }}" />
61
+ <meta name="twitter:title" content="{{ page_title | strip_html | normalize_whitespace }}" />
62
+ <meta name="twitter:description" content="{{ page_description | strip_html | normalize_whitespace }}" />
63
+ {% if page.twitter_image or page.og_image or page.image %}
64
+ <meta name="twitter:image" content="{{ page.twitter_image | default: page.og_image | default: page.image | absolute_url }}" />
65
+ {% elsif site.social.default_image %}
66
+ <meta name="twitter:image" content="{{ site.social.default_image | absolute_url }}" />
67
+ {% endif %}
68
+ <link rel="canonical" href="{{ canonical_url }}" />
69
+ {% if js_manifest and js_manifest.core %}
70
+ <link rel="modulepreload" href="{{ js_manifest.core | relative_url }}" crossorigin="anonymous" />
71
+ {% if js_manifest.features and js_manifest.features.search and site.features.search %}
72
+ <link rel="modulepreload" href="{{ js_manifest.features.search | relative_url }}" crossorigin="anonymous" />
73
+ {% endif %}
74
+ {% if js_manifest.features and js_manifest.features.math and math_enabled and math_engine == 'mathjax' %}
75
+ <link rel="modulepreload" href="{{ js_manifest.features.math | relative_url }}" crossorigin="anonymous" />
76
+ {% endif %}
77
+ {% endif %}
78
+ {% assign alternate_translations = page.translations %}
79
+ {% if alternate_translations %}
80
+ {% for locale in alternate_translations %}
81
+ <link rel="alternate" hreflang="{{ locale.code }}" href="{{ locale.url | absolute_url }}" />
82
+ {% endfor %}
83
+ {% assign has_x_default = alternate_translations | where: 'code', 'x-default' | size %}
84
+ {% if has_x_default == 0 %}
85
+ <link rel="alternate" hreflang="x-default" href="{{ canonical_url }}" />
86
+ {% endif %}
87
+ {% endif %}
88
+ <link rel="apple-touch-icon" sizes="180x180" href="{{ '/assets/img/favicons/apple-touch-icon.png' | relative_url }}" />
89
+ <link rel="icon" type="image/png" sizes="32x32" href="{{ '/assets/img/favicons/favicon-32x32.png' | relative_url }}" />
90
+ <link rel="icon" type="image/png" sizes="16x16" href="{{ '/assets/img/favicons/favicon-16x16.png' | relative_url }}" />
91
+ <link rel="manifest" href="{{ '/assets/img/favicons/site.webmanifest' | relative_url }}" />
92
+ <link rel="shortcut icon" href="{{ '/assets/img/favicons/favicon.ico' | relative_url }}" />
93
+ <meta name="msapplication-TileColor" content="#0b1d3d" />
94
+
95
+ {% if page.seo_title %}
96
+ <title>{{ page.seo_title | strip_html | normalize_whitespace }} | {{ site.title }}</title>
97
+ {% elsif page.title and page.title != site.title %}
98
+ <title>{{ page.title | strip_html | normalize_whitespace }} | {{ site.title }}</title>
99
+ {% else %}
100
+ <title>{{ site.title }}</title>
101
+ {% endif %}
102
+
103
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
104
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
105
+ <link rel="preload" href="{{ 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap' | add_sri }}" as="style" />
106
+ <link rel="stylesheet" href="{{ 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap' | add_sri }}" media="print" data-async-style />
107
+ <noscript>
108
+ <link rel="stylesheet" href="{{ 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Serif:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap' | add_sri }}" />
109
+ </noscript>
110
+
111
+ <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
112
+ <link rel="stylesheet" href="{{ prism_theme_url | add_sri }}" />
113
+ <link rel="stylesheet" href="{{ prism_line_numbers_url | add_sri }}" />
114
+ {% assign critical_config = site.critical_css | default: {} %}
115
+ {% assign critical_enabled = critical_config.enabled | default: false %}
116
+ {% assign main_stylesheet = '/assets/css/main.css' | relative_url %}
117
+ {% assign normalized_layout = page.layout | default: 'default' %}
118
+ {% assign critical_target = nil %}
119
+ {% if critical_enabled %}
120
+ {% if normalized_layout == 'home' %}
121
+ {% assign critical_target = 'home' %}
122
+ {% elsif normalized_layout == 'post' %}
123
+ {% assign critical_target = 'post' %}
124
+ {% else %}
125
+ {% assign critical_target = 'default' %}
126
+ {% endif %}
127
+ {% endif %}
128
+ {% assign critical_styles = '' %}
129
+ {% if critical_target == 'home' %}
130
+ {% capture critical_styles %}{% include critical-css/home.html %}{% endcapture %}
131
+ {% elsif critical_target == 'post' %}
132
+ {% capture critical_styles %}{% include critical-css/post.html %}{% endcapture %}
133
+ {% elsif critical_target == 'default' %}
134
+ {% capture critical_styles %}{% include critical-css/default.html %}{% endcapture %}
135
+ {% endif %}
136
+ {% assign trimmed_critical = critical_styles | strip %}
137
+ {% if trimmed_critical != '' %}
138
+ <style data-critical-css="{{ critical_target }}" nonce="{{ page.csp_nonce }}">
139
+ {{ trimmed_critical }}
140
+ </style>
141
+ {% endif %}
142
+ {% if trimmed_critical != '' %}
143
+ <link rel="preload" href="{{ main_stylesheet }}" as="style" />
144
+ <link rel="stylesheet" href="{{ main_stylesheet }}" media="print" data-async-style />
145
+ <noscript>
146
+ <link rel="stylesheet" href="{{ main_stylesheet }}" />
147
+ </noscript>
148
+ {% else %}
149
+ <link rel="stylesheet" href="{{ main_stylesheet }}" />
150
+ {% endif %}
151
+
152
+ {%- comment -%}
153
+ Async CSS promoter. The stylesheets above ship as media="print" so they do not
154
+ block first paint, then switch to media="all" once loaded. This has to run
155
+ from a nonced script: the CSP sets no 'unsafe-inline' in script-src, so the
156
+ inline onload="this.media='all'" handlers this replaces never fired, leaving
157
+ the main stylesheet stuck on print whenever critical CSS was inlined.
158
+ {%- endcomment -%}
159
+ <script nonce="{{ page.csp_nonce }}">
160
+ (function () {
161
+ var links = document.querySelectorAll('link[data-async-style]');
162
+ Array.prototype.forEach.call(links, function (link) {
163
+ var promote = function () { link.media = 'all'; };
164
+ if (link.sheet) {
165
+ promote();
166
+ } else {
167
+ link.addEventListener('load', promote, { once: true });
168
+ }
169
+ });
170
+ })();
171
+ </script>
172
+
173
+ {% if math_enabled %}
174
+ {% assign default_katex_cdn = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/' %}
175
+ {% assign katex_cdn = math_settings.katex_cdn | default: default_katex_cdn %}
176
+ {% assign katex_stylesheet_url = katex_cdn | append: 'katex.min.css' %}
177
+ {% assign katex_js_url = katex_cdn | append: 'katex.min.js' %}
178
+ {% assign katex_autorender_url = katex_cdn | append: 'contrib/auto-render.min.js' %}
179
+ {% assign default_mathjax_url = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js' %}
180
+ {% assign mathjax_url = math_settings.mathjax_cdn | default: default_mathjax_url %}
181
+ {% if math_engine == 'katex' %}
182
+ <link rel="stylesheet" href="{{ katex_stylesheet_url | add_sri }}" />
183
+ <script defer src="{{ katex_js_url | add_sri }}"></script>
184
+ <script defer src="{{ katex_autorender_url | add_sri }}"></script>
185
+ <script nonce="{{ page.csp_nonce }}">
186
+ document.addEventListener('DOMContentLoaded', function () {
187
+ if (window.renderMathInElement) {
188
+ window.renderMathInElement(document.body, {
189
+ delimiters: [
190
+ { left: '$$', right: '$$', display: true },
191
+ { left: '$', right: '$', display: false },
192
+ { left: '\\(', right: '\\)', display: false },
193
+ { left: '\\[', right: '\\]', display: true }
194
+ ],
195
+ throwOnError: false
196
+ });
197
+ }
198
+ });
199
+ </script>
200
+ {% else %}
201
+ <script nonce="{{ page.csp_nonce }}">
202
+ window.MathJax = {
203
+ tex: {
204
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
205
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
206
+ processEscapes: true,
207
+ processEnvironments: true,
208
+ packages: { '[+]': ['ams', 'mathtools', 'physics', 'mhchem', 'require', 'boldsymbol', 'braket', 'cancel'] },
209
+ tags: 'all',
210
+ tagSide: 'right',
211
+ tagIndent: '1.25em',
212
+ macros: {
213
+ E: '\\mathbb{E}',
214
+ Var: '\\mathrm{Var}',
215
+ Cov: '\\mathrm{Cov}',
216
+ sd: '\\mathrm{sd}',
217
+ se: '\\mathrm{se}',
218
+ Prob: '\\mathbb{P}',
219
+ bb: ['\\mathbb{#1}', 1],
220
+ vec: ['\\mathbf{#1}', 1],
221
+ boldsymbol: ['\\boldsymbol{#1}', 1],
222
+ argmin: ['\\operatorname*{arg\\,min}', 0],
223
+ argmax: ['\\operatorname*{arg\\,max}', 0],
224
+ given: '\\mid',
225
+ diff: ['\\,\\mathrm{d}#1', 1],
226
+ abs: ['\\lvert#1\\rvert', 1],
227
+ norm: ['\\lVert#1\\rVert', 1],
228
+ transpose: ['^{\\mathsf{T}}', 0],
229
+ inner: ['\\langle #1, #2 \\rangle', 2]
230
+ }
231
+ },
232
+ loader: {
233
+ load: [
234
+ '[tex]/require', '[tex]/ams', '[tex]/mathtools', '[tex]/physics', '[tex]/mhchem',
235
+ '[tex]/boldsymbol', '[tex]/braket', '[tex]/cancel', 'ui/menu', 'a11y/semantic-enrich', 'a11y/assistive-mml'
236
+ ]
237
+ },
238
+ options: {
239
+ enableAssistiveMml: true,
240
+ enableMenu: true,
241
+ skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'code', 'pre'],
242
+ renderActions: { addMenu: [0, '', ''] },
243
+ menuOptions: {
244
+ settings: {
245
+ assistiveMml: true,
246
+ collapsible: true,
247
+ explorer: true
248
+ }
249
+ }
250
+ },
251
+ chtml: { scale: 1, matchFontHeight: false, displayAlign: 'left', displayIndent: '0' },
252
+ svg: { fontCache: 'global' },
253
+ startup: {
254
+ ready() {
255
+ const MJ = MathJax;
256
+ MJ.startup.defaultReady();
257
+ if (window.DatalogMath && typeof window.DatalogMath.init === 'function') {
258
+ window.DatalogMath.init(MJ);
259
+ }
260
+ MJ.startup.promise.then(() => {
261
+ document.querySelectorAll('[data-math-alt]').forEach((el) => {
262
+ const altText = el.getAttribute('data-math-alt');
263
+ if (altText) {
264
+ el.setAttribute('aria-label', altText);
265
+ }
266
+ });
267
+ });
268
+ },
269
+ pageReady: () => {
270
+ document.body.classList.add('math-ready');
271
+ const liveRegion = document.getElementById('math-status');
272
+ if (liveRegion) { liveRegion.textContent = {{ 'global.math_ready' | t | jsonify }}; }
273
+ if (window.DatalogMath && typeof window.DatalogMath.onPageReady === 'function') {
274
+ window.DatalogMath.onPageReady();
275
+ }
276
+ return window.MathJax.startup.defaultPageReady();
277
+ }
278
+ }
279
+ };
280
+ </script>
281
+ <script src="{{ mathjax_url | add_sri }}" id="mathjax-script" async defer></script>
282
+ {% endif %}
283
+ {% endif %}
284
+
285
+ {% assign citation_source = page.citation_authors | default: page.authors %}
286
+ {% if page.title or page.citation_title %}
287
+ <meta name="citation_title" content="{{ page.citation_title | default: page_title | strip_html | normalize_whitespace }}" />
288
+ {% endif %}
289
+ {% if citation_source %}
290
+ {% capture citation_source_json %}{{ citation_source | jsonify }}{% endcapture %}
291
+ {% assign citation_source_first = citation_source_json | slice: 0, 1 %}
292
+ {% if citation_source_first == '[' %}
293
+ {% assign citation_author_list = citation_source %}
294
+ {% else %}
295
+ {% assign citation_author_list = citation_source | replace: ';', ',' | split: ',' %}
296
+ {% endif %}
297
+ {% for author in citation_author_list %}
298
+ <meta name="citation_author" content="{{ author | strip | escape }}" />
299
+ {% endfor %}
300
+ {% elsif page.author or site.author.name %}
301
+ <meta name="citation_author" content="{{ page.author | default: site.author.name | strip | escape }}" />
302
+ {% endif %}
303
+ {% if page.date %}
304
+ <meta name="citation_publication_date" content="{{ page.date | date: '%Y/%m/%d' }}" />
305
+ {% endif %}
306
+ {% if page.doi %}
307
+ <meta name="citation_doi" content="{{ page.doi }}" />
308
+ {% endif %}
309
+ {% if page.journal %}
310
+ <meta name="citation_journal_title" content="{{ page.journal }}" />
311
+ {% endif %}
312
+ {% if page.conference %}
313
+ <meta name="citation_conference_title" content="{{ page.conference }}" />
314
+ {% endif %}
315
+ {% if page.orcid or site.author.orcid %}
316
+ <meta name="citation_orcid" content="{{ page.orcid | default: site.author.orcid }}" />
317
+ {% endif %}
318
+ {% if page.dataset_doi %}
319
+ <meta name="citation_dataset_doi" content="{{ page.dataset_doi }}" />
320
+ {% endif %}
321
+ {% if page.citation_pdf %}
322
+ <link rel="citation_pdf_url" href="{{ page.citation_pdf | absolute_url }}" />
323
+ {% endif %}
324
+
325
+ <link rel="alternate" type="application/atom+xml" title="{{ site.title }}" href="{{ '/feed.xml' | absolute_url }}" />
326
+ <meta http-equiv="Permissions-Policy" content="interest-cohort=()" />
327
+ <meta name="google-site-verification" content="{{ site.google_site_verification }}" />
328
+ <meta name="msvalidate.01" content="{{ site.bing_site_verification }}" />
329
+ <meta name="yandex-verification" content="{{ site.yandex_site_verification }}" />
330
+ <meta name="baidu-site-verification" content="{{ site.baidu_site_verification }}" />
331
+ <meta name="plausible-domain" content="{{ site.url | replace: 'https://', '' | replace: 'http://', '' }}" />
332
+
333
+ <script nonce="{{ page.csp_nonce }}">
334
+ document.documentElement.classList.add('js');
335
+ </script>
336
+
337
+ {% include analytics.html %}
@@ -0,0 +1,48 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - items
5
+ optional:
6
+ - page
7
+ - contexts
8
+ ---
9
+ Renders the primary navigation list with active state awareness.
10
+ {%- endcomment -%}
11
+ {%- assign nav_items = include.items | default: '' -%}
12
+ {%- if nav_items == '' -%}
13
+ {%- assign nav_items = '' | split: '' -%}
14
+ {%- endif -%}
15
+ {%- assign active_page = include.page | default: page -%}
16
+ {%- assign contexts = include.contexts | default: '' -%}
17
+ {%- if contexts == '' -%}
18
+ {%- assign contexts = '' | split: '' -%}
19
+ {%- endif -%}
20
+ <ul class="nav-list">
21
+ {%- for item in nav_items -%}
22
+ {%- assign item_url = item.url | relative_url -%}
23
+ {%- assign is_active = false -%}
24
+ {%- assign nav_title = item.title | default: 'Untitled' | strip -%}
25
+ {%- assign nav_section = item.section | default: nav_title | replace: '_', ' ' | replace: '-', ' ' | strip -%}
26
+ {%- assign nav_description = item.description | default: '' -%}
27
+ {%- if nav_description == '' and item.description_key -%}
28
+ {%- capture nav_description -%}{% t item.description_key %}{%- endcapture -%}
29
+ {%- endif -%}
30
+ {%- if active_page.url == item.url or active_page.url == item_url -%}
31
+ {%- assign is_active = true -%}
32
+ {%- elsif item.section and contexts contains item.section -%}
33
+ {%- assign is_active = true -%}
34
+ {%- elsif item.url != '/' and active_page.url contains item.url -%}
35
+ {%- assign is_active = true -%}
36
+ {%- endif -%}
37
+ {%- if nav_description == '' -%}
38
+ {%- assign nav_description = nav_section | default: nav_title -%}
39
+ {%- assign nav_description = nav_description | append: ' resources' -%}
40
+ {%- endif -%}
41
+ <li class="nav-item" data-section="{{ item.section | default: nav_title | downcase }}">
42
+ <a class="nav-link{% if is_active %} is-active{% endif %}" href="{{ item_url }}"{% if is_active %} aria-current="page"{% endif %}>
43
+ <span class="nav-title">{{ nav_title }}</span>
44
+ <span class="nav-description">{{ nav_description | strip }}</span>
45
+ </a>
46
+ </li>
47
+ {%- endfor -%}
48
+ </ul>
@@ -0,0 +1,70 @@
1
+ {% assign localization_config = site.theme_options.localization %}
2
+ {% assign navigation_data = site.data.navigation %}
3
+ <header class="site-header" role="banner" data-sticky-header>
4
+ <div class="header-progress" aria-hidden="true">
5
+ <progress class="header-progress__bar" value="0" max="100" data-scroll-progress></progress>
6
+ </div>
7
+ <div class="visually-hidden" aria-live="polite" id="progress-announcement">Reading progress: <span data-scroll-progress-value>0</span>%</div>
8
+ <div class="container header-container">
9
+ <div class="header-primary">
10
+ {% assign brand_symbol = site.brand.accent_symbol | default: '∀ data · Σ insights' | strip %}
11
+ {% assign brand_home_name = site.title | default: site.name %}
12
+ <a class="site-brand" href="{{ '/' | relative_url }}" aria-label="{{ brand_home_name }} home">
13
+ <span class="site-logo" aria-hidden="true">
14
+ <svg class="logo-mark" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" role="img" focusable="false">
15
+ <title>DataLog logo</title>
16
+ <path d="M8 48c12-24 24-32 32-32 8 0 12 4 16 8" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" />
17
+ <path d="M44 16c0 4-4 8-8 8s-8-4-8-8 4-8 8-8 8 4 8 8z" fill="currentColor" opacity="0.25" />
18
+ </svg>
19
+ </span>
20
+ <span class="site-title-group">
21
+ <span class="site-title">{{ site.name | default: 'DataLog' }}</span>
22
+ <span class="site-tagline">{{ brand_symbol }}</span>
23
+ </span>
24
+ </a>
25
+ <div class="header-secondary">
26
+ {% if site.features.search %}
27
+ <form class="site-search" role="search" action="{{ '/search/' | relative_url }}" method="get">
28
+ <label class="visually-hidden" for="site-search-input">Search</label>
29
+ <input id="site-search-input" name="q" type="search" placeholder="Search..." autocomplete="off">
30
+ <button type="submit">Search</button>
31
+ </form>
32
+ {% endif %}
33
+ <div class="header-controls">
34
+ {% if site.features.dark_mode_toggle %}
35
+ <button class="header-control header-control--theme" type="button" data-toggle-dark-mode aria-pressed="false" aria-label="Toggle dark mode">
36
+ <svg class="theme-icon theme-icon--light" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
37
+ <circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
38
+ </svg>
39
+ <svg class="theme-icon theme-icon--dark" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
40
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
41
+ </svg>
42
+ </button>
43
+ {% endif %}
44
+ <button class="header-control header-control--icon nav-toggle" type="button" aria-expanded="false" aria-controls="site-nav" aria-label="Toggle navigation">
45
+ <span aria-hidden="true">☰</span>
46
+ </button>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ {% assign nav_items = navigation_data.header | default: navigation_data.main %}
51
+ {% if nav_items == nil %}
52
+ {% assign nav_items = '' | split: '' %}
53
+ {% assign nav_items = nav_items | push: {"title": "Blog", "url": "/blog/", "section": "blog"} %}
54
+ {% assign nav_items = nav_items | push: {"title": "Research", "url": "/research/", "section": "research"} %}
55
+ {% assign nav_items = nav_items | push: {"title": "Projects", "url": "/portfolio/", "section": "portfolio"} %}
56
+ {% assign nav_items = nav_items | push: {"title": "Datasets", "url": "/datasets/", "section": "datasets"} %}
57
+ {% assign nav_items = nav_items | push: {"title": "Visualizations", "url": "/visualizations/", "section": "visualizations"} %}
58
+ {% assign nav_items = nav_items | push: {"title": "Academic Ops", "url": "/academic/", "section": "academic"} %}
59
+ {% assign nav_items = nav_items | push: {"title": "About", "url": "/about/", "section": "about"} %}
60
+ {% endif %}
61
+ {% assign page_contexts = '' | split: '' %}
62
+ {% if page.section %}{% assign page_contexts = page_contexts | push: page.section %}{% endif %}
63
+ {% if page.layout %}{% assign page_contexts = page_contexts | push: page.layout %}{% endif %}
64
+ {% if page.collection %}{% assign page_contexts = page_contexts | push: page.collection %}{% endif %}
65
+ {% if page.type %}{% assign page_contexts = page_contexts | push: page.type %}{% endif %}
66
+ <nav id="site-nav" class="site-nav" role="navigation" aria-label="Primary navigation" data-open="true">
67
+ {% include header/navigation.html items=nav_items page=page contexts=page_contexts %}
68
+ </nav>
69
+ </div>
70
+ </header>
@@ -0,0 +1,21 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - items
5
+ optional:
6
+ - conjunction
7
+ - fallback
8
+ ---
9
+ Converts an array into a human readable sentence using the configured conjunction.
10
+ Pass an empty or nil array to emit the fallback value (defaults to blank).
11
+ {%- endcomment -%}
12
+ {%- assign items = include.items | default: '' -%}
13
+ {%- if items == blank or items == empty -%}
14
+ {{ include.fallback | default: '' }}
15
+ {%- else -%}
16
+ {%- if include.conjunction -%}
17
+ {{ items | array_to_sentence_string: include.conjunction }}
18
+ {%- else -%}
19
+ {{ items | array_to_sentence_string }}
20
+ {%- endif -%}
21
+ {%- endif -%}
@@ -0,0 +1,16 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - date
5
+ optional:
6
+ - format
7
+ - localization
8
+ ---
9
+ Formats a date using the localized format preferences.
10
+ Falls back to the localization config's date_format and finally "long".
11
+ {%- endcomment -%}
12
+ {%- if include.date -%}
13
+ {%- assign localization = include.localization | default: site.theme_options.localization -%}
14
+ {%- assign resolved_format = include.format | default: localization.date_format | default: 'long' -%}
15
+ {{ include.date | localize_date: resolved_format }}
16
+ {%- endif -%}
@@ -0,0 +1,26 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - url
5
+ - label
6
+ optional:
7
+ - icon
8
+ - rel
9
+ - target
10
+ - class
11
+ ---
12
+ Renders a consistently styled link with optional icon support.
13
+ External targets automatically receive noopener + noreferrer when a target is set.
14
+ {%- endcomment -%}
15
+ {%- if include.url and include.label -%}
16
+ {%- assign rel_value = include.rel | default: '' -%}
17
+ {%- if include.target and rel_value == '' -%}
18
+ {%- assign rel_value = 'noopener noreferrer' -%}
19
+ {%- endif -%}
20
+ <a{% if include.class %} class="{{ include.class }}"{% endif %} href="{{ include.url }}"{% if include.target %} target="{{ include.target }}"{% endif %}{% if rel_value != '' %} rel="{{ rel_value }}"{% endif %}>
21
+ {%- if include.icon -%}
22
+ <span class="link-icon" aria-hidden="true">{{ include.icon }}</span>
23
+ {%- endif -%}
24
+ <span class="link-label">{{ include.label }}</span>
25
+ </a>
26
+ {%- endif -%}