datalog-theme 0.7.0 → 0.9.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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +188 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +25 -17
  5. data/_data/cdn-integrity.yml +0 -30
  6. data/_data/i18n/en.yml +297 -0
  7. data/_data/i18n/es.yml +297 -0
  8. data/_data/i18n/pt.yml +297 -0
  9. data/_data/js_manifest.json +16 -0
  10. data/_includes/analytics/dashboard.html +3 -1
  11. data/_includes/components/api-function.html +20 -1
  12. data/_includes/components/author-bio.html +21 -11
  13. data/_includes/components/author-list.html +32 -0
  14. data/_includes/components/citation-tools.html +33 -25
  15. data/_includes/components/comments-thread.html +90 -0
  16. data/_includes/components/contact-form.html +120 -0
  17. data/_includes/components/correction-report.html +82 -0
  18. data/_includes/components/enhanced-code-block.html +1 -1
  19. data/_includes/components/enhanced-toc.html +6 -7
  20. data/_includes/components/license-link.html +13 -0
  21. data/_includes/components/license-notice.html +28 -0
  22. data/_includes/components/moderation-inbox.html +139 -0
  23. data/_includes/components/reactions.html +49 -0
  24. data/_includes/components/reading-list.html +31 -0
  25. data/_includes/components/reading-mode-toggle.html +65 -0
  26. data/_includes/components/reading-state-bookmark.html +27 -0
  27. data/_includes/components/reading-state-panel.html +71 -0
  28. data/_includes/components/reproducibility.html +61 -0
  29. data/_includes/components/responsive-image.html +3 -3
  30. data/_includes/components/revision-history.html +39 -0
  31. data/_includes/components/revision-notice.html +35 -0
  32. data/_includes/components/series-nav.html +64 -0
  33. data/_includes/components/subscribe-form.html +88 -0
  34. data/_includes/components/subscription-manage.html +68 -0
  35. data/_includes/components/webmentions.html +48 -0
  36. data/_includes/csp-meta.html +135 -11
  37. data/_includes/footer.html +22 -20
  38. data/_includes/head.html +111 -63
  39. data/_includes/header/navigation.html +12 -15
  40. data/_includes/header.html +28 -19
  41. data/_includes/layouts/default/article.html +9 -7
  42. data/_includes/meta/dynamic-services-config.html +14 -0
  43. data/_includes/meta/math-config.html +18 -10
  44. data/_includes/meta/person-json.html +27 -0
  45. data/_includes/meta/publisher.html +45 -0
  46. data/_includes/meta/schema.html +67 -30
  47. data/_includes/meta/scholarly.html +121 -0
  48. data/_includes/meta/scripts-loader.html +18 -32
  49. data/_includes/meta/webmention-discovery.html +14 -0
  50. data/_includes/post/related-posts.html +4 -7
  51. data/_includes/scripts.html +57 -0
  52. data/_includes/search/index-data.json +9 -34
  53. data/_layouts/dataset.html +5 -3
  54. data/_layouts/default.html +16 -8
  55. data/_layouts/notebook.html +1 -0
  56. data/_layouts/package.html +4 -2
  57. data/_layouts/page.html +15 -0
  58. data/_layouts/portfolio.html +1 -0
  59. data/_layouts/post.html +102 -23
  60. data/_layouts/project.html +4 -3
  61. data/_layouts/research.html +20 -8
  62. data/_plugins/analytics_dashboard.rb +9 -3
  63. data/_plugins/authors.rb +133 -0
  64. data/_plugins/config_validator.rb +231 -23
  65. data/_plugins/critical_css_check.rb +42 -0
  66. data/_plugins/csp_generator.rb +18 -28
  67. data/_plugins/datalog_bibliography.rb +9 -7
  68. data/_plugins/datalog_comments.rb +8 -5
  69. data/_plugins/datalog_slides.rb +9 -8
  70. data/_plugins/i18n.rb +13 -12
  71. data/_plugins/image_optimizer.rb +241 -178
  72. data/_plugins/licenses.rb +135 -0
  73. data/_plugins/math_preprocessor.rb +59 -7
  74. data/_plugins/notebook_converter.rb +23 -4
  75. data/_plugins/plugin_loader.rb +3 -1
  76. data/_plugins/publications_generator.rb +8 -2
  77. data/_plugins/references.rb +238 -0
  78. data/_plugins/reproducibility.rb +150 -0
  79. data/_plugins/revisions.rb +101 -0
  80. data/_plugins/rouge_highlight_filter.rb +42 -0
  81. data/_plugins/scholarly.rb +50 -0
  82. data/_plugins/search_code_blocks.rb +30 -0
  83. data/_plugins/search_normalizer.rb +15 -53
  84. data/_plugins/search_pages.rb +3 -4
  85. data/_plugins/series.rb +104 -0
  86. data/_plugins/statements.rb +87 -0
  87. data/_sass/_academic-dashboard.scss +262 -0
  88. data/_sass/_base.scss +20 -1
  89. data/_sass/_comments-thread.scss +159 -0
  90. data/_sass/_components.scss +64 -1153
  91. data/_sass/_features.scss +17 -0
  92. data/_sass/_layout.scss +385 -1
  93. data/_sass/_mathematical.scss +27 -0
  94. data/_sass/_moderation.scss +222 -0
  95. data/_sass/_notebooks.scss +322 -0
  96. data/_sass/_open-science-badges.scss +56 -0
  97. data/_sass/{_phase1-enhancements.scss → _post-components.scss} +5 -3
  98. data/_sass/_print.scss +291 -0
  99. data/_sass/_reactions.scss +89 -0
  100. data/_sass/_reading-state.scss +290 -0
  101. data/_sass/_search-page.scss +530 -0
  102. data/_sass/_search.scss +46 -0
  103. data/_sass/_service-forms.scss +204 -0
  104. data/_sass/_subscriptions.scss +140 -0
  105. data/_sass/_syntax-highlighting.scss +212 -97
  106. data/_sass/_theme.scss +40 -19
  107. data/_sass/_typography.scss +130 -0
  108. data/_sass/_utilities.scss +5 -0
  109. data/_sass/_variables.scss +6 -0
  110. data/_sass/_webmentions.scss +125 -0
  111. data/assets/css/main.scss +14 -0
  112. data/assets/js/dist/academic.js +1 -1
  113. data/assets/js/dist/analytics-dashboard.js +1 -1
  114. data/assets/js/dist/chunks/chunk-2DYDWUFX.js +1 -0
  115. data/assets/js/dist/chunks/chunk-PATLC23F.js +1 -0
  116. data/assets/js/dist/chunks/chunk-V7734B2G.js +1 -0
  117. data/assets/js/dist/comments.js +2 -0
  118. data/assets/js/dist/contact.js +1 -0
  119. data/assets/js/dist/core.js +1 -1
  120. data/assets/js/dist/corrections.js +1 -0
  121. data/assets/js/dist/loader.js +1 -1
  122. data/assets/js/dist/math.js +1 -1
  123. data/assets/js/dist/moderation.js +1 -0
  124. data/assets/js/dist/notebook.js +1 -1
  125. data/assets/js/dist/reactions.js +1 -0
  126. data/assets/js/dist/reading-state.js +1 -0
  127. data/assets/js/dist/search.js +1 -1
  128. data/assets/js/dist/sources.json +52 -0
  129. data/assets/js/dist/subscriptions.js +1 -0
  130. data/assets/js/dist/visualizations.js +11 -2
  131. data/assets/js/dist/webmentions.js +1 -0
  132. data/assets/js/loader.js +37 -1
  133. data/datalog-theme.gemspec +35 -23
  134. data/lib/datalog/cli.rb +43 -15
  135. data/lib/datalog/critical_css.rb +168 -0
  136. data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
  137. data/lib/datalog/plugins/comments.rb +33 -3
  138. data/lib/datalog/theme/installed_files.rb +113 -0
  139. data/lib/datalog/theme/package.rb +57 -0
  140. data/lib/datalog/theme/repository_checkout.rb +94 -0
  141. data/lib/datalog/theme/version.rb +5 -1
  142. data/lib/datalog/warning_filter.rb +5 -11
  143. data/lib/datalog-theme.rb +6 -0
  144. metadata +96 -147
  145. data/_data/academic.yml +0 -217
  146. data/_data/config/author.yml +0 -121
  147. data/_data/datasets.yml +0 -28
  148. data/_data/js_meta.json +0 -371
  149. data/_data/navigation.yml +0 -145
  150. data/_data/projects.yml +0 -41
  151. data/_data/publications.yml +0 -28
  152. data/_data/social.yml +0 -73
  153. data/_data/visualizations.yml +0 -51
  154. data/_includes/components/advanced-search.html +0 -682
  155. data/_includes/components/bookmark-system.html +0 -96
  156. data/_includes/components/comments.html +0 -244
  157. data/_includes/components/content-recommendations.html +0 -228
  158. data/_includes/components/email-preferences.html +0 -200
  159. data/_includes/components/enhanced-metadata.html +0 -228
  160. data/_includes/components/language-switcher.html +0 -396
  161. data/_includes/components/navigation-enhancements.html +0 -454
  162. data/_includes/components/newsletter-signup.html +0 -178
  163. data/_includes/components/popular-posts.html +0 -233
  164. data/_includes/components/reading-progress.html +0 -133
  165. data/_includes/components/reading-time.html +0 -121
  166. data/_includes/components/series-navigation.html +0 -124
  167. data/_includes/components/social-proof.html +0 -34
  168. data/_includes/components/user-preferences.html +0 -566
  169. data/_includes/meta/syntax-config.html +0 -19
  170. data/_layouts/archive.html +0 -282
  171. data/_layouts/post-sidebar.html +0 -183
  172. data/_sass/_phase3-enhancements.scss +0 -874
  173. data/_sass/_phase4-enhancements.scss +0 -1214
  174. data/_sass/_phase5-enhancements.scss +0 -414
  175. data/assets/js/academic.js +0 -262
  176. data/assets/js/analytics-dashboard.js +0 -382
  177. data/assets/js/core/dark-mode.js +0 -79
  178. data/assets/js/core/github-cards.js +0 -123
  179. data/assets/js/core/language-filter.js +0 -69
  180. data/assets/js/core/navigation.js +0 -184
  181. data/assets/js/core/scroll-progress.js +0 -45
  182. data/assets/js/core/search-hotkeys.js +0 -62
  183. data/assets/js/core/skip-links.js +0 -62
  184. data/assets/js/dist/manifest.json +0 -22
  185. data/assets/js/dist/meta.json +0 -371
  186. data/assets/js/main.js +0 -23
  187. data/assets/js/math.js +0 -818
  188. data/assets/js/notebook.js +0 -158
  189. data/assets/js/search/analytics.js +0 -91
  190. data/assets/js/search/app.js +0 -271
  191. data/assets/js/search/autocomplete.js +0 -120
  192. data/assets/js/search/engine.js +0 -260
  193. data/assets/js/search/filters.js +0 -45
  194. data/assets/js/search/render.js +0 -217
  195. data/assets/js/search/utils.js +0 -99
  196. data/assets/js/search.js +0 -354
  197. data/assets/js/visualizations.js +0 -816
  198. data/assets/publications/datalog-publications.bib +0 -8
  199. data/assets/publications/datalog-publications.ris +0 -9
  200. data/assets/publications/publications.bib +0 -30
  201. data/assets/templates/diogo-ribeiro-cv.md +0 -31
  202. data/assets/templates/diogo-ribeiro-cv.tex +0 -32
  203. data/lib/datalog/theme/theme.rb +0 -18
@@ -1,17 +1,141 @@
1
1
  {% assign csp_registry = site.data.csp | default: {} %}
2
2
  {% assign nonce_source = page.csp_nonce | default: csp_registry.nonces[page.path] | default: csp_registry.nonces[page.url] | default: '' %}
3
- {% assign script_hashes = page.csp_hashes | default: [] %}
4
- {% capture script_hash_directives -%}
5
- {%- for hash in script_hashes -%}
6
- 'sha256-{{ hash }}'{% unless forloop.last %} {% endunless %}
7
- {%- endfor -%}
8
- {%- endcapture -%}
3
+ {%- comment -%}
4
+ Sources a site adds for its own embeds, listed under `csp` in _config.yml:
5
+ frame_src for iframes (Shiny apps, slide decks, videos), and script_src,
6
+ style_src, font_src and connect_src for anything else.
7
+ {%- endcomment -%}
8
+ {% assign frame_hosts = site.csp.frame_src | join: ' ' %}
9
+ {% assign extra_script_src = site.csp.script_src | join: ' ' %}
10
+ {% assign extra_style_src = site.csp.style_src | join: ' ' %}
11
+ {% assign extra_font_src = site.csp.font_src | join: ' ' %}
12
+ {% assign extra_connect_src = site.csp.connect_src | join: ' ' %}
13
+ {%- comment -%} The dynamic services' origin, so the browser may call the site's backend (docs/dynamic-services.md). {%- endcomment -%}
14
+ {% assign services_origin = '' %}
15
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' %}
16
+ {% assign services_parts = site.dynamic_services.base_url | split: '/' %}
17
+ {% assign services_origin = services_parts[0] | append: '//' | append: services_parts[2] %}
18
+ {% endif %}
19
+ {%- comment -%} The comments endpoint, when the api provider keeps comments apart from the services (lib/datalog/plugins/comments.rb). {%- endcomment -%}
20
+ {% assign comments_origin = '' %}
21
+ {% assign comments_options = site.datalog_plugins.options['datalog-comments'] %}
22
+ {% assign comments_endpoint = page.datalog_comments.endpoint | default: comments_options.endpoint %}
23
+ {% if comments_endpoint and comments_endpoint != '' %}
24
+ {% assign comments_parts = comments_endpoint | split: '/' %}
25
+ {% assign comments_origin = comments_parts[0] | append: '//' | append: comments_parts[2] %}
26
+ {% endif %}
27
+ {%- comment -%} The moderation API, when it lives apart from the services, and only on the inbox page (docs/moderation.md). {%- endcomment -%}
28
+ {% assign moderation_origin = '' %}
29
+ {% if page.moderation_inbox and site.moderation.enabled == true and site.moderation.endpoint and site.moderation.endpoint != '' %}
30
+ {% assign moderation_parts = site.moderation.endpoint | split: '/' %}
31
+ {% assign moderation_origin = moderation_parts[0] | append: '//' | append: moderation_parts[2] %}
32
+ {% endif %}
33
+ {%- comment -%}
34
+ Plotly, the Jupyter widget manager and MathJax can't run under the strict
35
+ policy. Plotly inserts its rules into a <style> element it creates; the widget
36
+ manager adds <style> elements too, and compiles widget schemas with
37
+ new Function; MathJax's CHTML output adds the stylesheet its layout depends
38
+ on. Only the pages that run them get inline styles, and widget pages eval. A
39
+ page that loads such a library another way sets csp.unsafe_inline_styles or
40
+ csp.unsafe_eval in its front matter. A browser ignores 'unsafe-inline' in a
41
+ directive that also lists a nonce, so those pages drop the style nonce.
42
+ {%- endcomment -%}
43
+ {% assign csp_inline_styles = page.csp.unsafe_inline_styles %}
44
+ {% assign csp_eval = page.csp.unsafe_eval %}
45
+ {%- comment -%}
46
+ jsDelivr serves any npm package, so the policy names the packages this page
47
+ loads rather than the whole host: the math engine, from the URLs the head's
48
+ script tags use (math-config.html and head.html set them), and the chart
49
+ libraries the visualization and notebook scripts load for the blocks on the
50
+ page. Keep these in step with the URLs in assets/js/visualizations.js,
51
+ assets/js/notebook.js and _includes/analytics/dashboard.html;
52
+ tests/test_csp.rb checks that they are.
53
+ {%- endcomment -%}
54
+ {% assign cdn_scripts = '' %}
55
+ {% assign cdn_styles = '' %}
56
+ {% assign cdn_fonts = '' %}
57
+ {% assign cdn_connect = '' %}
58
+ {% assign cdn_frames = '' %}
59
+ {% if math_enabled %}
60
+ {% if math_engine == 'katex' %}
61
+ {% assign cdn_scripts = cdn_scripts | append: ' ' | append: katex_cdn %}
62
+ {% assign cdn_styles = cdn_styles | append: ' ' | append: katex_cdn %}
63
+ {% assign cdn_fonts = cdn_fonts | append: ' ' | append: katex_cdn %}
64
+ {% else %}
65
+ {%- comment -%} MathJax loads its components, fonts and speech data from the directory of its main script. {%- endcomment -%}
66
+ {% assign mathjax_file = mathjax_url | split: '/' | last %}
67
+ {% assign mathjax_dir_length = mathjax_url.size | minus: mathjax_file.size %}
68
+ {% assign mathjax_dir = mathjax_url | slice: 0, mathjax_dir_length %}
69
+ {% assign cdn_scripts = cdn_scripts | append: ' ' | append: mathjax_dir %}
70
+ {% assign cdn_fonts = cdn_fonts | append: ' ' | append: mathjax_dir %}
71
+ {% assign cdn_connect = cdn_connect | append: ' ' | append: mathjax_dir %}
72
+ {% assign csp_inline_styles = true %}
73
+ {% endif %}
74
+ {% endif %}
75
+ {% if content contains 'data-viz-type="plotly"' or content contains "data-viz-type='plotly'" or content contains 'notebook-output-plotly' %}
76
+ {% assign csp_inline_styles = true %}
77
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/plotly.js-dist-min@2.27.0/' %}
78
+ {% endif %}
79
+ {% if content contains 'data-viz-type="d3"' or content contains "data-viz-type='d3'" %}
80
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/d3@7/' %}
81
+ {% endif %}
82
+ {% if content contains 'data-viz-type="bokeh"' or content contains "data-viz-type='bokeh'" %}
83
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/@bokeh/bokehjs@3.3.3/' %}
84
+ {% endif %}
85
+ {% if content contains 'notebook-output-vega' %}
86
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/vega@5 https://cdn.jsdelivr.net/npm/vega-lite@5 https://cdn.jsdelivr.net/npm/vega-embed@6' %}
87
+ {% endif %}
88
+ {% if content contains 'npm/chart.js@4.4.0/' %}
89
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/chart.js@4.4.0/' %}
90
+ {% endif %}
91
+ {%- comment -%}
92
+ Widget pages load require.js from cdnjs, and allow all of jsDelivr: the widget
93
+ manager loads any widget package a notebook names from it, and its icon fonts.
94
+ {%- endcomment -%}
95
+ {% if content contains 'data-viz-type="ipywidgets"' or content contains "data-viz-type='ipywidgets'" or content contains 'application/vnd.jupyter.widget-state+json' %}
96
+ {% assign csp_inline_styles = true %}
97
+ {% assign csp_eval = true %}
98
+ {% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/' %}
99
+ {% assign cdn_fonts = cdn_fonts | append: ' https://cdn.jsdelivr.net' %}
100
+ {% endif %}
101
+ {%- comment -%}
102
+ The Disqus embed loads its script from the site's shortname subdomain of
103
+ disqus.com and its assets from disquscdn.com, shows the thread in an iframe
104
+ from disqus.com, and sizes that iframe with an inline style. The policy
105
+ allowed none of them.
106
+ {%- endcomment -%}
107
+ {% if content contains 'id="disqus_thread"' %}
108
+ {% assign csp_inline_styles = true %}
109
+ {% assign cdn_scripts = cdn_scripts | append: ' https://*.disqus.com https://*.disquscdn.com' %}
110
+ {% assign cdn_styles = cdn_styles | append: ' https://*.disquscdn.com' %}
111
+ {% assign cdn_connect = cdn_connect | append: ' https://*.disqus.com' %}
112
+ {% assign cdn_frames = cdn_frames | append: ' https://disqus.com' %}
113
+ {% endif %}
114
+ {%- comment -%}
115
+ Google's tag loads only on a site that sets google_analytics, and the policy
116
+ allowed its hosts on every site. These are the hosts Google documents for GA4,
117
+ which reports to regional subdomains such as region1.google-analytics.com.
118
+ {%- endcomment -%}
119
+ {% assign csp_analytics = false %}
120
+ {% if site.google_analytics and site.google_analytics != "" %}
121
+ {% assign csp_analytics = true %}
122
+ {% endif %}
123
+ {%- comment -%}
124
+ object-src, base-uri and form-action do not fall back to default-src. An
125
+ injected <base> tag could repoint the page's relative script URLs, which the
126
+ nonce would then authorise; every theme form submits to the site itself.
127
+ Observable serves classic notebook embeds from old.observablehq.com, and an
128
+ observablehq.com embed URL redirects there.
129
+ {%- endcomment -%}
9
130
  <meta http-equiv="Content-Security-Policy" content="
10
131
  default-src 'self';
11
- script-src 'self' 'nonce-{{ nonce_source }}'{% if script_hash_directives != '' %} {{ script_hash_directives | strip }}{% endif %} https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://www.googletagmanager.com https://www.google-analytics.com;
12
- style-src 'self' 'nonce-{{ nonce_source }}' https://fonts.googleapis.com https://cdn.jsdelivr.net;
132
+ script-src 'self' 'nonce-{{ nonce_source }}'{% if csp_eval %} 'unsafe-eval'{% endif %}{{ cdn_scripts }}{% if csp_analytics %} https://*.googletagmanager.com{% endif %}{% if extra_script_src != '' %} {{ extra_script_src }}{% endif %};
133
+ style-src 'self' {% if csp_inline_styles %}'unsafe-inline'{% else %}'nonce-{{ nonce_source }}'{% endif %} https://fonts.googleapis.com{{ cdn_styles }}{% if extra_style_src != '' %} {{ extra_style_src }}{% endif %};
13
134
  img-src 'self' data: https:;
14
- font-src 'self' https://fonts.gstatic.com data:;
15
- connect-src 'self' https://api.github.com https://www.google-analytics.com https://cdn.jsdelivr.net;
16
- frame-src 'self' https://observablehq.com;
135
+ font-src 'self' https://fonts.gstatic.com data:{{ cdn_fonts }}{% if extra_font_src != '' %} {{ extra_font_src }}{% endif %};
136
+ connect-src 'self' https://api.github.com{{ cdn_connect }}{% if csp_analytics %} https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com{% endif %}{% if services_origin != '' %} {{ services_origin }}{% endif %}{% if comments_origin != '' and comments_origin != services_origin %} {{ comments_origin }}{% endif %}{% if moderation_origin != '' and moderation_origin != services_origin %} {{ moderation_origin }}{% endif %}{% if extra_connect_src != '' %} {{ extra_connect_src }}{% endif %};
137
+ frame-src 'self' https://observablehq.com https://old.observablehq.com{{ cdn_frames }}{% if frame_hosts != '' %} {{ frame_hosts }}{% endif %};
138
+ object-src 'none';
139
+ base-uri 'self';
140
+ form-action 'self';
17
141
  " />
@@ -2,10 +2,11 @@
2
2
  {% assign footer_year = site.time | date: '%Y' %}
3
3
  {% assign navigation_data = site.data.navigation %}
4
4
  {% assign social_data = site.data.social %}
5
+ {%- comment -%} The column titles are <h2>: the footer follows the page's own outline, which starts at its <h1>. {%- endcomment %}
5
6
  <footer class="site-footer" role="contentinfo">
6
7
  <div class="container footer-container">
7
8
  <section class="footer-about">
8
- <h3>{{ site.name | default: 'DataLog' }}</h3>
9
+ <h2>{{ site.name | default: site.title }}</h2>
9
10
  <p class="footer-description">{{ site.description | strip_html | truncate: 160 }}</p>
10
11
  <p class="footer-author">
11
12
  <strong>{{ site.author.name }}</strong>
@@ -20,30 +21,24 @@
20
21
  {% endif %}
21
22
  </section>
22
23
 
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 %}
24
+ {%- comment -%} `footer:` in _data/navigation.yml drives this column, which is left out without it. {%- endcomment -%}
25
+ {% assign footer_links = navigation_data.footer %}
26
+ {% if footer_links.size > 0 %}
27
+ <nav class="footer-navigation" aria-labelledby="footer-explore-heading">
28
+ <h2 id="footer-explore-heading">Explore</h2>
27
29
  <ul class="footer-link-list">
28
- {% if footer_links and footer_links.size > 0 %}
29
30
  {% for item in footer_links %}
30
31
  <li><a href="{{ item.url | relative_url }}">{{ item.title }}</a></li>
31
32
  {% 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
33
  </ul>
41
34
  </nav>
35
+ {% endif %}
42
36
 
37
+ {% assign primary_social = social_data.primary %}
38
+ {% if primary_social.size > 0 or site.author.email %}
43
39
  <section class="footer-connect">
44
- <h3>Connect</h3>
45
- {% assign primary_social = social_data.primary %}
46
- {% if primary_social %}
40
+ <h2>Connect</h2>
41
+ {% if primary_social.size > 0 %}
47
42
  <ul class="footer-link-list">
48
43
  {% for profile in primary_social %}
49
44
  <li><a href="{{ profile.url }}" target="_blank" rel="{{ profile.rel | default: 'noopener' }}">{{ profile.label }}</a></li>
@@ -56,18 +51,25 @@
56
51
  </p>
57
52
  {% endif %}
58
53
  </section>
54
+ {% endif %}
59
55
 
60
56
  <section class="footer-subscribe">
61
- <h3>Stay updated</h3>
57
+ <h2>Stay updated</h2>
62
58
  <p>Follow via RSS or check back for new research and tutorials.</p>
59
+ {%- comment -%} jekyll-feed is a dependency of the theme, so /feed.xml exists even when _data/social.yml lists no feeds. {%- endcomment -%}
63
60
  {% assign rss_links = social_data.rss %}
64
- {% if rss_links %}
65
61
  <ul class="footer-link-list">
62
+ {% if rss_links.size > 0 %}
66
63
  {% for feed in rss_links %}
67
64
  <li><a href="{{ feed.url | relative_url }}">{{ feed.label }}</a></li>
68
65
  {% endfor %}
66
+ {% else %}
67
+ <li><a href="{{ '/feed.xml' | relative_url }}">RSS feed</a></li>
68
+ {% endif %}
69
69
  </ul>
70
- {% endif %}
70
+ {%- comment -%} The newsletter form, on a site with a backend that takes subscriptions {%- endcomment -%}
71
+ {% assign subscribe_placement = site.subscriptions.placement | default: 'footer' %}
72
+ {% if subscribe_placement contains 'footer' %}{% include components/subscribe-form.html where='footer' %}{% endif %}
71
73
  </section>
72
74
  </div>
73
75
  <div class="container footer-bottom">
data/_includes/head.html CHANGED
@@ -11,26 +11,28 @@
11
11
  {% assign keyword_list = raw_keywords | replace: ';', ',' | split: ',' %}
12
12
  {% endif %}
13
13
  {% include meta/math-config.html page=page %}
14
+ {%- comment -%} The math engine's URLs, which both the script tags below and the Content Security Policy use. {%- endcomment -%}
15
+ {% assign default_katex_cdn = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/' %}
16
+ {% assign katex_cdn = math_settings.katex_cdn | default: default_katex_cdn %}
17
+ {% assign default_mathjax_url = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js' %}
18
+ {% assign mathjax_url = math_settings.mathjax_cdn | default: default_mathjax_url %}
14
19
  {% assign js_manifest = site.data.js_manifest %}
15
- {% assign syntax_config = site.theme_options.syntax_highlighting %}
16
- {% assign prism_cdn = syntax_config.cdn | default: 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0' %}
17
- {% assign prism_theme = syntax_config.themes.dark | default: syntax_config.themes.light | default: 'prism-tomorrow' %}
18
- {% assign prism_theme_url = prism_cdn | append: '/themes/' | append: prism_theme | append: '.css' %}
19
- {% assign prism_line_numbers_url = prism_cdn | append: '/plugins/line-numbers/prism-line-numbers.min.css' %}
20
- {% include meta/syntax-config.html %}
21
20
  <meta charset="utf-8" />
22
21
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
22
+ {%- comment -%} Not include_cached: the CSP nonce is different on every page. {%- endcomment -%}
23
23
  {% include csp-meta.html %}
24
24
  <meta name="viewport" content="width=device-width, initial-scale=1" />
25
25
  <meta name="theme-color" content="#0b1d3d" />
26
26
  <meta name="description" content="{{ page_description | strip_html | normalize_whitespace }}" />
27
- <meta name="author" content="{{ page.author | default: site.author.name }}" />
27
+ {% assign head_authors = page | page_authors %}
28
+ <meta name="author" content="{{ head_authors | map: 'name' | join: ', ' | escape }}" />
28
29
  {% if keyword_list %}
29
30
  <meta name="keywords" content="{{ keyword_list | join: ', ' | strip }}" />
30
31
  {% endif %}
31
32
  <meta name="generator" content="Jekyll" />
32
33
  <meta name="referrer" content="no-referrer-when-downgrade" />
33
- <meta name="robots" content="index,follow" />
34
+ {%- comment -%} `robots:` in front matter keeps a page out of search results, as the 404, search and admin pages do. {%- endcomment %}
35
+ <meta name="robots" content="{{ page.robots | default: 'index,follow' }}" />
34
36
  <meta name="format-detection" content="telephone=no" />
35
37
  <meta name="application-name" content="{{ site.title }}" />
36
38
  <meta property="og:site_name" content="{{ site.title }}" />
@@ -59,14 +61,80 @@
59
61
  <meta name="twitter:image" content="{{ site.social.default_image | absolute_url }}" />
60
62
  {% endif %}
61
63
  <link rel="canonical" href="{{ canonical_url }}" />
64
+ {% include meta/webmention-discovery.html %}
65
+ {%- assign head_license = page | page_license %}
66
+ {% if head_license.url %}<link rel="license" href="{{ head_license.url | escape }}" />{% endif %}
62
67
  {% if js_manifest and js_manifest.core %}
63
68
  <link rel="modulepreload" href="{{ js_manifest.core | relative_url }}" crossorigin="anonymous" />
64
- {% if js_manifest.features and js_manifest.features.search and site.features.search %}
69
+ {%- comment -%} Only a page that renders the search app uses the search bundle. {%- endcomment -%}
70
+ {% if js_manifest.features and js_manifest.features.search and site.features.search and content contains 'data-search-app' %}
65
71
  <link rel="modulepreload" href="{{ js_manifest.features.search | relative_url }}" crossorigin="anonymous" />
66
72
  {% endif %}
67
73
  {% if js_manifest.features and js_manifest.features.math and math_enabled and math_engine == 'mathjax' %}
68
74
  <link rel="modulepreload" href="{{ js_manifest.features.math | relative_url }}" crossorigin="anonymous" />
69
75
  {% endif %}
76
+ {%- comment -%}
77
+ The loader requests a feature bundle only after the core bundle has loaded.
78
+ Preloading the bundles this page will use, on the same tests the loader
79
+ applies, starts those downloads alongside core.
80
+ {%- endcomment -%}
81
+ {% if js_manifest.features and js_manifest.features.visualizations and site.features.visualizations and content contains 'data-viz-type' %}
82
+ <link rel="modulepreload" href="{{ js_manifest.features.visualizations | relative_url }}" crossorigin="anonymous" />
83
+ {% endif %}
84
+ {%- comment -%} Posts carry the reading-state panel; a page with the saved-articles list carries data-reading-list. {%- endcomment -%}
85
+ {% if js_manifest.features and js_manifest.features['reading-state'] and site.theme_options.reading_state.enabled != false %}
86
+ {% if page.layout == 'post' or content contains 'data-reading-list' %}
87
+ <link rel="modulepreload" href="{{ js_manifest.features['reading-state'] | relative_url }}" crossorigin="anonymous" />
88
+ {% endif %}
89
+ {% endif %}
90
+ {%- comment -%} The correction-report form renders on posts of a site with a backend. {%- endcomment -%}
91
+ {% if js_manifest.features and js_manifest.features.corrections and page.layout == 'post' and page.corrections != false %}
92
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' and site.dynamic_services.features.corrections != false and site.corrections.enabled != false %}
93
+ <link rel="modulepreload" href="{{ js_manifest.features.corrections | relative_url }}" crossorigin="anonymous" />
94
+ {% endif %}
95
+ {% endif %}
96
+ {%- comment -%} The contact form renders on a page that asks for it, on a site with a backend. {%- endcomment -%}
97
+ {% if js_manifest.features and js_manifest.features.contact and page.contact_form %}
98
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' and site.dynamic_services.features.contact != false and site.contact.enabled != false %}
99
+ <link rel="modulepreload" href="{{ js_manifest.features.contact | relative_url }}" crossorigin="anonymous" />
100
+ {% endif %}
101
+ {% endif %}
102
+ {%- comment -%} The comments thread of the api provider, on a page that shows comments that way. {%- endcomment -%}
103
+ {% if js_manifest.features and js_manifest.features.comments and page.datalog_comments.provider == 'api' %}
104
+ <link rel="modulepreload" href="{{ js_manifest.features.comments | relative_url }}" crossorigin="anonymous" />
105
+ {% endif %}
106
+ {%- comment -%} "Was this useful?" renders on posts of a site with a backend. {%- endcomment -%}
107
+ {% if js_manifest.features and js_manifest.features.reactions and page.layout == 'post' and page.reactions != false %}
108
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' and site.dynamic_services.features.reactions != false and site.reactions.enabled != false %}
109
+ <link rel="modulepreload" href="{{ js_manifest.features.reactions | relative_url }}" crossorigin="anonymous" />
110
+ {% endif %}
111
+ {% endif %}
112
+ {%- comment -%} "Mentioned elsewhere" renders on posts of a site with a backend. {%- endcomment -%}
113
+ {% if js_manifest.features and js_manifest.features.webmentions and page.layout == 'post' and page.webmentions != false %}
114
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' and site.dynamic_services.features.webmentions != false and site.webmentions.enabled != false %}
115
+ <link rel="modulepreload" href="{{ js_manifest.features.webmentions | relative_url }}" crossorigin="anonymous" />
116
+ {% endif %}
117
+ {% endif %}
118
+ {%- comment -%} The page the newsletter's emails link to acts as soon as it loads; the footer form loads on demand. {%- endcomment -%}
119
+ {% if js_manifest.features and js_manifest.features.subscriptions and page.subscription_manage %}
120
+ {% if site.dynamic_services.base_url and site.dynamic_services.base_url != '' and site.dynamic_services.features.subscriptions != false and site.subscriptions.enabled != false %}
121
+ <link rel="modulepreload" href="{{ js_manifest.features.subscriptions | relative_url }}" crossorigin="anonymous" />
122
+ {% endif %}
123
+ {% endif %}
124
+ {%- comment -%} The moderation inbox loads its queue as soon as the page opens. {%- endcomment -%}
125
+ {% if js_manifest.features and js_manifest.features.moderation and page.moderation_inbox and site.moderation.enabled == true %}
126
+ <link rel="modulepreload" href="{{ js_manifest.features.moderation | relative_url }}" crossorigin="anonymous" />
127
+ {% endif %}
128
+ {% if js_manifest.features and js_manifest.features.notebook and page.notebook_post %}
129
+ <link rel="modulepreload" href="{{ js_manifest.features.notebook | relative_url }}" crossorigin="anonymous" />
130
+ {% endif %}
131
+ {% if js_manifest.features and js_manifest.features.academic %}
132
+ {% if site.features.academic_dashboard or site.features.citation_tracking %}
133
+ {% if content contains 'data-citation-metric' or content contains 'data-citation-table' or content contains 'data-citation-chart' %}
134
+ <link rel="modulepreload" href="{{ js_manifest.features.academic | relative_url }}" crossorigin="anonymous" />
135
+ {% endif %}
136
+ {% endif %}
137
+ {% endif %}
70
138
  {% endif %}
71
139
  {% assign alternate_translations = page.translations %}
72
140
  {% if alternate_translations %}
@@ -93,19 +161,20 @@
93
161
  <title>{{ site.title }}</title>
94
162
  {% endif %}
95
163
 
164
+ {%- comment -%}
165
+ Only the weights the stylesheet renders. Sans 700, Serif 400 and Mono 500
166
+ were requested as well, and no page of the demo site used them.
167
+ {%- endcomment -%}
168
+ {% assign google_fonts_url = 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600&family=IBM+Plex+Serif:wght@600;700&family=IBM+Plex+Mono:wght@400;600&display=swap' %}
96
169
  <link rel="preconnect" href="https://fonts.googleapis.com" />
97
170
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
98
- <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" />
99
- <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 media="print" data-async-style />
171
+ <link rel="preload" href="{{ google_fonts_url | add_sri }}" as="style" />
172
+ <link rel="stylesheet" href="{{ google_fonts_url | add_sri }}" media="print" data-async-style />
100
173
  <noscript>
101
- <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 }}" />
174
+ <link rel="stylesheet" href="{{ google_fonts_url | add_sri }}" />
102
175
  </noscript>
103
176
 
104
177
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
105
- {% if prism_enabled %}
106
- <link rel="stylesheet" href="{{ prism_theme_url | add_sri }}" />
107
- <link rel="stylesheet" href="{{ prism_line_numbers_url | add_sri }}" />
108
- {% endif %}
109
178
  {% assign critical_config = site.critical_css | default: {} %}
110
179
  {% assign critical_enabled = critical_config.enabled | default: false %}
111
180
  {% assign main_stylesheet = '/assets/css/main.css' | relative_url %}
@@ -166,13 +235,9 @@
166
235
  </script>
167
236
 
168
237
  {% if math_enabled %}
169
- {% assign default_katex_cdn = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/' %}
170
- {% assign katex_cdn = math_settings.katex_cdn | default: default_katex_cdn %}
171
238
  {% assign katex_stylesheet_url = katex_cdn | append: 'katex.min.css' %}
172
239
  {% assign katex_js_url = katex_cdn | append: 'katex.min.js' %}
173
240
  {% assign katex_autorender_url = katex_cdn | append: 'contrib/auto-render.min.js' %}
174
- {% assign default_mathjax_url = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js' %}
175
- {% assign mathjax_url = math_settings.mathjax_cdn | default: default_mathjax_url %}
176
241
  {% if math_engine == 'katex' %}
177
242
  <link rel="stylesheet" href="{{ katex_stylesheet_url | add_sri }}" />
178
243
  <script defer src="{{ katex_js_url | add_sri }}"></script>
@@ -200,7 +265,10 @@
200
265
  displayMath: [['$$', '$$'], ['\\[', '\\]']],
201
266
  processEscapes: true,
202
267
  processEnvironments: true,
203
- packages: { '[+]': ['ams', 'mathtools', 'physics', 'mhchem', 'require', 'boldsymbol', 'braket', 'cancel'] },
268
+ // No 'require': MathJax 3.2 stopped starting up with "Illegal characters
269
+ // used in \require prefix", and nothing was typeset. Every extension the
270
+ // pages use is loaded below, so authors never need \require.
271
+ packages: { '[+]': ['ams', 'mathtools', 'physics', 'mhchem', 'boldsymbol', 'braket', 'cancel'] },
204
272
  tags: 'all',
205
273
  tagSide: 'right',
206
274
  tagIndent: '1.25em',
@@ -226,7 +294,7 @@
226
294
  },
227
295
  loader: {
228
296
  load: [
229
- '[tex]/require', '[tex]/ams', '[tex]/mathtools', '[tex]/physics', '[tex]/mhchem',
297
+ '[tex]/ams', '[tex]/mathtools', '[tex]/physics', '[tex]/mhchem',
230
298
  '[tex]/boldsymbol', '[tex]/braket', '[tex]/cancel', 'ui/menu', 'a11y/semantic-enrich', 'a11y/assistive-mml'
231
299
  ]
232
300
  },
@@ -239,7 +307,10 @@
239
307
  settings: {
240
308
  assistiveMml: true,
241
309
  collapsible: true,
242
- explorer: true
310
+ // MathJax's explorer gives each equation tabindex="1" when it
311
+ // attaches, which takes the equations out of the page's tab order.
312
+ // The assistive MathML above is what screen readers read.
313
+ explorer: false
243
314
  }
244
315
  }
245
316
  },
@@ -268,7 +339,11 @@
268
339
  if (window.DatalogMath && typeof window.DatalogMath.onPageReady === 'function') {
269
340
  window.DatalogMath.onPageReady();
270
341
  }
271
- return window.MathJax.startup.defaultPageReady();
342
+ // Scripts that act on typeset math wait for this event: until MathJax
343
+ // loads, window.MathJax is only this configuration object.
344
+ return window.MathJax.startup.defaultPageReady().then(() => {
345
+ document.dispatchEvent(new CustomEvent('datalog:math-ready'));
346
+ });
272
347
  }
273
348
  }
274
349
  };
@@ -277,56 +352,29 @@
277
352
  {% endif %}
278
353
  {% endif %}
279
354
 
280
- {% assign citation_source = page.citation_authors | default: page.authors %}
281
- {% if page.title or page.citation_title %}
282
- <meta name="citation_title" content="{{ page.citation_title | default: page_title | strip_html | normalize_whitespace }}" />
283
- {% endif %}
284
- {% if citation_source %}
285
- {% capture citation_source_json %}{{ citation_source | jsonify }}{% endcapture %}
286
- {% assign citation_source_first = citation_source_json | slice: 0, 1 %}
287
- {% if citation_source_first == '[' %}
288
- {% assign citation_author_list = citation_source %}
289
- {% else %}
290
- {% assign citation_author_list = citation_source | replace: ';', ',' | split: ',' %}
291
- {% endif %}
292
- {% for author in citation_author_list %}
293
- <meta name="citation_author" content="{{ author | strip | escape }}" />
294
- {% endfor %}
295
- {% elsif page.author or site.author.name %}
296
- <meta name="citation_author" content="{{ page.author | default: site.author.name | strip | escape }}" />
297
- {% endif %}
298
- {% if page.date %}
299
- <meta name="citation_publication_date" content="{{ page.date | date: '%Y/%m/%d' }}" />
300
- {% endif %}
301
- {% if page.doi %}
302
- <meta name="citation_doi" content="{{ page.doi }}" />
303
- {% endif %}
304
- {% if page.journal %}
305
- <meta name="citation_journal_title" content="{{ page.journal }}" />
306
- {% endif %}
307
- {% if page.conference %}
308
- <meta name="citation_conference_title" content="{{ page.conference }}" />
309
- {% endif %}
310
- {% if page.orcid or site.author.orcid %}
311
- <meta name="citation_orcid" content="{{ page.orcid | default: site.author.orcid }}" />
312
- {% endif %}
313
- {% if page.dataset_doi %}
314
- <meta name="citation_dataset_doi" content="{{ page.dataset_doi }}" />
315
- {% endif %}
316
- {% if page.citation_pdf %}
317
- <link rel="citation_pdf_url" href="{{ page.citation_pdf | absolute_url }}" />
318
- {% endif %}
355
+ {%- comment -%} Highwire and Dublin Core tags, for a page read as a research article; the include decides which. {%- endcomment -%}
356
+ {% include meta/scholarly.html %}
319
357
 
320
358
  <link rel="alternate" type="application/atom+xml" title="{{ site.title }}" href="{{ '/feed.xml' | absolute_url }}" />
321
359
  <meta http-equiv="Permissions-Policy" content="interest-cohort=()" />
360
+ {%- comment -%} A verification tag renders only when the site sets its code: an empty one verifies nothing. {%- endcomment %}
361
+ {% if site.google_site_verification and site.google_site_verification != "" %}
322
362
  <meta name="google-site-verification" content="{{ site.google_site_verification }}" />
363
+ {% endif %}
364
+ {% if site.bing_site_verification and site.bing_site_verification != "" %}
323
365
  <meta name="msvalidate.01" content="{{ site.bing_site_verification }}" />
366
+ {% endif %}
367
+ {% if site.yandex_site_verification and site.yandex_site_verification != "" %}
324
368
  <meta name="yandex-verification" content="{{ site.yandex_site_verification }}" />
369
+ {% endif %}
370
+ {% if site.baidu_site_verification and site.baidu_site_verification != "" %}
325
371
  <meta name="baidu-site-verification" content="{{ site.baidu_site_verification }}" />
372
+ {% endif %}
326
373
  <meta name="plausible-domain" content="{{ site.url | replace: 'https://', '' | replace: 'http://', '' }}" />
327
374
 
328
375
  <script nonce="{{ page.csp_nonce }}">
329
376
  document.documentElement.classList.add('js');
330
377
  </script>
331
378
 
379
+ {%- comment -%} Not include_cached: its inline script carries the page's CSP nonce. {%- endcomment -%}
332
380
  {% include analytics.html %}
@@ -3,37 +3,34 @@
3
3
  required:
4
4
  - items
5
5
  optional:
6
- - page
7
- - contexts
6
+ - active
7
+ - lang
8
8
  ---
9
- Renders the primary navigation list with active state awareness.
9
+ Renders the primary navigation list. `active` lists the indexes of the items that
10
+ mark the current section, each between commas (",2,"); header.html works them out
11
+ from the page. Nothing else here depends on the page, which is what lets
12
+ header.html render this with include_cached. `lang` is passed only so that each
13
+ page language gets its own copy of any translated descriptions.
10
14
  {%- endcomment -%}
11
15
  {%- assign nav_items = include.items | default: '' -%}
12
16
  {%- if nav_items == '' -%}
13
17
  {%- assign nav_items = '' | split: '' -%}
14
18
  {%- endif -%}
15
- {%- assign active_page = include.page | default: page -%}
16
- {%- assign contexts = include.contexts | default: '' -%}
17
- {%- if contexts == '' -%}
18
- {%- assign contexts = '' | split: '' -%}
19
- {%- endif -%}
19
+ {%- assign active_items = include.active | default: '' -%}
20
20
  <ul class="nav-list">
21
21
  {%- for item in nav_items -%}
22
22
  {%- assign item_url = item.url | relative_url -%}
23
+ {%- capture item_marker -%},{{ forloop.index0 }},{%- endcapture -%}
23
24
  {%- assign is_active = false -%}
25
+ {%- if active_items contains item_marker -%}
26
+ {%- assign is_active = true -%}
27
+ {%- endif -%}
24
28
  {%- assign nav_title = item.title | default: 'Untitled' | strip -%}
25
29
  {%- assign nav_section = item.section | default: nav_title | replace: '_', ' ' | replace: '-', ' ' | strip -%}
26
30
  {%- assign nav_description = item.description | default: '' -%}
27
31
  {%- if nav_description == '' and item.description_key -%}
28
32
  {%- capture nav_description -%}{% t item.description_key %}{%- endcapture -%}
29
33
  {%- 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
34
  {%- if nav_description == '' -%}
38
35
  {%- assign nav_description = nav_section | default: nav_title -%}
39
36
  {%- assign nav_description = nav_description | append: ' resources' -%}