From 69f275c15c475332b713c1022a0ea8538b556104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:50:02 +0200 Subject: [PATCH 01/29] feat(gallery): redesign gallery with intent-driven landing Replace the single carousel gallery with an intent-driven landing and six category spoke pages. The landing offers a category chooser, a section rail, and curated featured examples with animated hover previews; each spoke page lists its examples with keyboard-operable category filters and working sort and search. Drive every card from YAML under docs/gallery/data/, with a curated featured.yml and per-category lists, and single-source the feature links and browse chips from that data. Consolidate thumbnails under thumbnails/ and add capture tooling for still, PDF, and video previews, documented in READMEs. Meet WCAG AA on the interactive chips and heading order, keep the legacy implementation for reference, and skip the freeze check for the intentionally deleted freeze entry. --- .githooks/check-freeze.sh | 13 + .github/workflows/preview.yml | 11 +- .../quartoorg/scss/partials/_gallery.scss | 296 +++++++++++++++++ .../quartoorg/scss/partials/_site.scss | 1 + .../gallery/index/execute-results/html.json | 15 - _quarto.yml | 13 + _tools/screenshots/README.md | 44 +++ _tools/screenshots/SETUP.md | 6 + _tools/screenshots/package-lock.json | 29 ++ _tools/screenshots/package.json | 7 + _tools/screenshots/scripts/PREVIEWS.md | 89 +++++ .../scripts/capture-card-thumbs.mjs | 143 ++++++++ .../scripts/capture-pdf-thumbs.mjs | 170 ++++++++++ .../screenshots/scripts/capture-previews.mjs | 267 +++++++++++++++ _tools/screenshots/scripts/help.js | 7 +- docs/gallery/README.md | 65 ++++ docs/gallery/_metadata.yml | 14 + docs/gallery/articles/advanced-layout-pdf.png | Bin 191186 -> 0 bytes docs/gallery/articles/articles-pdf.png | Bin 259104 -> 0 bytes docs/gallery/assets/_browse-chips.ejs.md | 19 ++ docs/gallery/assets/_caps.ejs.md | 9 + docs/gallery/assets/_card.ejs.md | 35 ++ docs/gallery/assets/_chooser.ejs.md | 15 + docs/gallery/assets/_featured.ejs.md | 110 +++++++ docs/gallery/assets/_jumpnav.ejs.md | 109 +++++++ docs/gallery/assets/_preview.html | 188 +++++++++++ docs/gallery/browse.qmd | 26 ++ docs/gallery/carousel.R | 64 ---- docs/gallery/carousel.yml | 25 -- docs/gallery/dashboards-monitoring.qmd | 28 ++ .../gallery/dashboards/ggplotly-dashboard.png | Bin 283166 -> 0 bytes docs/gallery/dashboards/ojs-flights.jpg | Bin 75812 -> 0 bytes .../dashboards/waste-sites-dashboard.png | Bin 1455706 -> 0 bytes docs/gallery/data/dashboards-monitoring.yml | 191 +++++++++++ docs/gallery/data/featured.yml | 293 +++++++++++++++++ docs/gallery/data/personal-community.yml | 211 ++++++++++++ docs/gallery/data/reports-analytics.yml | 97 ++++++ docs/gallery/data/research-scholarship.yml | 104 ++++++ docs/gallery/data/software-documentation.yml | 127 ++++++++ docs/gallery/data/teaching-learning.yml | 304 ++++++++++++++++++ docs/gallery/index.qmd | 140 ++------ docs/gallery/legacy/README.md | 8 + docs/gallery/{ => legacy}/gallery.ejs | 0 docs/gallery/{ => legacy}/gallery.yml | 180 +++++------ docs/gallery/personal-community.qmd | 28 ++ .../presentations/presentations-beamer.png | Bin 92547 -> 0 bytes docs/gallery/presentations/presentations.png | Bin 148515 -> 0 bytes docs/gallery/reports-analytics.qmd | 28 ++ docs/gallery/research-scholarship.qmd | 28 ++ docs/gallery/software-documentation.qmd | 28 ++ docs/gallery/teaching-learning.qmd | 28 ++ .../customer-churn-dashboard.png | Bin .../dashing-through-snow.png | Bin .../diamonds-dashboard.png | Bin .../gapminder-dashboard.png | Bin .../dashboards-monitoring/gh-dashboard.png | Bin 0 -> 151508 bytes .../housing-market-dashboard.png | Bin .../dashboards-monitoring}/ld-dashboard.png | Bin .../dashboards-monitoring/mynorfolk.png | Bin 0 -> 147256 bytes .../nfl-injuries-dashboard.png | Bin .../nz-quakes-dashboard.png | Bin .../dashboards-monitoring}/ojs-flights.png | Bin .../ojs-penguins-dashboard.png | Bin .../dashboards-monitoring}/olympics-game.png | Bin .../penguins-dashboard.png | Bin .../pyopensci-software-review.png | Bin 0 -> 149662 bytes .../restaurant-dashboard.png | Bin .../retirement-gallery.png | Bin .../dashboards-monitoring/stock-explorer.png | Bin 0 -> 156911 bytes .../weather-ojs-dashboard.jpg | Bin .../personal-community-isabelizimm.mp4 | Bin 0 -> 118470 bytes .../personal-community-isabelizimm.webm | Bin 0 -> 112587 bytes .../personal-community-noahweidig.mp4 | Bin 0 -> 415835 bytes .../personal-community-noahweidig.webm | Bin 0 -> 296078 bytes .../featured/personal-community-rainbowr.mp4 | Bin 0 -> 88253 bytes .../featured/personal-community-rainbowr.webm | Bin 0 -> 90667 bytes .../featured/reports-analytics-closeread.mp4 | Bin 0 -> 332789 bytes .../featured/reports-analytics-closeread.webm | Bin 0 -> 274459 bytes .../featured/research-scholarship-affcom.mp4 | Bin 0 -> 48668 bytes .../featured/research-scholarship-affcom.webm | Bin 0 -> 51849 bytes .../research-scholarship-causal-inference.mp4 | Bin 0 -> 480786 bytes ...research-scholarship-causal-inference.webm | Bin 0 -> 342597 bytes .../software-documentation-great-docs.mp4 | Bin 0 -> 447249 bytes .../software-documentation-great-docs.webm | Bin 0 -> 390077 bytes .../software-documentation-gribouille.mp4 | Bin 0 -> 205050 bytes .../software-documentation-gribouille.webm | Bin 0 -> 158290 bytes .../software-documentation-positron.mp4 | Bin 0 -> 90783 bytes .../software-documentation-positron.webm | Bin 0 -> 93289 bytes .../teaching-learning-dataviz-course.mp4 | Bin 0 -> 215498 bytes .../teaching-learning-dataviz-course.webm | Bin 0 -> 192722 bytes .../teaching-learning-feature-eng.mp4 | Bin 0 -> 48931 bytes .../teaching-learning-feature-eng.webm | Bin 0 -> 54288 bytes .../teaching-learning-textrecipes.mp4 | Bin 0 -> 110071 bytes .../teaching-learning-textrecipes.webm | Bin 0 -> 108576 bytes .../legacy}/books-telling-stories.png | Bin .../{books => thumbnails/legacy}/ci-in-r.png | Bin .../legacy}/mynorfolk-dash.png | Bin .../legacy}/presentations-textrecipes.png | Bin .../legacy}/stock-explorer-dashboard.png | Bin .../legacy}/websites-rainbowr.png | Bin .../personal-community/bea-milz.png} | Bin .../chris-von-csefalvay.png} | Bin .../personal-community/dkapitan.png} | Bin .../personal-community/fluidsyndicate.png} | Bin .../personal-community/forbo7-landing.png} | Bin .../personal-community/hamel.png} | Bin .../personal-community/ipardalis.png} | Bin .../personal-community/isabelizimm.png | Bin 0 -> 402446 bytes .../personal-community/masiello-group.png} | Bin .../personal-community/mcanouil.png | Bin 0 -> 172247 bytes .../personal-community/mike-mahoney.png} | Bin .../personal-community/mockup.png} | Bin .../personal-community/nasa-openscapes.png} | Bin .../personal-community/nascent-peru.png | Bin 0 -> 332092 bytes .../personal-community}/nhs-r-website.png | Bin .../personal-community/noahweidig.png | Bin 0 -> 350019 bytes .../personal-community/quartotip.png} | Bin .../personal-community/rainbowr.png | Bin 0 -> 262649 bytes .../real-world-data-science.png} | Bin .../personal-community/vistales.png} | Bin .../personal-community/wannabe-rstats-fu.png} | Bin .../personal-community}/website-ala-labs.png | Bin .../advanced-layout-html.png | Bin .../reports-analytics/advanced-layout-pdf.png | Bin 0 -> 194466 bytes .../reports-analytics/closeread.png | Bin 0 -> 238313 bytes .../reports-analytics/html.png} | Bin .../reports-analytics/jupyter.png} | Bin .../reports-analytics/msword.png} | Bin .../reports-analytics/ojs.png} | Bin .../reports-analytics/shiny.png} | Bin .../thumbnails/reports-analytics/tfff.png | Bin 0 -> 259143 bytes .../thumbnails/reports-analytics/whr.png | Bin 0 -> 430970 bytes .../research-scholarship/affcom.png | Bin 0 -> 129060 bytes .../research-scholarship/causal-inference.png | Bin 0 -> 388420 bytes .../cleaning-bd-in-r.png} | Bin .../heiss-publications.png | Bin 0 -> 297748 bytes .../mcanouil-publications.png | Bin 0 -> 103439 bytes .../thumbnails/research-scholarship/pdf.png | Bin 0 -> 136162 bytes .../research-scholarship/r4csr.png} | Bin .../research-scholarship}/r4pde.png | Bin .../research-scholarship/telling-stories.png | Bin 0 -> 256209 bytes .../research-scholarship}/tsar.png | Bin .../software-documentation/devito.png} | Bin .../software-documentation/great-docs.png | Bin 0 -> 371540 bytes .../software-documentation/gribouille.png | Bin 0 -> 147927 bytes .../software-documentation/ibis.png} | Bin .../software-documentation/mrgsolve.png} | Bin .../software-documentation/nbdev.png} | Bin .../software-documentation/positron.png | Bin 0 -> 222772 bytes .../quarto-extensions.png | Bin 0 -> 149640 bytes .../software-documentation/quarto.png} | Bin .../r-development-guide.png} | Bin .../software-documentation/r-manuals.png} | Bin .../software-documentation/r-pkgs.png} | Bin .../software-documentation}/utilitr.png | Bin .../2021-cloud-hackathon.png} | Bin .../anthology-experimental-designs.png} | Bin .../teaching-learning/arrow-dplyr.png} | Bin .../teaching-learning/arrow-workshop.png} | Bin .../thumbnails/teaching-learning/beamer.png | Bin 0 -> 61502 bytes .../book-analyse-conceptions-french.png | Bin .../teaching-learning}/books_lsj.png | Bin .../teaching-learning/cookbook-rpolars.png} | Bin .../teaching-learning/datascienceinabox.png} | Bin .../teaching-learning/dataviz-course.png | Bin 0 -> 291575 bytes .../teaching-learning/des-rap-book.png | Bin 0 -> 829291 bytes .../educators-perspective-tidyverse.png} | Bin .../teaching-learning/feature-eng.png | Bin 0 -> 113745 bytes .../teaching-learning}/geocompy.png | Bin .../teaching-learning/hertie-coding-club.png} | Bin .../teaching-learning/hopr.png} | Bin .../teaching-learning/julia-workshop.png} | Bin .../teaching-learning/jupyter.png} | Bin .../teaching-learning/linogaliana.png} | Bin .../teaching-learning/mlr3book.png} | Bin .../teaching-learning}/modern-polars.png | Bin .../nfl-analytics-with-r.PNG | Bin .../opescapes-quarto-tutorial.png} | Bin .../teaching-learning/penguins-story.png} | Bin .../teaching-learning/powerpoint.png} | Bin .../practical-deep-learning.png} | Bin .../teaching-learning/python-for-data.png} | Bin .../quarto-the-practical-guide.png | Bin 0 -> 411524 bytes .../teaching-learning/r4ds.png} | Bin .../teaching-learning/revealjs.png} | Bin .../teaching-learning/sta210.png} | Bin .../streamlining-with-r.png} | Bin .../teaching-learning/textrecipes.png | Bin 0 -> 147278 bytes ...ebsite-m.canouil.dev_quarto-extensions.png | Bin 653636 -> 0 bytes .../websites/website-mickael.canouil.fr.png | Bin 993538 -> 0 bytes docs/websites/website-listings-custom.qmd | 6 +- 191 files changed, 3304 insertions(+), 315 deletions(-) create mode 100644 _extensions/quartoorg/scss/partials/_gallery.scss delete mode 100644 _freeze/docs/gallery/index/execute-results/html.json create mode 100644 _tools/screenshots/README.md create mode 100644 _tools/screenshots/scripts/PREVIEWS.md create mode 100644 _tools/screenshots/scripts/capture-card-thumbs.mjs create mode 100644 _tools/screenshots/scripts/capture-pdf-thumbs.mjs create mode 100644 _tools/screenshots/scripts/capture-previews.mjs create mode 100644 docs/gallery/README.md create mode 100644 docs/gallery/_metadata.yml delete mode 100644 docs/gallery/articles/advanced-layout-pdf.png delete mode 100644 docs/gallery/articles/articles-pdf.png create mode 100644 docs/gallery/assets/_browse-chips.ejs.md create mode 100644 docs/gallery/assets/_caps.ejs.md create mode 100644 docs/gallery/assets/_card.ejs.md create mode 100644 docs/gallery/assets/_chooser.ejs.md create mode 100644 docs/gallery/assets/_featured.ejs.md create mode 100644 docs/gallery/assets/_jumpnav.ejs.md create mode 100644 docs/gallery/assets/_preview.html create mode 100644 docs/gallery/browse.qmd delete mode 100644 docs/gallery/carousel.R delete mode 100644 docs/gallery/carousel.yml create mode 100644 docs/gallery/dashboards-monitoring.qmd delete mode 100644 docs/gallery/dashboards/ggplotly-dashboard.png delete mode 100644 docs/gallery/dashboards/ojs-flights.jpg delete mode 100644 docs/gallery/dashboards/waste-sites-dashboard.png create mode 100644 docs/gallery/data/dashboards-monitoring.yml create mode 100644 docs/gallery/data/featured.yml create mode 100644 docs/gallery/data/personal-community.yml create mode 100644 docs/gallery/data/reports-analytics.yml create mode 100644 docs/gallery/data/research-scholarship.yml create mode 100644 docs/gallery/data/software-documentation.yml create mode 100644 docs/gallery/data/teaching-learning.yml create mode 100644 docs/gallery/legacy/README.md rename docs/gallery/{ => legacy}/gallery.ejs (100%) rename docs/gallery/{ => legacy}/gallery.yml (81%) create mode 100644 docs/gallery/personal-community.qmd delete mode 100644 docs/gallery/presentations/presentations-beamer.png delete mode 100644 docs/gallery/presentations/presentations.png create mode 100644 docs/gallery/reports-analytics.qmd create mode 100644 docs/gallery/research-scholarship.qmd create mode 100644 docs/gallery/software-documentation.qmd create mode 100644 docs/gallery/teaching-learning.qmd rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/customer-churn-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/dashing-through-snow.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/diamonds-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/gapminder-dashboard.png (100%) create mode 100644 docs/gallery/thumbnails/dashboards-monitoring/gh-dashboard.png rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/housing-market-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/ld-dashboard.png (100%) create mode 100644 docs/gallery/thumbnails/dashboards-monitoring/mynorfolk.png rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/nfl-injuries-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/nz-quakes-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/ojs-flights.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/ojs-penguins-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/olympics-game.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/penguins-dashboard.png (100%) create mode 100644 docs/gallery/thumbnails/dashboards-monitoring/pyopensci-software-review.png rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/restaurant-dashboard.png (100%) rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/retirement-gallery.png (100%) create mode 100644 docs/gallery/thumbnails/dashboards-monitoring/stock-explorer.png rename docs/gallery/{dashboards => thumbnails/dashboards-monitoring}/weather-ojs-dashboard.jpg (100%) create mode 100644 docs/gallery/thumbnails/featured/personal-community-isabelizimm.mp4 create mode 100644 docs/gallery/thumbnails/featured/personal-community-isabelizimm.webm create mode 100644 docs/gallery/thumbnails/featured/personal-community-noahweidig.mp4 create mode 100644 docs/gallery/thumbnails/featured/personal-community-noahweidig.webm create mode 100644 docs/gallery/thumbnails/featured/personal-community-rainbowr.mp4 create mode 100644 docs/gallery/thumbnails/featured/personal-community-rainbowr.webm create mode 100644 docs/gallery/thumbnails/featured/reports-analytics-closeread.mp4 create mode 100644 docs/gallery/thumbnails/featured/reports-analytics-closeread.webm create mode 100644 docs/gallery/thumbnails/featured/research-scholarship-affcom.mp4 create mode 100644 docs/gallery/thumbnails/featured/research-scholarship-affcom.webm create mode 100644 docs/gallery/thumbnails/featured/research-scholarship-causal-inference.mp4 create mode 100644 docs/gallery/thumbnails/featured/research-scholarship-causal-inference.webm create mode 100644 docs/gallery/thumbnails/featured/software-documentation-great-docs.mp4 create mode 100644 docs/gallery/thumbnails/featured/software-documentation-great-docs.webm create mode 100644 docs/gallery/thumbnails/featured/software-documentation-gribouille.mp4 create mode 100644 docs/gallery/thumbnails/featured/software-documentation-gribouille.webm create mode 100644 docs/gallery/thumbnails/featured/software-documentation-positron.mp4 create mode 100644 docs/gallery/thumbnails/featured/software-documentation-positron.webm create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-dataviz-course.mp4 create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-dataviz-course.webm create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-feature-eng.mp4 create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-feature-eng.webm create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-textrecipes.mp4 create mode 100644 docs/gallery/thumbnails/featured/teaching-learning-textrecipes.webm rename docs/gallery/{books => thumbnails/legacy}/books-telling-stories.png (100%) rename docs/gallery/{books => thumbnails/legacy}/ci-in-r.png (100%) rename docs/gallery/{dashboards => thumbnails/legacy}/mynorfolk-dash.png (100%) rename docs/gallery/{presentations => thumbnails/legacy}/presentations-textrecipes.png (100%) rename docs/gallery/{dashboards => thumbnails/legacy}/stock-explorer-dashboard.png (100%) rename docs/gallery/{websites => thumbnails/legacy}/websites-rainbowr.png (100%) rename docs/gallery/{websites/websites-bea-milz.png => thumbnails/personal-community/bea-milz.png} (100%) rename docs/gallery/{websites/websites-chris-von-csefalvay.png => thumbnails/personal-community/chris-von-csefalvay.png} (100%) rename docs/gallery/{websites/websites-dkapitan.png => thumbnails/personal-community/dkapitan.png} (100%) rename docs/gallery/{websites/websites-fluidsyndicate.png => thumbnails/personal-community/fluidsyndicate.png} (100%) rename docs/gallery/{websites/websites-forbo7-landing.png => thumbnails/personal-community/forbo7-landing.png} (100%) rename docs/gallery/{websites/websites-hamel.png => thumbnails/personal-community/hamel.png} (100%) rename docs/gallery/{websites/websites-ipardalis.png => thumbnails/personal-community/ipardalis.png} (100%) create mode 100644 docs/gallery/thumbnails/personal-community/isabelizimm.png rename docs/gallery/{websites/websites-masiello-group.png => thumbnails/personal-community/masiello-group.png} (100%) create mode 100644 docs/gallery/thumbnails/personal-community/mcanouil.png rename docs/gallery/{websites/websites-mike-mahoney.png => thumbnails/personal-community/mike-mahoney.png} (100%) rename docs/gallery/{websites/websites-mockup.png => thumbnails/personal-community/mockup.png} (100%) rename docs/gallery/{websites/websites-nasa-openscapes.png => thumbnails/personal-community/nasa-openscapes.png} (100%) create mode 100644 docs/gallery/thumbnails/personal-community/nascent-peru.png rename docs/gallery/{websites => thumbnails/personal-community}/nhs-r-website.png (100%) create mode 100644 docs/gallery/thumbnails/personal-community/noahweidig.png rename docs/gallery/{websites/websites-quartotip.png => thumbnails/personal-community/quartotip.png} (100%) create mode 100644 docs/gallery/thumbnails/personal-community/rainbowr.png rename docs/gallery/{websites/websites-real-world-data-science.png => thumbnails/personal-community/real-world-data-science.png} (100%) rename docs/gallery/{websites/websites-vistales.png => thumbnails/personal-community/vistales.png} (100%) rename docs/gallery/{websites/websites-wannabe-rstats-fu.png => thumbnails/personal-community/wannabe-rstats-fu.png} (100%) rename docs/gallery/{websites => thumbnails/personal-community}/website-ala-labs.png (100%) rename docs/gallery/{articles => thumbnails/reports-analytics}/advanced-layout-html.png (100%) create mode 100644 docs/gallery/thumbnails/reports-analytics/advanced-layout-pdf.png create mode 100644 docs/gallery/thumbnails/reports-analytics/closeread.png rename docs/gallery/{articles/articles-html.png => thumbnails/reports-analytics/html.png} (100%) rename docs/gallery/{interactive/interactive-jupyter.png => thumbnails/reports-analytics/jupyter.png} (100%) rename docs/gallery/{articles/articles-msword.png => thumbnails/reports-analytics/msword.png} (100%) rename docs/gallery/{interactive/interactive-ojs.png => thumbnails/reports-analytics/ojs.png} (100%) rename docs/gallery/{interactive/interactive-shiny.png => thumbnails/reports-analytics/shiny.png} (100%) create mode 100644 docs/gallery/thumbnails/reports-analytics/tfff.png create mode 100644 docs/gallery/thumbnails/reports-analytics/whr.png create mode 100644 docs/gallery/thumbnails/research-scholarship/affcom.png create mode 100644 docs/gallery/thumbnails/research-scholarship/causal-inference.png rename docs/gallery/{books/books-cleaning-bd-in-r.png => thumbnails/research-scholarship/cleaning-bd-in-r.png} (100%) create mode 100644 docs/gallery/thumbnails/research-scholarship/heiss-publications.png create mode 100644 docs/gallery/thumbnails/research-scholarship/mcanouil-publications.png create mode 100644 docs/gallery/thumbnails/research-scholarship/pdf.png rename docs/gallery/{books/books-r4csr.png => thumbnails/research-scholarship/r4csr.png} (100%) rename docs/gallery/{books => thumbnails/research-scholarship}/r4pde.png (100%) create mode 100644 docs/gallery/thumbnails/research-scholarship/telling-stories.png rename docs/gallery/{books => thumbnails/research-scholarship}/tsar.png (100%) rename docs/gallery/{websites/websites-devito.png => thumbnails/software-documentation/devito.png} (100%) create mode 100644 docs/gallery/thumbnails/software-documentation/great-docs.png create mode 100644 docs/gallery/thumbnails/software-documentation/gribouille.png rename docs/gallery/{websites/websites-ibis.png => thumbnails/software-documentation/ibis.png} (100%) rename docs/gallery/{websites/websites-mrgsolve.png => thumbnails/software-documentation/mrgsolve.png} (100%) rename docs/gallery/{websites/websites-nbdev.png => thumbnails/software-documentation/nbdev.png} (100%) create mode 100644 docs/gallery/thumbnails/software-documentation/positron.png create mode 100644 docs/gallery/thumbnails/software-documentation/quarto-extensions.png rename docs/gallery/{websites/websites-quarto.png => thumbnails/software-documentation/quarto.png} (100%) rename docs/gallery/{books/books-r-development-guide.png => thumbnails/software-documentation/r-development-guide.png} (100%) rename docs/gallery/{websites/websites-r-manuals.png => thumbnails/software-documentation/r-manuals.png} (100%) rename docs/gallery/{books/books-r-pkgs.png => thumbnails/software-documentation/r-pkgs.png} (100%) rename docs/gallery/{books => thumbnails/software-documentation}/utilitr.png (100%) rename docs/gallery/{websites/websites-2021-cloud-hackathon.png => thumbnails/teaching-learning/2021-cloud-hackathon.png} (100%) rename docs/gallery/{presentations/presentations-anthology-experimental-designs.png => thumbnails/teaching-learning/anthology-experimental-designs.png} (100%) rename docs/gallery/{presentations/presentations-arrow-dplyr.png => thumbnails/teaching-learning/arrow-dplyr.png} (100%) rename docs/gallery/{websites/websites-arrow-workshop.png => thumbnails/teaching-learning/arrow-workshop.png} (100%) create mode 100644 docs/gallery/thumbnails/teaching-learning/beamer.png rename docs/gallery/{books => thumbnails/teaching-learning}/book-analyse-conceptions-french.png (100%) rename docs/gallery/{books => thumbnails/teaching-learning}/books_lsj.png (100%) rename docs/gallery/{books/books-cookbook-rpolars.png => thumbnails/teaching-learning/cookbook-rpolars.png} (100%) rename docs/gallery/{websites/websites-datascienceinabox.png => thumbnails/teaching-learning/datascienceinabox.png} (100%) create mode 100644 docs/gallery/thumbnails/teaching-learning/dataviz-course.png create mode 100644 docs/gallery/thumbnails/teaching-learning/des-rap-book.png rename docs/gallery/{presentations/presentations-educators-perspective-tidyverse.png => thumbnails/teaching-learning/educators-perspective-tidyverse.png} (100%) create mode 100644 docs/gallery/thumbnails/teaching-learning/feature-eng.png rename docs/gallery/{books => thumbnails/teaching-learning}/geocompy.png (100%) rename docs/gallery/{websites/websites-hertie-coding-club.png => thumbnails/teaching-learning/hertie-coding-club.png} (100%) rename docs/gallery/{websites/websites-hopr.png => thumbnails/teaching-learning/hopr.png} (100%) rename docs/gallery/{websites/websites-julia-workshop.png => thumbnails/teaching-learning/julia-workshop.png} (100%) rename docs/gallery/{websites/websites-jupyter.png => thumbnails/teaching-learning/jupyter.png} (100%) rename docs/gallery/{websites/websites-linogaliana.png => thumbnails/teaching-learning/linogaliana.png} (100%) rename docs/gallery/{books/books-mlr3book.png => thumbnails/teaching-learning/mlr3book.png} (100%) rename docs/gallery/{books => thumbnails/teaching-learning}/modern-polars.png (100%) rename docs/gallery/{books => thumbnails/teaching-learning}/nfl-analytics-with-r.PNG (100%) rename docs/gallery/{websites/websites-opescapes-quarto-tutorial.png => thumbnails/teaching-learning/opescapes-quarto-tutorial.png} (100%) rename docs/gallery/{presentations/presentations-penguins-story.png => thumbnails/teaching-learning/penguins-story.png} (100%) rename docs/gallery/{presentations/presentations-powerpoint.png => thumbnails/teaching-learning/powerpoint.png} (100%) rename docs/gallery/{websites/websites-practical-deep-learning.png => thumbnails/teaching-learning/practical-deep-learning.png} (100%) rename docs/gallery/{books/books-python-for-data.png => thumbnails/teaching-learning/python-for-data.png} (100%) create mode 100644 docs/gallery/thumbnails/teaching-learning/quarto-the-practical-guide.png rename docs/gallery/{books/books-r4ds.png => thumbnails/teaching-learning/r4ds.png} (100%) rename docs/gallery/{presentations/presentations-revealjs.png => thumbnails/teaching-learning/revealjs.png} (100%) rename docs/gallery/{websites/websites-sta210.png => thumbnails/teaching-learning/sta210.png} (100%) rename docs/gallery/{presentations/presentations-streamlining-with-r.png => thumbnails/teaching-learning/streamlining-with-r.png} (100%) create mode 100644 docs/gallery/thumbnails/teaching-learning/textrecipes.png delete mode 100644 docs/gallery/websites/website-m.canouil.dev_quarto-extensions.png delete mode 100644 docs/gallery/websites/website-mickael.canouil.fr.png diff --git a/.githooks/check-freeze.sh b/.githooks/check-freeze.sh index a5ddd16231..6c39d76895 100755 --- a/.githooks/check-freeze.sh +++ b/.githooks/check-freeze.sh @@ -39,6 +39,19 @@ while IFS= read -r qmd; do [ -n "$qmd" ] || continue freeze_rel="_freeze/${qmd%.qmd}/execute-results/html.json" + # Skip when the freeze file is intentionally removed in this change: the + # page no longer executes code (e.g. converted to the markdown engine), so + # its freeze entry is vestigial and correctly deleted, not stale. + if [ "$MODE" = "commit" ]; then + if git diff --cached --diff-filter=D --name-only 2>/dev/null | grep -Fxq "$freeze_rel"; then + continue + fi + else + if git diff "${REMOTE}..HEAD" --diff-filter=D --name-only 2>/dev/null | grep -Fxq "$freeze_rel"; then + continue + fi + fi + # Read freeze JSON from git objects, not working tree, to avoid false passes # when the freeze file is updated on disk but not yet staged. if [ "$MODE" = "commit" ]; then diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 1e9ab01d9f..c2eca77709 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -227,9 +227,14 @@ jobs: 'docs/extensions/listings/custom-formats.yml': 'docs/extensions/index.html', 'docs/extensions/listings/revealjs-formats.yml': 'docs/extensions/index.html', 'docs/extensions/listings/revealjs.yml': 'docs/extensions/index.html', - // Gallery data files → gallery index - 'docs/gallery/carousel.yml': 'docs/gallery/index.html', - 'docs/gallery/gallery.yml': 'docs/gallery/index.html', + // Gallery data files → gallery pages + 'docs/gallery/data/featured.yml': 'docs/gallery/index.html', + 'docs/gallery/data/reports-analytics.yml': 'docs/gallery/reports-analytics.html', + 'docs/gallery/data/dashboards-monitoring.yml': 'docs/gallery/dashboards-monitoring.html', + 'docs/gallery/data/research-scholarship.yml': 'docs/gallery/research-scholarship.html', + 'docs/gallery/data/teaching-learning.yml': 'docs/gallery/teaching-learning.html', + 'docs/gallery/data/software-documentation.yml': 'docs/gallery/software-documentation.html', + 'docs/gallery/data/personal-community.yml': 'docs/gallery/personal-community.html', // Guide listing → guide index 'docs/guide/guide.yml': 'docs/guide/index.html', // Download data → download index diff --git a/_extensions/quartoorg/scss/partials/_gallery.scss b/_extensions/quartoorg/scss/partials/_gallery.scss new file mode 100644 index 0000000000..b36cea705e --- /dev/null +++ b/_extensions/quartoorg/scss/partials/_gallery.scss @@ -0,0 +1,296 @@ +// Gallery design tokens. Light values here; dark overrides below +// under `body.quarto-dark`, mirroring the site theme toggle (no extra JS). + +:root { + --gal-bg: #ffffff; + --gal-panel: #ffffff; + --gal-ink: #1c2733; + --gal-muted: #5d6b7b; + --gal-line: #dde3ea; + --gal-chip: #eef1f5; + --gal-chip-ink: #3f5266; + --gal-chip-line: #e2e7ec; + --gal-accent: #3f6699; + --gal-ring: #1a73e8; + --gal-interactive-bg: rgba(18, 165, 148, 0.16); + --gal-interactive-ink: #0a6b5e; + --gal-interactive-line: rgba(18, 165, 148, 0.30); + + // category accent colours + --cat-reports: #3b7dd8; + --cat-dashboards: #12a594; + --cat-research: #8b5cf6; + --cat-teaching: #e8863c; + --cat-docs: #546e91; + --cat-personal: #d6457f; +} + +body.quarto-dark { + --gal-bg: #161f28; + --gal-panel: #1d2833; + --gal-ink: #e8eef4; + --gal-muted: #a4b4c4; + --gal-line: #2c3a48; + --gal-chip: #26333f; + --gal-chip-ink: #c4d2df; + --gal-chip-line: #33424f; + --gal-accent: #8fbdf0; + --gal-ring: #7fb2ff; + --gal-interactive-ink: #2fd4bf; +} + +// per-category accent, applied via a `.cat-` class +.cat-reports { --c: var(--cat-reports); } +.cat-dashboards { --c: var(--cat-dashboards); } +.cat-research { --c: var(--cat-research); } +.cat-teaching { --c: var(--cat-teaching); } +.cat-docs { --c: var(--cat-docs); } +.cat-personal { --c: var(--cat-personal); } + +// Empty title block reserves space at the top; hide only when empty so titled +// pages keep theirs. +body.gallery header#title-block-header:empty { display: none; } + +// On the landing (body.gallery-landing) the page `title:` is the eyebrow above +// the hero heading, so style it like the old `.kicker` label and drop the +// theme's title-block chrome (rule, spacing, metadata). +.gallery-landing #title-block-header { + margin-block-end: 0; border-block-end: 0; padding-block-end: 0; + .title { + letter-spacing: 0.14em; text-transform: uppercase; + font-size: 0.75rem; color: var(--gal-accent); font-weight: 700; + margin: 0; + } + .quarto-title-meta, .subtitle { display: none; } +} + +// ---------------------------------------------------------------- hero chooser +.gal-hero { padding: 0.5rem 0 0.4rem; } +.gal-hero h1 { font-size: 2.25rem; line-height: 1.1; margin: 0.4rem 0 0.3rem; font-weight: 800; } +.gal-hero .lede { color: var(--gal-muted); font-size: 1rem; margin: 0 0 1.4rem; } + +.gal-chooser { + display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; + padding: 0 0 1.6rem; list-style: none; margin: 0; +} +@media (max-width: 900px) { .gal-chooser { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 600px) { .gal-chooser { grid-template-columns: 1fr; } } + +.gal-chooser > li { display: flex; } // stretch the card to the grid row height +.gal-choice { + position: relative; display: block; overflow: hidden; text-decoration: none; + width: 100%; // fill the flex item so wrapped taglines don't make one card taller + border: 1px solid var(--gal-line); border-radius: 12px; padding: 0.95rem 1rem 0.9rem; + background: var(--gal-panel); color: var(--gal-ink); +} +.gal-choice::before { content: ""; position: absolute; left: 0; top: 0; height: 4px; width: 100%; background: var(--c); } +.gal-choice:hover { border-color: var(--c); } +.gal-choice:focus-visible { outline: 3px solid var(--gal-ring); outline-offset: 2px; } +.gal-choice .row { display: flex; align-items: center; justify-content: space-between; } +.gal-choice .ic { font-size: 1.2rem; } +.gal-choice h2 { margin: 0.55rem 0 0.2rem; font-size: 1rem; } +.gal-choice p { margin: 0; font-size: 0.8rem; color: var(--gal-muted); line-height: 1.35; } + +// --------------------------------------------------------- floating jump rail +// In-page navigation as a floating rail pinned to the right edge (à la +// mickael.canouil.fr): a collapsed icon column whose labels expand leftwards on +// hover / keyboard focus, so the centred content never shifts. Scrollspy (in +// _jumpnav.ejs.md) marks the active section with .active + aria-current. Below +// $gal-rail-bp the same markup becomes a horizontal bottom dock. The listing +// wrapper carries no layout because the nav is `position: fixed`. +$gal-rail-bp: 991.98px; + +#jumpnav { margin: 0; } +.gal-rail { + position: fixed; + top: 5rem; + right: 1rem; + bottom: 1rem; + z-index: 1020; + display: flex; + align-items: center; + justify-content: flex-end; + max-width: min(18rem, 22vw); + pointer-events: none; + transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s ease; + + &.gal-rail--tucked { + opacity: 0; + visibility: hidden; + transform: translateX(120%); + } + + ul { + display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; + max-height: 100%; margin: 0; padding: 0.5rem; list-style: none; + overflow-y: auto; scrollbar-width: none; + border: 1px solid var(--gal-line); border-radius: 14px; + background: color-mix(in srgb, var(--gal-bg) 92%, transparent); + backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); + pointer-events: auto; + &::-webkit-scrollbar { display: none; } + } + li { width: 100%; margin: 0; } + + &:hover .gal-rail__label, + &:focus-within .gal-rail__label { max-width: 12rem; padding-inline-start: 0.5rem; opacity: 1; } +} + +.gal-rail__link { + display: flex; flex-direction: row-reverse; align-items: center; justify-content: flex-start; + padding: 0.2rem; border-radius: 10px; color: var(--gal-ink); text-decoration: none; + outline-offset: 2px; + transition: color 0.15s ease, background-color 0.15s ease; + &:hover, &:focus-visible { + color: var(--c, var(--gal-accent)); + background: color-mix(in srgb, var(--c, var(--gal-accent)) 16%, transparent); + text-decoration: none; + } + &.active { + color: var(--c, var(--gal-accent)); + background: color-mix(in srgb, var(--c, var(--gal-accent)) 24%, transparent); + } + &:focus-visible { outline: 2px solid var(--gal-ring); } +} + +.gal-rail__mark { + display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; + width: 1.75rem; height: 1.75rem; font-size: 1.05rem; +} + +.gal-rail__label { + max-width: 0; overflow: hidden; white-space: nowrap; + font-size: 0.82rem; font-weight: 600; letter-spacing: 0.01em; opacity: 0; + will-change: max-width, opacity; + // Grow the box first, then fade the text in (opacity delayed), so the label + // never paints while still clipped — the main cause of the reveal flicker. + // One shared easing curve keeps width, padding and text in step. + transition: + max-width 0.3s cubic-bezier(0.4, 0, 0.2, 1), + padding 0.3s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.18s ease 0.09s; +} + +.cat-browse { --c: var(--gal-accent); } + +// Bottom dock: below the breakpoint a right-edge rail would sit on the body, so +// the same markup docks along the bottom edge as a horizontal, swipeable strip +// with the label shown on the active chip only. +@media (max-width: $gal-rail-bp) { + // Reserve a band at the page end so the fixed dock never traps the last + // content beneath it (the footer tuck only clears the footer itself). + body.gallery { padding-bottom: 4rem; } + + .gal-rail { + inset: auto 0 0 0; align-items: stretch; max-width: none; + &.gal-rail--tucked { transform: none; } + ul { + flex-direction: row; align-items: center; width: 100%; max-height: none; + padding: 0.35rem 0.5rem; overflow-x: auto; overflow-y: hidden; + border-width: 1px 0 0; border-radius: 0; + } + li { + width: auto; + &:first-child { margin-inline-start: auto; } + &:last-child { margin-inline-end: auto; } + } + // Cancel the bar-wide reveal so the whole dock does not expand; the active + // and the focused chip each still show their label (below). + &:hover .gal-rail__label, + &:focus-within .gal-rail__label { max-width: 0; padding-inline-start: 0; opacity: 0; } + } + .gal-rail__link { + flex-direction: row; min-width: 2.75rem; min-height: 2.75rem; + justify-content: center; padding: 0.25rem 0.35rem; + } + // Eased (not snapped) so hover and active-on-scroll reveals glide; kept short + // because the active chip retargets as sections pass. + .gal-rail__label { + transition: + max-width 0.24s cubic-bezier(0.4, 0, 0.2, 1), + padding 0.24s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.16s ease 0.06s; + } + // Named for screen readers at every size (label kept in the a11y tree, only + // clipped); shown visually on the active chip, the hovered chip, and the + // keyboard-focused one, so pointer and keyboard users both see the label, not + // a bare icon. Per-chip (not bar-wide) so the dock never expands as a whole. + .gal-rail__link.active .gal-rail__label, + .gal-rail__link:hover .gal-rail__label, + .gal-rail__link:focus-visible .gal-rail__label { max-width: 12rem; padding-inline-start: 0.35rem; opacity: 1; } +} + +// ---------------------------------------------------------------- sections +.gal-featured-intro { margin: 1.6rem 0 0.2rem; } +.gal-featured-intro h2 { font-size: 1.4rem; font-weight: 800; margin: 0 0 0.3rem; } +.gal-featured-intro p { color: var(--gal-muted); font-size: 1rem; margin: 0; } + +.gal-section { padding: 1.9rem 0 0.3rem; scroll-margin-top: 5rem; } +#browse-by-format { scroll-margin-top: 5rem; } +.gal-section .shead { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; margin-bottom: 0.2rem; } +.gal-section .shead .l { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; } +.gal-section h2 { font-size: 1.4rem; margin: 0; font-weight: 800; position: relative; padding-left: 0.9rem; } +.gal-section h2::before { content: ""; position: absolute; left: 0; top: 0.2rem; bottom: 0.2rem; width: 5px; border-radius: 3px; background: var(--c); } +.gal-section h2 a { color: inherit; text-decoration: none; display: inline-flex; align-items: baseline; gap: 0.5rem; } +.gal-section h2 .ic { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; } +.gal-section .tag { color: var(--gal-muted); font-size: 0.85rem; } +.gal-seeall { white-space: nowrap; color: var(--gal-accent); text-decoration: none; font-weight: 600; font-size: 0.82rem; } + +.gal-caps { margin: 0.55rem 0 1rem; font-size: 0.78rem; color: var(--gal-muted); } +.gal-caps b { color: var(--gal-ink); font-weight: 600; } +.gal-caps a { display: inline-block; background: var(--gal-chip); color: var(--gal-accent); text-decoration: none; padding: 0.18rem 0.6rem; border-radius: 20px; margin: 0 0.35rem 0.35rem 0; font-weight: 600; font-size: 0.72rem; border: 1px solid var(--gal-chip-line); } + +// ------------------------------------------------------------------- cards +.gal-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.1rem; list-style: none; margin: 0; padding: 0; } +@media (max-width: 900px) { .gal-cards { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 600px) { .gal-cards { grid-template-columns: 1fr; } } + +.gal-card { border: 1px solid var(--gal-line); border-radius: 12px; overflow: hidden; background: var(--gal-panel); display: flex; flex-direction: column; } +.gal-card:focus-within { outline: 3px solid var(--gal-ring); outline-offset: 2px; } +.gal-card .thumb { height: 172px; display: flex; align-items: flex-end; padding: 0.6rem 0.75rem; color: #fff; font-size: 0.74rem; font-weight: 600; background: linear-gradient(135deg, var(--c, var(--gal-accent)), color-mix(in srgb, var(--c, var(--gal-accent)) 68%, #000)); } +// `contain` shows the whole screenshot; the letterbox blanks take the card's +// category colour (the same accent used for image-less card headers), falling back +// to the neutral surface where a card is not scoped to one category (browse grid). +.gal-card img.thumb-img, .gal-card video.thumb-img { width: 100%; height: 172px; object-fit: contain; object-position: center; display: block; background: var(--c, var(--gal-chip)); } +// Featured hover preview: static poster with the