datalog-theme 0.10.1 → 0.11.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +4 -2
  5. data/_data/i18n/en.yml +55 -3
  6. data/_data/i18n/es.yml +55 -3
  7. data/_data/i18n/pt.yml +55 -3
  8. data/_includes/analytics/dashboard.html +24 -9
  9. data/_includes/components/academic-dashboard.html +168 -133
  10. data/_includes/components/author-bio.html +7 -5
  11. data/_includes/components/author-list.html +6 -5
  12. data/_includes/components/citation-tools.html +2 -1
  13. data/_includes/components/content-provenance.html +19 -1
  14. data/_includes/components/correction-report.html +15 -8
  15. data/_includes/components/hero.html +22 -15
  16. data/_includes/components/package-index.html +121 -0
  17. data/_includes/components/package-install.html +27 -50
  18. data/_includes/components/post-list.html +14 -0
  19. data/_includes/components/responsive-image.html +15 -21
  20. data/_includes/footer.html +1 -1
  21. data/_includes/head.html +70 -11
  22. data/_includes/layouts/default/article.html +76 -46
  23. data/_includes/meta/dataset-json.html +171 -0
  24. data/_includes/meta/math-config.html +15 -1
  25. data/_includes/meta/package-json.html +69 -0
  26. data/_includes/meta/person-json.html +36 -13
  27. data/_includes/meta/publisher.html +15 -0
  28. data/_includes/meta/schema.html +108 -23
  29. data/_includes/meta/scholarly.html +10 -5
  30. data/_includes/post/related-posts.html +17 -43
  31. data/_includes/scripts.html +2 -2
  32. data/_includes/search/index-data.json +10 -1
  33. data/_includes/search/page.html +11 -6
  34. data/_layouts/archive.html +67 -0
  35. data/_layouts/dataset.html +2 -1
  36. data/_layouts/default.html +13 -11
  37. data/_layouts/docs.html +53 -0
  38. data/_layouts/home.html +30 -1
  39. data/_layouts/notebook.html +5 -1
  40. data/_layouts/package.html +38 -21
  41. data/_layouts/portfolio.html +1 -0
  42. data/_layouts/post.html +21 -62
  43. data/_layouts/project.html +2 -1
  44. data/_layouts/research.html +14 -2
  45. data/_plugins/analytics_dashboard.rb +4 -1
  46. data/_plugins/archive.rb +114 -0
  47. data/_plugins/authors.rb +50 -1
  48. data/_plugins/citation_exports.rb +12 -1
  49. data/_plugins/config_validator.rb +77 -2
  50. data/_plugins/correction_fallback.rb +110 -0
  51. data/_plugins/image_optimizer.rb +129 -22
  52. data/_plugins/math_preprocessor.rb +7 -48
  53. data/_plugins/notebook_converter.rb +44 -5
  54. data/_plugins/packages.rb +84 -0
  55. data/_plugins/page_dates.rb +37 -0
  56. data/_plugins/references.rb +16 -2
  57. data/_plugins/related_posts.rb +149 -0
  58. data/_plugins/search_sections.rb +110 -0
  59. data/_plugins/site_identity.rb +42 -0
  60. data/_plugins/social_cards.rb +17 -0
  61. data/_sass/_academic-dashboard.scss +18 -30
  62. data/_sass/_base.scss +2 -0
  63. data/_sass/_components.scss +21 -23
  64. data/_sass/_docs.scss +143 -0
  65. data/_sass/_features.scss +6 -0
  66. data/_sass/_layout.scss +65 -6
  67. data/_sass/_mathematical.scss +61 -19
  68. data/_sass/_notebooks.scss +1 -32
  69. data/_sass/_package-docs.scss +6 -9
  70. data/_sass/_post-components.scss +23 -23
  71. data/_sass/_print.scss +1 -1
  72. data/_sass/_search-page.scss +75 -0
  73. data/_sass/_search.scss +17 -26
  74. data/_sass/_syntax-highlighting.scss +23 -1
  75. data/_sass/_theme.scss +1 -0
  76. data/_sass/_utilities.scss +87 -40
  77. data/_sass/_variables.scss +31 -29
  78. data/assets/css/main.scss +2 -1
  79. data/assets/js/dist/academic.js +1 -1
  80. data/assets/js/dist/analytics-dashboard.js +1 -1
  81. data/assets/js/dist/chunks/chunk-TNVD6UAM.js +1 -0
  82. data/assets/js/dist/comments.js +1 -1
  83. data/assets/js/dist/contact.js +1 -1
  84. data/assets/js/dist/core.js +1 -1
  85. data/assets/js/dist/corrections.js +5 -1
  86. data/assets/js/dist/loader.js +1 -1
  87. data/assets/js/dist/math.js +2 -1
  88. data/assets/js/dist/moderation.js +1 -1
  89. data/assets/js/dist/reactions.js +1 -1
  90. data/assets/js/dist/search.js +1 -1
  91. data/assets/js/dist/sources.json +20 -16
  92. data/assets/js/dist/subscriptions.js +1 -1
  93. data/assets/js/loader.js +6 -2
  94. data/lib/datalog/audit/checks.rb +269 -0
  95. data/lib/datalog/audit/known_keys.rb +61 -0
  96. data/lib/datalog/audit/site_reader.rb +118 -0
  97. data/lib/datalog/audit/source_file.rb +85 -0
  98. data/lib/datalog/audit.rb +145 -0
  99. data/lib/datalog/citations/bibtex.rb +200 -0
  100. data/lib/datalog/citations/entry.rb +333 -0
  101. data/lib/datalog/citations/markup.rb +79 -0
  102. data/lib/datalog/cli.rb +164 -89
  103. data/lib/datalog/critical_css.rb +126 -21
  104. data/lib/datalog/latex_speech/words.json +88 -0
  105. data/lib/datalog/latex_speech.rb +355 -0
  106. data/lib/datalog/packages/command.rb +51 -0
  107. data/lib/datalog/packages/refresh.rb +187 -0
  108. data/lib/datalog/packages.rb +177 -0
  109. data/lib/datalog/plugin_system.rb +5 -0
  110. data/lib/datalog/plugins/citations.rb +325 -109
  111. data/lib/datalog/site_config.rb +26 -0
  112. data/lib/datalog/social_cards/font.rb +286 -0
  113. data/lib/datalog/social_cards/fonts/IBMPlexSans-Regular.ttf +0 -0
  114. data/lib/datalog/social_cards/fonts/IBMPlexSerif-SemiBold.ttf +0 -0
  115. data/lib/datalog/social_cards/fonts/OFL.txt +92 -0
  116. data/lib/datalog/social_cards/geometry.rb +51 -0
  117. data/lib/datalog/social_cards/outline.rb +54 -0
  118. data/lib/datalog/social_cards/plain_text.rb +258 -0
  119. data/lib/datalog/social_cards/template.rb +322 -0
  120. data/lib/datalog/social_cards/template.svg +17 -0
  121. data/lib/datalog/social_cards/typesetter.rb +178 -0
  122. data/lib/datalog/social_cards.rb +369 -0
  123. data/lib/datalog/theme/updater.rb +307 -0
  124. data/lib/datalog/theme/version.rb +1 -1
  125. metadata +44 -7
  126. data/_includes/components/enhanced-code-block.html +0 -212
  127. data/_includes/components/performance-monitor.html +0 -170
  128. data/_includes/components/viz-table-fallback.html +0 -19
  129. data/_plugins/datalog_bibliography.rb +0 -21
  130. data/assets/js/dist/chunks/chunk-WIRUK3OZ.js +0 -1
@@ -25,6 +25,8 @@ Parameters:
25
25
  {%- assign author_data = bio_authors | first -%}
26
26
  {%- endif -%}
27
27
  {%- assign author_name = author_data.name | default: include.author | default: site.author.name | escape -%}
28
+ {%- comment -%} `me` on the site author's profiles, never on a guest's unless their record sets profile_rel {%- endcomment -%}
29
+ {%- assign profile_rel = author_data | author_profile_rel | escape -%}
28
30
 
29
31
  <aside class="author-bio{% if compact %} author-bio--compact{% endif %}" itemscope itemtype="https://schema.org/Person">
30
32
  <div class="author-bio__inner">
@@ -95,7 +97,7 @@ Parameters:
95
97
  <a href="https://github.com/{{ author_data.github }}"
96
98
  class="author-bio__social-link author-bio__social-link--github"
97
99
  target="_blank"
98
- rel="noopener noreferrer"
100
+ rel="{{ profile_rel }}"
99
101
  itemprop="sameAs"
100
102
  aria-label="{{ author_name }} on GitHub">
101
103
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -111,7 +113,7 @@ Parameters:
111
113
  <a href="https://twitter.com/{{ author_data.twitter }}"
112
114
  class="author-bio__social-link author-bio__social-link--twitter"
113
115
  target="_blank"
114
- rel="noopener noreferrer"
116
+ rel="{{ profile_rel }}"
115
117
  itemprop="sameAs"
116
118
  aria-label="{{ author_name }} on Twitter">
117
119
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -127,7 +129,7 @@ Parameters:
127
129
  <a href="https://linkedin.com/in/{{ author_data.linkedin }}"
128
130
  class="author-bio__social-link author-bio__social-link--linkedin"
129
131
  target="_blank"
130
- rel="noopener noreferrer"
132
+ rel="{{ profile_rel }}"
131
133
  itemprop="sameAs"
132
134
  aria-label="{{ author_name }} on LinkedIn">
133
135
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -143,7 +145,7 @@ Parameters:
143
145
  <a href="{{ author_data.orcid }}"
144
146
  class="author-bio__social-link author-bio__social-link--orcid"
145
147
  target="_blank"
146
- rel="noopener noreferrer"
148
+ rel="{{ profile_rel }}"
147
149
  itemprop="sameAs"
148
150
  aria-label="{{ author_name }} ORCID profile">
149
151
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -159,7 +161,7 @@ Parameters:
159
161
  <a href="{{ author_data.google_scholar }}"
160
162
  class="author-bio__social-link author-bio__social-link--scholar"
161
163
  target="_blank"
162
- rel="noopener noreferrer"
164
+ rel="{{ profile_rel }}"
163
165
  itemprop="sameAs"
164
166
  aria-label="{{ author_name }} Google Scholar profile">
165
167
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@@ -10,22 +10,23 @@ Lists the people who wrote or contributed to a page as schema.org Person
10
10
  items: each name, linked to the person's url when there is one, with their
11
11
  role and affiliation. `people` comes from `page | page_authors` or
12
12
  `page | page_contributors`; `property` is the microdata property, author
13
- (the default) or contributor.
13
+ (the default) or contributor, and `false` for a list in no item.
14
14
  {%- endcomment -%}
15
15
  {%- assign list_property = include.property | default: 'author' -%}
16
+ {%- if include.property == false -%}{%- assign list_property = nil -%}{%- endif -%}
16
17
  <ul class="author-list">
17
18
  {%- for person in include.people -%}
18
- <li class="author-list__person" itemprop="{{ list_property }}" itemscope itemtype="https://schema.org/{% if person.type == 'Organization' %}Organization{% else %}Person{% endif %}">
19
+ <li class="author-list__person"{% if list_property %} itemprop="{{ list_property }}" itemscope itemtype="https://schema.org/{% if person.type == 'Organization' %}Organization{% else %}Person{% endif %}"{% endif %}>
19
20
  {%- if person.url -%}
20
21
  {%- assign person_href = person.url -%}
21
22
  {%- unless person_href contains '://' -%}{%- assign person_href = person_href | relative_url -%}{%- endunless -%}
22
- <a href="{{ person_href | escape }}" itemprop="url"><span itemprop="name">{{ person.name | escape }}</span></a>
23
+ <a href="{{ person_href | escape }}"{% if list_property %} itemprop="url"{% endif %}><span{% if list_property %} itemprop="name"{% endif %}>{{ person.name | escape }}</span></a>
23
24
  {%- else -%}
24
- <span itemprop="name">{{ person.name | escape }}</span>
25
+ <span{% if list_property %} itemprop="name"{% endif %}>{{ person.name | escape }}</span>
25
26
  {%- endif -%}
26
27
  {%- if person.role %} <span class="author-list__role">({{ person.role | escape }})</span>{%- endif -%}
27
28
  {%- if person.affiliation and include.show_affiliation != false -%}
28
- <span class="post-author-affiliation" itemprop="affiliation">{{ person.affiliation | escape }}</span>
29
+ <span class="post-author-affiliation"{% if list_property %} itemprop="affiliation"{% endif %}>{{ person.affiliation | escape }}</span>
29
30
  {%- endif -%}
30
31
  </li>
31
32
  {%- endfor -%}
@@ -1,6 +1,7 @@
1
1
  {% assign citation_title = include.title | default: page.title | default: site.title %}
2
2
  {% assign citation_url = include.url | default: page.url | default: '/' | absolute_url %}
3
- {% assign citation_date = include.date | default: page.date %}
3
+ {%- comment -%} The date given, else the page's own; an undated page's is the build's, and no year (#411). {%- endcomment -%}
4
+ {% if include.date %}{% assign citation_date = include.date %}{% else %}{% assign citation_date = page | published_date %}{% endif %}
4
5
  {% assign citation_year = citation_date | date: '%Y' %}
5
6
  {%- comment -%} `authors`: records from `page | page_authors`, or names. Without it, the page's authors. {%- endcomment -%}
6
7
  {% if include.authors %}
@@ -4,14 +4,31 @@ required:
4
4
  - page
5
5
  optional:
6
6
  - date_format
7
+ - pointer
7
8
  ---
8
9
  Editorial provenance note built from the `why_this_exists`, `evidence`,
9
10
  `methodology` and `reviewed_at` front-matter fields. Renders nothing when
10
11
  none of them is set.
12
+
13
+ With `pointer=true` it renders instead the row of the post's metadata list
14
+ that points to the note when the note follows the article: when the article
15
+ was reviewed, and a link to the note.
11
16
  {%- endcomment -%}
12
17
  {%- assign prov = include.page -%}
13
18
  {%- if prov.why_this_exists or prov.evidence or prov.methodology or prov.reviewed_at -%}
14
- <aside class="content-provenance" aria-labelledby="content-provenance-heading">
19
+ {%- if include.pointer -%}
20
+ <div>
21
+ <dt class="post-meta-term">{% t 'post.provenance.heading' %}</dt>
22
+ <dd class="post-meta-definition">
23
+ {%- if prov.reviewed_at -%}
24
+ {%- capture reviewed_date -%}{% include helpers/date-format.html date=prov.reviewed_at format=include.date_format %}{%- endcapture -%}
25
+ {% t 'post.provenance.reviewed_on' date: reviewed_date %} ·
26
+ {% endif -%}
27
+ <a href="#content-provenance">{% t 'post.provenance.link' %}</a>
28
+ </dd>
29
+ </div>
30
+ {%- else -%}
31
+ <aside id="content-provenance" class="content-provenance" aria-labelledby="content-provenance-heading">
15
32
  <h2 id="content-provenance-heading" class="content-provenance__heading">{% t 'post.provenance.heading' %}</h2>
16
33
  <dl class="content-provenance__list">
17
34
  {%- if prov.why_this_exists -%}
@@ -41,3 +58,4 @@ none of them is set.
41
58
  </dl>
42
59
  </aside>
43
60
  {%- endif -%}
61
+ {%- endif -%}
@@ -2,17 +2,14 @@
2
2
  ---
3
3
  optional: []
4
4
  ---
5
- "Report an error or suggest a correction" (assets/js/corrections/form.js):
6
- structured feedback about an article, apart from comments, sent to the
7
- site's dynamic services (docs/dynamic-services.md) and never shown on the
8
- page. Renders only when the site has a backend with the corrections feature
9
- on, `corrections.enabled` is not false, and the page does not say
10
- `corrections: false`. The categories come from `corrections.categories`,
11
- their labels from `corrections.categories.*` in _data/i18n.
5
+ "Report an error or suggest a correction": a private form when dynamic
6
+ services offer corrections, or an issue/email link on a static site.
7
+ `corrections.enabled: false` or page `corrections: false` removes both.
12
8
  {%- endcomment -%}
13
9
  {%- assign services = site.dynamic_services -%}
14
10
  {%- assign corrections = site.corrections -%}
15
- {%- if services.base_url and services.base_url != '' and services.features.corrections != false and corrections.enabled != false and page.corrections != false -%}
11
+ {%- if corrections.enabled != false and page.corrections != false -%}
12
+ {%- if services.base_url and services.base_url != '' and services.features.corrections != false -%}
16
13
  {%- assign categories = corrections.categories -%}
17
14
  {%- if categories == nil or categories.size == 0 -%}
18
15
  {%- assign categories = "mathematical-error,factual-error,citation,code,reproducibility,typo,accessibility,other" | split: "," -%}
@@ -79,4 +76,14 @@ their labels from `corrections.categories.*` in _data/i18n.
79
76
  <p class="service-form__status" data-form-status role="status" aria-live="polite" hidden></p>
80
77
  </form>
81
78
  </details>
79
+ {%- else -%}
80
+ {%- assign article_url = page.url | absolute_url -%}
81
+ {%- assign fallback = page | correction_fallback: article_url -%}
82
+ {%- if fallback -%}
83
+ <div class="correction-report correction-report--fallback" id="correction-report">
84
+ <a href="{{ fallback.href | escape }}" data-correction-fallback data-correction-body-param="{{ fallback.body_param | escape }}" data-correction-section-label="{{ 'corrections.fallback.section' | t | escape }}" data-correction-quote-label="{{ 'corrections.fallback.quote' | t | escape }}">{% t 'corrections.summary' %}</a>
85
+ {% if fallback.kind == 'issue' %}<p class="correction-report__note">{% t 'corrections.fallback.public_note' %}</p>{% endif %}
86
+ </div>
87
+ {%- endif -%}
88
+ {%- endif -%}
82
89
  {%- endif -%}
@@ -1,33 +1,40 @@
1
- {% assign hero_bg = page.hero_image | default: '/assets/img/hero-detail.webp' %}
1
+ {% assign hero_bg = page.hero_image %}
2
2
  {% assign hero_bg_small = page.hero_image_small %}
3
- {% if page.hero_image == nil and hero_bg_small == nil %}
4
- {% assign hero_bg_small = '/assets/img/hero-detail-640.webp' %}
5
- {% endif %}
6
3
  {%- comment -%}
7
- The hero is the largest paint on the page. A CSS background is only requested
8
- once the stylesheet applies, so preload it; small screens get a 640 px
9
- variant (page.hero_image_small when a page brings its own hero_image).
4
+ The gradient is the default. When a page supplies an image, preload the
5
+ appropriate size because the CSS background would otherwise start late.
10
6
  {%- endcomment -%}
11
- {% if hero_bg_small %}
7
+ {% if hero_bg and hero_bg_small %}
12
8
  <link rel="preload" as="image" href="{{ hero_bg_small | relative_url }}" media="(max-width: 640px)" fetchpriority="high" />
13
9
  <link rel="preload" as="image" href="{{ hero_bg | relative_url }}" media="(min-width: 641px)" fetchpriority="high" />
14
- {% else %}
10
+ {% elsif hero_bg %}
15
11
  <link rel="preload" as="image" href="{{ hero_bg | relative_url }}" fetchpriority="high" />
16
12
  {% endif %}
13
+ {% if hero_bg %}
17
14
  <style nonce="{{ page.csp_nonce }}">
18
- .hero { --hero-bg: url('{{ hero_bg | relative_url }}'); }
15
+ .hero--image { --hero-bg: url('{{ hero_bg | relative_url }}'); }
19
16
  {% if hero_bg_small %}
20
- @media (max-width: 640px) { .hero { --hero-bg: url('{{ hero_bg_small | relative_url }}'); } }
17
+ @media (max-width: 640px) { .hero--image { --hero-bg: url('{{ hero_bg_small | relative_url }}'); } }
21
18
  {% endif %}
22
19
  </style>
23
- <section class="hero">
20
+ {% endif %}
21
+ <section class="hero{% if include.contained %} hero--contained{% endif %}{% if hero_bg %} hero--image{% endif %}">
24
22
  <div class="hero-overlay"></div>
25
23
  <div class="container hero-content">
26
24
  <h1>{{ page.hero_title | default: site.title | escape }}</h1>
27
- <p class="hero-tagline">{{ page.hero_tagline | default: site.hero_tagline }}</p>
28
- {% if page.hero_cta_url %}
25
+ {% assign hero_tagline = page.hero_tagline | default: site.hero_tagline | default: site.description %}
26
+ {% if hero_tagline %}<p class="hero-tagline">{{ hero_tagline | escape }}</p>{% endif %}
27
+ {% if page.hero_cta_url or page.hero_secondary_cta_url %}
28
+ <div class="hero-actions">
29
+ {% if page.hero_cta_url %}
29
30
  {% capture hero_cta_fallback %}{% t 'home.read_more' %}{% endcapture %}
30
- <a class="btn btn-primary" href="{{ page.hero_cta_url | relative_url }}">{{ page.hero_cta_label | default: hero_cta_fallback | strip }}</a>
31
+ <a class="btn btn-primary" href="{{ page.hero_cta_url | relative_url }}">{{ page.hero_cta_label | default: hero_cta_fallback | strip | escape }}</a>
32
+ {% endif %}
33
+ {% if page.hero_secondary_cta_url %}
34
+ {% capture hero_secondary_fallback %}{% t 'home.explore_more' %}{% endcapture %}
35
+ <a class="btn btn-secondary" href="{{ page.hero_secondary_cta_url | relative_url }}">{{ page.hero_secondary_cta_label | default: hero_secondary_fallback | strip | escape }}</a>
36
+ {% endif %}
37
+ </div>
31
38
  {% endif %}
32
39
  </div>
33
40
  </section>
@@ -0,0 +1,121 @@
1
+ {%- comment -%}
2
+ Package Index Component
3
+ Every package in the packages collection with its latest release, the command
4
+ that installs it and what it is for, as a card grid or a table. The release
5
+ comes from _data/package_releases.yml when `datalog packages refresh` has
6
+ written it, else from the package's front matter, as on the package page.
7
+
8
+ Usage:
9
+ {% include components/package-index.html %}
10
+ {% include components/package-index.html style="table" group_by="language" %}
11
+
12
+ Parameters (all optional):
13
+ - style: cards (default) or table
14
+ - group_by: a front matter field, such as language or group; one heading
15
+ per value, in alphabetical order, and the packages without it last
16
+ - packages: the packages to list (default: site.packages)
17
+ - heading_level: the level of the first headings it writes (default: 2);
18
+ with group_by, a card's heading is one level below its group's, and
19
+ neither goes below h6
20
+ {%- endcomment -%}
21
+
22
+ {%- assign index_packages = include.packages | default: site.packages -%}
23
+ {%- assign index_level = include.heading_level | default: 2 | plus: 0 | at_least: 1 | at_most: 6 -%}
24
+ {%- if include.group_by -%}
25
+ {%- assign index_item_level = index_level | plus: 1 | at_most: 6 -%}
26
+ {%- assign index_groups = index_packages | group_by: include.group_by | sort: 'name' -%}
27
+ {%- assign index_named = index_groups | where_exp: 'group', 'group.name != ""' -%}
28
+ {%- assign index_unnamed = index_groups | where: 'name', '' -%}
29
+ {%- assign index_groups = index_named | concat: index_unnamed -%}
30
+ {%- else -%}
31
+ {%- assign index_item_level = index_level -%}
32
+ {%- assign index_groups = index_packages | group_by_exp: 'package', '""' -%}
33
+ {%- endif -%}
34
+ {%- capture index_label %}{% t 'packages.index.title' %}{% endcapture -%}
35
+
36
+ {%- if index_packages.size > 0 -%}
37
+ <div class="package-index" data-package-index>
38
+ {%- for group in index_groups -%}
39
+ {%- if include.group_by -%}
40
+ {%- capture group_title %}{% if group.name == '' %}{% t 'packages.index.other' %}{% else %}{{ group.name }}{% endif %}{% endcapture -%}
41
+ {%- else -%}
42
+ {%- assign group_title = index_label -%}
43
+ {%- endif -%}
44
+ {%- if include.group_by %}
45
+ <h{{ index_level }} class="package-index__group">{{ group_title | strip | escape }}</h{{ index_level }}>
46
+ {%- endif -%}
47
+
48
+ {%- if include.style == 'table' %}
49
+ <div class="content-table" role="region" tabindex="0" aria-label="{{ group_title | strip | escape }}">
50
+ <table class="package-index__table">
51
+ <thead>
52
+ <tr>
53
+ <th scope="col">{% t 'packages.index.package' %}</th>
54
+ <th scope="col">{% t 'packages.index.release' %}</th>
55
+ <th scope="col">{% t 'packages.index.install' %}</th>
56
+ <th scope="col">{% t 'packages.index.purpose' %}</th>
57
+ </tr>
58
+ </thead>
59
+ <tbody>
60
+ {%- for package in group.items -%}
61
+ {%- assign release = package | package_release -%}
62
+ {%- assign install = package | package_install_tabs | first -%}
63
+ <tr data-package="{{ package.title | slugify }}">
64
+ <th scope="row"><a href="{{ package.url | relative_url }}">{{ package.title | escape }}</a></th>
65
+ <td>
66
+ {%- if release.version -%}
67
+ <span data-package-version>v{{ release.version | escape }}</span>
68
+ {%- if release.prerelease %} · {% t 'packages.prerelease' %}{% endif -%}
69
+ {%- if release.yanked %} · {% t 'packages.yanked' %}{% endif -%}
70
+ {%- if release.released %}<br><time datetime="{{ release.released | escape }}">{{ release.released | localize_date: 'short' }}</time>{% endif -%}
71
+ {%- endif -%}
72
+ </td>
73
+ <td>{% if install and install.id != 'git' %}<code translate="no">{{ install.commands.first.command | escape }}</code>{% endif %}</td>
74
+ <td>{{ package.tagline | default: package.description | escape }}</td>
75
+ </tr>
76
+ {%- endfor %}
77
+ </tbody>
78
+ </table>
79
+ </div>
80
+ {%- else %}
81
+ <div class="card-grid">
82
+ {%- for package in group.items -%}
83
+ {%- assign release = package | package_release -%}
84
+ {%- assign install = package | package_install_tabs | first -%}
85
+ {%- assign registry_link = package | package_links | first %}
86
+ <article class="card project-card" data-package="{{ package.title | slugify }}">
87
+ <p class="card-meta">
88
+ {%- if package.language %}<span class="post-meta__badge">{{ package.language | escape }}</span>{% endif -%}
89
+ {%- if release.version %} <span class="post-meta__badge" data-package-version>v{{ release.version | escape }}</span>{% endif -%}
90
+ {%- if release.prerelease %} <span>{% t 'packages.prerelease' %}</span>{% endif -%}
91
+ {%- if release.yanked %} <span>{% t 'packages.yanked' %}</span>{% endif -%}
92
+ {%- if release.license %} <span>{{ release.license | escape }}</span>{% endif -%}
93
+ </p>
94
+ <h{{ index_item_level }}><a href="{{ package.url | relative_url }}">{% if package.icon %}{{ package.icon }} {% endif %}{{ package.title | escape }}</a></h{{ index_item_level }}>
95
+ {%- if package.tagline %}
96
+ <p><strong>{{ package.tagline | escape }}</strong></p>
97
+ {%- endif -%}
98
+ {%- if package.description %}
99
+ <p>{{ package.description | escape }}</p>
100
+ {%- endif -%}
101
+ {%- if install and install.id != 'git' %}
102
+ <p><code translate="no">{{ install.commands.first.command | escape }}</code></p>
103
+ {%- endif %}
104
+ <div class="project-links">
105
+ <a class="btn btn-primary" href="{{ package.url | relative_url }}">{% t 'packages.documentation' %}</a>
106
+ {%- if package.github_url %}
107
+ <a class="btn btn-secondary" href="{{ package.github_url | escape }}" target="_blank" rel="noopener">GitHub</a>
108
+ {%- endif -%}
109
+ {%- if registry_link %}
110
+ <a class="btn btn-secondary" href="{{ registry_link.url | escape }}" target="_blank" rel="noopener">{{ registry_link.label }}</a>
111
+ {%- endif %}
112
+ </div>
113
+ </article>
114
+ {%- endfor %}
115
+ </div>
116
+ {%- endif -%}
117
+ {%- endfor %}
118
+ </div>
119
+ {%- else %}
120
+ <p class="package-index__empty">{% t 'packages.index.empty' %}</p>
121
+ {%- endif -%}
@@ -1,25 +1,23 @@
1
1
  {%- comment -%}
2
2
  Package Installation Component
3
- Displays installation instructions for different package managers
3
+ Installation commands for a package, one tab per registry the page names in
4
+ `registry:` (pip, conda, CRAN, cargo, gem with its Gemfile line, npm, Pkg),
5
+ then Git. A page that names none keeps the tabs of its language: pip, conda
6
+ and Git for Python, CRAN and GitHub for R. A package with neither a registry
7
+ nor a repository gets no panel, never an empty one.
4
8
 
5
- Parameters:
6
- - language: python, r, julia, etc.
7
- - package_name: Name of the package
8
- - pip_command: Custom pip install command
9
- - conda_command: Custom conda install command
10
- - cran_command: Custom R install command
11
- - git_url: GitHub clone URL
9
+ Parameters (all optional; the page's front matter fills them in):
10
+ - language: python, r, rust, ruby, javascript, julia, ...
11
+ - package_name: Name of the package (default: the page title)
12
+ - pip_command, conda_command, cran_command: replace that tab's command
13
+ - git_url: repository to clone (default: the page's github_url)
12
14
 
13
15
  The tabs and the copy buttons are wired by the core bundle
14
16
  (assets/js/core/install-tabs.js, assets/js/core/copy-buttons.js).
15
17
  {%- endcomment -%}
16
18
 
17
- {%- assign language = include.language | default: "python" -%}
18
19
  {%- assign package_name = include.package_name | default: page.title -%}
19
- {%- assign pip_command = include.pip_command -%}
20
- {%- assign conda_command = include.conda_command -%}
21
- {%- assign cran_command = include.cran_command -%}
22
- {%- assign git_url = include.git_url | default: page.github_url -%}
20
+ {%- assign tabs = page | package_install_tabs: language: include.language, name: package_name, git_url: include.git_url, pip: include.pip_command, conda: include.conda_command, cran: include.cran_command -%}
23
21
  {%- comment -%}
24
22
  The id is the package's, not "installation": a page whose Markdown has an
25
23
  `## Installation` heading gets that id from kramdown, and two elements
@@ -29,66 +27,44 @@ The tabs and the copy buttons are wired by the core bundle
29
27
  {%- capture copied_label %}{% t 'package_install.copied' %}{% endcapture -%}
30
28
  {%- capture copy_error_label %}{% t 'package_install.copy_error' %}{% endcapture -%}
31
29
 
30
+ {%- if tabs.size > 0 -%}
32
31
  <div class="package-install" id="{{ install_id }}">
33
32
  <h2 class="package-install__title" id="{{ install_id }}-title">{% t 'package_install.title' %}</h2>
34
33
 
35
- {%- if language == "python" -%}
36
- {%- assign tabs = 'pip,conda,git' | split: ',' -%}
37
- {%- assign tab_labels = 'pip,conda,Git' | split: ',' -%}
38
- {%- elsif language == "r" -%}
39
- {%- assign tabs = 'cran,github' | split: ',' -%}
40
- {%- assign tab_labels = 'CRAN,GitHub' | split: ',' -%}
41
- {%- endif -%}
42
-
43
- {%- if tabs -%}
44
34
  <div class="package-install__tabs" data-install-tabs>
45
35
  <div class="package-install__tab-buttons" role="tablist" aria-labelledby="{{ install_id }}-title">
46
36
  {%- for tab in tabs -%}
47
37
  <button type="button"
48
38
  class="package-install__tab-btn{% if forloop.first %} package-install__tab-btn--active{% endif %}"
49
39
  role="tab"
50
- id="{{ install_id }}-tab-{{ tab }}"
51
- aria-controls="{{ install_id }}-panel-{{ tab }}"
40
+ id="{{ install_id }}-tab-{{ tab.id }}"
41
+ aria-controls="{{ install_id }}-panel-{{ tab.id }}"
52
42
  aria-selected="{% if forloop.first %}true{% else %}false{% endif %}"
53
43
  tabindex="{% if forloop.first %}0{% else %}-1{% endif %}"
54
- data-tab="{{ tab }}">
55
- {{ tab_labels[forloop.index0] }}
44
+ data-tab="{{ tab.id }}">
45
+ {{ tab.label }}
56
46
  </button>
57
47
  {%- endfor -%}
58
48
  </div>
59
49
 
60
50
  {%- for tab in tabs -%}
61
- {%- assign command = '' -%}
62
- {%- assign console_key = 'package_install.terminal' -%}
63
- {%- case tab -%}
64
- {%- when 'pip' -%}
65
- {%- capture command %}{{ pip_command | default: "pip install " | append: package_name }}{% endcapture -%}
66
- {%- when 'conda' -%}
67
- {%- capture command %}{{ conda_command | default: "conda install " | append: package_name }}{% endcapture -%}
68
- {%- when 'git' -%}
69
- {%- capture command -%}git clone {{ git_url }}
70
- cd {{ package_name }}
71
- pip install -e .{%- endcapture -%}
72
- {%- when 'cran' -%}
73
- {%- assign console_key = 'package_install.r_console' -%}
74
- {%- capture command %}{{ cran_command | default: "install.packages('" | append: package_name | append: "')" }}{% endcapture -%}
75
- {%- when 'github' -%}
76
- {%- assign console_key = 'package_install.r_console' -%}
77
- {%- capture command %}devtools::install_github("{{ git_url | remove: "https://github.com/" }}"){% endcapture -%}
78
- {%- endcase -%}
79
51
  <div class="package-install__tab-content"
80
52
  role="tabpanel"
81
- id="{{ install_id }}-panel-{{ tab }}"
82
- aria-labelledby="{{ install_id }}-tab-{{ tab }}"
53
+ id="{{ install_id }}-panel-{{ tab.id }}"
54
+ aria-labelledby="{{ install_id }}-tab-{{ tab.id }}"
83
55
  tabindex="0"
84
- data-tab-content="{{ tab }}"{% unless forloop.first %} hidden{% endunless %}>
56
+ data-tab-content="{{ tab.id }}"{% unless forloop.first %} hidden{% endunless %}>
57
+ {%- for command in tab.commands -%}
58
+ {%- assign command_id = install_id | append: '-command-' | append: tab.id -%}
59
+ {%- unless forloop.first %}{% assign command_id = command_id | append: '-' | append: forloop.index %}{% endunless -%}
60
+ {%- assign console_key = 'package_install.' | append: command.console -%}
85
61
  <div class="package-install__code-block">
86
62
  <div class="package-install__code-header">
87
63
  <span class="package-install__code-label">{{ console_key | t }}</span>
88
64
  <button type="button"
89
65
  class="package-install__copy-btn"
90
66
  data-copy-target
91
- data-target="{{ install_id }}-command-{{ tab }}"
67
+ data-target="{{ command_id }}"
92
68
  data-copied-label="{{ copied_label | strip | escape }}"
93
69
  data-error-label="{{ copy_error_label | strip | escape }}">
94
70
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
@@ -98,10 +74,11 @@ pip install -e .{%- endcapture -%}
98
74
  {% t 'package_install.copy' %}
99
75
  </button>
100
76
  </div>
101
- <pre><code id="{{ install_id }}-command-{{ tab }}">{{ command | strip }}</code></pre>
77
+ <pre><code id="{{ command_id }}">{{ command.command | escape }}</code></pre>
102
78
  </div>
79
+ {%- endfor -%}
103
80
  </div>
104
81
  {%- endfor -%}
105
82
  </div>
106
- {%- endif -%}
107
83
  </div>
84
+ {%- endif -%}
@@ -0,0 +1,14 @@
1
+ {%- assign variant = include.variant | default: 'dated' -%}
2
+ <ul class="archive-list archive-list--{{ variant | escape }}">
3
+ {%- for post in include.posts %}
4
+ <li>
5
+ <a href="{{ post.url | relative_url }}">{{ post.title | escape }}</a>
6
+ {%- if variant == 'teaser' and post.description %}
7
+ <p>{{ post.description | strip_html | escape }}</p>
8
+ {%- endif %}
9
+ {%- if variant == 'dated' %}
10
+ <time class="archive-meta" datetime="{{ post.date | date: '%Y-%m-%d' }}">{{ post.date | localize_date | escape }}</time>
11
+ {%- endif %}
12
+ </li>
13
+ {%- endfor %}
14
+ </ul>
@@ -26,29 +26,23 @@
26
26
  {% assign loading_mode = include.loading | default: site.datalog_image_config.lazy_loading | default: 'lazy' %}
27
27
  {% if responsive_entry %}
28
28
  <picture>
29
- {% for source in responsive_entry.sources %}
30
- {% assign srcset_items = '' %}
31
- {% for variant in source.variants %}
32
- {% assign variant_url = variant.url | relative_url %}
33
- {% assign descriptor = variant.width | append: 'w' %}
34
- {% if forloop.first %}
35
- {% assign srcset_items = variant_url | append: ' ' | append: descriptor %}
36
- {% else %}
37
- {% assign srcset_items = srcset_items | append: ', ' | append: variant_url | append: ' ' | append: descriptor %}
38
- {% endif %}
39
- {% endfor %}
40
- <source type="{{ source.type }}" srcset="{{ srcset_items }}" sizes="{{ requested_sizes }}">
29
+ {% comment %}
30
+ The same figure exported for a dark page, if there is one. It comes
31
+ first: a <picture> takes the first source whose media and type both
32
+ match, so a dark source after a light one is never reached. Its own
33
+ format is offered too, for a browser with neither AVIF nor WebP.
34
+ {% endcomment %}
35
+ {% assign dark_entry = responsive_entry.dark %}
36
+ {% for source in dark_entry.sources %}
37
+ <source media="(prefers-color-scheme: dark)" data-dark-source type="{{ source.type }}" srcset="{{ source.variants | image_srcset }}" sizes="{{ requested_sizes }}">
41
38
  {% endfor %}
42
- {% assign fallback_srcset = '' %}
43
- {% for variant in responsive_entry.fallback.variants %}
44
- {% assign variant_url = variant.url | relative_url %}
45
- {% assign descriptor = variant.width | append: 'w' %}
46
- {% if forloop.first %}
47
- {% assign fallback_srcset = variant_url | append: ' ' | append: descriptor %}
48
- {% else %}
49
- {% assign fallback_srcset = fallback_srcset | append: ', ' | append: variant_url | append: ' ' | append: descriptor %}
50
- {% endif %}
39
+ {% if dark_entry.fallback.variants.size > 0 %}
40
+ <source media="(prefers-color-scheme: dark)" data-dark-source{% if dark_entry.fallback.type %} type="{{ dark_entry.fallback.type }}"{% endif %} srcset="{{ dark_entry.fallback.variants | image_srcset }}" sizes="{{ requested_sizes }}">
41
+ {% endif %}
42
+ {% for source in responsive_entry.sources %}
43
+ <source type="{{ source.type }}" srcset="{{ source.variants | image_srcset }}" sizes="{{ requested_sizes }}">
51
44
  {% endfor %}
45
+ {% assign fallback_srcset = responsive_entry.fallback.variants | image_srcset %}
52
46
  {% assign fallback_default = responsive_entry.fallback.variants | last %}
53
47
  {% assign fallback_src = fallback_default.url | relative_url %}
54
48
  <img src="{{ fallback_src }}" srcset="{{ fallback_srcset }}" sizes="{{ requested_sizes }}" alt="{{ alt_text }}" loading="{{ loading_mode }}" decoding="async"{% if responsive_entry.width %} width="{{ responsive_entry.width }}"{% endif %}{% if responsive_entry.height %} height="{{ responsive_entry.height }}"{% endif %}{% if include.class %} class="{{ include.class }}"{% endif %}>
@@ -16,7 +16,7 @@
16
16
  </p>
17
17
  {% if site.author.orcid %}
18
18
  <p class="footer-orcid">
19
- <a href="{{ site.author.orcid }}" rel="me noopener" target="_blank">ORCID {{ site.author.orcid | replace: 'https://orcid.org/', '' }}</a>
19
+ <a href="{{ site.author.orcid }}" rel="{{ site.author | author_profile_rel | escape }}" target="_blank">ORCID {{ site.author.orcid | replace: 'https://orcid.org/', '' }}</a>
20
20
  </p>
21
21
  {% endif %}
22
22
  </section>