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,10 +1,31 @@
1
1
  {% assign localization_config = site.theme_options.localization %}
2
2
  {% assign navigation_data = site.data.navigation %}
3
+ {%- comment -%} `header:` (or `main:`) in _data/navigation.yml lists the links. Without it the header has no navigation, rather than links to sections the site may not have. {%- endcomment -%}
4
+ {% assign nav_items = navigation_data.header | default: navigation_data.main %}
5
+ {%- comment -%}
6
+ The navigation is the same on every page except for which links mark the current
7
+ section, so header/navigation.html renders from the indexes of those links (",2,")
8
+ and is cached for each distinct set.
9
+ {%- endcomment -%}
10
+ {% assign page_contexts = '' | split: '' %}
11
+ {% if page.section %}{% assign page_contexts = page_contexts | push: page.section %}{% endif %}
12
+ {% if page.layout %}{% assign page_contexts = page_contexts | push: page.layout %}{% endif %}
13
+ {% if page.collection %}{% assign page_contexts = page_contexts | push: page.collection %}{% endif %}
14
+ {% if page.type %}{% assign page_contexts = page_contexts | push: page.type %}{% endif %}
15
+ {%- capture active_items -%}
16
+ {%- for item in nav_items -%}
17
+ {%- assign item_url = item.url | relative_url -%}
18
+ {%- if page.url == item.url or page.url == item_url -%},{{ forloop.index0 }}
19
+ {%- elsif item.section and page_contexts contains item.section -%},{{ forloop.index0 }}
20
+ {%- elsif item.url != '/' and page.url contains item.url -%},{{ forloop.index0 }}
21
+ {%- endif -%}
22
+ {%- endfor -%},
23
+ {%- endcapture -%}
3
24
  <header class="site-header" role="banner" data-sticky-header>
4
25
  <div class="header-progress" aria-hidden="true">
5
26
  <progress class="header-progress__bar" value="0" max="100" data-scroll-progress></progress>
6
27
  </div>
7
- <div class="visually-hidden" aria-live="polite" id="progress-announcement">Reading progress: <span data-scroll-progress-value>0</span>%</div>
28
+ {%- comment -%} No live region for the percentage: screen readers announced it on every scroll event. {%- endcomment %}
8
29
  <div class="container header-container">
9
30
  <div class="header-primary">
10
31
  {% assign brand_symbol = site.brand.accent_symbol | default: '∀ data · Σ insights' | strip %}
@@ -18,7 +39,7 @@
18
39
  </svg>
19
40
  </span>
20
41
  <span class="site-title-group">
21
- <span class="site-title">{{ site.name | default: 'DataLog' }}</span>
42
+ <span class="site-title">{{ site.name | default: site.title }}</span>
22
43
  <span class="site-tagline">{{ brand_symbol }}</span>
23
44
  </span>
24
45
  </a>
@@ -41,30 +62,18 @@
41
62
  </svg>
42
63
  </button>
43
64
  {% endif %}
65
+ {% if nav_items.size > 0 %}
44
66
  <button class="header-control header-control--icon nav-toggle" type="button" aria-expanded="false" aria-controls="site-nav" aria-label="Toggle navigation">
45
67
  <span aria-hidden="true">☰</span>
46
68
  </button>
69
+ {% endif %}
47
70
  </div>
48
71
  </div>
49
72
  </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 %}
73
+ {% if nav_items.size > 0 %}
66
74
  <nav id="site-nav" class="site-nav" role="navigation" aria-label="Primary navigation" data-open="false">
67
- {% include header/navigation.html items=nav_items page=page contexts=page_contexts %}
75
+ {% include_cached header/navigation.html items=nav_items active=active_items lang=page.lang %}
68
76
  </nav>
77
+ {% endif %}
69
78
  </div>
70
79
  </header>
@@ -19,7 +19,11 @@ Renders the standard article scaffold used by the default layout.
19
19
  {%- endif -%}
20
20
  <header class="article-header">
21
21
  {%- unless hero_overlay_title -%}
22
- {%- if article_page.title -%}
22
+ {%- comment -%}
23
+ `show_title: false`, in a page's front matter or a layout's, leaves the <h1> to a
24
+ page or layout that renders its own heading, so the page has one.
25
+ {%- endcomment -%}
26
+ {%- if article_page.title and article_page.show_title != false and layout.show_title != false -%}
23
27
  <h1 class="article-title" itemprop="headline">{{ article_page.title }}</h1>
24
28
  {%- endif -%}
25
29
  {%- if article_page.subtitle -%}
@@ -48,14 +52,12 @@ Renders the standard article scaffold used by the default layout.
48
52
  </dd>
49
53
  </div>
50
54
  {%- endif -%}
51
- {%- assign author_name = article_page.author | default: site.author.name -%}
55
+ {%- assign article_authors = article_page | page_authors -%}
52
56
  {%- comment -%} `show_author: false` hides the byline, for pages that are site chrome rather than articles. {%- endcomment -%}
53
- {%- if author_name and article_page.show_author != false -%}
57
+ {%- if article_authors.size > 0 and article_page.show_author != false -%}
54
58
  <div>
55
- <dt class="visually-hidden">{% t 'article.meta.author' %}</dt>
56
- <dd itemprop="author" itemscope itemtype="https://schema.org/Person">
57
- <span itemprop="name">{{ author_name }}</span>
58
- </dd>
59
+ <dt class="visually-hidden">{% if article_authors.size > 1 %}{% t 'article.meta.authors' %}{% else %}{% t 'article.meta.author' %}{% endif %}</dt>
60
+ <dd>{% include components/author-list.html people=article_authors show_affiliation=false %}</dd>
59
61
  </div>
60
62
  {%- endif -%}
61
63
  </dl>
@@ -0,0 +1,14 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ The public settings of the site's dynamic services (`dynamic_services` in
6
+ _config.yml), for assets/js/dynamic-services/client.js, on a site that sets
7
+ a base URL. Every reader's browser reads this, so it holds no credential:
8
+ the configuration validator stops the build on a key that names one.
9
+ {%- endcomment -%}
10
+ {%- if site.dynamic_services.base_url and site.dynamic_services.base_url != '' %}
11
+ <script nonce="{{ page.csp_nonce }}">
12
+ window.DatalogDynamicServices = {{ site.dynamic_services | jsonify }};
13
+ </script>
14
+ {%- endif -%}
@@ -8,12 +8,20 @@ optional:
8
8
  Computes math rendering settings shared by layouts.
9
9
  Exposes math_enabled, math_engine, math_status_id, and math_has_expressions variables.
10
10
 
11
- math_enabled resolves, in order: the page's `mathjax` or `math` front matter,
12
- then `theme_options.math.render_on_load` (falling back to `features.mathjax`).
13
- With `render_on_load: auto` the engine is only loaded when the rendered page
14
- contains math (`$`, `\(`, `\[` or kramdown's `math/tex` scripts) or declares
15
- `math_expressions`; `true` loads it on every page; `false` only on pages that
16
- opt in.
11
+ math_enabled resolves, in order: the page's `math` front matter, then its
12
+ `mathjax` front matter, then `theme_options.math.render_on_load` (falling back
13
+ to `features.mathjax`). `mathjax` is an alias read only when `math` is unset: it
14
+ used to be read first, so a page could not turn off with `math: false` what a
15
+ `mathjax: true` in front matter defaults had turned on.
16
+ _plugins/math_preprocessor.rb resolves the two the same way.
17
+ With `render_on_load: auto` the engine is only loaded on pages with math: the
18
+ math preprocessor records each expression it wraps in `math_expressions`, and
19
+ leaves code alone. Kramdown's `math/tex` scripts and the preprocessor's
20
+ `math-expression--source` wrappers in the rendered page count too: notebook
21
+ pages carry the wrappers but record no expressions of their own. Searching the
22
+ rendered page for `$`, `\(` or `\[` instead loaded MathJax for shell variables,
23
+ prices and escaped parentheses in code. `true` loads it on every page; `false`
24
+ only on pages that opt in.
17
25
  {%- endcomment -%}
18
26
  {%- assign math_settings = site.theme_options.math | default: {} -%}
19
27
  {%- assign math_engine = include.page.math_engine | default: math_settings.engine | default: 'mathjax' -%}
@@ -29,13 +37,13 @@ opt in.
29
37
  {%- if math_load == nil -%}
30
38
  {%- assign math_load = site.features.mathjax -%}
31
39
  {%- endif -%}
32
- {%- if include.page.mathjax != nil -%}
33
- {%- assign math_enabled = include.page.mathjax -%}
34
- {%- elsif include.page.math != nil -%}
40
+ {%- if include.page.math != nil -%}
35
41
  {%- assign math_enabled = include.page.math -%}
42
+ {%- elsif include.page.mathjax != nil -%}
43
+ {%- assign math_enabled = include.page.mathjax -%}
36
44
  {%- elsif math_load == 'auto' -%}
37
45
  {%- assign math_enabled = math_has_expressions -%}
38
- {%- if content contains 'math/tex' or content contains '$' or content contains '\(' or content contains '\[' -%}
46
+ {%- if content contains 'math/tex' or content contains 'math-expression--source' -%}
39
47
  {%- assign math_enabled = true -%}
40
48
  {%- endif -%}
41
49
  {%- else -%}
@@ -0,0 +1,27 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - person
5
+ ---
6
+ One schema.org Person, as JSON, for a record from `page | page_authors` or
7
+ `page | page_contributors`. The site's own author links to the site when the
8
+ record names no url of its own.
9
+ {%- endcomment -%}
10
+ {%- assign person_url = include.person.url -%}
11
+ {%- if person_url == nil and include.person.site_author -%}{%- assign person_url = site.url -%}{%- endif -%}
12
+ {
13
+ "@type": "Person",
14
+ "name": {{ include.person.name | jsonify }}
15
+ {%- if person_url -%},
16
+ "url": {{ person_url | absolute_url | jsonify }}
17
+ {%- endif -%}
18
+ {%- if include.person.affiliation -%},
19
+ "affiliation": {
20
+ "@type": "Organization",
21
+ "name": {{ include.person.affiliation | jsonify }}
22
+ }
23
+ {%- endif -%}
24
+ {%- if include.person.same_as.size > 0 -%},
25
+ "sameAs": {{ include.person.same_as | jsonify }}
26
+ {%- endif -%}
27
+ }
@@ -0,0 +1,45 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ Resolves who publishes the site, for structured data. Sets publisher_type
6
+ ("Person" or "Organization"), publisher_name, publisher_url and, for an
7
+ Organization, publisher_logo and publisher_logo_default (true when the logo is
8
+ the theme's 512px icon, whose size is known).
9
+
10
+ `publisher` in _config.yml names the publisher. Without it, the site's author
11
+ publishes as a Person, or the site title as an Organization when there is no
12
+ author name. The author's affiliation is not the publisher: schema.html puts it
13
+ on the author.
14
+ {%- endcomment -%}
15
+ {%- assign site_author_name = site.author.name | default: site.author -%}
16
+ {%- if site.publisher.type == 'Organization' -%}
17
+ {%- assign publisher_type = 'Organization' -%}
18
+ {%- else -%}
19
+ {%- assign publisher_type = 'Person' -%}
20
+ {%- endif -%}
21
+ {%- assign publisher_name = site.publisher.name -%}
22
+ {%- if publisher_type == 'Person' -%}
23
+ {%- assign publisher_name = publisher_name | default: site_author_name -%}
24
+ {%- if publisher_name == nil or publisher_name == '' -%}
25
+ {%- assign publisher_type = 'Organization' -%}
26
+ {%- endif -%}
27
+ {%- endif -%}
28
+ {%- if publisher_type == 'Organization' -%}
29
+ {%- assign publisher_name = publisher_name | default: site.title -%}
30
+ {%- endif -%}
31
+ {%- if site.publisher.url -%}
32
+ {%- assign publisher_url = site.publisher.url | absolute_url -%}
33
+ {%- else -%}
34
+ {%- assign publisher_url = site.url -%}
35
+ {%- endif -%}
36
+ {%- assign publisher_logo = nil -%}
37
+ {%- assign publisher_logo_default = false -%}
38
+ {%- if publisher_type == 'Organization' -%}
39
+ {%- if site.publisher.logo -%}
40
+ {%- assign publisher_logo = site.publisher.logo | absolute_url -%}
41
+ {%- else -%}
42
+ {%- assign publisher_logo = '/assets/img/favicons/android-chrome-512x512.png' | absolute_url -%}
43
+ {%- assign publisher_logo_default = true -%}
44
+ {%- endif -%}
45
+ {%- endif -%}
@@ -10,12 +10,13 @@ Provides rich structured data for:
10
10
  - Article/BlogPosting/TechnicalArticle schema for posts
11
11
  - WebPage schema for standard pages
12
12
  - Author information with social profile links
13
- - Publisher organization with branding
13
+ - Publisher: a Person or an Organization, from `publisher` in _config.yml
14
14
  - Images, keywords, and content metadata
15
15
 
16
16
  Defaults to TechnicalArticle for posts, WebPage for other pages.
17
17
  {%- endcomment -%}
18
18
  {%- assign schema_page = include.page -%}
19
+ {%- include meta/publisher.html -%}
19
20
  {%- assign is_post = false -%}
20
21
  {%- if schema_page.layout == 'post' or schema_page.collection == 'posts' -%}
21
22
  {%- assign is_post = true -%}
@@ -30,7 +31,8 @@ Defaults to TechnicalArticle for posts, WebPage for other pages.
30
31
  {%- assign schema_nonce = schema_page.csp_nonce | default: page.csp_nonce | default: nonce_lookup[schema_page.path] | default: nonce_lookup[page.path] | default: nonce_lookup[page.url] -%}
31
32
  {%- assign description = schema_page.description | default: schema_page.excerpt | strip_html | strip_newlines | truncate: 300 -%}
32
33
  {%- assign page_url = schema_page.url | absolute_url -%}
33
- {%- assign author_name = schema_page.author | default: site.author.name -%}
34
+ {%- assign schema_authors = schema_page | page_authors -%}
35
+ {%- assign schema_contributors = schema_page | page_contributors -%}
34
36
  {%- assign word_count = schema_page.content | strip_html | number_of_words -%}
35
37
  {%- assign modified = schema_page.last_modified_at | default: schema_page.updated | default: schema_page.date -%}
36
38
  <script type="application/ld+json" nonce="{{ schema_nonce }}">
@@ -41,8 +43,9 @@ Defaults to TechnicalArticle for posts, WebPage for other pages.
41
43
  "@type": "WebPage",
42
44
  "@id": {{ page_url | jsonify }}
43
45
  },
44
- "headline": {{ schema_page.title | truncate: 110 | jsonify }},
45
- {%- if description -%}
46
+ "headline": {{ schema_page.title | default: site.title | truncate: 110 | jsonify }},
47
+ {%- comment -%} Values the page doesn't have are left out: "description": "" and "dateModified": "" are invalid structured data. {%- endcomment -%}
48
+ {%- if description and description != "" -%}
46
49
  "description": {{ description | jsonify }},
47
50
  {%- endif -%}
48
51
  "url": {{ page_url | jsonify }},
@@ -64,7 +67,9 @@ Defaults to TechnicalArticle for posts, WebPage for other pages.
64
67
  {%- if schema_page.date -%}
65
68
  "datePublished": "{{ schema_page.date | date_to_xmlschema }}",
66
69
  {%- endif -%}
70
+ {%- if modified -%}
67
71
  "dateModified": "{{ modified | date_to_xmlschema }}",
72
+ {%- endif -%}
68
73
  {%- if word_count > 0 -%}
69
74
  "wordCount": {{ word_count }},
70
75
  {%- endif -%}
@@ -77,38 +82,35 @@ Defaults to TechnicalArticle for posts, WebPage for other pages.
77
82
  {%- if is_post -%}
78
83
  "inLanguage": "{{ schema_page.lang | default: site.locale | default: 'en' | split: '_' | first }}",
79
84
  {%- endif -%}
80
- "author": {
81
- "@type": "Person",
82
- "name": {{ author_name | jsonify }},
83
- "url": {{ site.url | jsonify }}
84
- {%- if site.author.orcid -%},
85
- "sameAs": [
86
- {{ site.author.orcid | jsonify }}
87
- {%- if site.author.github -%},
88
- "https://github.com/{{ site.author.github }}"
89
- {%- endif -%}
90
- {%- if site.author.twitter -%},
91
- "https://twitter.com/{{ site.author.twitter }}"
92
- {%- endif -%}
93
- {%- if site.author.linkedin -%},
94
- "https://linkedin.com/in/{{ site.author.linkedin }}"
95
- {%- endif -%}
96
- {%- if site.author.researchgate -%},
97
- {{ site.author.researchgate | jsonify }}
98
- {%- endif -%}
99
- ]
100
- {%- endif -%}
101
- },
85
+ {%- comment -%} One author is an object, as it always was; several are a list; a site without an author has none. {%- endcomment -%}
86
+ {%- if schema_authors.size > 0 -%}
87
+ "author": {% if schema_authors.size > 1 %}[{% endif %}
88
+ {%- for author in schema_authors -%}
89
+ {% include meta/person-json.html person=author %}{% unless forloop.last %},{% endunless %}
90
+ {%- endfor -%}
91
+ {% if schema_authors.size > 1 %}]{% endif %},
92
+ {%- endif -%}
93
+ {%- if schema_contributors.size > 0 -%}
94
+ "contributor": [
95
+ {%- for contributor in schema_contributors -%}
96
+ {% include meta/person-json.html person=contributor %}{% unless forloop.last %},{% endunless %}
97
+ {%- endfor -%}
98
+ ],
99
+ {%- endif -%}
102
100
  "publisher": {
103
- "@type": "Organization",
104
- "name": {{ site.author.affiliation | default: site.title | jsonify }},
105
- "url": {{ site.url | jsonify }},
101
+ "@type": {{ publisher_type | jsonify }},
102
+ "name": {{ publisher_name | jsonify }},
103
+ "url": {{ publisher_url | jsonify }}
104
+ {%- if publisher_logo -%},
106
105
  "logo": {
107
106
  "@type": "ImageObject",
108
- "url": {{ '/assets/img/favicons/android-chrome-512x512.png' | absolute_url | jsonify }},
107
+ "url": {{ publisher_logo | jsonify }}
108
+ {%- if publisher_logo_default -%},
109
109
  "width": 512,
110
110
  "height": 512
111
+ {%- endif -%}
111
112
  }
113
+ {%- endif -%}
112
114
  }
113
115
  {%- if schema_page.doi -%},
114
116
  "identifier": {
@@ -120,6 +122,41 @@ Defaults to TechnicalArticle for posts, WebPage for other pages.
120
122
  {%- if schema_page.citation_key -%},
121
123
  "citation": {{ schema_page.citation_key | jsonify }}
122
124
  {%- endif -%}
125
+ {%- comment -%} The licence of the text and figures, and who holds the copyright. {%- endcomment -%}
126
+ {%- assign content_license = schema_page | page_license -%}
127
+ {%- if content_license -%}
128
+ {%- if content_license.url -%},
129
+ "license": {{ content_license.url | jsonify }}
130
+ {%- endif -%}
131
+ {%- if content_license.year -%},
132
+ "copyrightYear": {{ content_license.year | jsonify }}
133
+ {%- endif -%}
134
+ {%- if content_license.holder -%},
135
+ "copyrightHolder": {% if content_license.people %}{% if content_license.holders.size > 1 %}[{% endif %}
136
+ {%- for holder in content_license.holders -%}
137
+ { "@type": "Person", "name": {{ holder | jsonify }} }{% unless forloop.last %},{% endunless %}
138
+ {%- endfor -%}
139
+ {% if content_license.holders.size > 1 %}]{% endif %}{% else %}{ "@type": "Organization", "name": {{ content_license.holder | jsonify }} }{% endif %}
140
+ {%- endif -%}
141
+ {%- endif -%}
142
+ {%- comment -%} Each correction in the revision history, with its date, summary and link. {%- endcomment -%}
143
+ {%- assign corrections = schema_page.revisions | where: 'type', 'correction' -%}
144
+ {%- if corrections and corrections.size > 0 -%},
145
+ "correction": [
146
+ {%- for correction in corrections -%}
147
+ {
148
+ "@type": "CorrectionComment",
149
+ "datePublished": "{{ correction.date | date_to_xmlschema }}",
150
+ "text": {{ correction.summary | jsonify }}
151
+ {%- if correction.details_url -%}
152
+ {%- assign correction_url = correction.details_url -%}
153
+ {%- unless correction_url contains '://' -%}{%- assign correction_url = correction_url | absolute_url -%}{%- endunless -%},
154
+ "url": {{ correction_url | jsonify }}
155
+ {%- endif -%}
156
+ }{% unless forloop.last %},{% endunless %}
157
+ {%- endfor -%}
158
+ ]
159
+ {%- endif -%}
123
160
  }
124
161
  </script>
125
162
  {%- comment -%} Add BreadcrumbList schema for posts {%- endcomment -%}
@@ -0,0 +1,121 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ Scholarly discovery metadata for a page read as a research article: the
6
+ Highwire meta tags Google Scholar and reference managers read, and their
7
+ Dublin Core equivalents. Only a page the `scholarly` filter accepts gets them
8
+ (_plugins/scholarly.rb): a research article, a page with `scholarly: true`,
9
+ or every post when _config.yml sets `scholarly: true`. A field the page
10
+ lacks leaves its tag out. The authors are the page's (page_authors), as in
11
+ the byline, the JSON-LD and the citation exports; `citation_authors` names
12
+ the indexed authors alone.
13
+ {%- endcomment -%}
14
+ {%- assign is_scholarly = page | scholarly -%}
15
+ {%- if is_scholarly and page.title -%}
16
+ {%- include meta/publisher.html -%}
17
+ {%- assign scholarly_title = page.citation_title | default: page.title | strip_html | normalize_whitespace -%}
18
+ {%- assign scholarly_url = page.url | absolute_url -%}
19
+ {%- assign scholarly_authors = page | page_authors -%}
20
+ {%- assign scholarly_names = scholarly_authors | map: 'name' -%}
21
+ {%- assign scholarly_override = false -%}
22
+ {%- if page.citation_authors -%}
23
+ {%- assign scholarly_override = true -%}
24
+ {%- capture citation_source_json -%}{{ page.citation_authors | jsonify }}{%- endcapture -%}
25
+ {%- assign citation_source_first = citation_source_json | slice: 0, 1 -%}
26
+ {%- if citation_source_first == '[' -%}
27
+ {%- assign scholarly_names = page.citation_authors -%}
28
+ {%- else -%}
29
+ {%- assign scholarly_names = page.citation_authors | replace: ';', ',' | split: ',' -%}
30
+ {%- endif -%}
31
+ {%- endif -%}
32
+ {%- assign scholarly_pdf = page.pdf_url | default: page.citation_pdf -%}
33
+ {%- assign scholarly_journal = page.journal | default: page.publication -%}
34
+ {%- assign scholarly_issue = page.issue | default: page.number -%}
35
+ {%- assign scholarly_keywords = page.keywords | default: page.tags -%}
36
+ {%- assign scholarly_publisher = page.publisher | default: publisher_name -%}
37
+ {%- assign scholarly_language = page.lang | default: site.locale | default: 'en' | split: '_' | first | split: '-' | first -%}
38
+ {%- assign scholarly_license = page | page_license -%}
39
+ {%- assign scholarly_description = page.description | default: page.excerpt | strip_html | normalize_whitespace | truncate: 300 -%}
40
+ <meta name="citation_title" content="{{ scholarly_title | escape }}" />
41
+ {%- if scholarly_override %}
42
+ {%- for name in scholarly_names %}
43
+ <meta name="citation_author" content="{{ name | strip | escape }}" />
44
+ {%- endfor %}
45
+ {%- else %}
46
+ {%- for author in scholarly_authors %}
47
+ <meta name="citation_author" content="{{ author.name | strip | escape }}" />
48
+ {%- if author.affiliation %}
49
+ <meta name="citation_author_institution" content="{{ author.affiliation | strip | escape }}" />
50
+ {%- endif %}
51
+ {%- if author.orcid %}
52
+ <meta name="citation_author_orcid" content="{{ author.orcid | escape }}" />
53
+ {%- endif %}
54
+ {%- endfor %}
55
+ {%- endif %}
56
+ {%- if page.date %}
57
+ <meta name="citation_publication_date" content="{{ page.date | date: '%Y/%m/%d' }}" />
58
+ {%- endif %}
59
+ <meta name="citation_public_url" content="{{ scholarly_url }}" />
60
+ <meta name="citation_fulltext_html_url" content="{{ scholarly_url }}" />
61
+ {%- if scholarly_pdf %}
62
+ <meta name="citation_pdf_url" content="{{ scholarly_pdf | absolute_url }}" />
63
+ {%- endif %}
64
+ {%- if page.doi %}
65
+ <meta name="citation_doi" content="{{ page.doi | escape }}" />
66
+ {%- endif %}
67
+ {%- if scholarly_journal %}
68
+ <meta name="citation_journal_title" content="{{ scholarly_journal | escape }}" />
69
+ {%- endif %}
70
+ {%- if page.conference %}
71
+ <meta name="citation_conference_title" content="{{ page.conference | escape }}" />
72
+ {%- endif %}
73
+ {%- if page.volume %}
74
+ <meta name="citation_volume" content="{{ page.volume | escape }}" />
75
+ {%- endif %}
76
+ {%- if scholarly_issue %}
77
+ <meta name="citation_issue" content="{{ scholarly_issue | escape }}" />
78
+ {%- endif %}
79
+ {%- if page.pages %}
80
+ {%- assign page_range = page.pages | append: '' | replace: '–', '-' | replace: '—', '-' | split: '-' %}
81
+ <meta name="citation_firstpage" content="{{ page_range[0] | strip | escape }}" />
82
+ {%- if page_range.size > 1 %}
83
+ <meta name="citation_lastpage" content="{{ page_range[1] | strip | escape }}" />
84
+ {%- endif %}
85
+ {%- endif %}
86
+ {%- if page.issn %}
87
+ <meta name="citation_issn" content="{{ page.issn | escape }}" />
88
+ {%- endif %}
89
+ {%- if page.isbn %}
90
+ <meta name="citation_isbn" content="{{ page.isbn | escape }}" />
91
+ {%- endif %}
92
+ <meta name="citation_publisher" content="{{ scholarly_publisher | escape }}" />
93
+ <meta name="citation_language" content="{{ scholarly_language }}" />
94
+ {%- if scholarly_keywords and scholarly_keywords.size > 0 %}
95
+ <meta name="citation_keywords" content="{{ scholarly_keywords | join: '; ' | escape }}" />
96
+ {%- endif %}
97
+ <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
98
+ <meta name="DC.title" content="{{ scholarly_title | escape }}" />
99
+ {%- for name in scholarly_names %}
100
+ <meta name="DC.creator" content="{{ name | strip | escape }}" />
101
+ {%- endfor %}
102
+ {%- if page.date %}
103
+ <meta name="DC.date" content="{{ page.date | date: '%Y-%m-%d' }}" />
104
+ {%- endif %}
105
+ {%- if page.doi %}
106
+ {%- assign scholarly_identifier = page.doi -%}
107
+ {%- unless scholarly_identifier contains '://' -%}{%- assign scholarly_identifier = 'https://doi.org/' | append: page.doi -%}{%- endunless %}
108
+ <meta name="DC.identifier" content="{{ scholarly_identifier | escape }}" />
109
+ {%- else %}
110
+ <meta name="DC.identifier" content="{{ scholarly_url }}" />
111
+ {%- endif %}
112
+ <meta name="DC.type" content="Text" />
113
+ <meta name="DC.language" content="{{ scholarly_language }}" />
114
+ <meta name="DC.publisher" content="{{ scholarly_publisher | escape }}" />
115
+ {%- if scholarly_license.url %}
116
+ <meta name="DC.rights" content="{{ scholarly_license.url | escape }}" />
117
+ {%- endif %}
118
+ {%- if scholarly_description and scholarly_description != '' %}
119
+ <meta name="DC.description" content="{{ scholarly_description | escape }}" />
120
+ {%- endif %}
121
+ {%- endif -%}
@@ -2,26 +2,18 @@
2
2
  ---
3
3
  required:
4
4
  - location
5
- optional:
6
- - syntax_config
7
5
  ---
8
- Outputs Prism assets in the head and shared data bootstrapping scripts in the body.
9
- Pass location="head" or location="body" to control which block renders.
6
+ Outputs the page data scripts and the feature loader at the end of the body
7
+ (location="body"). location="head" used to render Prism's scripts. Code is now
8
+ highlighted by Rouge when the site builds, so the head renders nothing.
10
9
  {%- endcomment -%}
11
- {%- assign syntax = include.syntax_config | default: site.theme_options.syntax_highlighting | default: {} -%}
12
- {%- assign prism_cdn = syntax.cdn | default: 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0' -%}
13
- {%- assign default_components = 'python|r|sql|julia|javascript' | split: '|' -%}
14
- {%- assign prism_components = syntax.components | default: default_components -%}
15
- {%- include meta/syntax-config.html -%}
16
- {%- if include.location == 'head' and prism_enabled -%}
17
- <script defer src="{{ (prism_cdn | append: '/prism.min.js') | add_sri }}"></script>
18
- {%- for component in prism_components -%}
19
- {%- unless component == 'core' -%}
20
- <script defer src="{{ (prism_cdn | append: '/components/prism-' | append: component | append: '.min.js') | add_sri }}"></script>
21
- {%- endunless -%}
22
- {%- endfor -%}
23
- <script defer src="{{ (prism_cdn | append: '/plugins/normalize-whitespace/prism-normalize-whitespace.min.js') | add_sri }}"></script>
24
- {%- elsif include.location == 'body' -%}
10
+ {%- if include.location == 'body' -%}
11
+ {%- comment -%}
12
+ Only academic.js reads the academic and publication data, and the loader
13
+ runs it only on pages with citation metrics, tables or charts. Inlined on
14
+ every page, it was a quarter of the home page's HTML.
15
+ {%- endcomment -%}
16
+ {%- if content contains 'data-citation-metric' or content contains 'data-citation-table' or content contains 'data-citation-chart' -%}
25
17
  {%- assign publications = site.data.publications | default: {} -%}
26
18
  <script nonce="{{ page.csp_nonce }}">
27
19
  window.DatalogAcademic = {{ site.data.academic | jsonify }};
@@ -32,22 +24,16 @@ Pass location="head" or location="body" to control which block renders.
32
24
  "yearly_totals": {{ publications.yearly_totals | jsonify }}
33
25
  };
34
26
  </script>
27
+ {%- endif -%}
28
+ {%- comment -%} Not include_cached: scripts.html reads the page's math and notebook settings and CSP nonce. {%- endcomment -%}
35
29
  {% include scripts.html %}
30
+ {%- comment -%}
31
+ core/github-cards.js reads the integration settings. The theme options and
32
+ content taxonomy were inlined here as well, and no script read them.
33
+ {%- endcomment -%}
36
34
  <script nonce="{{ page.csp_nonce }}">
37
- window.DatalogTheme = {{ site.theme_options | jsonify }};
38
35
  window.DatalogIntegrations = {{ site.integrations | jsonify }};
39
- window.DatalogContent = {{ site.content | jsonify }};
40
- </script>
41
- <script nonce="{{ page.csp_nonce }}">
42
- document.addEventListener('DOMContentLoaded', function () {
43
- if (window.Prism && window.Prism.plugins && window.Prism.plugins.NormalizeWhitespace) {
44
- Prism.plugins.NormalizeWhitespace.setDefaults({
45
- 'remove-trailing': true,
46
- 'remove-indent': true,
47
- 'left-trim': true,
48
- 'right-trim': true
49
- });
50
- }
51
- });
52
36
  </script>
37
+ {%- comment -%} The dynamic services' public settings, on a site that has a backend. {%- endcomment -%}
38
+ {% include meta/dynamic-services-config.html %}
53
39
  {%- endif -%}
@@ -0,0 +1,14 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ Webmention discovery (W3C Webmention, section 3.1.2): the receiver a site
6
+ names in `webmentions.endpoint` is advertised in every page's head, so a
7
+ website that links here can notify it. GitHub Pages cannot send the HTTP
8
+ Link header form, so the <link> form is the one the theme uses. Nothing is
9
+ advertised without an endpoint or with `webmentions.enabled: false`.
10
+ {%- endcomment -%}
11
+ {%- assign webmentions = site.webmentions -%}
12
+ {%- if webmentions.enabled != false and webmentions.endpoint and webmentions.endpoint != '' -%}
13
+ <link rel="webmention" href="{{ webmentions.endpoint }}" />
14
+ {%- endif -%}
@@ -10,17 +10,14 @@ Builds a list of related posts based on overlapping tags or categories.
10
10
  Falls back to a friendly message when no related content is available.
11
11
  {%- endcomment -%}
12
12
  {%- assign related_limit = include.limit | default: 3 -%}
13
- {%- assign source_posts = site.collections.posts.docs | default: site.posts | default: '' | split: '' -%}
14
- {%- assign layout_filtered = source_posts | where: 'layout', 'post' -%}
15
- {%- assign collection_filtered = source_posts | where: 'collection', 'posts' -%}
16
- {%- assign candidate_posts = layout_filtered | concat: collection_filtered -%}
17
- {%- assign sorted_candidates = candidate_posts | sort: 'date' | reverse -%}
13
+ {%- comment -%} site.posts is already newest first. {%- endcomment -%}
18
14
  {%- assign rendered_count = 0 -%}
19
15
  <section class="post-related" aria-labelledby="post-related-heading">
20
16
  <h2 id="post-related-heading">Related posts</h2>
21
17
  <ul class="post-related-list">
22
- {%- for candidate in sorted_candidates -%}
23
- {%- if candidate.url != include.page.url and rendered_count < related_limit -%}
18
+ {%- for candidate in site.posts -%}
19
+ {%- if rendered_count >= related_limit -%}{%- break -%}{%- endif -%}
20
+ {%- if candidate.url != include.page.url -%}
24
21
  {%- assign overlap = 0 -%}
25
22
  {%- if include.page.tags and candidate.tags -%}
26
23
  {%- for tag in include.page.tags -%}