datalog-theme 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +125 -0
- data/CITATION.cff +2 -2
- data/README.md +23 -17
- data/_data/cdn-integrity.yml +0 -30
- data/_includes/analytics/dashboard.html +3 -1
- data/_includes/components/api-function.html +20 -1
- data/_includes/components/enhanced-code-block.html +1 -1
- data/_includes/csp-meta.html +115 -11
- data/_includes/footer.html +19 -20
- data/_includes/head.html +60 -23
- data/_includes/header/navigation.html +12 -15
- data/_includes/header.html +28 -19
- data/_includes/layouts/default/article.html +5 -1
- data/_includes/meta/math-config.html +9 -5
- data/_includes/meta/schema.html +5 -2
- data/_includes/meta/scripts-loader.html +16 -32
- data/_includes/post/related-posts.html +4 -7
- data/_includes/search/index-data.json +9 -34
- data/_layouts/dataset.html +1 -0
- data/_layouts/default.html +16 -8
- data/_layouts/notebook.html +1 -0
- data/_layouts/package.html +1 -0
- data/_layouts/portfolio.html +1 -0
- data/_layouts/post.html +20 -5
- data/_layouts/project.html +2 -1
- data/_plugins/analytics_dashboard.rb +9 -3
- data/_plugins/config_validator.rb +12 -7
- data/_plugins/csp_generator.rb +18 -28
- data/_plugins/datalog_bibliography.rb +9 -7
- data/_plugins/datalog_comments.rb +8 -5
- data/_plugins/datalog_slides.rb +9 -8
- data/_plugins/i18n.rb +7 -8
- data/_plugins/image_optimizer.rb +17 -6
- data/_plugins/math_preprocessor.rb +33 -3
- data/_plugins/notebook_converter.rb +23 -4
- data/_plugins/plugin_loader.rb +3 -1
- data/_plugins/publications_generator.rb +8 -2
- data/_plugins/rouge_highlight_filter.rb +42 -0
- data/_plugins/search_code_blocks.rb +30 -0
- data/_plugins/search_normalizer.rb +15 -53
- data/_plugins/search_pages.rb +3 -4
- data/_sass/_academic-dashboard.scss +262 -0
- data/_sass/_base.scss +12 -0
- data/_sass/_components.scss +64 -1153
- data/_sass/_features.scss +17 -0
- data/_sass/_layout.scss +1 -1
- data/_sass/_notebooks.scss +322 -0
- data/_sass/_open-science-badges.scss +56 -0
- data/_sass/{_phase1-enhancements.scss → _post-components.scss} +1 -1
- data/_sass/_search-page.scss +530 -0
- data/_sass/_search.scss +46 -0
- data/_sass/_syntax-highlighting.scss +212 -97
- data/_sass/_theme.scss +29 -19
- data/_sass/_typography.scss +14 -0
- data/assets/css/main.scss +14 -0
- data/assets/js/dist/academic.js +1 -1
- data/assets/js/dist/analytics-dashboard.js +1 -1
- data/assets/js/dist/chunks/chunk-225H5YXE.js +1 -0
- data/assets/js/dist/core.js +1 -1
- data/assets/js/dist/loader.js +1 -1
- data/assets/js/dist/notebook.js +1 -1
- data/assets/js/dist/search.js +1 -1
- data/assets/js/dist/visualizations.js +11 -2
- data/assets/js/loader.js +3 -1
- data/datalog-theme.gemspec +36 -23
- data/lib/datalog/cli.rb +34 -14
- data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
- data/lib/datalog/theme/package.rb +57 -0
- data/lib/datalog/theme/repository_checkout.rb +90 -0
- data/lib/datalog/theme/version.rb +1 -1
- data/lib/datalog/warning_filter.rb +5 -11
- data/lib/datalog-theme.rb +5 -0
- metadata +48 -133
- data/_data/academic.yml +0 -217
- data/_data/config/author.yml +0 -121
- data/_data/datasets.yml +0 -28
- data/_data/js_meta.json +0 -371
- data/_data/navigation.yml +0 -145
- data/_data/projects.yml +0 -41
- data/_data/publications.yml +0 -28
- data/_data/social.yml +0 -73
- data/_data/visualizations.yml +0 -51
- data/_includes/components/advanced-search.html +0 -682
- data/_includes/components/bookmark-system.html +0 -96
- data/_includes/components/comments.html +0 -244
- data/_includes/components/content-recommendations.html +0 -228
- data/_includes/components/email-preferences.html +0 -200
- data/_includes/components/enhanced-metadata.html +0 -228
- data/_includes/components/language-switcher.html +0 -396
- data/_includes/components/navigation-enhancements.html +0 -454
- data/_includes/components/newsletter-signup.html +0 -178
- data/_includes/components/popular-posts.html +0 -233
- data/_includes/components/reading-progress.html +0 -133
- data/_includes/components/reading-time.html +0 -121
- data/_includes/components/series-navigation.html +0 -124
- data/_includes/components/social-proof.html +0 -34
- data/_includes/components/user-preferences.html +0 -566
- data/_includes/meta/syntax-config.html +0 -19
- data/_layouts/archive.html +0 -282
- data/_layouts/post-sidebar.html +0 -183
- data/_sass/_phase3-enhancements.scss +0 -874
- data/_sass/_phase4-enhancements.scss +0 -1214
- data/_sass/_phase5-enhancements.scss +0 -414
- data/assets/js/academic.js +0 -262
- data/assets/js/analytics-dashboard.js +0 -382
- data/assets/js/core/dark-mode.js +0 -79
- data/assets/js/core/github-cards.js +0 -123
- data/assets/js/core/language-filter.js +0 -69
- data/assets/js/core/navigation.js +0 -184
- data/assets/js/core/scroll-progress.js +0 -45
- data/assets/js/core/search-hotkeys.js +0 -62
- data/assets/js/core/skip-links.js +0 -62
- data/assets/js/dist/manifest.json +0 -22
- data/assets/js/dist/meta.json +0 -371
- data/assets/js/main.js +0 -23
- data/assets/js/math.js +0 -818
- data/assets/js/notebook.js +0 -158
- data/assets/js/search/analytics.js +0 -91
- data/assets/js/search/app.js +0 -271
- data/assets/js/search/autocomplete.js +0 -120
- data/assets/js/search/engine.js +0 -260
- data/assets/js/search/filters.js +0 -45
- data/assets/js/search/render.js +0 -217
- data/assets/js/search/utils.js +0 -99
- data/assets/js/search.js +0 -354
- data/assets/js/visualizations.js +0 -816
- data/assets/publications/datalog-publications.bib +0 -8
- data/assets/publications/datalog-publications.ris +0 -9
- data/assets/publications/publications.bib +0 -30
- data/assets/templates/diogo-ribeiro-cv.md +0 -31
- data/assets/templates/diogo-ribeiro-cv.tex +0 -32
- data/lib/datalog/theme/theme.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76c51ad2ebacf140c696deb3abdf2b8bff74bd31a9594533ddd65bd9c9a3aba4
|
|
4
|
+
data.tar.gz: 5b9d40c77ee4e740774d09ce6fd5c26a6f16c8c92da17d69a611e0a3d00cc930
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 06a2ac68844fdc67bbed3abb7640d1ac13920964454dda355e5c08fb8d0627cbae16d1585677695b94d92bf6e9a568b427ed59871bf5ec2aa2ad02fcbd2f60b8
|
|
7
|
+
data.tar.gz: 8616c20c4894822cc7b047a83668b5f42d58b4e11799320273b697423e4af3e2aa498824e175f65c03fae05fc29793663ed859435a7f640c0e0ab85b7a6f71d1
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,131 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [0.8.0] - 2026-09-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `tests/test_csp_pages.rb` checks that every nonce in a page matches its policy, that MathJax and Disqus pages get what they load, and that Observable's classic embeds may be framed (#196).
|
|
10
|
+
- `csp.script_src`, `csp.style_src`, `csp.font_src` and `csp.connect_src` in `_config.yml` add sources to the Content Security Policy, as `csp.frame_src` does for iframes (#196).
|
|
11
|
+
- The policy sets `object-src 'none'`, `base-uri 'self'` and `form-action 'self'`. None of them falls back to `default-src`, so all three were open (#196).
|
|
12
|
+
- `tests/test_csp.rb` checks which pages get the looser policy. `tests/integration/csp-charts.spec.js` loads the real Plotly and widget manager, checks that the chart and the widget render, and fails on any script or style violation. Unit tests in `tests/js/visualizations.test.js` cover the order in which chart libraries and require.js load (#195).
|
|
13
|
+
- A `rouge_highlight` Liquid filter highlights code passed to an include as the site builds. The package API examples and the enhanced code block, which printed its code unescaped, use it, and the notebook converter highlights code cells the same way (#197).
|
|
14
|
+
- The head preloads the visualization, notebook and academic bundles on the pages that use them, as it already did for search and math, so they download alongside the core bundle instead of after it (#197).
|
|
15
|
+
- `tests/test_rouge_highlighting.rb` checks that code is highlighted as the site builds and that pages load no Prism. `tests/test_feature_loading.rb` checks the new preloads and which pages inline the academic data, and a Playwright test checks that the copy button labels the language and leaves out line numbers (#197).
|
|
16
|
+
- Ruby Tests jobs on Ruby 3.3 and 3.4 in the Tests workflow run the Ruby suite on the newer releases, next to the existing job on 3.2. `tests/test_gem_package.rb` checks the Ruby requirement, that every runtime dependency has an upper bound, that the unused and optional gems stay out, and which script files the gem ships (#203).
|
|
17
|
+
- `tests/test_site_output.rb` checks that every in-page link on the built site reaches an element on that page (#206).
|
|
18
|
+
- A Docker Images workflow builds `Dockerfile` and `Dockerfile.dev`, without pushing, on pull requests that change what they are built from (#205).
|
|
19
|
+
- `bundle exec rake test` builds the demo site and runs the Minitest suite, the same command as the Tests workflow, and is the default Rake task. `tests/test_site_output.rb` takes over what the `ci:verify` scripts checked and no other suite did: `CITATION.cff` matching the theme version, citation exports and scholar metadata on posts, the math status live region, `noopener` on every link that opens a new tab, and sandboxed app embeds. The browser suite checks that code blocks in a post get a labelled copy button, which the post layout adds when the page loads (#204).
|
|
20
|
+
- A Lint job in the Tests workflow runs ESLint and RuboCop, and the test summary fails when it does. Both linters were configured in the repository but ran in no workflow. RuboCop is now a development dependency, pinned because the repository has no `Gemfile.lock`; the offenses that predate the job are listed in `.rubocop_todo.yml`, so new code has to pass (#204).
|
|
21
|
+
- `tests/test_workflows.rb` checks the release and CI guards described below, and `tests/js/cdn-integrity.test.js` runs the Subresource Integrity check from `tests/test_sri.js`, a script no test command ran (#204).
|
|
22
|
+
- `tests/test_gem_consumer.rb` builds a minimal site against the packaged theme and against a checkout of the repository, and fails if the build breaks or publishes anything that identifies the maintainer.
|
|
23
|
+
- `tests/test_navigation_cache.rb` checks that each section still marks only its own navigation link now that the navigation is cached.
|
|
24
|
+
- The performance tests fail if the stylesheet grows past 25 KB gzipped, as they already did for the core script bundle.
|
|
25
|
+
- `tests/test_related_posts.rb` checks that a post lists the posts it shares a tag with.
|
|
26
|
+
- `csp.frame_src` in `_config.yml` lists the hosts a site embeds iframes from, such as Shiny apps, slide decks or videos, and the Content Security Policy allows them next to Observable.
|
|
27
|
+
- `tests/test_feature_loading.rb` checks which pages load MathJax and the search bundle.
|
|
28
|
+
- `show_title: false` in a page's or a layout's front matter leaves out the title the default layout prints, for pages and layouts that render their own `<h1>`.
|
|
29
|
+
- `tests/test_page_structure.rb` checks that no built page has more than one `<h1>`, the footer's headings and landmark name, the color scheme script at the top of `<body>` and the heights of the academic chart's bars. `tests/js/blocked-storage.test.js` covers dark mode and the core initializers with storage blocked, and the browser suite checks that the saved theme applies before any script bundle loads and that the core bundle still loads when storage is blocked.
|
|
30
|
+
- `tests/test_head_metadata.rb` checks that each head tag appears once, that empty verification tags are left out, that the 404, search and admin pages carry `noindex` and stay out of the sitemap, and that every page's JSON-LD parses without empty values.
|
|
31
|
+
- Tests for the fixes to the config validator, the warning filter, notebook images and languages, the analytics cache, plugin hook registration, `{% t %}` options, `datalog publish` and `datalog new post`, in the existing test files for each.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Each page's Content Security Policy allows only the jsDelivr packages that page loads: the math engine's directory, and Plotly, D3, BokehJS, Vega or Chart.js where the page uses them. The policy allowed all of jsDelivr, which serves any npm package, on every page. Widget pages still allow all of jsDelivr, and they are the only pages that allow require.js from cdnjs (#196).
|
|
36
|
+
- Google's analytics hosts are in the policy only on a site that sets `google_analytics`. They are the hosts Google documents for GA4, including the regional `*.google-analytics.com` hosts GA4 reports to (#196).
|
|
37
|
+
- The Content Security Policy is looser on pages with a Plotly or ipywidgets block and unchanged on every other page. Plotly pages allow inline styles in place of the style nonce. Widget pages also allow `'unsafe-eval'` and fonts from jsDelivr. A page that loads either library another way can set `csp.unsafe_inline_styles` or `csp.unsafe_eval` in its front matter (#195).
|
|
38
|
+
- Code is highlighted by Rouge alone, when the site builds. Pages with code also loaded Prism from jsDelivr (seven scripts and two stylesheets on a post), which highlighted the blocks again in the browser and turned every language it had no grammar for, such as bash and yaml, into plain text. The theme now styles Rouge's tokens and line numbers in light and dark mode, in greys that meet 4.5:1 contrast (the comment grey Prism used measured 2.33:1 in light mode), and gives every code block tabindex="0", as Prism did, so a wide block can be scrolled from the keyboard. Search results show code snippets as plain text (#197).
|
|
39
|
+
- The academic and publication data is inlined only on pages that render citation metrics, tables or charts, the only pages whose script reads it. On the home page it was nearly a quarter of the HTML (#197).
|
|
40
|
+
- The image optimizer fetches one image per page early: the first image in the post or page content, and none on a page that preloads its hero. It gave the first image anywhere on the page both `loading="lazy"` and `fetchpriority="high"`, which was a post card below the hero on the home page and a related-post thumbnail at the bottom of tutorials (#197).
|
|
41
|
+
- Google Fonts is asked for the eight weights the stylesheet uses instead of eleven, and the font stylesheet link no longer repeats its `media` and `data-async-style` attributes (#197).
|
|
42
|
+
- The gem requires Ruby 3.2, the version the sass-embedded and nokogiri releases it resolves need; it claimed 3.0. Every runtime dependency is bounded below its next major version (`~> 1.15` rather than `>= 1.15`), so a breaking release arrives through a pull request instead of an untested `bundle update` (#203).
|
|
43
|
+
- `googleauth` is no longer a dependency of the theme. Only the analytics dashboard with a GA4 property configured uses it, and every site installed it with its Google Cloud dependencies; a site that uses the dashboard adds `gem "googleauth"` to its Gemfile, and without it the dashboard says so (#203).
|
|
44
|
+
- The Docker images build on `ruby:3.4-slim` and serve from `nginx:1.30-alpine`. `ruby:3.2-slim` is end of life, and 1.27 was an nginx mainline branch that no longer gets releases (#203).
|
|
45
|
+
- The pre-commit hook runs lint-staged only: ESLint and the Vitest tests related to the staged JavaScript. It used to run `npm audit`, which needs the network, and the whole Vitest suite on every commit; both still run on every pull request (#205).
|
|
46
|
+
- Dependabot pull requests are titled `chore(deps)`, `chore(deps-dev)` and `ci(deps)`. The prefixes repeated the scope Dependabot appends, which gave titles like `chore(deps-dev)(deps-dev)` (#205).
|
|
47
|
+
- The accessibility, broken link, dependency review and Lighthouse workflows cancel a pull request's superseded runs, the accessibility workflow installs a pinned `pa11y-ci` and uses the `http-server` devDependency, and `package.json` is marked private so `npm publish` refuses to publish the repository's tooling (#205).
|
|
48
|
+
- `gem-release.yml` publishes only from a `v*` tag, a manual run included, and stops when the tag does not match `lib/datalog/theme/version.rb`. The tag job in `release.yml` builds the script bundles and the gem and runs `scripts/verify_gem_package.rb` before it creates the tag, so a broken package no longer leaves a tag and a GitHub release for a gem that never published (#204).
|
|
49
|
+
- The Python security audit runs `pip-audit` on `requirements.txt`. It used to collect `import` lines from `scripts/`, which name modules rather than packages, and ignore every result (#204).
|
|
50
|
+
- `search.json` no longer stores a normalized copy of each document's title, summary, content, tags and languages. The search engine normalizes them in the browser, once per document, with the function it applies to queries; the copy was 41% of the file, and queries and documents had been normalized by different code. With the code blocks below added, the demo's index goes from 219 KB to 137 KB.
|
|
51
|
+
- The Tests workflow runs the Playwright suite and enforces the coverage thresholds on pull requests. The coverage steps waited for a Node 20 leg the matrix no longer has, and the browser specs only ran in the deploy after a merge, so both kinds of failure surfaced on `develop` instead of on the pull request.
|
|
52
|
+
- MathJax loads only on pages with math, and the search bundle only on the search page. With `render_on_load: auto`, MathJax loaded wherever a dollar sign or an escaped parenthesis appeared in the rendered page, including shell variables, prices and inline scripts, and the demo also turned it on for every post; it now follows the expressions the math preprocessor finds, and on the demo loads on 6 pages instead of 28. The search bundle was preloaded and run on every page because the header's search form matched the loader's check; it now loads on the one page that renders the search app.
|
|
53
|
+
- The release workflow promotes a `release/vX.Y.Z` branch to `main` instead of promoting `develop` itself, so the pull request and the merge commit on `main` name the release rather than reading "from develop". `develop` still receives the version bump.
|
|
54
|
+
- The stylesheet carries the styles of an optional feature only when the site uses it: search (`features.search`), visualizations (`features.visualizations`), notebook pages, the `packages` collection, the academic dashboard (`features.academic_dashboard`) and open science badges (badges in `_data/academic.yml`). `assets/css/main.scss` configures the new `_sass/_features.scss` from the site's settings, and each partial loads those styles at the position they always had, so a site with every feature on gets the same stylesheet byte for byte. With all six off it shrinks from 169 KB to 122 KB, or from 27.6 KB to 20.5 KB gzipped. A site that replaced `main.scss` with a plain `@use "theme"` keeps the complete stylesheet. `_sass/_phase1-enhancements.scss` is now `_sass/_post-components.scss`.
|
|
55
|
+
- The layouts use `jekyll-include-cache`, a dependency the theme already declared but never used. The footer and skip link are rendered once per build (the skip link once per page language) and the header navigation once per distinct current section, where each was rendered on every page before: on the demo site the navigation renders 10 times instead of 53. The CSP meta tag, the script loader and the analytics snippet stay per page because each carries that page's CSP nonce. Requiring the theme now also loads `jekyll-include-cache`.
|
|
56
|
+
- The documentation is organised by task. `docs/README.md` indexes the guides by what a reader wants to do; the phase summaries, the configuration refactoring plan and the 2025 security audit moved to `docs/history/` under a note that they are not maintained; and the Phase 1 features guide became `docs/components.md`, without the `phase1_features` settings the theme never read and with instructions that work for a site using the gem. The installation guide lost its leftover citation markers, and the README and the starter template pin the current `~> 0.7` series.
|
|
57
|
+
- The installation guide covers what a site supplies itself (pages, navigation, social links), installing from a Git checkout, and publishing to GitHub Pages with GitHub Actions. It replaces instructions for the built-in Pages build, which cannot run the theme.
|
|
58
|
+
|
|
59
|
+
### Deprecated
|
|
60
|
+
|
|
61
|
+
- `theme_options.syntax_highlighting` no longer has an effect, and a build that sets it prints a warning (#197).
|
|
62
|
+
|
|
63
|
+
### Removed
|
|
64
|
+
|
|
65
|
+
- The CSP generator's inline script hashes. It computed them after a page had rendered, too late to reach the policy written into its head, and every inline script already carries the nonce (#196).
|
|
66
|
+
- Prism: its scripts and stylesheets, their SRI entries, the `meta/syntax-config.html` include, the `syntax_highlighting` page setting and the `theme_options.syntax_highlighting` block in the demo configuration (#197).
|
|
67
|
+
- `window.DatalogTheme` and `window.DatalogContent`, which every page inlined and no script read (#197).
|
|
68
|
+
- `jekyll-archives` and `jekyll-remote-theme` from the gem's dependencies, which nothing in the theme used, and the 22 unbundled script sources from the gem. Pages load the bundles in `assets/js/dist` and `assets/js/loader.js`; every site copied the sources into its published output as well. A site that installs the theme from a checkout still has them (#203).
|
|
69
|
+
- Settings in the demo `_config.yml` that nothing reads: `features.math_toolkit`, `math_search`, `accessibility_skip_link`, `academic_calendar` and `notebook_support`, `theme_options.math.equation_numbering`, and `integrations.binder` and `integrations.colab`, whose buttons are configured under `notebooks:` (#206).
|
|
70
|
+
- `rake ci:verify` and its twelve scripts in `scripts/`. Most checked that source files contained particular strings, repeated what Minitest, Vitest and Playwright already cover, and passed whether or not the built site worked. The Tests workflow no longer sets up Python, which only one of them needed (#204).
|
|
71
|
+
- `project-sync.yml`, which only printed what it would have done, and `tests/test_critical_css.js`, `tests/test_search_accessibility.js` and `tests/test_viz_accessibility.js`, which no test command ran and which failed against the current sources (#204).
|
|
72
|
+
- `lib/datalog/theme/theme.rb`, a theme registration hook that nothing required.
|
|
73
|
+
- Includes and layouts that no layout, page or plugin used, with the styles written for them: the `archive` and `post-sidebar` layouts, and the user preferences panel, popular posts, back-to-top button and keyboard shortcuts panel (`navigation-enhancements`), social proof, enhanced metadata, reading progress, reading time, content recommendations, comments, language switcher, bookmark, email preferences, advanced search, newsletter signup and series navigation includes. Several read `phase2_features` to `phase5_features` settings that nothing defined. Comments still render through the `datalog-comments` plugin. The rules in those stylesheets that did style rendered pages (the `kbd` element, fieldsets, `.button` and the search result cards) moved to the partials for what they style, and `_sass/_phase3-enhancements.scss`, `_phase4-enhancements.scss` and `_phase5-enhancements.scss` are gone. Together with the feature gating above, the demo's stylesheet goes from 169 KB to 134 KB (27.6 KB to 23 KB gzipped), and a site with every optional feature off gets 85 KB (15.7 KB gzipped).
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- MathJax typesets math again. Its configuration loaded the `\require` extension, which stopped MathJax 3.2 while starting up (`Illegal characters used in \require prefix`), so no page rendered an equation. Every extension the pages use is loaded directly, so authors don't need `\require`.
|
|
78
|
+
- Posts with math no longer throw `Cannot read properties of undefined (reading 'then')`. The post layout read `MathJax.startup.promise` before MathJax had loaded; MathJax now announces typeset math with a `datalog:math-ready` event.
|
|
79
|
+
- Equations are no longer taken out of the tab order. MathJax's explorer gave each one `tabindex="1"`, which axe reports; it is turned off, and the assistive MathML screen readers use stays on.
|
|
80
|
+
- The math preprocessor's wrapper has `role="math"`. It carried an `aria-label` with no role, which ARIA forbids, and axe failed the page once MathJax rendered the expression inside it.
|
|
81
|
+
- Notebook pages run their inline scripts. The pages are created after the CSP generator assigns nonces, and their templates printed an empty `page.csp_nonce`, so the browser refused every inline script in the head. MathJax's inserted stylesheet is allowed on math pages.
|
|
82
|
+
- Bokeh blocks render. The theme loaded BokehJS's core bundle, which has no `Bokeh.Plotting`; it now loads the API bundle too, and logs a failed load instead of ignoring it.
|
|
83
|
+
- Disqus comments load. The policy refused Disqus's script, stylesheet, iframe and the inline style that sizes the iframe.
|
|
84
|
+
- Observable embeds display. An `observablehq.com` embed redirects to `old.observablehq.com`, which the policy refused. The demo's two embeds pointed at notebooks that return 404 and now embed D3's zoomable sunburst and bar chart.
|
|
85
|
+
- The demo post's slide deck loads. It pointed at a host that does not exist; it now embeds the reveal.js demo deck, and `revealjs.com` is in the demo's `csp.frame_src`.
|
|
86
|
+
- KaTeX's fonts load. The policy refused the fonts its stylesheet requests from jsDelivr (#196).
|
|
87
|
+
- Plotly charts render. Plotly inserts its rules into a `<style>` element it creates, which the policy refused, so every Plotly block reported that Plotly failed to load (#195).
|
|
88
|
+
- Jupyter widgets render. The policy refused the widget manager's `<style>` elements, the `new Function` it compiles widget schemas with, and its icon fonts. The theme also called a `WidgetManager` that `@jupyter-widgets/html-manager` does not export, and the error was swallowed; it now uses `HTMLManager` (#195).
|
|
89
|
+
- A page with a widget no longer loses its Plotly, D3 or BokehJS chart depending on which script loads first. require.js, which the widget manager loads, made a bundle that ran after it register as an anonymous module, and require.js threw `Mismatched anonymous define()`. Bundles requested after require.js now load through it (#195).
|
|
90
|
+
- The package API include's "See Also" list treated its comma-separated `see_also` string as a single item, so every list became one link to an anchor that did not exist; on the StatFlow page six of them led nowhere. It now splits the list, and StatFlow only lists functions it documents. The Plotly showcase post's contents linked to a heading written as raw HTML without an id, which now has one (#206).
|
|
91
|
+
- Documentation that contradicted the code: the testing guide and the coverage review process quoted coverage thresholds of 20% and 80% where `vitest.config.js` enforces 88/78/83/88; the testing guide still listed Percy; the configuration guide described a comments configuration the plugin does not read, Binder and Colab settings nothing reads, and the MathJax detection #194 replaced; the user guide sent notebook metadata to an unread `_data/notebooks.yml` and Binder links to an unread `integrations.notebooks`; `_config.yml` pointed at `_data/config` files that do not exist; `_data/config/author.yml` linked to a missing page; and the Minimal Mistakes post linked to a docs page the site does not build (#206).
|
|
92
|
+
- Neither Docker image built. `Dockerfile` copied a `Gemfile.lock` the repository does not have, then built the script bundles without esbuild, a dev dependency it had skipped; `Dockerfile.dev` ran `bundle install` without the gemspec the Gemfile loads. Both copy what the gemspec requires, install the OpenSSL and YAML headers that gems such as `openssl` compile against, drop the Python they installed for a notebook check that is gone, and use Node.js 22 like CI (#205).
|
|
93
|
+
- The config validator stopped a build with "Invalid type for 'author'" for `author: Jane Doe`, and with "Invalid value for 'url'" for `url: ""`, which `jekyll new` writes. Both are accepted (#202).
|
|
94
|
+
- Loading the theme broke `warn` keyword arguments for the whole build: a `Kernel#warn` override printed `uplevel:` and `category:` as a hash after the message. The override is gone; the `Warning` filter beside it still silences the same two messages (#202).
|
|
95
|
+
- Notebook images whose base64 data Jupyter had split over lines or ended with a newline failed the data URI check and lost their `src`. The data is joined without whitespace first (#202).
|
|
96
|
+
- A notebook's language went into a code cell's `class` attribute unescaped; it is now cut down to the characters a class name can hold (#202).
|
|
97
|
+
- The analytics dashboard cached a missing-configuration or error report for a day, so after `GA4_PROPERTY_ID` was set it went on saying analytics wasn't configured. Only successful reports are cached (#202).
|
|
98
|
+
- Every DataLog plugin hook ran twice for each post: the loader registered its hooks for posts as well as documents, and Jekyll fires both for a post (#202).
|
|
99
|
+
- `{% t %}` split its options on every comma, so a quoted value such as `name: "Doe, Jane"` reached the translation as a fragment (#202).
|
|
100
|
+
- `datalog publish` built without `JEKYLL_ENV=production`, so the published site left out the analytics tag and included the development CSP logger, and it ignored the exit status of `git commit` and `git push`, so a rejected push still ended as a publish. It builds for production and exits with an error when either step fails (#202).
|
|
101
|
+
- `datalog new post` wrote the title, summary, author and tags between plain quotes, so a title with a double quote or a tag with a colon produced front matter that didn't parse (#202).
|
|
102
|
+
- The `datalog_slides`, `datalog_comments` and `datalog_bibliography` fallback tags, which stand in when their plugin is disabled, printed "feature coming soon", the slides one with the page's raw configuration, on a page that set the key by hand. They render nothing and log a warning naming the plugin to enable (#202).
|
|
103
|
+
- Search never matched code: every document's code list in `search.json` was empty, because the index template split the content on backticks after Jekyll had already rendered posts to HTML. `_plugins/search_code_blocks.rb` collects fenced code blocks from the source before rendering, and the demo's index now carries 34 of them (#198).
|
|
104
|
+
- The 404, search and admin pages asked search engines to index them, the search and admin pages were listed in `sitemap.xml`, and all three appeared in site search. The robots tag now comes from `robots:` in front matter, and those pages set `noindex`, `sitemap: false` and `exclude_from_search: true` (#198, #199).
|
|
105
|
+
- Every page carried the `keywords`, `format-detection` and jsDelivr `preconnect` tags twice, written by both `head.html` and the default layout, and empty Google, Bing, Yandex and Baidu verification tags when the site set no codes (#199).
|
|
106
|
+
- The JSON-LD had `"dateModified": ""` on 26 pages, `"description": ""` where a page had no description, and `"headline": null` on the home page. Values a page doesn't have are left out, and the headline falls back to the site title (#199).
|
|
107
|
+
- A blocked `localStorage` stopped every script feature on the page. Where storage access throws (Safari with all cookies blocked, sandboxed iframes, some privacy extensions), the dark mode toggle threw while the core bundle loaded, the loader gave up, and search, math, visualizations and the academic features never started. Dark mode now treats blocked storage as no saved choice, and each core initializer runs on its own, so a failure is logged without stopping the others (#201).
|
|
108
|
+
- Readers who chose the dark theme saw each page in the light theme first, because the core bundle applied the theme after the page had been drawn. A small nonced script at the top of `<body>` now applies the saved or system choice before anything paints (#201).
|
|
109
|
+
- GitHub repository cards kept their "—" placeholders when the API request failed, with no sign the numbers weren't coming, and asked again on every page view against the unauthenticated limit of 60 requests an hour. A card whose request failed now shows the translated "N/A" and is marked `data-github-state="error"`, and the failure is remembered for ten minutes (#201).
|
|
110
|
+
- Fourteen demo pages had more than one `<h1>`: the default layout printed the title, and so did the dataset, project, portfolio, notebook and package layouts, the 404 page, the archive, category and tag pages and the CV page. Those layouts and pages now set `show_title: false`. Headings in notebook markdown cells move down a level, since a notebook usually opens with its title, and package API examples render as code rather than Markdown, which had turned every Python comment into a heading (15 `<h1>`s on the StatFlow page) (#200).
|
|
111
|
+
- The footer's column titles were `<h3>` regardless of the page above them, and its navigation was an unnamed landmark next to "Primary navigation". The titles are `<h2>` with the same look, and the navigation takes its name from the "Explore" heading (#200).
|
|
112
|
+
- Screen readers announced "Reading progress: N%" on every scroll event, because the percentage sat in a live region. The live region is gone; the progress bar stays hidden from assistive technology (#200).
|
|
113
|
+
- On narrow screens, Escape moved focus to the menu button even with the menu closed, for example while clearing the search field. It now acts only when the menu is open (#200).
|
|
114
|
+
- The bars of the citations-by-year chart on `/academic/` had no height: each set it in a `style` attribute, which the Content Security Policy drops. The heights now come from a nonced style block (#195).
|
|
115
|
+
- Related posts never appeared: the list of posts was split into single characters before it was filtered, so every post said "No related posts yet".
|
|
116
|
+
- Search dropped every letter outside ASCII from its index, so accented, Greek, Cyrillic and CJK words could not be found, and every build printed "[search_normalizer] unicode_normalize gem not available": `String#unicode_normalize` is part of Ruby, not a gem. The browser also cut queries down to the letters a to z; both now keep letters of any script.
|
|
117
|
+
- The search page trapped keyboard focus: Tab from the input or any filter cycled through the filters, so the results could not be reached.
|
|
118
|
+
- Search results inserted text from the index as HTML, and highlighting several words could put one `<mark>` inside the tags of another ("remark" became `re<<mark>ma</mark>rk>`). Results and suggestions are now escaped and highlighted in one pass, and index content is stripped of markup in an inert document.
|
|
119
|
+
- A `_data/publications.yml` written as a list of entries stopped the build with a `TypeError`. A list is now read as the manual entries.
|
|
120
|
+
- The math preprocessor wrapped dollar signs inside code as math, inserting markup into shell, R and SQL snippets, and read prices such as "$5 a month, or $50 a year" as an expression. Fenced code, highlight tags and inline code are left alone, and inline math follows Pandoc's rule: the opening `$` is followed by a non-space, and the closing `$` follows one and is not followed by a digit.
|
|
121
|
+
- The analytics dashboard never rendered: its script uses `export` but was loaded as a classic script from the unbundled source, which failed to parse. It now loads as a module from the built bundle.
|
|
122
|
+
- The Copy buttons of the citation tools on posts, datasets and projects did nothing: their handler lived in the academic bundle, which those pages never load. The core bundle now handles them.
|
|
123
|
+
- Visualizations were refused by the theme's own Content Security Policy. D3 and scripted Bokeh blocks ran their code with `new Function`, which the policy refuses; the code now runs as a script carrying the page's nonce. Plotly and Bokeh loaded from hosts the policy does not list, and Bokeh also requested a stylesheet BokehJS 3 does not publish; both load from jsDelivr now. Observable blocks ignored `data-viz-src`, the attribute the user guide documents; they now accept it, and take embed addresses only from observablehq.com, so a `javascript:` or `data:` URL in the markup never becomes the frame's source. Iframes from any host but Observable were refused. On the demo, the D3 chart, the Observable embed and the Shiny app now render in Chromium. Plotly and ipywidgets charts still fail, because those libraries insert inline styles or evaluate strings, which the policy forbids, and Bokeh has not been confirmed to render.
|
|
124
|
+
- Sites installing the gem published part of the demo site. The maintainer's CV templates and publication exports were copied into every site, and the demo's social profiles, contact addresses and academic profiles reached the footer and the script data on every page through `_data`. The gem now contains only the `_data` files the layouts need (translations, the script manifest and CDN integrity hashes) and none of the demo's downloads, and `scripts/verify_gem_package.rb` refuses a gem that does.
|
|
125
|
+
- A site installing the theme from a Git checkout or a local path inherited the whole demo site. Jekyll merged the demo's `_config.yml` into the site's configuration, so the build stopped on a `datasets` feed for a collection the site did not have, and a site that declared the collection to get past it carried the maintainer's author details, contact addresses and social profiles. The build now stops with an explanation until the site sets `ignore_theme_config: true`, and with that set the theme also leaves out the demo's `_data` files and downloads.
|
|
126
|
+
- The repository and the gem carried `_data/js_meta.json`, the esbuild metafile, whose committed copy had fallen behind the sources: its byte counts described an older build than the bundles it shipped with, and running `npm run build:js` left it modified. The metafile now stays with the bundles in `assets/js/dist/` and out of the gem. The build also no longer rewrites an unchanged `_data/js_manifest.json`, which Windows checkouts reported as modified because of line endings, and the test and gem release workflows fail if the committed manifest does not match the sources.
|
|
127
|
+
- The README said notebooks publish under `/blog/` and that GitHub Pages builds a site with the `github-pages` gem. Notebooks publish under `/notebooks/`, and the build GitHub Pages runs by itself cannot load the theme's plugins, so the README now points to the GitHub Actions workflow in the installation guide.
|
|
128
|
+
- Without `_data/navigation.yml` the header and footer linked to the demo's sections (Research, Projects, Datasets, Academic Ops), which a site using the theme does not have, and the header and footer showed "DataLog" rather than the site's title. The navigation and the footer's "Explore" and "Connect" columns are now left out when there is nothing to list, and the name falls back to `title`.
|
|
129
|
+
|
|
5
130
|
## [0.7.0] - 2026-09-12
|
|
6
131
|
|
|
7
132
|
### Added
|
data/CITATION.cff
CHANGED
|
@@ -16,8 +16,8 @@ abstract: >-
|
|
|
16
16
|
It offers integrated notebook publishing, advanced math rendering, interactive
|
|
17
17
|
visualization workflows, and reproducibility tooling optimised for open science communities.
|
|
18
18
|
license: MIT
|
|
19
|
-
version: 0.
|
|
20
|
-
date-released: 2026-09-
|
|
19
|
+
version: 0.8.0
|
|
20
|
+
date-released: 2026-09-14
|
|
21
21
|
keywords:
|
|
22
22
|
- data-science
|
|
23
23
|
- jekyll
|
data/README.md
CHANGED
|
@@ -74,13 +74,15 @@ site; the rest is reference content you can copy from.
|
|
|
74
74
|
|
|
75
75
|
## Documentation
|
|
76
76
|
|
|
77
|
+
- [Documentation Index](docs/README.md) — every guide, grouped by what you want to do.
|
|
77
78
|
- [Documentation Site](docs/site/README.md) — source for the live `datalog-theme.github.io` documentation hub with feature walk-throughs, interactive demos, and migration guides.
|
|
78
79
|
- [User Guide](docs/user-guide.md) — comprehensive documentation covering installation, notebooks, math, visualizations, research workflows, accessibility, performance, and collaboration best practices for DataLog users.
|
|
79
80
|
- [Environment Setup Guide](docs/environment-setup.md) — configure environment variables, secrets, and integrations for analytics, testing, and deployment.
|
|
80
81
|
- [Scripts Reference](docs/scripts-reference.md) — complete reference for all build, test, import/export, and utility scripts.
|
|
81
82
|
- [Changelog](CHANGELOG.md) — release highlights and upgrade guidance for each published version of the DataLog theme.
|
|
82
83
|
- [Template Repository Guide](docs/template-repository.md) — instructions for publishing a GitHub template with starter content, configuration, and automated deployments.
|
|
83
|
-
- [Installation Guide](docs/install.md) —
|
|
84
|
+
- [Installation Guide](docs/install.md) — adding the theme to a site, installing from a Git checkout, publishing with GitHub Actions, and local and Docker setup.
|
|
85
|
+
- [Post Components](docs/components.md) — sharing buttons, breadcrumbs, author cards, the table of contents and difficulty badges.
|
|
84
86
|
- [Migrating from Minimal Mistakes](docs/migrating-from-minimal-mistakes.md) — the front-matter fields DataLog reads natively (hero and teaser images, SEO title and description, `classes: wide`, `redirect_from`) and the settings that keep existing URLs.
|
|
85
87
|
- [Plugin Development Guide](docs/plugin-development.md) — understand the hook system and learn how to package extensions for reuse.
|
|
86
88
|
- [Security Policy](SECURITY.md) — report security vulnerabilities and learn about security best practices.
|
|
@@ -150,7 +152,7 @@ Once configured, Chart.js visualizations will highlight top-performing posts, se
|
|
|
150
152
|
|
|
151
153
|
DataLog ships with an opinionated notebook-to-post pipeline tailored for technical storytelling:
|
|
152
154
|
|
|
153
|
-
1. **Drop `.ipynb` files into `_notebooks/`** — the custom generator transforms each notebook into a
|
|
155
|
+
1. **Drop `.ipynb` files into `_notebooks/`** — the custom generator transforms each notebook into a page under `/notebooks/<slug>/` while keeping a downloadable copy at `/notebooks/<slug>.ipynb`.
|
|
154
156
|
2. **Leverage notebook metadata** — optional fields like `title`, `tags`, `keywords`, `difficulty`, and execution metadata will surface in the rendered article header and sidebar.
|
|
155
157
|
3. **Preserve interactivity** — HTML outputs, Plotly figures, and widget placeholders are embedded automatically with responsive styling and dark-mode aware formatting.
|
|
156
158
|
4. **Launch live sessions** — configure `notebooks.repository` and `notebooks.branch` in `_config.yml` to enable Binder and Google Colab links for each notebook, alongside GitHub source references and clone instructions.
|
|
@@ -159,9 +161,8 @@ DataLog ships with an opinionated notebook-to-post pipeline tailored for technic
|
|
|
159
161
|
Matplotlib/Seaborn plots, LaTeX, and code syntax highlighting are optimized for both desktop and mobile viewing, while cell numbering and input/output differentiation mirror the native Jupyter experience.
|
|
160
162
|
|
|
161
163
|
4. **Deploy to GitHub Pages**
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
- GitHub Pages will automatically build the site using the `github-pages` gem
|
|
164
|
+
- The build GitHub Pages runs by itself cannot load the theme's plugins, so build and publish with GitHub Actions: see [Publish with GitHub Pages](docs/install.md#23-publish-with-github-pages)
|
|
165
|
+
- `.github/workflows/deploy.yml` publishes this repository's demo site that way
|
|
165
166
|
|
|
166
167
|
## Data Science Workflow Integration
|
|
167
168
|
|
|
@@ -187,7 +188,7 @@ Matplotlib/Seaborn plots, LaTeX, and code syntax highlighting are optimized for
|
|
|
187
188
|
The `_config.yml` file exposes an opinionated set of options crafted for research teams:
|
|
188
189
|
|
|
189
190
|
- `theme_options.math` toggles between **MathJax** and **KaTeX** engines, equation numbering, and accessibility defaults.
|
|
190
|
-
-
|
|
191
|
+
- Code blocks are highlighted by Rouge when the site builds, and the theme styles Rouge's output for light and dark mode, so code needs no settings.
|
|
191
192
|
- `theme_options.visualizations` controls default behaviour for Plotly, D3, Bokeh, Observable, Shiny, and widget embeds.
|
|
192
193
|
- `theme_options.taxonomy`, `content.research_areas`, and `content.methodologies` organize content by research area and methodology for archive navigation.
|
|
193
194
|
- `integrations.github` enables live repository metrics with caching support for portfolio cards, while Binder/Colab/Kaggle toggles control interactive notebook links.
|
|
@@ -207,35 +208,40 @@ Data-driven configuration allows you to publish or reorder projects, datasets, s
|
|
|
207
208
|
Add the theme gem to your Jekyll site:
|
|
208
209
|
|
|
209
210
|
```ruby
|
|
210
|
-
gem "datalog-theme", "~> 0.
|
|
211
|
+
gem "datalog-theme", "~> 0.7"
|
|
211
212
|
```
|
|
212
213
|
|
|
213
|
-
Then enable it in `_config.yml
|
|
214
|
+
Then enable it in `_config.yml`. Naming the theme under `plugins:` registers its Liquid tags, and the build needs an author name:
|
|
214
215
|
|
|
215
216
|
```yml
|
|
216
217
|
theme: datalog-theme
|
|
218
|
+
plugins:
|
|
219
|
+
- datalog-theme
|
|
220
|
+
author:
|
|
221
|
+
name: Your Name
|
|
217
222
|
```
|
|
218
223
|
|
|
219
|
-
|
|
224
|
+
The [installation guide](docs/install.md) covers the files a site supplies itself, installing from a Git checkout, and publishing to GitHub Pages. GitHub Pages cannot build a site that uses this theme by itself, so the guide publishes it with GitHub Actions.
|
|
220
225
|
|
|
221
226
|
## Continuous Integration & Testing
|
|
222
227
|
|
|
223
|
-
The
|
|
228
|
+
The Tests workflow (`.github/workflows/test.yml`) runs on every pull request:
|
|
224
229
|
|
|
225
|
-
-
|
|
226
|
-
-
|
|
227
|
-
-
|
|
228
|
-
-
|
|
230
|
+
- Vitest unit tests for the JavaScript, with coverage thresholds.
|
|
231
|
+
- A Jekyll build of the demo site, then the Minitest suite against the output: plugins, templates, the Content Security Policy, packaging and performance budgets.
|
|
232
|
+
- Playwright browser tests, including axe accessibility checks in both themes.
|
|
233
|
+
- ESLint and RuboCop.
|
|
229
234
|
|
|
230
|
-
Run the
|
|
235
|
+
Separate workflows audit dependencies and run CodeQL, Pa11y and Lighthouse. Run the unit and Ruby suites locally with:
|
|
231
236
|
|
|
232
237
|
```bash
|
|
233
|
-
|
|
238
|
+
npm test
|
|
239
|
+
bundle exec rake test
|
|
234
240
|
```
|
|
235
241
|
|
|
236
242
|
## Demo Site
|
|
237
243
|
|
|
238
|
-
The repository doubles as a demo site and content laboratory. Explore the curated examples locally
|
|
244
|
+
The repository doubles as a demo site and content laboratory, published at <https://diogoribeiro7.github.io/analytics-blog-jekyll/>. Explore the curated examples locally with `bundle exec jekyll serve`.
|
|
239
245
|
|
|
240
246
|
## Citation & Academic Metadata
|
|
241
247
|
|
data/_data/cdn-integrity.yml
CHANGED
|
@@ -13,36 +13,6 @@ https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js:
|
|
|
13
13
|
https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js:
|
|
14
14
|
crossorigin: anonymous
|
|
15
15
|
integrity: sha384-AHAnt9ZhGeHIrydA1Kp1L7FN+2UosbF7RQg6C+9Is/a7kDpQ1684C2iH2VWil6r4
|
|
16
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-javascript.min.js:
|
|
17
|
-
crossorigin: anonymous
|
|
18
|
-
integrity: sha384-D44bgYYKvaiDh4cOGlj1dbSDpSctn2FSUj118HZGmZEShZcO2v//Q5vvhNy206pp
|
|
19
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-julia.min.js:
|
|
20
|
-
crossorigin: anonymous
|
|
21
|
-
integrity: sha384-joWnGJCIIBw7UmQ231RAVzCNiATJS38xk7yfiIDHRBJeYiBPvacMLMvx9d49VnrH
|
|
22
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-python.min.js:
|
|
23
|
-
crossorigin: anonymous
|
|
24
|
-
integrity: sha384-WJdEkJKrbsqw0evQ4GB6mlsKe5cGTxBOw4KAEIa52ZLB7DDpliGkwdme/HMa5n1m
|
|
25
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-r.min.js:
|
|
26
|
-
crossorigin: anonymous
|
|
27
|
-
integrity: sha384-a0dW6ZXBBtsBzzpPHKLx+AdpKmRJXfTGeCGNpzDA83/BoZoTUknyIAwMDuOTBfkS
|
|
28
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-sql.min.js:
|
|
29
|
-
crossorigin: anonymous
|
|
30
|
-
integrity: sha384-/MKWdycCDliku23mP5sYXbZNuXrzgmQO/jsVxwPFn99dVOaXRyKsqDjarqpueGAp
|
|
31
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.css:
|
|
32
|
-
crossorigin: anonymous
|
|
33
|
-
integrity: sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv
|
|
34
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/normalize-whitespace/prism-normalize-whitespace.min.js:
|
|
35
|
-
crossorigin: anonymous
|
|
36
|
-
integrity: sha384-1Q1Kn1ruXt6wc5JfXB25OWRaEVBJ5OQ0gfL/pneNkXoVmWmhkBacvG9Rls1+yB2h
|
|
37
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js:
|
|
38
|
-
crossorigin: anonymous
|
|
39
|
-
integrity: sha384-BGaNxfftg+9+TtC098wxawPFVEUpKYvaiCgbB0iqAMjK/4jDdmUY+oGxrPNvnXEf
|
|
40
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-coy.css:
|
|
41
|
-
crossorigin: anonymous
|
|
42
|
-
integrity: sha384-/HnXSmP1Tv+9YA13kJX5sL1eVi3XeI57BUEGl+PiVlv6pPcxsbVrHaiw+OepvnSd
|
|
43
|
-
https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.css:
|
|
44
|
-
crossorigin: anonymous
|
|
45
|
-
integrity: sha384-RCpAEDK2BSI4uVvV9kefzLdwlNUNZkCZJdOE2LkEa3jtLRcv2YrEVSbM4vwbCCW2
|
|
46
16
|
https://giscus.app/client.js:
|
|
47
17
|
crossorigin: anonymous
|
|
48
18
|
integrity: sha384-UwLZGbJGvkTzz0719+xEzUm/idqwzs0yZN8aB9Se5vUXHbyRyDWw9yqZTIsOsJ7x
|
|
@@ -145,5 +145,7 @@
|
|
|
145
145
|
window.__DATALOG_ANALYTICS__ = {};
|
|
146
146
|
{% endif %}
|
|
147
147
|
</script>
|
|
148
|
-
|
|
148
|
+
{%- comment -%} The built bundle, as a module: the script uses `export`, which a classic script cannot parse. {%- endcomment %}
|
|
149
|
+
{%- assign dashboard_bundle = site.data.js_manifest.entrypoints['analytics-dashboard'] | default: '/assets/js/dist/analytics-dashboard.js' %}
|
|
150
|
+
<script type="module" src="{{ dashboard_bundle | relative_url }}"></script>
|
|
149
151
|
</div>
|
|
@@ -74,19 +74,38 @@ Parameters:
|
|
|
74
74
|
<div class="api-function__section">
|
|
75
75
|
<h4 class="api-function__section-title">Examples</h4>
|
|
76
76
|
<div class="api-function__examples">
|
|
77
|
+
{%- comment -%}
|
|
78
|
+
Examples are code. Through markdownify, a Python comment such as
|
|
79
|
+
"# Two-sample t-test" became a page heading. Examples written as
|
|
80
|
+
Markdown with fenced code blocks still render as Markdown.
|
|
81
|
+
{%- endcomment -%}
|
|
82
|
+
{% if include.examples contains '```' %}
|
|
77
83
|
{{ include.examples | markdownify }}
|
|
84
|
+
{% else %}
|
|
85
|
+
{% assign example_language = include.language | default: page.language | default: 'text' | downcase %}
|
|
86
|
+
<pre class="highlight" tabindex="0"><code class="language-{{ example_language }}">{{ include.examples | strip | rouge_highlight: example_language }}</code></pre>
|
|
87
|
+
{% endif %}
|
|
78
88
|
</div>
|
|
79
89
|
</div>
|
|
80
90
|
{% endif %}
|
|
81
91
|
|
|
82
92
|
{% if include.see_also %}
|
|
93
|
+
{%- comment -%}
|
|
94
|
+
`see_also` is a comma-separated list of functions documented on the same page, such as
|
|
95
|
+
`see_also="mannwhitneyu, anova"`. The loop used to take the whole string as one item, so two
|
|
96
|
+
names made a single link to an anchor that did not exist.
|
|
97
|
+
{%- endcomment -%}
|
|
98
|
+
{% assign see_also_items = include.see_also | split: "," %}
|
|
83
99
|
<div class="api-function__section">
|
|
84
100
|
<h4 class="api-function__section-title">See Also</h4>
|
|
85
101
|
<ul class="api-function__see-also">
|
|
86
|
-
{% for
|
|
102
|
+
{% for raw_item in see_also_items %}
|
|
103
|
+
{% assign item = raw_item | strip %}
|
|
104
|
+
{% if item != "" %}
|
|
87
105
|
<li>
|
|
88
106
|
<a href="#{{ item | slugify }}"><code>{{ item }}</code></a>
|
|
89
107
|
</li>
|
|
108
|
+
{% endif %}
|
|
90
109
|
{% endfor %}
|
|
91
110
|
</ul>
|
|
92
111
|
</div>
|
|
@@ -104,7 +104,7 @@ Parameters:
|
|
|
104
104
|
</div>
|
|
105
105
|
</div>
|
|
106
106
|
|
|
107
|
-
<pre class="enhanced-code-block__pre{% if show_line_numbers %} enhanced-code-block__pre--numbered{% endif %}"><code id="{{ code_id }}" class="language-{{ language }}" data-code-content>{{ code_content }}</code></pre>
|
|
107
|
+
<pre class="highlight enhanced-code-block__pre{% if show_line_numbers %} enhanced-code-block__pre--numbered{% endif %}" tabindex="0"><code id="{{ code_id }}" class="language-{{ language }}" data-code-content>{{ code_content | rouge_highlight: language }}</code></pre>
|
|
108
108
|
|
|
109
109
|
{%- comment -%} Feedback message {%- endcomment -%}
|
|
110
110
|
<div class="enhanced-code-block__feedback" data-feedback role="status" aria-live="polite"></div>
|
data/_includes/csp-meta.html
CHANGED
|
@@ -1,17 +1,121 @@
|
|
|
1
1
|
{% assign csp_registry = site.data.csp | default: {} %}
|
|
2
2
|
{% assign nonce_source = page.csp_nonce | default: csp_registry.nonces[page.path] | default: csp_registry.nonces[page.url] | default: '' %}
|
|
3
|
-
{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{
|
|
3
|
+
{%- comment -%}
|
|
4
|
+
Sources a site adds for its own embeds, listed under `csp` in _config.yml:
|
|
5
|
+
frame_src for iframes (Shiny apps, slide decks, videos), and script_src,
|
|
6
|
+
style_src, font_src and connect_src for anything else.
|
|
7
|
+
{%- endcomment -%}
|
|
8
|
+
{% assign frame_hosts = site.csp.frame_src | join: ' ' %}
|
|
9
|
+
{% assign extra_script_src = site.csp.script_src | join: ' ' %}
|
|
10
|
+
{% assign extra_style_src = site.csp.style_src | join: ' ' %}
|
|
11
|
+
{% assign extra_font_src = site.csp.font_src | join: ' ' %}
|
|
12
|
+
{% assign extra_connect_src = site.csp.connect_src | join: ' ' %}
|
|
13
|
+
{%- comment -%}
|
|
14
|
+
Plotly, the Jupyter widget manager and MathJax can't run under the strict
|
|
15
|
+
policy. Plotly inserts its rules into a <style> element it creates; the widget
|
|
16
|
+
manager adds <style> elements too, and compiles widget schemas with
|
|
17
|
+
new Function; MathJax's CHTML output adds the stylesheet its layout depends
|
|
18
|
+
on. Only the pages that run them get inline styles, and widget pages eval. A
|
|
19
|
+
page that loads such a library another way sets csp.unsafe_inline_styles or
|
|
20
|
+
csp.unsafe_eval in its front matter. A browser ignores 'unsafe-inline' in a
|
|
21
|
+
directive that also lists a nonce, so those pages drop the style nonce.
|
|
22
|
+
{%- endcomment -%}
|
|
23
|
+
{% assign csp_inline_styles = page.csp.unsafe_inline_styles %}
|
|
24
|
+
{% assign csp_eval = page.csp.unsafe_eval %}
|
|
25
|
+
{%- comment -%}
|
|
26
|
+
jsDelivr serves any npm package, so the policy names the packages this page
|
|
27
|
+
loads rather than the whole host: the math engine, from the URLs the head's
|
|
28
|
+
script tags use (math-config.html and head.html set them), and the chart
|
|
29
|
+
libraries the visualization and notebook scripts load for the blocks on the
|
|
30
|
+
page. Keep these in step with the URLs in assets/js/visualizations.js,
|
|
31
|
+
assets/js/notebook.js and _includes/analytics/dashboard.html;
|
|
32
|
+
tests/test_csp.rb checks that they are.
|
|
33
|
+
{%- endcomment -%}
|
|
34
|
+
{% assign cdn_scripts = '' %}
|
|
35
|
+
{% assign cdn_styles = '' %}
|
|
36
|
+
{% assign cdn_fonts = '' %}
|
|
37
|
+
{% assign cdn_connect = '' %}
|
|
38
|
+
{% assign cdn_frames = '' %}
|
|
39
|
+
{% if math_enabled %}
|
|
40
|
+
{% if math_engine == 'katex' %}
|
|
41
|
+
{% assign cdn_scripts = cdn_scripts | append: ' ' | append: katex_cdn %}
|
|
42
|
+
{% assign cdn_styles = cdn_styles | append: ' ' | append: katex_cdn %}
|
|
43
|
+
{% assign cdn_fonts = cdn_fonts | append: ' ' | append: katex_cdn %}
|
|
44
|
+
{% else %}
|
|
45
|
+
{%- comment -%} MathJax loads its components, fonts and speech data from the directory of its main script. {%- endcomment -%}
|
|
46
|
+
{% assign mathjax_file = mathjax_url | split: '/' | last %}
|
|
47
|
+
{% assign mathjax_dir_length = mathjax_url.size | minus: mathjax_file.size %}
|
|
48
|
+
{% assign mathjax_dir = mathjax_url | slice: 0, mathjax_dir_length %}
|
|
49
|
+
{% assign cdn_scripts = cdn_scripts | append: ' ' | append: mathjax_dir %}
|
|
50
|
+
{% assign cdn_fonts = cdn_fonts | append: ' ' | append: mathjax_dir %}
|
|
51
|
+
{% assign cdn_connect = cdn_connect | append: ' ' | append: mathjax_dir %}
|
|
52
|
+
{% assign csp_inline_styles = true %}
|
|
53
|
+
{% endif %}
|
|
54
|
+
{% endif %}
|
|
55
|
+
{% if content contains 'data-viz-type="plotly"' or content contains "data-viz-type='plotly'" or content contains 'notebook-output-plotly' %}
|
|
56
|
+
{% assign csp_inline_styles = true %}
|
|
57
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/plotly.js-dist-min@2.27.0/' %}
|
|
58
|
+
{% endif %}
|
|
59
|
+
{% if content contains 'data-viz-type="d3"' or content contains "data-viz-type='d3'" %}
|
|
60
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/d3@7/' %}
|
|
61
|
+
{% endif %}
|
|
62
|
+
{% if content contains 'data-viz-type="bokeh"' or content contains "data-viz-type='bokeh'" %}
|
|
63
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/@bokeh/bokehjs@3.3.3/' %}
|
|
64
|
+
{% endif %}
|
|
65
|
+
{% if content contains 'notebook-output-vega' %}
|
|
66
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/vega@5 https://cdn.jsdelivr.net/npm/vega-lite@5 https://cdn.jsdelivr.net/npm/vega-embed@6' %}
|
|
67
|
+
{% endif %}
|
|
68
|
+
{% if content contains 'npm/chart.js@4.4.0/' %}
|
|
69
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net/npm/chart.js@4.4.0/' %}
|
|
70
|
+
{% endif %}
|
|
71
|
+
{%- comment -%}
|
|
72
|
+
Widget pages load require.js from cdnjs, and allow all of jsDelivr: the widget
|
|
73
|
+
manager loads any widget package a notebook names from it, and its icon fonts.
|
|
74
|
+
{%- endcomment -%}
|
|
75
|
+
{% if content contains 'data-viz-type="ipywidgets"' or content contains "data-viz-type='ipywidgets'" or content contains 'application/vnd.jupyter.widget-state+json' %}
|
|
76
|
+
{% assign csp_inline_styles = true %}
|
|
77
|
+
{% assign csp_eval = true %}
|
|
78
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/' %}
|
|
79
|
+
{% assign cdn_fonts = cdn_fonts | append: ' https://cdn.jsdelivr.net' %}
|
|
80
|
+
{% endif %}
|
|
81
|
+
{%- comment -%}
|
|
82
|
+
The Disqus embed loads its script from the site's shortname subdomain of
|
|
83
|
+
disqus.com and its assets from disquscdn.com, shows the thread in an iframe
|
|
84
|
+
from disqus.com, and sizes that iframe with an inline style. The policy
|
|
85
|
+
allowed none of them.
|
|
86
|
+
{%- endcomment -%}
|
|
87
|
+
{% if content contains 'id="disqus_thread"' %}
|
|
88
|
+
{% assign csp_inline_styles = true %}
|
|
89
|
+
{% assign cdn_scripts = cdn_scripts | append: ' https://*.disqus.com https://*.disquscdn.com' %}
|
|
90
|
+
{% assign cdn_styles = cdn_styles | append: ' https://*.disquscdn.com' %}
|
|
91
|
+
{% assign cdn_connect = cdn_connect | append: ' https://*.disqus.com' %}
|
|
92
|
+
{% assign cdn_frames = cdn_frames | append: ' https://disqus.com' %}
|
|
93
|
+
{% endif %}
|
|
94
|
+
{%- comment -%}
|
|
95
|
+
Google's tag loads only on a site that sets google_analytics, and the policy
|
|
96
|
+
allowed its hosts on every site. These are the hosts Google documents for GA4,
|
|
97
|
+
which reports to regional subdomains such as region1.google-analytics.com.
|
|
98
|
+
{%- endcomment -%}
|
|
99
|
+
{% assign csp_analytics = false %}
|
|
100
|
+
{% if site.google_analytics and site.google_analytics != "" %}
|
|
101
|
+
{% assign csp_analytics = true %}
|
|
102
|
+
{% endif %}
|
|
103
|
+
{%- comment -%}
|
|
104
|
+
object-src, base-uri and form-action do not fall back to default-src. An
|
|
105
|
+
injected <base> tag could repoint the page's relative script URLs, which the
|
|
106
|
+
nonce would then authorise; every theme form submits to the site itself.
|
|
107
|
+
Observable serves classic notebook embeds from old.observablehq.com, and an
|
|
108
|
+
observablehq.com embed URL redirects there.
|
|
109
|
+
{%- endcomment -%}
|
|
9
110
|
<meta http-equiv="Content-Security-Policy" content="
|
|
10
111
|
default-src 'self';
|
|
11
|
-
script-src 'self' 'nonce-{{ nonce_source }}'{% if
|
|
12
|
-
style-src 'self' 'nonce-{{ nonce_source }}' https://fonts.googleapis.com
|
|
112
|
+
script-src 'self' 'nonce-{{ nonce_source }}'{% if csp_eval %} 'unsafe-eval'{% endif %}{{ cdn_scripts }}{% if csp_analytics %} https://*.googletagmanager.com{% endif %}{% if extra_script_src != '' %} {{ extra_script_src }}{% endif %};
|
|
113
|
+
style-src 'self' {% if csp_inline_styles %}'unsafe-inline'{% else %}'nonce-{{ nonce_source }}'{% endif %} https://fonts.googleapis.com{{ cdn_styles }}{% if extra_style_src != '' %} {{ extra_style_src }}{% endif %};
|
|
13
114
|
img-src 'self' data: https:;
|
|
14
|
-
font-src 'self' https://fonts.gstatic.com data
|
|
15
|
-
connect-src 'self' https://api.github.com https
|
|
16
|
-
frame-src 'self' https://observablehq.com;
|
|
115
|
+
font-src 'self' https://fonts.gstatic.com data:{{ cdn_fonts }}{% if extra_font_src != '' %} {{ extra_font_src }}{% endif %};
|
|
116
|
+
connect-src 'self' https://api.github.com{{ cdn_connect }}{% if csp_analytics %} https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com{% endif %}{% if extra_connect_src != '' %} {{ extra_connect_src }}{% endif %};
|
|
117
|
+
frame-src 'self' https://observablehq.com https://old.observablehq.com{{ cdn_frames }}{% if frame_hosts != '' %} {{ frame_hosts }}{% endif %};
|
|
118
|
+
object-src 'none';
|
|
119
|
+
base-uri 'self';
|
|
120
|
+
form-action 'self';
|
|
17
121
|
" />
|
data/_includes/footer.html
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
{% assign footer_year = site.time | date: '%Y' %}
|
|
3
3
|
{% assign navigation_data = site.data.navigation %}
|
|
4
4
|
{% assign social_data = site.data.social %}
|
|
5
|
+
{%- comment -%} The column titles are <h2>: the footer follows the page's own outline, which starts at its <h1>. {%- endcomment %}
|
|
5
6
|
<footer class="site-footer" role="contentinfo">
|
|
6
7
|
<div class="container footer-container">
|
|
7
8
|
<section class="footer-about">
|
|
8
|
-
<
|
|
9
|
+
<h2>{{ site.name | default: site.title }}</h2>
|
|
9
10
|
<p class="footer-description">{{ site.description | strip_html | truncate: 160 }}</p>
|
|
10
11
|
<p class="footer-author">
|
|
11
12
|
<strong>{{ site.author.name }}</strong>
|
|
@@ -20,30 +21,24 @@
|
|
|
20
21
|
{% endif %}
|
|
21
22
|
</section>
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
{%- comment -%} `footer:` in _data/navigation.yml drives this column, which is left out without it. {%- endcomment -%}
|
|
25
|
+
{% assign footer_links = navigation_data.footer %}
|
|
26
|
+
{% if footer_links.size > 0 %}
|
|
27
|
+
<nav class="footer-navigation" aria-labelledby="footer-explore-heading">
|
|
28
|
+
<h2 id="footer-explore-heading">Explore</h2>
|
|
27
29
|
<ul class="footer-link-list">
|
|
28
|
-
{% if footer_links and footer_links.size > 0 %}
|
|
29
30
|
{% for item in footer_links %}
|
|
30
31
|
<li><a href="{{ item.url | relative_url }}">{{ item.title }}</a></li>
|
|
31
32
|
{% endfor %}
|
|
32
|
-
{% else %}
|
|
33
|
-
<li><a href="{{ '/blog/' | relative_url }}">Blog</a></li>
|
|
34
|
-
<li><a href="{{ '/research/' | relative_url }}">Research</a></li>
|
|
35
|
-
<li><a href="{{ '/portfolio/' | relative_url }}">Projects</a></li>
|
|
36
|
-
<li><a href="{{ '/datasets/' | relative_url }}">Datasets</a></li>
|
|
37
|
-
<li><a href="{{ '/visualizations/' | relative_url }}">Visualizations</a></li>
|
|
38
|
-
<li><a href="{{ '/about/' | relative_url }}">About</a></li>
|
|
39
|
-
{% endif %}
|
|
40
33
|
</ul>
|
|
41
34
|
</nav>
|
|
35
|
+
{% endif %}
|
|
42
36
|
|
|
37
|
+
{% assign primary_social = social_data.primary %}
|
|
38
|
+
{% if primary_social.size > 0 or site.author.email %}
|
|
43
39
|
<section class="footer-connect">
|
|
44
|
-
<
|
|
45
|
-
{%
|
|
46
|
-
{% if primary_social %}
|
|
40
|
+
<h2>Connect</h2>
|
|
41
|
+
{% if primary_social.size > 0 %}
|
|
47
42
|
<ul class="footer-link-list">
|
|
48
43
|
{% for profile in primary_social %}
|
|
49
44
|
<li><a href="{{ profile.url }}" target="_blank" rel="{{ profile.rel | default: 'noopener' }}">{{ profile.label }}</a></li>
|
|
@@ -56,18 +51,22 @@
|
|
|
56
51
|
</p>
|
|
57
52
|
{% endif %}
|
|
58
53
|
</section>
|
|
54
|
+
{% endif %}
|
|
59
55
|
|
|
60
56
|
<section class="footer-subscribe">
|
|
61
|
-
<
|
|
57
|
+
<h2>Stay updated</h2>
|
|
62
58
|
<p>Follow via RSS or check back for new research and tutorials.</p>
|
|
59
|
+
{%- comment -%} jekyll-feed is a dependency of the theme, so /feed.xml exists even when _data/social.yml lists no feeds. {%- endcomment -%}
|
|
63
60
|
{% assign rss_links = social_data.rss %}
|
|
64
|
-
{% if rss_links %}
|
|
65
61
|
<ul class="footer-link-list">
|
|
62
|
+
{% if rss_links.size > 0 %}
|
|
66
63
|
{% for feed in rss_links %}
|
|
67
64
|
<li><a href="{{ feed.url | relative_url }}">{{ feed.label }}</a></li>
|
|
68
65
|
{% endfor %}
|
|
66
|
+
{% else %}
|
|
67
|
+
<li><a href="{{ '/feed.xml' | relative_url }}">RSS feed</a></li>
|
|
68
|
+
{% endif %}
|
|
69
69
|
</ul>
|
|
70
|
-
{% endif %}
|
|
71
70
|
</section>
|
|
72
71
|
</div>
|
|
73
72
|
<div class="container footer-bottom">
|