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
@@ -0,0 +1,65 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ The reading-mode control of a post: a button that hides the site's chrome
6
+ and the panels around the article (`body.reading-mode`, styled in
7
+ _sass/_print.scss) and leaves the article with its metadata, its table of
8
+ contents and the way back. Nothing is duplicated: the same article is shown
9
+ with less around it. Escape leaves the mode. `theme_options.reading_mode.enabled:
10
+ false` removes the control; `remember: true` keeps the choice in localStorage
11
+ from one page to the next.
12
+ {%- endcomment -%}
13
+ {%- assign reading_mode = site.theme_options.reading_mode -%}
14
+ {%- unless reading_mode.enabled == false -%}
15
+ {%- capture reading_enter %}{% t 'post.reading_mode.enter' %}{% endcapture -%}
16
+ {%- capture reading_exit %}{% t 'post.reading_mode.exit' %}{% endcapture -%}
17
+ <div class="reading-mode-bar">
18
+ <button type="button" class="post-tool reading-mode-toggle" data-reading-mode-toggle aria-pressed="false" aria-describedby="reading-mode-hint"
19
+ data-label-enter="{{ reading_enter | strip | escape }}" data-label-exit="{{ reading_exit | strip | escape }}"{% if reading_mode.remember %} data-reading-mode-remember{% endif %}>
20
+ <svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
21
+ <path d="M2 4h6a4 4 0 0 1 4 4v12a3 3 0 0 0-3-3H2z"></path>
22
+ <path d="M22 4h-6a4 4 0 0 0-4 4v12a3 3 0 0 1 3-3h7z"></path>
23
+ </svg>
24
+ <span data-reading-mode-label>{{ reading_enter | strip }}</span>
25
+ </button>
26
+ <span class="visually-hidden" id="reading-mode-hint">{% t 'post.reading_mode.hint' %}</span>
27
+ </div>
28
+ <script nonce="{{ page.csp_nonce }}">
29
+ // Reading mode: a class on the body, the button's state and label, Escape to
30
+ // leave, and the choice remembered only when the site asks for it.
31
+ (function () {
32
+ var toggle = document.querySelector('[data-reading-mode-toggle]');
33
+ if (!toggle) return;
34
+ var label = toggle.querySelector('[data-reading-mode-label]');
35
+ var remember = toggle.hasAttribute('data-reading-mode-remember');
36
+ var key = 'datalog-reading-mode';
37
+
38
+ function apply(on) {
39
+ document.body.classList.toggle('reading-mode', on);
40
+ toggle.setAttribute('aria-pressed', on ? 'true' : 'false');
41
+ label.textContent = toggle.getAttribute(on ? 'data-label-exit' : 'data-label-enter');
42
+ if (!remember) return;
43
+ try {
44
+ if (on) localStorage.setItem(key, 'on');
45
+ else localStorage.removeItem(key);
46
+ } catch (error) {}
47
+ }
48
+
49
+ toggle.addEventListener('click', function () {
50
+ apply(!document.body.classList.contains('reading-mode'));
51
+ });
52
+ document.addEventListener('keydown', function (event) {
53
+ if (event.key === 'Escape' && document.body.classList.contains('reading-mode')) {
54
+ apply(false);
55
+ toggle.focus();
56
+ }
57
+ });
58
+ if (remember) {
59
+ try {
60
+ if (localStorage.getItem(key) === 'on') apply(true);
61
+ } catch (error) {}
62
+ }
63
+ })();
64
+ </script>
65
+ {%- endunless -%}
@@ -0,0 +1,27 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ The "Save for later" button of a post (assets/js/reading-state/ui.js): a
6
+ bookmark kept in this browser, and a link to the saved articles when the
7
+ site has a page for them (theme_options.reading_state.list_url). Renders
8
+ nothing when reading state or bookmarks are off.
9
+ {%- endcomment -%}
10
+ {%- assign reading_state = site.theme_options.reading_state -%}
11
+ {%- unless reading_state.enabled == false or reading_state.bookmarks == false -%}
12
+ {%- capture label_save %}{% t 'post.reading_state.save' %}{% endcapture -%}
13
+ {%- capture label_saved %}{% t 'post.reading_state.saved' %}{% endcapture -%}
14
+ {%- capture label_unavailable %}{% t 'post.reading_state.unavailable' %}{% endcapture -%}
15
+ <button type="button" class="post-tool bookmark-toggle" data-bookmark-toggle aria-pressed="false"
16
+ data-article="{{ page.url | relative_url }}" data-title="{{ page.title | escape }}"
17
+ data-label-save="{{ label_save | strip | escape }}" data-label-saved="{{ label_saved | strip | escape }}"
18
+ data-unavailable="{{ label_unavailable | strip | escape }}">
19
+ <svg aria-hidden="true" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
20
+ <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
21
+ </svg>
22
+ <span data-bookmark-label>{{ label_save | strip }}</span>
23
+ </button>
24
+ {%- if reading_state.list_url %}
25
+ <a class="post-tool post-tool--link" href="{{ reading_state.list_url | relative_url }}">{% t 'post.reading_state.saved_list' %}</a>
26
+ {%- endif %}
27
+ {%- endunless -%}
@@ -0,0 +1,71 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ A post's reading state (assets/js/reading-state/ui.js): the "resume where
6
+ you left off" prompt, the toolbar that appears over a selection, the panel
7
+ of private highlights and notes, and the controls to export, import and
8
+ erase the reader's data. Everything stays in this browser. The markup is
9
+ inert until the reading-state bundle runs; a browser without storage sees
10
+ the message and disabled controls. Renders nothing when reading state is
11
+ off; without progress or highlights, only the data controls remain.
12
+ {%- endcomment -%}
13
+ {%- assign reading_state = site.theme_options.reading_state -%}
14
+ {%- unless reading_state.enabled == false -%}
15
+ {%- assign want_progress = true -%}{%- if reading_state.progress == false -%}{%- assign want_progress = false -%}{%- endif -%}
16
+ {%- assign want_highlights = true -%}{%- if reading_state.highlights == false -%}{%- assign want_highlights = false -%}{%- endif -%}
17
+ {%- capture progress_label %}{% t 'post.reading_state.progress' %}{% endcapture -%}
18
+ {%- capture erase_confirm %}{% t 'post.reading_state.erase_confirm' %}{% endcapture -%}
19
+ {%- capture imported %}{% t 'post.reading_state.imported' %}{% endcapture -%}
20
+ {%- capture import_failed %}{% t 'post.reading_state.import_failed' %}{% endcapture -%}
21
+ {%- capture exported %}{% t 'post.reading_state.exported' %}{% endcapture -%}
22
+ {%- capture erased_article %}{% t 'post.reading_state.erased_article' %}{% endcapture -%}
23
+ {%- capture erased_all %}{% t 'post.reading_state.erased_all' %}{% endcapture -%}
24
+ <div class="reading-state" data-reading-state data-article="{{ page.url | relative_url }}" data-title="{{ page.title | escape }}" data-progress="{{ want_progress }}" data-highlights="{{ want_highlights }}">
25
+ {%- if want_progress %}
26
+ <div class="reading-resume" data-reading-resume data-progress-label="{{ progress_label | strip | escape }}" role="region" aria-labelledby="reading-resume-heading" hidden>
27
+ <p class="reading-resume__text"><strong id="reading-resume-heading">{% t 'post.reading_state.resume' %}</strong> <span data-reading-resume-detail></span></p>
28
+ <div class="reading-resume__actions">
29
+ <button type="button" class="post-tool" data-reading-resume-go>{% t 'post.reading_state.resume_button' %}</button>
30
+ <button type="button" class="post-tool" data-reading-resume-dismiss>{% t 'post.reading_state.dismiss' %}</button>
31
+ </div>
32
+ </div>
33
+ {%- endif %}
34
+ {%- if want_highlights %}
35
+ <div class="reading-toolbar" data-reading-toolbar role="toolbar" aria-label="{% t 'post.reading_state.highlight' %}" hidden>
36
+ <button type="button" data-reading-highlight>{% t 'post.reading_state.highlight' %}</button>
37
+ <button type="button" data-reading-note>{% t 'post.reading_state.note' %}</button>
38
+ </div>
39
+ {%- endif %}
40
+ <section class="reading-notes" aria-labelledby="reading-notes-heading" data-reading-panel>
41
+ <h2 id="reading-notes-heading" class="reading-notes__heading">{% if want_highlights %}{% t 'post.reading_state.highlights_heading' %}{% else %}{% t 'post.reading_state.data_heading' %}{% endif %}</h2>
42
+ <p class="reading-notes__intro">{% t 'post.reading_state.intro' %}{% if want_highlights %} {% t 'post.reading_state.shortcuts' %}{% endif %}</p>
43
+ <p class="reading-notes__unavailable" data-reading-unavailable hidden>{% t 'post.reading_state.unavailable' %}</p>
44
+ {%- if want_highlights %}
45
+ <p class="reading-notes__empty" data-reading-empty>{% t 'post.reading_state.empty' %}</p>
46
+ <ul class="reading-notes__list" data-reading-list-items></ul>
47
+ <template data-reading-item-template>
48
+ <li class="reading-note" data-annotation>
49
+ <blockquote class="reading-note__quote" data-annotation-quote></blockquote>
50
+ <p class="reading-note__meta"><span data-annotation-section></span> <span class="reading-note__lost" data-annotation-lost hidden>{% t 'post.reading_state.lost' %}</span></p>
51
+ <label class="reading-note__label"><span>{% t 'post.reading_state.note_label' %}</span><textarea rows="2" data-annotation-note></textarea></label>
52
+ <div class="reading-note__actions">
53
+ <button type="button" class="post-tool" data-annotation-go>{% t 'post.reading_state.go_to' %}</button>
54
+ <button type="button" class="post-tool" data-annotation-remove>{% t 'post.reading_state.remove' %}</button>
55
+ </div>
56
+ </li>
57
+ </template>
58
+ {%- endif %}
59
+ <details class="reading-data">
60
+ <summary>{% t 'post.reading_state.data_heading' %}</summary>
61
+ <div class="reading-data__actions">
62
+ <button type="button" class="post-tool" data-reading-export data-done="{{ exported | strip | escape }}">{% t 'post.reading_state.export' %}</button>
63
+ <label class="post-tool reading-data__import">{% t 'post.reading_state.import' %}<input type="file" accept="application/json,.json" data-reading-import data-done="{{ imported | strip | escape }}" data-failed="{{ import_failed | strip | escape }}"></label>
64
+ <button type="button" class="post-tool" data-reading-erase-article data-done="{{ erased_article | strip | escape }}">{% t 'post.reading_state.erase_article' %}</button>
65
+ <button type="button" class="post-tool" data-reading-erase-all data-confirm="{{ erase_confirm | strip | escape }}" data-done="{{ erased_all | strip | escape }}">{% t 'post.reading_state.erase_all' %}</button>
66
+ </div>
67
+ <p class="reading-data__status" data-reading-status aria-live="polite"></p>
68
+ </details>
69
+ </section>
70
+ </div>
71
+ {%- endunless -%}
@@ -0,0 +1,61 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - page
5
+ ---
6
+ "Reproduce this analysis": the code, data, notebook, environment and results
7
+ behind an article (`reproducibility` in front matter, read by the
8
+ page_reproducibility filter, _plugins/reproducibility.rb). Shows the
9
+ artifacts given, each with its identifiers, and renders nothing without one.
10
+ Site paths already carry the baseurl.
11
+ {%- endcomment -%}
12
+ {%- assign reproduce = include.page | page_reproducibility -%}
13
+ {%- if reproduce -%}
14
+ <section class="reproduce" aria-labelledby="reproduce-heading">
15
+ <h2 id="reproduce-heading" class="reproduce__heading">{% t 'post.reproduce.heading' %}</h2>
16
+ <p class="reproduce__intro">{% t 'post.reproduce.intro' %}</p>
17
+ <dl class="reproduce__list">
18
+ {%- for artifact in reproduce.artifacts %}
19
+ {%- assign kind_key = 'post.reproduce.' | append: artifact.kind %}
20
+ <div class="reproduce__item reproduce__item--{{ artifact.kind }}">
21
+ <dt>{{ kind_key | t }}</dt>
22
+ <dd>
23
+ {%- if artifact.url %}
24
+ <a class="reproduce__link" href="{{ artifact.url | escape }}"{% if artifact.external %} rel="external noopener"{% endif %}>{{ artifact.label | escape }}</a>
25
+ {%- endif %}
26
+ {%- if artifact.ref %}
27
+ {%- capture ref_text -%}
28
+ {%- if artifact.ref_url -%}
29
+ <a href="{{ artifact.ref_url | escape }}" rel="external noopener"><code>{{ artifact.ref | escape }}</code></a>
30
+ {%- else -%}
31
+ <code>{{ artifact.ref | escape }}</code>
32
+ {%- endif -%}
33
+ {%- endcapture %}
34
+ <span class="reproduce__detail">{% t 'post.reproduce.ref' ref: ref_text %}</span>
35
+ {%- endif %}
36
+ {%- if artifact.version %}
37
+ {%- assign version_text = artifact.version | escape %}
38
+ <span class="reproduce__detail">{% t 'post.reproduce.version' version: version_text %}</span>
39
+ {%- endif %}
40
+ {%- if artifact.doi %}
41
+ <span class="reproduce__detail">DOI {{ artifact.doi | escape }}</span>
42
+ {%- endif %}
43
+ {%- if artifact.file %}
44
+ {%- if artifact.file_url %}
45
+ <a class="reproduce__link" href="{{ artifact.file_url | escape }}"{% if artifact.file_url contains '://' %} rel="external noopener"{% endif %}><code>{{ artifact.file | escape }}</code></a>
46
+ {%- else %}
47
+ <code>{{ artifact.file | escape }}</code>
48
+ {%- endif %}
49
+ {%- endif %}
50
+ {%- if artifact.container %}
51
+ <span class="reproduce__detail">{% t 'post.reproduce.container' %} <code>{{ artifact.container | escape }}</code></span>
52
+ {%- endif %}
53
+ {%- if artifact.archive %}
54
+ <a class="reproduce__link" href="{{ artifact.archive | escape }}" rel="external noopener">{% t 'post.reproduce.archive' %}: {{ artifact.archive_label | escape }}</a>
55
+ {%- endif %}
56
+ </dd>
57
+ </div>
58
+ {%- endfor %}
59
+ </dl>
60
+ </section>
61
+ {%- endif -%}
@@ -2,7 +2,7 @@
2
2
  {% assign alt_text = include.alt | to_s %}
3
3
  {% if image_src == '' or alt_text == '' %}
4
4
  {% comment %}Missing required parameters{% endcomment %}
5
- {% assign fallback_loading = include.loading | default: site.config.datalog_image_config.lazy_loading | default: 'lazy' %}
5
+ {% assign fallback_loading = include.loading | default: site.datalog_image_config.lazy_loading | default: 'lazy' %}
6
6
  <img src="{{ image_src }}" alt="{{ alt_text }}" loading="{{ fallback_loading }}" decoding="async" />
7
7
  {% else %}
8
8
  {% assign baseurl = site.baseurl | default: '' %}
@@ -22,8 +22,8 @@
22
22
  {% assign normalized_src = normalized_src | replace: '//', '/' %}
23
23
  {% assign responsive_entry = manifest[normalized_src] %}
24
24
  {% endif %}
25
- {% assign requested_sizes = include.sizes | default: site.config.datalog_image_config.default_sizes | default: '100vw' %}
26
- {% assign loading_mode = include.loading | default: site.config.datalog_image_config.lazy_loading | default: 'lazy' %}
25
+ {% assign requested_sizes = include.sizes | default: site.datalog_image_config.default_sizes | default: '100vw' %}
26
+ {% assign loading_mode = include.loading | default: site.datalog_image_config.lazy_loading | default: 'lazy' %}
27
27
  {% if responsive_entry %}
28
28
  <picture>
29
29
  {% for source in responsive_entry.sources %}
@@ -0,0 +1,39 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - page
5
+ optional:
6
+ - date_format
7
+ ---
8
+ The revision history of an article (`revisions`, sorted newest first by
9
+ _plugins/revisions.rb), after its body, ending with the publication date.
10
+ Renders nothing for a page without revisions.
11
+ {%- endcomment -%}
12
+ {%- assign revisions = include.page.revisions -%}
13
+ {%- if revisions and revisions.size > 0 -%}
14
+ <section class="revision-history" id="revision-history" aria-labelledby="revision-history-heading">
15
+ <h2 id="revision-history-heading">{% t 'post.revisions.heading' %}</h2>
16
+ <ul class="revision-history__list">
17
+ {%- for revision in revisions -%}
18
+ {%- assign type_key = 'post.revisions.types.' | append: revision.type -%}
19
+ <li class="revision-history__item revision-history__item--{{ revision.type }}">
20
+ <time class="revision-history__date" datetime="{{ revision.date | date: '%Y-%m-%d' }}">{% include helpers/date-format.html date=revision.date format=include.date_format %}</time>
21
+ <span class="revision-history__type">{{ type_key | t }}</span>
22
+ <span class="revision-history__summary">{{ revision.summary | escape }}
23
+ {%- if revision.details_url -%}
24
+ {%- assign details_url = revision.details_url -%}
25
+ {%- unless details_url contains '://' -%}{%- assign details_url = details_url | relative_url -%}{%- endunless %}
26
+ <a class="revision-history__details" href="{{ details_url | escape }}">{% t 'post.revisions.details' %}</a>
27
+ {%- endif -%}
28
+ </span>
29
+ </li>
30
+ {%- endfor -%}
31
+ {%- if include.page.date -%}
32
+ <li class="revision-history__item revision-history__item--published">
33
+ <time class="revision-history__date" datetime="{{ include.page.date | date: '%Y-%m-%d' }}">{% include helpers/date-format.html date=include.page.date format=include.date_format %}</time>
34
+ <span class="revision-history__type">{% t 'post.revisions.types.published' %}</span>
35
+ </li>
36
+ {%- endif -%}
37
+ </ul>
38
+ </section>
39
+ {%- endif -%}
@@ -0,0 +1,35 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - page
5
+ optional:
6
+ - date_format
7
+ ---
8
+ The newest correction or update of an article (`revision_notice`, set from
9
+ `revisions` by _plugins/revisions.rb), announced under the metadata with a
10
+ link to the full history. Renders nothing without one, or with
11
+ `revision_notice: false` in front matter.
12
+ {%- endcomment -%}
13
+ {%- assign revision = include.page.revision_notice -%}
14
+ {%- if revision -%}
15
+ {%- capture revision_date -%}{% include helpers/date-format.html date=revision.date format=include.date_format %}{%- endcapture -%}
16
+ {%- assign revision_date = revision_date | strip -%}
17
+ <aside class="revision-notice revision-notice--{{ revision.type }}" aria-labelledby="revision-notice-lead">
18
+ <p class="revision-notice__text">
19
+ <strong id="revision-notice-lead" class="revision-notice__lead">
20
+ {%- if revision.type == 'correction' -%}
21
+ {% t 'post.revisions.corrected_on' date: revision_date %}
22
+ {%- else -%}
23
+ {% t 'post.revisions.updated_on' date: revision_date %}
24
+ {%- endif -%}
25
+ </strong>
26
+ {{ revision.summary | escape }}
27
+ {%- if revision.details_url -%}
28
+ {%- assign details_url = revision.details_url -%}
29
+ {%- unless details_url contains '://' -%}{%- assign details_url = details_url | relative_url -%}{%- endunless %}
30
+ <a class="revision-notice__details" href="{{ details_url | escape }}">{% t 'post.revisions.details' %}</a>
31
+ {%- endif %}
32
+ <a class="revision-notice__history" href="#revision-history">{% t 'post.revisions.history_link' %}</a>
33
+ </p>
34
+ </aside>
35
+ {%- endif -%}
@@ -0,0 +1,64 @@
1
+ {%- comment -%}
2
+ ---
3
+ required:
4
+ - page
5
+ optional:
6
+ - compact
7
+ ---
8
+ Navigation within an article series (`series` in front matter, resolved by
9
+ _plugins/series.rb): the series title, "Part k of n", every part in order
10
+ with the current one marked, and the previous and next parts. With
11
+ `compact: true`, the previous and next parts alone, for the end of the
12
+ article. Renders nothing for a page that is not part of a series.
13
+ {%- endcomment -%}
14
+ {%- assign series = include.page.series -%}
15
+ {%- if series.id -%}
16
+ {%- capture part_of -%}{% t 'post.series.part_of' part: series.position total: series.count %}{%- endcapture -%}
17
+ {%- capture nav_label -%}{% t 'post.series.nav_label' title: series.title %}{%- endcapture -%}
18
+ {%- capture series_links -%}
19
+ {%- if series.previous or series.next %}
20
+ <div class="series-nav__links">
21
+ {%- if series.previous %}
22
+ <a class="series-nav__link series-nav__link--previous" rel="prev" href="{{ series.previous.url | relative_url }}">
23
+ <span class="series-nav__link-label">{% t 'post.series.previous' %}</span>
24
+ <span class="series-nav__link-title">{{ series.previous.title | escape }}</span>
25
+ </a>
26
+ {%- endif %}
27
+ {%- if series.next %}
28
+ <a class="series-nav__link series-nav__link--next" rel="next" href="{{ series.next.url | relative_url }}">
29
+ <span class="series-nav__link-label">{% t 'post.series.next' %}</span>
30
+ <span class="series-nav__link-title">{{ series.next.title | escape }}</span>
31
+ </a>
32
+ {%- endif %}
33
+ </div>
34
+ {%- endif %}
35
+ {%- endcapture -%}
36
+ {%- if include.compact -%}
37
+ {%- if series.previous or series.next -%}
38
+ <nav class="series-nav series-nav--compact" aria-label="{{ nav_label | strip | escape }}">
39
+ <p class="series-nav__context">{{ series.title | escape }} · {{ part_of | strip }}</p>
40
+ {{- series_links }}
41
+ </nav>
42
+ {%- endif -%}
43
+ {%- else -%}
44
+ <nav class="series-nav" aria-labelledby="series-nav-heading">
45
+ <p class="series-nav__heading" id="series-nav-heading">
46
+ <span class="series-nav__label">{% t 'post.series.label' %}</span>
47
+ <span class="series-nav__title">{{ series.title | escape }}</span>
48
+ <span class="series-nav__position">{{ part_of | strip }}</span>
49
+ </p>
50
+ {%- if series.description %}
51
+ <p class="series-nav__description">{{ series.description | escape }}</p>
52
+ {%- endif %}
53
+ <progress class="series-nav__progress" value="{{ series.position }}" max="{{ series.count }}" aria-hidden="true"></progress>
54
+ <ol class="series-nav__list">
55
+ {%- for part in series.parts %}
56
+ <li class="series-nav__part{% if part.current %} series-nav__part--current{% endif %}">
57
+ <a href="{{ part.url | relative_url }}"{% if part.current %} aria-current="page"{% endif %}>{{ part.title | escape }}</a>
58
+ </li>
59
+ {%- endfor %}
60
+ </ol>
61
+ {{- series_links }}
62
+ </nav>
63
+ {%- endif -%}
64
+ {%- endif -%}
@@ -0,0 +1,88 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional:
4
+ - where
5
+ ---
6
+ The newsletter subscribe form (assets/js/subscriptions/form.js): an email
7
+ address and, when `subscriptions.topics` lists any, what to receive, sent
8
+ to the site's dynamic services (docs/dynamic-services.md). Renders only
9
+ when the site has a backend with the subscriptions feature on and
10
+ `subscriptions.enabled` is not false; the footer and the post layout
11
+ include it where `subscriptions.placement` says. `where` ("footer",
12
+ "post" or "page", the default) keeps the ids apart when a page carries
13
+ more than one, and picks the heading level.
14
+
15
+ The footer is an include_cached, rendered once per language and reused on
16
+ every page, so the footer form carries nothing of the page: the script
17
+ reads the page's address from its canonical link and its language from
18
+ <html lang>. For the same reason the block has no accessible name of its
19
+ own, which would make two same-named landmarks on a post.
20
+ {%- endcomment -%}
21
+ {%- assign services = site.dynamic_services -%}
22
+ {%- assign subscriptions = site.subscriptions -%}
23
+ {%- if services.base_url and services.base_url != '' and services.features.subscriptions != false and subscriptions.enabled != false -%}
24
+ {%- assign where = include.where | default: 'page' -%}
25
+ {%- assign topics = subscriptions.topics -%}
26
+ {%- assign privacy_url = subscriptions.privacy_url | default: nil -%}
27
+ {%- capture labels_json -%}
28
+ {
29
+ "sending": {{ 'subscriptions.sending' | t | jsonify }},
30
+ "pending": {{ 'subscriptions.pending' | t | jsonify }},
31
+ "confirmed": {{ 'subscriptions.confirmed' | t | jsonify }},
32
+ "duplicate": {{ 'subscriptions.duplicate' | t | jsonify }},
33
+ "email_invalid": {{ 'subscriptions.email_invalid' | t | jsonify }},
34
+ "topics_required": {{ 'subscriptions.topics_required' | t | jsonify }},
35
+ "errors": {
36
+ {%- assign kinds = "disabled,unsupported,version,timeout,network,malformed,unauthorized,forbidden,not_found,conflict,invalid,rate_limited,server,http,aborted,reference" | split: "," -%}
37
+ {%- for kind in kinds -%}
38
+ {%- assign kind_key = "dynamic_services.errors." | append: kind -%}
39
+ {{ kind | jsonify }}: {{ kind_key | t | jsonify }}{% unless forloop.last %},{% endunless %}
40
+ {%- endfor -%}
41
+ }
42
+ }
43
+ {%- endcapture -%}
44
+ <section class="subscribe subscribe--{{ where }}" data-subscribe{% unless where == 'footer' %} data-subscribe-source="{{ page.url | absolute_url }}" data-subscribe-locale="{{ page.lang | default: site.lang | default: 'en' }}"{% endunless %} data-subscribe-double-opt-in="{% if subscriptions.double_opt_in == false %}false{% else %}true{% endif %}">
45
+ <script type="application/json" data-subscribe-labels>{{ labels_json | strip }}</script>
46
+ {%- if where == 'footer' %}
47
+ <h3 class="subscribe__heading" id="subscribe-heading-{{ where }}">{% t 'footer.subscribe_title' %}</h3>
48
+ {%- else %}
49
+ <h2 class="subscribe__heading" id="subscribe-heading-{{ where }}">{% t 'footer.subscribe_title' %}</h2>
50
+ {%- endif %}
51
+ <p class="subscribe__description">{% t 'footer.subscribe_description' %}</p>
52
+ <form class="service-form subscribe__form" id="subscribe-form-{{ where }}" data-state="idle" aria-busy="false" novalidate>
53
+ <fieldset class="service-form__fields">
54
+ <legend class="visually-hidden">{% t 'footer.subscribe_title' %}</legend>
55
+ <div class="service-form__field">
56
+ <label for="subscribe-email-{{ where }}">{% t 'footer.newsletter_label' %}</label>
57
+ <input id="subscribe-email-{{ where }}" name="email" type="email" required autocomplete="email">
58
+ <p class="service-form__error" data-error-for="email" hidden></p>
59
+ </div>
60
+ {%- if topics and topics.size > 0 %}
61
+ <fieldset class="subscribe__topics">
62
+ <legend>{% t 'subscriptions.topics_legend' %}</legend>
63
+ {%- for topic in topics %}
64
+ {%- assign topic_key = "subscriptions.topics." | append: topic %}
65
+ <label class="subscribe__topic" for="subscribe-topic-{{ where }}-{{ topic | slugify }}">
66
+ <input id="subscribe-topic-{{ where }}-{{ topic | slugify }}" type="checkbox" name="topics" value="{{ topic | escape }}" checked>
67
+ {{ topic_key | t }}
68
+ </label>
69
+ {%- endfor %}
70
+ <p class="service-form__error" data-error-for="topics" hidden></p>
71
+ </fieldset>
72
+ {%- endif %}
73
+ <div class="service-form__trap" aria-hidden="true">
74
+ <label for="subscribe-website-{{ where }}">Website</label>
75
+ <input id="subscribe-website-{{ where }}" name="website" type="text" tabindex="-1" autocomplete="off">
76
+ </div>
77
+ </fieldset>
78
+ <p class="service-form__privacy">
79
+ {%- if subscriptions.double_opt_in == false %}{% t 'subscriptions.consent' %}{% else %}{% t 'subscriptions.consent_double' %}{% endif %}
80
+ {%- if privacy_url %} <a href="{{ privacy_url | relative_url }}">{% t 'subscriptions.privacy_link' %}</a>{% endif -%}
81
+ </p>
82
+ <div class="service-form__actions">
83
+ <button type="submit" class="post-tool">{% t 'footer.newsletter_button' %}</button>
84
+ </div>
85
+ <p class="service-form__status" data-form-status role="status" aria-live="polite" hidden></p>
86
+ </form>
87
+ </section>
88
+ {%- endif -%}
@@ -0,0 +1,68 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ The page the newsletter's emails link to (assets/js/subscriptions/manage.js):
6
+ `?confirm=<token>` confirms a subscription, `?unsubscribe=<token>` ends one
7
+ after a press of the button, `?manage=<token>` changes its topics. Rendered
8
+ by the page layout when the page says `subscription_manage: true`. Without
9
+ a backend offering the feature it says so, since a link in an old email
10
+ may still lead here.
11
+ {%- endcomment -%}
12
+ {%- assign services = site.dynamic_services -%}
13
+ {%- assign subscriptions = site.subscriptions -%}
14
+ {%- if services.base_url and services.base_url != '' and services.features.subscriptions != false and subscriptions.enabled != false -%}
15
+ {%- assign topics = subscriptions.topics -%}
16
+ {%- capture labels_json -%}
17
+ {
18
+ "confirming": {{ 'subscriptions.manage.confirming' | t | jsonify }},
19
+ "confirmed": {{ 'subscriptions.manage.confirmed' | t | jsonify }},
20
+ "invalid_link": {{ 'subscriptions.manage.invalid_link' | t | jsonify }},
21
+ "unsubscribing": {{ 'subscriptions.manage.unsubscribing' | t | jsonify }},
22
+ "unsubscribed": {{ 'subscriptions.manage.unsubscribed' | t | jsonify }},
23
+ "loading": {{ 'subscriptions.manage.loading' | t | jsonify }},
24
+ "saving": {{ 'subscriptions.manage.saving' | t | jsonify }},
25
+ "saved": {{ 'subscriptions.manage.saved' | t | jsonify }},
26
+ "errors": {
27
+ {%- assign kinds = "disabled,unsupported,version,timeout,network,malformed,unauthorized,forbidden,not_found,conflict,invalid,rate_limited,server,http,aborted,reference" | split: "," -%}
28
+ {%- for kind in kinds -%}
29
+ {%- assign kind_key = "dynamic_services.errors." | append: kind -%}
30
+ {{ kind | jsonify }}: {{ kind_key | t | jsonify }}{% unless forloop.last %},{% endunless %}
31
+ {%- endfor -%}
32
+ }
33
+ }
34
+ {%- endcapture -%}
35
+ <section class="subscription-manage" id="subscription-manage" data-subscription-manage data-state="idle" aria-busy="false">
36
+ <script type="application/json" nonce="{{ page.csp_nonce }}" data-manage-labels>{{ labels_json | strip }}</script>
37
+ <p class="subscription-manage__status" data-manage-status role="status" aria-live="polite" hidden></p>
38
+ <p class="subscription-manage__idle" data-manage-idle>{% t 'subscriptions.manage.idle' %}</p>
39
+ <div class="subscription-manage__panel" data-manage-unsubscribe-panel hidden>
40
+ <p>{% t 'subscriptions.manage.unsubscribe_question' %}</p>
41
+ <button type="button" class="post-tool" data-manage-unsubscribe>{% t 'subscriptions.manage.unsubscribe' %}</button>
42
+ </div>
43
+ <form class="service-form subscription-manage__panel" id="subscription-preferences" data-manage-preferences hidden novalidate>
44
+ {%- if topics and topics.size > 0 %}
45
+ <fieldset class="subscribe__topics">
46
+ <legend>{% t 'subscriptions.manage.preferences' %}</legend>
47
+ {%- for topic in topics %}
48
+ {%- assign topic_key = "subscriptions.topics." | append: topic %}
49
+ <label class="subscribe__topic" for="manage-topic-{{ topic | slugify }}">
50
+ <input id="manage-topic-{{ topic | slugify }}" type="checkbox" name="topics" value="{{ topic | escape }}">
51
+ {{ topic_key | t }}
52
+ </label>
53
+ {%- endfor %}
54
+ </fieldset>
55
+ {%- endif %}
56
+ <div class="service-form__actions">
57
+ {%- if topics and topics.size > 0 %}
58
+ <button type="submit" class="post-tool">{% t 'subscriptions.manage.save' %}</button>
59
+ {%- endif %}
60
+ <button type="button" class="post-tool" data-manage-unsubscribe>{% t 'subscriptions.manage.unsubscribe' %}</button>
61
+ </div>
62
+ </form>
63
+ </section>
64
+ {%- else -%}
65
+ <section class="subscription-manage" id="subscription-manage">
66
+ <p class="subscription-manage__idle">{% t 'subscriptions.manage.unavailable' %}</p>
67
+ </section>
68
+ {%- endif -%}
@@ -0,0 +1,48 @@
1
+ {%- comment -%}
2
+ ---
3
+ optional: []
4
+ ---
5
+ "Mentioned elsewhere" (assets/js/webmentions/list.js): the links, replies
6
+ and reposts other websites sent about this article, read through the
7
+ site's dynamic services (docs/dynamic-services.md) from what the
8
+ Webmention receiver verified. Apart from the comments, which are hosted
9
+ here. Renders only when the site has a backend with the webmentions
10
+ feature on, `webmentions.enabled` is not false, and the page does not say
11
+ `webmentions: false`. The kinds shown come from `webmentions.types`.
12
+ The receiver itself is advertised by meta/webmention-discovery.html.
13
+ {%- endcomment -%}
14
+ {%- assign services = site.dynamic_services -%}
15
+ {%- assign webmentions = site.webmentions -%}
16
+ {%- if services.base_url and services.base_url != '' and services.features.webmentions != false and webmentions.enabled != false and page.webmentions != false -%}
17
+ {%- assign types = webmentions.types -%}
18
+ {%- if types == nil or types.size == 0 -%}
19
+ {%- assign types = "mention,reply" | split: "," -%}
20
+ {%- endif -%}
21
+ {%- capture labels_json -%}
22
+ {
23
+ "loading": {{ 'webmentions.loading' | t | jsonify }},
24
+ "empty": {{ 'webmentions.empty' | t | jsonify }},
25
+ "retry": {{ 'webmentions.retry' | t | jsonify }},
26
+ "types": {
27
+ "mention": {{ 'webmentions.types.mention' | t | jsonify }},
28
+ "reply": {{ 'webmentions.types.reply' | t | jsonify }},
29
+ "repost": {{ 'webmentions.types.repost' | t | jsonify }},
30
+ "like": {{ 'webmentions.types.like' | t | jsonify }}
31
+ },
32
+ "errors": {
33
+ {%- assign kinds = "disabled,unsupported,version,timeout,network,malformed,unauthorized,forbidden,not_found,conflict,invalid,rate_limited,server,http,aborted,reference" | split: "," -%}
34
+ {%- for kind in kinds -%}
35
+ {%- assign kind_key = "dynamic_services.errors." | append: kind -%}
36
+ {{ kind | jsonify }}: {{ kind_key | t | jsonify }}{% unless forloop.last %},{% endunless %}
37
+ {%- endfor -%}
38
+ }
39
+ }
40
+ {%- endcapture -%}
41
+ <section class="webmentions" id="webmentions" data-webmentions data-webmentions-target="{{ page.url | absolute_url }}" data-webmentions-types="{{ types | join: ',' }}" data-state="idle" aria-labelledby="webmentions-heading">
42
+ <script type="application/json" nonce="{{ page.csp_nonce }}" data-webmentions-labels>{{ labels_json | strip }}</script>
43
+ <h2 class="webmentions__heading" id="webmentions-heading">{% t 'webmentions.heading' %}</h2>
44
+ <p class="webmentions__intro">{% t 'webmentions.intro' %}</p>
45
+ <p class="webmentions__status" data-webmentions-status role="status" aria-live="polite">{% t 'webmentions.loading' %}</p>
46
+ <ul class="webmentions__list" data-webmentions-list hidden></ul>
47
+ </section>
48
+ {%- endif -%}