unaltraweb 0.3.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 +7 -0
- data/LICENSE +20 -0
- data/Makefile +412 -0
- data/README.md +226 -0
- data/_config.yml +842 -0
- data/_data/i18n/ca.yml +278 -0
- data/_data/i18n/en.yml +278 -0
- data/_data/i18n/es.yml +278 -0
- data/_includes/audio.liquid +30 -0
- data/_includes/bib_search.liquid +5 -0
- data/_includes/blog-list.liquid +66 -0
- data/_includes/book-citation.liquid +33 -0
- data/_includes/citation.liquid +26 -0
- data/_includes/custom_head.liquid +3 -0
- data/_includes/custom_scripts.liquid +5 -0
- data/_includes/cv/list.liquid +5 -0
- data/_includes/cv/list_groups.liquid +51 -0
- data/_includes/cv/map.liquid +29 -0
- data/_includes/cv/nested_list.liquid +16 -0
- data/_includes/cv/time_table.liquid +118 -0
- data/_includes/cv-download-card.liquid +26 -0
- data/_includes/developer-mode-switcher.liquid +24 -0
- data/_includes/disqus.liquid +13 -0
- data/_includes/distill_scripts.liquid +298 -0
- data/_includes/documentation-download-detail.liquid +76 -0
- data/_includes/documentation-downloads.liquid +71 -0
- data/_includes/documentation-profile-attributes.liquid +4 -0
- data/_includes/documentation-section-toc.liquid +9 -0
- data/_includes/documentation-sidebar.liquid +112 -0
- data/_includes/figure.liquid +87 -0
- data/_includes/footer.liquid +66 -0
- data/_includes/giscus.liquid +25 -0
- data/_includes/head.liquid +220 -0
- data/_includes/header.liquid +544 -0
- data/_includes/latest_posts.liquid +61 -0
- data/_includes/localized-date.liquid +5 -0
- data/_includes/manual-bibliography.liquid +2 -0
- data/_includes/manual-featured-readings.liquid +12 -0
- data/_includes/manual-other-readings.liquid +12 -0
- data/_includes/manual-page-toc.liquid +11 -0
- data/_includes/manual-sidebar.liquid +58 -0
- data/_includes/manual-teachers.liquid +74 -0
- data/_includes/metadata.liquid +278 -0
- data/_includes/news.liquid +48 -0
- data/_includes/newsletter.liquid +68 -0
- data/_includes/page-hero.liquid +96 -0
- data/_includes/page-link.liquid +8 -0
- data/_includes/pagination.liquid +22 -0
- data/_includes/post-reading-time.liquid +29 -0
- data/_includes/previous-next.liquid +37 -0
- data/_includes/profile-card.liquid +49 -0
- data/_includes/profile-feature-matrix.liquid +75 -0
- data/_includes/profile-highlights.liquid +122 -0
- data/_includes/project-grid.liquid +26 -0
- data/_includes/project-resource-link.liquid +45 -0
- data/_includes/project-resources.liquid +21 -0
- data/_includes/projects.liquid +38 -0
- data/_includes/projects_horizontal.liquid +37 -0
- data/_includes/publications-metrics-summary.liquid +69 -0
- data/_includes/publications-summary.liquid +127 -0
- data/_includes/reading-biblio-controls.liquid +65 -0
- data/_includes/reading-cover-card.liquid +93 -0
- data/_includes/reading-rating.liquid +11 -0
- data/_includes/recommended-readings.liquid +30 -0
- data/_includes/related_posts.liquid +39 -0
- data/_includes/repository/repo.liquid +48 -0
- data/_includes/repository/repo_trophies.liquid +44 -0
- data/_includes/repository/repo_user.liquid +35 -0
- data/_includes/resume/awards.liquid +19 -0
- data/_includes/resume/basics.liquid +28 -0
- data/_includes/resume/certificates.liquid +35 -0
- data/_includes/resume/education.liquid +54 -0
- data/_includes/resume/interests.liquid +34 -0
- data/_includes/resume/languages.liquid +31 -0
- data/_includes/resume/projects.liquid +32 -0
- data/_includes/resume/publications.liquid +28 -0
- data/_includes/resume/references.liquid +31 -0
- data/_includes/resume/skills.liquid +33 -0
- data/_includes/resume/volunteer.liquid +52 -0
- data/_includes/resume/work.liquid +52 -0
- data/_includes/scripts.liquid +364 -0
- data/_includes/search-data.js.liquid +341 -0
- data/_includes/selected_papers.liquid +3 -0
- data/_includes/t.liquid +31 -0
- data/_includes/team-grid.liquid +172 -0
- data/_includes/video.liquid +97 -0
- data/_layouts/about.liquid +93 -0
- data/_layouts/archive.liquid +45 -0
- data/_layouts/bib.liquid +677 -0
- data/_layouts/book-review.liquid +225 -0
- data/_layouts/book-shelf.liquid +66 -0
- data/_layouts/cv.liquid +127 -0
- data/_layouts/default.liquid +70 -0
- data/_layouts/distill.liquid +132 -0
- data/_layouts/documentation-download-detail.liquid +5 -0
- data/_layouts/documentation-home.liquid +100 -0
- data/_layouts/documentation-page.liquid +45 -0
- data/_layouts/manual-bib.liquid +73 -0
- data/_layouts/manual-chapter.liquid +99 -0
- data/_layouts/manual-featured-bib.liquid +100 -0
- data/_layouts/manual-home.liquid +120 -0
- data/_layouts/none.liquid +1 -0
- data/_layouts/outputs.liquid +29 -0
- data/_layouts/page.liquid +52 -0
- data/_layouts/post.liquid +95 -0
- data/_layouts/profile.liquid +36 -0
- data/_layouts/profiles.liquid +36 -0
- data/_layouts/project.liquid +7 -0
- data/_layouts/repositories.liquid +58 -0
- data/_layouts/theses.liquid +126 -0
- data/_plugins/bibliography_profiles.rb +164 -0
- data/_plugins/callouts.rb +104 -0
- data/_plugins/code_blocks.rb +277 -0
- data/_plugins/computation_figure_images.rb +266 -0
- data/_plugins/computation_sources.rb +42 -0
- data/_plugins/content_search_index.rb +210 -0
- data/_plugins/details.rb +23 -0
- data/_plugins/external-posts.rb +124 -0
- data/_plugins/figure_captions.rb +800 -0
- data/_plugins/file-exists.rb +22 -0
- data/_plugins/google-scholar-citations.rb +86 -0
- data/_plugins/hide-custom-bibtex.rb +18 -0
- data/_plugins/inspirehep-citations.rb +57 -0
- data/_plugins/localized_visual_sources.rb +145 -0
- data/_plugins/manual_release_metadata.rb +47 -0
- data/_plugins/mermaid_mmd_images.rb +233 -0
- data/_plugins/profile-pages.rb +28 -0
- data/_plugins/remove-accents.rb +32 -0
- data/_plugins/reproducible_build_time.rb +55 -0
- data/_plugins/search-data.rb +83 -0
- data/_plugins/theme-cache-bust.rb +56 -0
- data/_plugins/vega_visual_images.rb +290 -0
- data/_plugins/web_capture_images.rb +154 -0
- data/_sass/_base.scss +2133 -0
- data/_sass/_blog.scss +67 -0
- data/_sass/_callouts.scss +100 -0
- data/_sass/_custom.scss +437 -0
- data/_sass/_cv.scss +274 -0
- data/_sass/_developer.scss +97 -0
- data/_sass/_distill.scss +185 -0
- data/_sass/_documentation.scss +2220 -0
- data/_sass/_layout.scss +218 -0
- data/_sass/_manual.scss +2691 -0
- data/_sass/_profile.scss +323 -0
- data/_sass/_projects.scss +163 -0
- data/_sass/_reading.scss +465 -0
- data/_sass/_site-custom.scss +3 -0
- data/_sass/_tabs.scss +48 -0
- data/_sass/_team.scss +230 -0
- data/_sass/_themes.scss +254 -0
- data/_sass/_typograms.scss +132 -0
- data/_sass/_variables.scss +52 -0
- data/_sass/font-awesome/_animated.scss +152 -0
- data/_sass/font-awesome/_bordered-pulled.scss +20 -0
- data/_sass/font-awesome/_core.scss +49 -0
- data/_sass/font-awesome/_fixed-width.scss +7 -0
- data/_sass/font-awesome/_functions.scss +57 -0
- data/_sass/font-awesome/_icons.scss +13 -0
- data/_sass/font-awesome/_list.scss +18 -0
- data/_sass/font-awesome/_mixins.scss +65 -0
- data/_sass/font-awesome/_rotated-flipped.scss +31 -0
- data/_sass/font-awesome/_screen-reader.scss +14 -0
- data/_sass/font-awesome/_shims.scss +1578 -0
- data/_sass/font-awesome/_sizing.scss +16 -0
- data/_sass/font-awesome/_stacked.scss +32 -0
- data/_sass/font-awesome/_variables.scss +5044 -0
- data/_sass/font-awesome/brands.scss +30 -0
- data/_sass/font-awesome/fontawesome.scss +21 -0
- data/_sass/font-awesome/regular.scss +27 -0
- data/_sass/font-awesome/solid.scss +27 -0
- data/_sass/font-awesome/v4-shims.scss +11 -0
- data/_sass/tabler-icons/tabler-icons-filled.scss +1646 -0
- data/_sass/tabler-icons/tabler-icons-outline.scss +9859 -0
- data/_sass/tabler-icons/tabler-icons.scss +11463 -0
- data/_scripts/cronitor-analytics-setup.js +9 -0
- data/_scripts/giscus-setup.js +48 -0
- data/_scripts/google-analytics-setup.js +9 -0
- data/_scripts/open-panel-analytics-setup.js +14 -0
- data/_scripts/photoswipe-setup.js +11 -0
- data/assets/audio/epicaly-short-113909.mp3 +0 -0
- data/assets/bibliography/2018-12-22-distill.bib +7 -0
- data/assets/css/academicons.min.css +1 -0
- data/assets/css/bootstrap-toc.min.css +4 -0
- data/assets/css/bootstrap.min.css +7 -0
- data/assets/css/bootstrap.min.css.map +1 -0
- data/assets/css/jekyll-pygments-themes-github.css +209 -0
- data/assets/css/jekyll-pygments-themes-native.css +232 -0
- data/assets/css/jupyter-grade3.css +3758 -0
- data/assets/css/jupyter-monokai.css +3758 -0
- data/assets/css/jupyter.css +383 -0
- data/assets/css/main.scss +36 -0
- data/assets/css/mdb.min.css +48 -0
- data/assets/css/mdb.min.css.map +1 -0
- data/assets/css/scholar-icons.css +386 -0
- data/assets/fonts/academicons.ttf +0 -0
- data/assets/fonts/academicons.woff +0 -0
- data/assets/fonts/scholar-icons.ttf +0 -0
- data/assets/fonts/scholar-icons.woff +0 -0
- data/assets/fonts/tabler-icons-filled.ttf +0 -0
- data/assets/fonts/tabler-icons-filled.woff +0 -0
- data/assets/fonts/tabler-icons-filled.woff2 +0 -0
- data/assets/fonts/tabler-icons-outline.ttf +0 -0
- data/assets/fonts/tabler-icons-outline.woff +0 -0
- data/assets/fonts/tabler-icons-outline.woff2 +0 -0
- data/assets/fonts/tabler-icons.ttf +0 -0
- data/assets/fonts/tabler-icons.woff +0 -0
- data/assets/fonts/tabler-icons.woff2 +0 -0
- data/assets/html/relativity.html +15 -0
- data/assets/img/1.jpg +0 -0
- data/assets/img/10.jpg +0 -0
- data/assets/img/11.jpg +0 -0
- data/assets/img/12.jpg +0 -0
- data/assets/img/2.jpg +0 -0
- data/assets/img/3.jpg +0 -0
- data/assets/img/4.jpg +0 -0
- data/assets/img/5.jpg +0 -0
- data/assets/img/6.jpg +0 -0
- data/assets/img/7.jpg +0 -0
- data/assets/img/8.jpg +0 -0
- data/assets/img/9.jpg +0 -0
- data/assets/img/book_covers/the_godfather.jpg +0 -0
- data/assets/img/brand/dosquartsdedocs-logo-cafe.svg +31 -0
- data/assets/img/brand/dosquartsdedocs-logo-footer-cafe.svg +31 -0
- data/assets/img/brand/dosquartsdedocs-logo-white.svg +31 -0
- data/assets/img/brand/dosquartsdedocs-logo.svg +31 -0
- data/assets/img/prof_pic.jpg +0 -0
- data/assets/img/prof_pic_color.png +0 -0
- data/assets/img/profile-placeholder.svg +8 -0
- data/assets/img/publication_preview/brownian-motion.gif +0 -0
- data/assets/img/publication_preview/goodchild1992-gis-cover.jpg +0 -0
- data/assets/img/publication_preview/gutierrez2020-jtrg-preview.jpg +0 -0
- data/assets/img/publication_preview/harvey1989-postmodernity-cover.jpg +0 -0
- data/assets/img/publication_preview/tobler1970-economic-geography-cover.jpg +0 -0
- data/assets/img/publication_preview/tuan1977-space-place-cover.jpg +0 -0
- data/assets/img/publication_preview/wave-mechanics.gif +0 -0
- data/assets/img/publication_preview/zaragozi2025-rooftop-pv-preview.jpg +0 -0
- data/assets/img/rhino.png +0 -0
- data/assets/img/team/aaron-gutierrez.png +0 -0
- data/assets/img/team/alba-font.png +0 -0
- data/assets/img/team/alba-viana.png +0 -0
- data/assets/img/team/alejandro-gonzalez.png +0 -0
- data/assets/img/team/ana-pastor.png +0 -0
- data/assets/img/team/antoni-domenech.png +0 -0
- data/assets/img/team/benito-zaragozi.png +0 -0
- data/assets/img/team/cinta-sanz.png +0 -0
- data/assets/img/team/daniel-miravet.png +0 -0
- data/assets/img/team/eugenia-altamirano.png +0 -0
- data/assets/img/team/fiammetta-brandajs.png +0 -0
- data/assets/img/team/francesc-gonzalez.png +0 -0
- data/assets/img/team/isabel-paulino.png +0 -0
- data/assets/img/team/joan-borras.png +0 -0
- data/assets/img/team/julie-wilson.png +0 -0
- data/assets/img/team/liliana-sole.png +0 -0
- data/assets/img/team/maria-casado.png +0 -0
- data/assets/img/team/maria-medina.png +0 -0
- data/assets/img/team/marta-nello.png +0 -0
- data/assets/img/team/mogrify +1 -0
- data/assets/img/team/oscar-saladie.png +0 -0
- data/assets/img/team/paolo-russo.png +0 -0
- data/assets/img/team/raquel-santos.png +0 -0
- data/assets/img/team/salvador-anton.png +0 -0
- data/assets/img/team/sunsi-huertas.png +0 -0
- data/assets/img/team/user-placeholder.png +0 -0
- data/assets/img/team/wilbert-den-hoed.png +0 -0
- data/assets/img/team/xavier-delclos.png +0 -0
- data/assets/img/template_error.png +0 -0
- data/assets/js/bibsearch.js +70 -0
- data/assets/js/bootstrap-toc.min.js +5 -0
- data/assets/js/bootstrap.bundle.min.js +7 -0
- data/assets/js/bootstrap.bundle.min.js.map +1 -0
- data/assets/js/callouts.js +115 -0
- data/assets/js/chartjs-setup.js +14 -0
- data/assets/js/common.js +117 -0
- data/assets/js/content-search-match.js +159 -0
- data/assets/js/content-search.js +441 -0
- data/assets/js/copy_code.js +60 -0
- data/assets/js/custom.js +6 -0
- data/assets/js/developer-mode.js +103 -0
- data/assets/js/diff2html-setup.js +20 -0
- data/assets/js/distillpub/overrides.js +27 -0
- data/assets/js/distillpub/template.v2.js +9616 -0
- data/assets/js/distillpub/template.v2.js.map +1 -0
- data/assets/js/distillpub/transforms.v2.js +14557 -0
- data/assets/js/distillpub/transforms.v2.js.map +1 -0
- data/assets/js/documentation.js +435 -0
- data/assets/js/echarts-setup.js +29 -0
- data/assets/js/highlight-search-term.js +110 -0
- data/assets/js/jupyter_new_tab.js +18 -0
- data/assets/js/leaflet-setup.js +22 -0
- data/assets/js/manual.js +308 -0
- data/assets/js/masonry.js +12 -0
- data/assets/js/mathjax-setup.js +46 -0
- data/assets/js/mermaid-setup.js +37 -0
- data/assets/js/newsletter.js +105 -0
- data/assets/js/no_defer.js +24 -0
- data/assets/js/plotly-setup.js +52 -0
- data/assets/js/profile-nav.js +92 -0
- data/assets/js/progress-bar.js +73 -0
- data/assets/js/pseudocode-setup.js +18 -0
- data/assets/js/search/base-styles.min.js +286 -0
- data/assets/js/search/command-score.min.js +7 -0
- data/assets/js/search/hotkeys-js/hotkeys.esm.min.js +18 -0
- data/assets/js/search/lit/decorators.min.js +7 -0
- data/assets/js/search/lit/directives/class-map.min.js +7 -0
- data/assets/js/search/lit/directives/join.min.js +7 -0
- data/assets/js/search/lit/directives/live.min.js +7 -0
- data/assets/js/search/lit/directives/ref.min.js +7 -0
- data/assets/js/search/lit/directives/repeat.min.js +7 -0
- data/assets/js/search/lit/directives/unsafe-html.min.js +7 -0
- data/assets/js/search/lit/index.min.js +7 -0
- data/assets/js/search/lit-element/lit-element.min.js +12 -0
- data/assets/js/search/lit-html/directives/class-map.min.js +22 -0
- data/assets/js/search/lit-html/directives/join.min.js +12 -0
- data/assets/js/search/lit-html/directives/live.min.js +28 -0
- data/assets/js/search/lit-html/directives/ref.min.js +32 -0
- data/assets/js/search/lit-html/directives/repeat.min.js +27 -0
- data/assets/js/search/lit-html/directives/unsafe-html.min.js +22 -0
- data/assets/js/search/lit-html/is-server.min.js +12 -0
- data/assets/js/search/lit-html/lit-html.min.js +12 -0
- data/assets/js/search/ninja-action.min.js +101 -0
- data/assets/js/search/ninja-footer.min.js +62 -0
- data/assets/js/search/ninja-header.min.js +78 -0
- data/assets/js/search/ninja-keys.min.js +39 -0
- data/assets/js/search/reactive-element/decorators/custom-element.min.js +12 -0
- data/assets/js/search/reactive-element/decorators/event-options.min.js +12 -0
- data/assets/js/search/reactive-element/decorators/property.min.js +22 -0
- data/assets/js/search/reactive-element/decorators/query-all.min.js +17 -0
- data/assets/js/search/reactive-element/decorators/query-assigned-elements.min.js +17 -0
- data/assets/js/search/reactive-element/decorators/query-assigned-nodes.min.js +17 -0
- data/assets/js/search/reactive-element/decorators/query-async.min.js +17 -0
- data/assets/js/search/reactive-element/decorators/query.min.js +17 -0
- data/assets/js/search/reactive-element/decorators/state.min.js +27 -0
- data/assets/js/search/reactive-element/reactive-element.min.js +17 -0
- data/assets/js/search-setup.js +17 -0
- data/assets/js/shortcut-key.js +11 -0
- data/assets/js/tabs.min.js +5 -0
- data/assets/js/theme.js +314 -0
- data/assets/js/tooltips-setup.js +3 -0
- data/assets/js/typograms.js +1341 -0
- data/assets/js/vanilla-back-to-top.min.js +1 -0
- data/assets/js/vega-setup.js +24 -0
- data/assets/js/venobox-setup.js +5 -0
- data/assets/js/wechat.js +14 -0
- data/assets/js/zoom.js +15 -0
- data/assets/json/resume.json +98 -0
- data/assets/json/table_data.json +128 -0
- data/assets/jupyter/blog.ipynb +48 -0
- data/assets/pdf/example_pdf.pdf +0 -0
- data/assets/plotly/demo.html +72 -0
- data/assets/video/pexels-engin-akyurt-6069112-960x540-30fps.mp4 +0 -0
- data/assets/webfonts/fa-brands-400.ttf +0 -0
- data/assets/webfonts/fa-brands-400.woff2 +0 -0
- data/assets/webfonts/fa-regular-400.ttf +0 -0
- data/assets/webfonts/fa-regular-400.woff2 +0 -0
- data/assets/webfonts/fa-solid-900.ttf +0 -0
- data/assets/webfonts/fa-solid-900.woff2 +0 -0
- data/assets/webfonts/fa-v4compatibility.ttf +0 -0
- data/assets/webfonts/fa-v4compatibility.woff2 +0 -0
- data/docs/Gemfile +5 -0
- data/docs/_config.yml +83 -0
- data/docs/_documentation/en/01-quick-start.md +115 -0
- data/docs/_documentation/en/02-tools.md +146 -0
- data/docs/_documentation/en/03-usage.md +107 -0
- data/docs/_documentation/en/04-jekyll-basics.md +51 -0
- data/docs/_documentation/en/05-pages-collections.md +68 -0
- data/docs/_documentation/en/06-github-web-editing.md +92 -0
- data/docs/_documentation/en/10-profiles.md +125 -0
- data/docs/_documentation/en/11-unaltreselfie.md +39 -0
- data/docs/_documentation/en/12-unaltreprojecte.md +38 -0
- data/docs/_documentation/en/13-unaltremanual.md +237 -0
- data/docs/_documentation/en/14-unaltredocs.md +92 -0
- data/docs/_documentation/en/15-profile-checklist.md +39 -0
- data/docs/_documentation/en/20-syntax.md +353 -0
- data/docs/_documentation/en/21-themes.md +103 -0
- data/docs/_documentation/en/22-feature-reference.md +56 -0
- data/docs/_documentation/en/23-front-matter.md +51 -0
- data/docs/_documentation/en/24-data-files.md +28 -0
- data/docs/_documentation/en/30-customization.md +448 -0
- data/docs/_documentation/en/31-template.md +55 -0
- data/docs/_documentation/en/32-development.md +108 -0
- data/docs/_documentation/en/33-reusable-workflows.md +136 -0
- data/docs/_documentation/en/40-distribution.md +164 -0
- data/docs/_documentation/en/41-bibliometrics.md +137 -0
- data/docs/_documentation/en/42-docker-image.md +185 -0
- data/docs/_documentation/en/50-faq.md +33 -0
- data/docs/_pages/ca/index.md +35 -0
- data/docs/_pages/en/index.md +35 -0
- data/docs/_pages/es/index.md +35 -0
- data/docs/agents/action-prompts/00-start-site-session.txt +10 -0
- data/docs/agents/action-prompts/05-create-new-web.txt +5 -0
- data/docs/agents/action-prompts/10-content-update.txt +9 -0
- data/docs/agents/action-prompts/15-edit-default-content.txt +8 -0
- data/docs/agents/action-prompts/20-manual-teaching-materials.txt +18 -0
- data/docs/agents/action-prompts/22-manual-style-audit.txt +14 -0
- data/docs/agents/action-prompts/23-manual-structure-audit.txt +17 -0
- data/docs/agents/action-prompts/25-translation-prepublish.txt +8 -0
- data/docs/agents/action-prompts/30-project-site-update.txt +7 -0
- data/docs/agents/action-prompts/40-documentation-update.txt +7 -0
- data/docs/agents/action-prompts/50-bibliography-entry.txt +7 -0
- data/docs/agents/action-prompts/60-bibliometrics-refresh.txt +7 -0
- data/docs/agents/action-prompts/70-build-and-review.txt +12 -0
- data/docs/agents/manual-authoring-components.md +255 -0
- data/docs/agents/mcp-contract.md +162 -0
- data/docs/agents/quarto-computation-adoption.md +102 -0
- data/docs/assets/img/unaltraweb-docs-hero.svg +36 -0
- data/lib/unaltraweb/version.rb +8 -0
- data/lib/unaltraweb.rb +31 -0
- data/requirements.txt +5 -0
- data/scripts/biblio/fetch_scimago_csv.sh +126 -0
- data/scripts/biblio/metrics_common.py +154 -0
- data/scripts/biblio/metrics_merge_meta.py +73 -0
- data/scripts/biblio/metrics_update.py +826 -0
- data/scripts/computations/python/Dockerfile +37 -0
- data/scripts/computations/r/Dockerfile +31 -0
- data/scripts/computations/render.py +1267 -0
- data/scripts/cv/render_pdf_preview.sh +36 -0
- data/scripts/deploy/publish_branch.sh +80 -0
- data/scripts/generate_logo_variants.py +47 -0
- data/scripts/manual/Dockerfile +31 -0
- data/scripts/manual/build_pdf.py +1780 -0
- data/scripts/manual/filters/bibliography.lua +164 -0
- data/scripts/manual/filters/code-blocks.lua +102 -0
- data/scripts/manual/filters/figure-captions.lua +35 -0
- data/scripts/manual/publish_release.sh +281 -0
- data/scripts/manual/templates/manual.tex +494 -0
- data/scripts/manual/verify_release_assets.py +650 -0
- data/scripts/test_gem_build.py +128 -0
- data/scripts/test_reproducible_jekyll_build.py +191 -0
- data/scripts/test_wheel_install.py +282 -0
- data/scripts/unaltraweb-docker-mount.sh +36 -0
- data/scripts/unaltraweb-mcp-bootstrap.sh +105 -0
- data/scripts/unaltraweb-mcp-cleanup.sh +73 -0
- data/scripts/unaltraweb-mcp-project-id.sh +34 -0
- data/scripts/validate_distribution.py +563 -0
- data/scripts/validate_workflows.py +1285 -0
- data/scripts/web_captures/Dockerfile +31 -0
- data/scripts/web_captures/capture.mjs +157 -0
- data/scripts/web_captures/package-lock.json +56 -0
- data/scripts/web_captures/package.json +9 -0
- data/scripts/web_captures/render.py +867 -0
- data/src/unaltraweb_mcp/component-contract.json +153 -0
- data/src/unaltraweb_mcp/component-contract.schema.json +87 -0
- data/src/unaltraweb_mcp/docker_mount.py +19 -0
- metadata +861 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
---
|
|
4
|
+
{% assign year = page.date | date: '%Y' %}
|
|
5
|
+
{% assign tags = page.tags | join: '' %}
|
|
6
|
+
{% assign categories = page.categories | join: '' %}
|
|
7
|
+
|
|
8
|
+
{% capture created_on_text %}{% include t.liquid key='post.created_on' default='Created on' %}{% endcapture %}
|
|
9
|
+
{% capture by_text %}{% include t.liquid key='post.by' default='by' %}{% endcapture %}
|
|
10
|
+
{% capture updated_on_text %}{% include t.liquid key='post.last_updated_on' default='last updated on' %}{% endcapture %}
|
|
11
|
+
{% capture references_text %}{% include t.liquid key='post.references' default='References' %}{% endcapture %}
|
|
12
|
+
{% capture published_date %}{% include localized-date.liquid date=page.date format_key='date.formats.long' default_format='%B %-d, %Y' %}{% endcapture %}
|
|
13
|
+
{% if page.last_updated %}
|
|
14
|
+
{% capture updated_date %}{% include localized-date.liquid date=page.last_updated format_key='date.formats.long' default_format='%B %-d, %Y' %}{% endcapture %}
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% capture reading_time_html %}{% include post-reading-time.liquid item=page content=content %}{% endcapture %}
|
|
17
|
+
{% assign reading_time_html = reading_time_html | strip %}
|
|
18
|
+
|
|
19
|
+
{% if page._styles %}
|
|
20
|
+
<style type="text/css">
|
|
21
|
+
{{ page._styles }}
|
|
22
|
+
</style>
|
|
23
|
+
{% endif %}
|
|
24
|
+
|
|
25
|
+
<div class="post">
|
|
26
|
+
<header class="post-header">
|
|
27
|
+
<h1 class="post-title">{{ page.title }}</h1>
|
|
28
|
+
<p class="post-meta">
|
|
29
|
+
{{ created_on_text | strip }} {{ published_date | strip }}
|
|
30
|
+
{% if page.author %}{{ by_text | strip }} {{ page.author }}{% endif %}
|
|
31
|
+
{% if page.last_updated %}, {{ updated_on_text | strip }} {{ updated_date | strip }}{% endif %}
|
|
32
|
+
{% if reading_time_html != '' %} • {{ reading_time_html }}{% endif %}
|
|
33
|
+
{% if page.meta %}• {{ page.meta }}{% endif %}
|
|
34
|
+
</p>
|
|
35
|
+
<p class="post-tags">
|
|
36
|
+
<i class="fa-solid fa-calendar fa-sm"></i> {{ year }}
|
|
37
|
+
|
|
38
|
+
{% if tags != '' %}
|
|
39
|
+
·
|
|
40
|
+
{% for tag in page.tags %}
|
|
41
|
+
<i class="fa-solid fa-hashtag fa-sm"></i> {{ tag }}
|
|
42
|
+
{% unless forloop.last %}
|
|
43
|
+
|
|
44
|
+
{% endunless %}
|
|
45
|
+
{% endfor %}
|
|
46
|
+
{% endif %}
|
|
47
|
+
|
|
48
|
+
{% if categories != '' %}
|
|
49
|
+
·
|
|
50
|
+
{% for category in page.categories %}
|
|
51
|
+
<i class="fa-solid fa-tag fa-sm"></i> {{ category }}
|
|
52
|
+
{% unless forloop.last %}
|
|
53
|
+
|
|
54
|
+
{% endunless %}
|
|
55
|
+
{% endfor %}
|
|
56
|
+
{% endif %}
|
|
57
|
+
</p>
|
|
58
|
+
</header>
|
|
59
|
+
|
|
60
|
+
<article class="post-content">
|
|
61
|
+
{% if page.toc and page.toc.beginning %}
|
|
62
|
+
<div id="table-of-contents">
|
|
63
|
+
{% toc %}
|
|
64
|
+
</div>
|
|
65
|
+
<hr>
|
|
66
|
+
{% endif %}
|
|
67
|
+
<div id="markdown-content">
|
|
68
|
+
{{ content }}
|
|
69
|
+
</div>
|
|
70
|
+
</article>
|
|
71
|
+
|
|
72
|
+
{% if page.citation %}
|
|
73
|
+
{% include citation.liquid %}
|
|
74
|
+
{% endif %}
|
|
75
|
+
|
|
76
|
+
{% if page.related_publications %}
|
|
77
|
+
<h2>{{ references_text | strip }}</h2>
|
|
78
|
+
<div class="publications">
|
|
79
|
+
{% bibliography --group_by none --cited %}
|
|
80
|
+
</div>
|
|
81
|
+
{% endif %}
|
|
82
|
+
|
|
83
|
+
{% if site.related_blog_posts and site.related_blog_posts.enabled %}
|
|
84
|
+
{% if page.related_posts == null or page.related_posts %}
|
|
85
|
+
{% include related_posts.liquid %}
|
|
86
|
+
{% endif %}
|
|
87
|
+
{% endif %}
|
|
88
|
+
|
|
89
|
+
{% if site.disqus_shortname and page.disqus_comments %}
|
|
90
|
+
{% include disqus.liquid %}
|
|
91
|
+
{% endif %}
|
|
92
|
+
{% if site.giscus and page.giscus_comments %}
|
|
93
|
+
{% include giscus.liquid %}
|
|
94
|
+
{% endif %}
|
|
95
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<div class="post profile-page">
|
|
6
|
+
{% assign profile_author = page.author | default: site.author %}
|
|
7
|
+
{% assign current_lang = page.lang | default: site.default_lang | default: site.lang %}
|
|
8
|
+
{% assign profile_author_name_key = 'name_' | append: current_lang %}
|
|
9
|
+
{% assign profile_author_name = profile_author[profile_author_name_key] | default: profile_author.name | default: '' %}
|
|
10
|
+
{% assign show_profile_title = true %}
|
|
11
|
+
{% if page.hide_title or page.title == profile_author_name %}
|
|
12
|
+
{% assign show_profile_title = false %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
{% if show_profile_title or page.description %}
|
|
16
|
+
<header class="post-header">
|
|
17
|
+
{% if show_profile_title %}<h1 class="post-title">{{ page.title }}</h1>{% endif %}
|
|
18
|
+
{% if page.description %}<p class="post-description">{{ page.description }}</p>{% endif %}
|
|
19
|
+
</header>
|
|
20
|
+
{% endif %}
|
|
21
|
+
|
|
22
|
+
{% if profile_author %}
|
|
23
|
+
<div class="profile-page-grid">
|
|
24
|
+
<div class="profile-page-sidebar">
|
|
25
|
+
{% include profile-card.liquid author=profile_author %}
|
|
26
|
+
</div>
|
|
27
|
+
<article class="profile-page-content">
|
|
28
|
+
{{ content }}
|
|
29
|
+
</article>
|
|
30
|
+
</div>
|
|
31
|
+
{% else %}
|
|
32
|
+
<article class="profile-page-content">
|
|
33
|
+
{{ content }}
|
|
34
|
+
</article>
|
|
35
|
+
{% endif %}
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
---
|
|
4
|
+
<div class="post">
|
|
5
|
+
<article>
|
|
6
|
+
{% if page.profiles %}
|
|
7
|
+
{% for profile in page.profiles %}
|
|
8
|
+
<hr>
|
|
9
|
+
<div class="profile float-{% if profile.align == 'left' %}left{% else %}right{% endif %}">
|
|
10
|
+
{% if profile.image %}
|
|
11
|
+
{% assign profile_image_path = profile.image | prepend: 'assets/img/' %}
|
|
12
|
+
{% if profile.image_circular %}
|
|
13
|
+
{% assign profile_image_class = 'img-fluid z-depth-1 rounded-circle' %}
|
|
14
|
+
{% else %}
|
|
15
|
+
{% assign profile_image_class = 'img-fluid z-depth-1 rounded' %}
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% capture sizes %}(min-width: {{ site.max_width }}) {{ site.max_width | minus: 30 | times: 0.3}}px, (min-width: 576px) 30vw, 95vw"{% endcapture %}
|
|
18
|
+
{% include figure.liquid loading="eager" path=profile_image_path class=profile_image_class sizes=sizes alt=profile.image %}
|
|
19
|
+
{% endif %}
|
|
20
|
+
{% if profile.more_info %}
|
|
21
|
+
<div class="more-info">{{ profile.more_info }}</div>
|
|
22
|
+
{% endif %}
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="clearfix">
|
|
26
|
+
{% if profile.content %}
|
|
27
|
+
{% capture profile_content %}{% include_relative {{ profile.content }} %}{% endcapture %}
|
|
28
|
+
{{ profile_content | markdownify }}
|
|
29
|
+
{% else %}
|
|
30
|
+
{{ content }}
|
|
31
|
+
{% endif %}
|
|
32
|
+
</div>
|
|
33
|
+
{% endfor %}
|
|
34
|
+
{% endif %}
|
|
35
|
+
</article>
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
---
|
|
4
|
+
{{ content }}
|
|
5
|
+
|
|
6
|
+
{% capture github_users_text %}{% include t.liquid key='repositories.github_users' default='GitHub users' %}{% endcapture %}
|
|
7
|
+
{% capture github_repositories_text %}{% include t.liquid key='repositories.github_repositories' default='GitHub repositories' %}{% endcapture %}
|
|
8
|
+
{% capture empty_repositories_text %}{% include t.liquid key='repositories.empty' default='Add GitHub users or repositories in `_data/repositories.yml` to populate this section.' %}{% endcapture %}
|
|
9
|
+
|
|
10
|
+
{% assign has_github_users = false %}
|
|
11
|
+
{% if site.data.repositories.github_users and site.data.repositories.github_users.size > 0 %}
|
|
12
|
+
{% assign has_github_users = true %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
{% assign has_github_repos = false %}
|
|
16
|
+
{% if site.data.repositories.github_repos and site.data.repositories.github_repos.size > 0 %}
|
|
17
|
+
{% assign has_github_repos = true %}
|
|
18
|
+
{% endif %}
|
|
19
|
+
|
|
20
|
+
{% if has_github_users %}
|
|
21
|
+
<h2>{{ github_users_text | strip }}</h2>
|
|
22
|
+
|
|
23
|
+
<div class="repositories d-flex flex-wrap flex-md-row flex-column justify-content-between align-items-center">
|
|
24
|
+
{% for user in site.data.repositories.github_users %}
|
|
25
|
+
{% include repository/repo_user.liquid username=user %}
|
|
26
|
+
{% endfor %}
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
{% if site.repo_trophies.enabled %}
|
|
30
|
+
<hr>
|
|
31
|
+
{% for user in site.data.repositories.github_users %}
|
|
32
|
+
{% if site.data.repositories.github_users.size > 1 %}
|
|
33
|
+
<h3>{{ user }}</h3>
|
|
34
|
+
{% endif %}
|
|
35
|
+
<div class="repositories d-flex flex-wrap flex-md-row flex-column justify-content-between align-items-center">
|
|
36
|
+
{% include repository/repo_trophies.liquid username=user %}
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{% unless forloop.last %}
|
|
40
|
+
<hr>
|
|
41
|
+
{% endunless %}
|
|
42
|
+
{% endfor %}
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% endif %}
|
|
45
|
+
|
|
46
|
+
{% if has_github_repos %}
|
|
47
|
+
<h2>{{ github_repositories_text | strip }}</h2>
|
|
48
|
+
|
|
49
|
+
<div class="repositories d-flex flex-wrap flex-md-row flex-column justify-content-between align-items-center">
|
|
50
|
+
{% for repo in site.data.repositories.github_repos %}
|
|
51
|
+
{% include repository/repo.liquid repository=repo %}
|
|
52
|
+
{% endfor %}
|
|
53
|
+
</div>
|
|
54
|
+
{% endif %}
|
|
55
|
+
|
|
56
|
+
{% unless has_github_users or has_github_repos %}
|
|
57
|
+
<p>{{ empty_repositories_text | strip }}</p>
|
|
58
|
+
{% endunless %}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
{%- assign current_lang = page.lang | default: site.default_lang | default: site.lang -%}
|
|
6
|
+
{%- assign theses_for_lang = site.theses | where: "lang", current_lang -%}
|
|
7
|
+
{%- assign theses_without_lang = site.theses | where_exp: "thesis", "thesis.lang == nil" -%}
|
|
8
|
+
{%- if theses_for_lang and theses_for_lang.size > 0 -%}
|
|
9
|
+
{%- assign theses_to_show = theses_for_lang | concat: theses_without_lang -%}
|
|
10
|
+
{%- else -%}
|
|
11
|
+
{%- assign theses_to_show = theses_without_lang -%}
|
|
12
|
+
{%- endif -%}
|
|
13
|
+
{%- assign theses_sorted = theses_to_show | sort: "order" -%}
|
|
14
|
+
|
|
15
|
+
{% capture empty_text %}{% include t.liquid key='theses.empty' default='No theses found yet.' %}{% endcapture %}
|
|
16
|
+
{% capture student_text %}{% include t.liquid key='theses.student' default='Student' %}{% endcapture %}
|
|
17
|
+
{% capture status_text %}{% include t.liquid key='theses.status' default='Status' %}{% endcapture %}
|
|
18
|
+
{% capture institution_text %}{% include t.liquid key='theses.institution' default='Institution' %}{% endcapture %}
|
|
19
|
+
{% capture year_text %}{% include t.liquid key='theses.year' default='Year' %}{% endcapture %}
|
|
20
|
+
{% capture supervisors_text %}{% include t.liquid key='theses.supervisors' default='Supervisors' %}{% endcapture %}
|
|
21
|
+
{% capture image_source_text %}{% include t.liquid key='theses.image_source' default='Source' %}{% endcapture %}
|
|
22
|
+
|
|
23
|
+
{{ content }}
|
|
24
|
+
|
|
25
|
+
{%- if theses_sorted == nil or theses_sorted.size == 0 -%}
|
|
26
|
+
<p>{{ empty_text | strip }}</p>
|
|
27
|
+
{%- endif -%}
|
|
28
|
+
|
|
29
|
+
{%- for t in theses_sorted -%}
|
|
30
|
+
<hr>
|
|
31
|
+
|
|
32
|
+
{%- assign title_key = "title_" | append: current_lang -%}
|
|
33
|
+
{%- assign summary_key = "summary_" | append: current_lang -%}
|
|
34
|
+
{%- assign institution_key = "institution_" | append: current_lang -%}
|
|
35
|
+
{%- assign more_info_key = "more_info_" | append: current_lang -%}
|
|
36
|
+
{%- assign status_key = "status_" | append: current_lang -%}
|
|
37
|
+
{%- assign image_alt_key = "image_alt_" | append: current_lang -%}
|
|
38
|
+
{%- assign image_caption_key = "image_caption_" | append: current_lang -%}
|
|
39
|
+
{%- assign image_source_key = "image_source_" | append: current_lang -%}
|
|
40
|
+
|
|
41
|
+
{%- assign localized_title = t[title_key] | default: t.title -%}
|
|
42
|
+
{%- assign localized_institution = t[institution_key] | default: t.institution -%}
|
|
43
|
+
{%- assign localized_more_info = t[more_info_key] | default: t.more_info -%}
|
|
44
|
+
{%- assign localized_status_raw = t[status_key] | default: t.status -%}
|
|
45
|
+
{%- assign localized_image_alt = t[image_alt_key] | default: t.image_alt | default: t.student -%}
|
|
46
|
+
{%- assign localized_image_caption = t[image_caption_key] | default: t.image_caption -%}
|
|
47
|
+
{%- assign localized_image_source = t[image_source_key] | default: t.image_source -%}
|
|
48
|
+
{%- assign image_source_url = t.image_source_url -%}
|
|
49
|
+
{%- assign image_source_domain = nil -%}
|
|
50
|
+
{%- if image_source_url -%}
|
|
51
|
+
{%- assign image_source_domain = image_source_url | replace: 'https://', '' | replace: 'http://', '' | split: '/' | first -%}
|
|
52
|
+
{%- endif -%}
|
|
53
|
+
|
|
54
|
+
{%- assign status_i18n_key = "theses.status_values." | append: localized_status_raw -%}
|
|
55
|
+
{% capture localized_status %}{% include t.liquid key=status_i18n_key default=localized_status_raw %}{% endcapture %}
|
|
56
|
+
|
|
57
|
+
{%- assign align = t.align | default: "right" -%}
|
|
58
|
+
<div class="profile float-{% if align == 'left' %}left{% else %}right{% endif %}">
|
|
59
|
+
|
|
60
|
+
{%- if t.image -%}
|
|
61
|
+
{%- if t.image contains '://' -%}
|
|
62
|
+
{%- assign profile_image_path = t.image -%}
|
|
63
|
+
{%- else -%}
|
|
64
|
+
{%- assign profile_image_path = t.image | prepend: 'assets/img/' -%}
|
|
65
|
+
{%- endif -%}
|
|
66
|
+
|
|
67
|
+
{%- if t.image_circular -%}
|
|
68
|
+
{%- assign profile_image_class = 'img-fluid z-depth-1 rounded-circle' -%}
|
|
69
|
+
{%- else -%}
|
|
70
|
+
{%- assign profile_image_class = 'img-fluid z-depth-1 rounded' -%}
|
|
71
|
+
{%- endif -%}
|
|
72
|
+
|
|
73
|
+
{%- capture sizes -%}
|
|
74
|
+
(min-width: {{ site.max_width }}) {{ site.max_width | minus: 30 | times: 0.3 }}px,
|
|
75
|
+
(min-width: 576px) 30vw,
|
|
76
|
+
95vw
|
|
77
|
+
{%- endcapture -%}
|
|
78
|
+
|
|
79
|
+
{%- capture thesis_image_caption -%}
|
|
80
|
+
{%- if localized_image_caption -%}
|
|
81
|
+
{{ localized_image_caption }}
|
|
82
|
+
{%- endif -%}
|
|
83
|
+
{%- if localized_image_source or image_source_url -%}
|
|
84
|
+
{%- if localized_image_caption -%} {% endif -%}
|
|
85
|
+
<span class="thesis-image-source">
|
|
86
|
+
{{ image_source_text | strip }}:
|
|
87
|
+
{%- if image_source_url -%}
|
|
88
|
+
<a href="{{ image_source_url }}" target="_blank" rel="noopener noreferrer">
|
|
89
|
+
{{ localized_image_source | default: image_source_domain }}
|
|
90
|
+
</a>
|
|
91
|
+
{%- else -%}
|
|
92
|
+
{{ localized_image_source }}
|
|
93
|
+
{%- endif -%}
|
|
94
|
+
</span>
|
|
95
|
+
{%- endif -%}
|
|
96
|
+
{%- endcapture -%}
|
|
97
|
+
|
|
98
|
+
{%- if t.image contains '://' -%}
|
|
99
|
+
{% include figure.liquid url=profile_image_path class=profile_image_class sizes=sizes alt=localized_image_alt caption=thesis_image_caption loading="lazy" avoid_scaling=true %}
|
|
100
|
+
{%- else -%}
|
|
101
|
+
{% include figure.liquid path=profile_image_path class=profile_image_class sizes=sizes alt=localized_image_alt caption=thesis_image_caption loading="lazy" %}
|
|
102
|
+
{%- endif -%}
|
|
103
|
+
{%- endif -%}
|
|
104
|
+
|
|
105
|
+
{%- if localized_more_info -%}
|
|
106
|
+
<div class="more-info">{{ localized_more_info }}</div>
|
|
107
|
+
{%- endif -%}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div class="clearfix">
|
|
111
|
+
{%- if localized_title -%}<h2>{{ localized_title }}</h2>{%- endif -%}
|
|
112
|
+
{%- if t.student -%}<p><strong>{{ student_text | strip }}:</strong> {{ t.student }}</p>{%- endif -%}
|
|
113
|
+
{%- if localized_status_raw -%}<p><strong>{{ status_text | strip }}:</strong> {{ localized_status | strip }}</p>{%- endif -%}
|
|
114
|
+
{%- if localized_institution -%}<p><strong>{{ institution_text | strip }}:</strong> {{ localized_institution }}</p>{%- endif -%}
|
|
115
|
+
{%- if t.year -%}<p><strong>{{ year_text | strip }}:</strong> {{ t.year }}</p>{%- endif -%}
|
|
116
|
+
{%- if t.supervisors -%}<p><strong>{{ supervisors_text | strip }}:</strong> {{ t.supervisors }}</p>{%- endif -%}
|
|
117
|
+
|
|
118
|
+
{%- if t[summary_key] -%}
|
|
119
|
+
{{ t[summary_key] | markdownify }}
|
|
120
|
+
{%- elsif t.summary -%}
|
|
121
|
+
{{ t.summary | markdownify }}
|
|
122
|
+
{%- else -%}
|
|
123
|
+
{{ t.content }}
|
|
124
|
+
{%- endif -%}
|
|
125
|
+
</div>
|
|
126
|
+
{%- endfor -%}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
require "jekyll/scholar"
|
|
5
|
+
|
|
6
|
+
module Unaltraweb
|
|
7
|
+
module BibliographyProfiles
|
|
8
|
+
PROFILE_SORTS = {
|
|
9
|
+
"unaltreselfie" => {
|
|
10
|
+
"sort_by" => %w[year month name title],
|
|
11
|
+
"order" => %w[descending descending ascending ascending],
|
|
12
|
+
"group_by" => "year",
|
|
13
|
+
"group_order" => "descending"
|
|
14
|
+
},
|
|
15
|
+
"unaltreprojecte" => {
|
|
16
|
+
"sort_by" => %w[year month name title],
|
|
17
|
+
"order" => %w[descending descending ascending ascending],
|
|
18
|
+
"group_by" => "year",
|
|
19
|
+
"group_order" => "descending"
|
|
20
|
+
},
|
|
21
|
+
"unaltremanual" => {
|
|
22
|
+
"sort_by" => %w[name year title],
|
|
23
|
+
"order" => %w[ascending ascending ascending],
|
|
24
|
+
"group_by" => "none",
|
|
25
|
+
"group_order" => "ascending",
|
|
26
|
+
"query" => "@*",
|
|
27
|
+
"source" => "_bibliography"
|
|
28
|
+
}
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
module_function
|
|
32
|
+
|
|
33
|
+
def configure(site)
|
|
34
|
+
profile = site.config.dig("unaltraweb", "site_profile").to_s
|
|
35
|
+
settings = PROFILE_SORTS[profile]
|
|
36
|
+
return unless settings
|
|
37
|
+
|
|
38
|
+
site.config["scholar"] ||= {}
|
|
39
|
+
site.config["scholar"].merge!(settings)
|
|
40
|
+
if profile == "unaltremanual"
|
|
41
|
+
manual = site.config.dig("unaltraweb", "manual") || {}
|
|
42
|
+
manual = {} unless manual.is_a?(Hash)
|
|
43
|
+
bibliography = (manual["bibliography_file"] || "manual.bib").to_s.strip
|
|
44
|
+
unless bibliography.match?(/\A[A-Za-z0-9][A-Za-z0-9_.-]*\.bib\z/) && File.basename(bibliography) == bibliography
|
|
45
|
+
raise Jekyll::Errors::FatalException, "unaltraweb.manual.bibliography_file must be a .bib filename under _bibliography/"
|
|
46
|
+
end
|
|
47
|
+
validate_bibliography_location(site, bibliography)
|
|
48
|
+
site.config["scholar"]["bibliography"] = bibliography
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def validate_bibliography_location(site, bibliography)
|
|
53
|
+
return unless site.respond_to?(:source) && site.source
|
|
54
|
+
|
|
55
|
+
source = File.realpath(site.source)
|
|
56
|
+
root = File.join(source, "_bibliography")
|
|
57
|
+
return unless File.exist?(root) || File.symlink?(root)
|
|
58
|
+
|
|
59
|
+
resolved_root = File.realpath(root)
|
|
60
|
+
target = File.join(root, bibliography)
|
|
61
|
+
resolved_target = if File.exist?(target) || File.symlink?(target)
|
|
62
|
+
File.realpath(target)
|
|
63
|
+
else
|
|
64
|
+
target
|
|
65
|
+
end
|
|
66
|
+
root_prefix = resolved_root.end_with?(File::SEPARATOR) ? resolved_root : "#{resolved_root}#{File::SEPARATOR}"
|
|
67
|
+
source_prefix = source.end_with?(File::SEPARATOR) ? source : "#{source}#{File::SEPARATOR}"
|
|
68
|
+
confined = (resolved_root == source || resolved_root.start_with?(source_prefix)) && resolved_target.start_with?(root_prefix)
|
|
69
|
+
return if confined
|
|
70
|
+
|
|
71
|
+
raise Jekyll::Errors::FatalException, "unaltraweb.manual.bibliography_file must remain under the site's _bibliography/ directory"
|
|
72
|
+
rescue Errno::ENOENT, Errno::ELOOP
|
|
73
|
+
raise Jekyll::Errors::FatalException, "unaltraweb.manual.bibliography_file must resolve safely under _bibliography/"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def strip_web_access(reference, doi = nil, *urls)
|
|
77
|
+
rendered = reference.to_s.dup
|
|
78
|
+
variants = access_variants(doi, *urls).sort_by { |value| -value.length }
|
|
79
|
+
loop do
|
|
80
|
+
previous = rendered.dup
|
|
81
|
+
variants.each do |value|
|
|
82
|
+
escaped = Regexp.escape(value)
|
|
83
|
+
rendered.sub!(%r{\s*(?:doi:\s*)?(?:<a\b[^>]*>\s*)?#{escaped}(?:\s*</a>)?\s*\.?(?=(?:\s*</[a-z][^>]*>)*\s*\z)}i, "")
|
|
84
|
+
end
|
|
85
|
+
break if rendered == previous
|
|
86
|
+
end
|
|
87
|
+
rendered.rstrip
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def access_variants(doi, *urls)
|
|
91
|
+
values = []
|
|
92
|
+
normalized_doi = doi.to_s.strip.sub(%r{\Ahttps?://(?:dx\.)?doi\.org/}i, "").sub(/\Adoi:\s*/i, "")
|
|
93
|
+
unless normalized_doi.empty?
|
|
94
|
+
values.concat([
|
|
95
|
+
"https://doi.org/#{normalized_doi}",
|
|
96
|
+
"http://doi.org/#{normalized_doi}",
|
|
97
|
+
"http://dx.doi.org/#{normalized_doi}",
|
|
98
|
+
"doi:#{normalized_doi}",
|
|
99
|
+
normalized_doi
|
|
100
|
+
])
|
|
101
|
+
end
|
|
102
|
+
urls.each { |url| values << url.to_s.strip unless url.to_s.strip.empty? }
|
|
103
|
+
values.flat_map { |value| [value, CGI.escapeHTML(value)] }.uniq
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def strip_reference_ids(reference)
|
|
107
|
+
reference.to_s.gsub(/\s+id=(['"])[^'"]*\1/i, "")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def escape_liquid_markers(value)
|
|
111
|
+
value.to_s.gsub("{{", "<span>{</span>{").gsub("{%", "<span>{</span>%")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def fold_sort_value(value)
|
|
115
|
+
BibTeX::Value.new(value.to_s).convert(:latex).to_s.unicode_normalize(:nfkd).gsub(/\p{Mn}/, "")
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module ScholarProfileRendering
|
|
120
|
+
def resolve_sort_value(entry, key)
|
|
121
|
+
value = super
|
|
122
|
+
return value unless key == "name" && unaltraweb_profile_sorting?
|
|
123
|
+
|
|
124
|
+
BibTeX::Value.new(BibliographyProfiles.fold_sort_value(value))
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def render_bibliography(entry, index = nil)
|
|
128
|
+
citation_numbers = context && context["citation_numbers"]
|
|
129
|
+
if index && unaltraweb_profile_sorting? && citation_numbers&.key?(entry.key) && unaltraweb_numeric_bibliography_style?
|
|
130
|
+
index = citation_numbers[entry.key]
|
|
131
|
+
end
|
|
132
|
+
super(entry, index)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def unaltraweb_profile_sorting?
|
|
138
|
+
BibliographyProfiles::PROFILE_SORTS.key?(site&.config&.dig("unaltraweb", "site_profile").to_s)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def unaltraweb_numeric_bibliography_style?
|
|
142
|
+
@unaltraweb_numeric_bibliography_styles ||= {}
|
|
143
|
+
@unaltraweb_numeric_bibliography_styles[style] ||= styles(style).to_xml.include?('variable="citation-number"')
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
module BibliographyProfileFilters
|
|
148
|
+
def stripBibliographyAccess(input, doi = nil, *urls)
|
|
149
|
+
BibliographyProfiles.strip_web_access(input, doi, *urls)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def stripBibliographyIds(input)
|
|
153
|
+
BibliographyProfiles.strip_reference_ids(input)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def escapeLiquidMarkers(input)
|
|
157
|
+
BibliographyProfiles.escape_liquid_markers(input)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
Jekyll::Scholar::Utilities.prepend(Unaltraweb::ScholarProfileRendering) unless Jekyll::Scholar::Utilities.ancestors.include?(Unaltraweb::ScholarProfileRendering)
|
|
163
|
+
Liquid::Template.register_filter(Unaltraweb::BibliographyProfileFilters)
|
|
164
|
+
Jekyll::Hooks.register(:site, :post_read) { |site| Unaltraweb::BibliographyProfiles.configure(site) }
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
module Unaltraweb
|
|
6
|
+
module Callouts
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
TYPES = %w[info example warning objectives danger].freeze
|
|
10
|
+
DEFAULT_LABELS = {
|
|
11
|
+
"ca" => {
|
|
12
|
+
"info" => "NOTA",
|
|
13
|
+
"example" => "EXEMPLE",
|
|
14
|
+
"warning" => "ADVERTÈNCIA",
|
|
15
|
+
"objectives" => "OBJECTIUS D'APRENENTATGE",
|
|
16
|
+
"danger" => "ATENCIÓ"
|
|
17
|
+
},
|
|
18
|
+
"es" => {
|
|
19
|
+
"info" => "NOTA",
|
|
20
|
+
"example" => "EJEMPLO",
|
|
21
|
+
"warning" => "ADVERTENCIA",
|
|
22
|
+
"objectives" => "OBJETIVOS DE APRENDIZAJE",
|
|
23
|
+
"danger" => "ATENCIÓN"
|
|
24
|
+
},
|
|
25
|
+
"en" => {
|
|
26
|
+
"info" => "NOTE",
|
|
27
|
+
"example" => "EXAMPLE",
|
|
28
|
+
"warning" => "WARNING",
|
|
29
|
+
"objectives" => "LEARNING OBJECTIVES",
|
|
30
|
+
"danger" => "CAUTION"
|
|
31
|
+
}
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
def transform_html(html, site:, lang:)
|
|
35
|
+
source = html.to_s
|
|
36
|
+
return source unless source.match?(/<blockquote(?:\s|>)/i)
|
|
37
|
+
|
|
38
|
+
fragment = Nokogiri::HTML::DocumentFragment.parse(source)
|
|
39
|
+
labels = labels_for(site, lang)
|
|
40
|
+
|
|
41
|
+
fragment.css("blockquote").each do |blockquote|
|
|
42
|
+
if blockquote.element_children.any? { |child| child.name == "blockquote" }
|
|
43
|
+
add_classes(blockquote, "uw-callout-wrapper")
|
|
44
|
+
next
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
depth = blockquote.ancestors("blockquote").length
|
|
48
|
+
next if depth.zero?
|
|
49
|
+
|
|
50
|
+
type = TYPES[[depth, TYPES.length].min - 1]
|
|
51
|
+
add_classes(blockquote, "uw-callout", "uw-callout-#{type}")
|
|
52
|
+
blockquote["data-callout"] = type
|
|
53
|
+
add_title(blockquote, labels.fetch(type))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
fragment.to_html
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def detect_lang(doc)
|
|
60
|
+
configured = doc.data["lang"].to_s
|
|
61
|
+
return normalize_lang(configured) unless configured.empty?
|
|
62
|
+
|
|
63
|
+
relative_path = doc.respond_to?(:relative_path) ? doc.relative_path.to_s : ""
|
|
64
|
+
path_lang = relative_path.tr("\\", "/").split("/")[1].to_s
|
|
65
|
+
fallback = doc.site.config["default_lang"] || doc.site.config["lang"] || "en"
|
|
66
|
+
normalize_lang(path_lang.empty? ? fallback : path_lang)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def labels_for(site, lang)
|
|
70
|
+
normalized_lang = normalize_lang(lang)
|
|
71
|
+
default_lang = normalize_lang(site.config["default_lang"] || site.config["lang"] || "en")
|
|
72
|
+
i18n = site.data["i18n"] || {}
|
|
73
|
+
configured = i18n.dig(normalized_lang, "callouts") || i18n.dig(default_lang, "callouts") || {}
|
|
74
|
+
defaults = DEFAULT_LABELS[normalized_lang] || DEFAULT_LABELS[default_lang] || DEFAULT_LABELS.fetch("en")
|
|
75
|
+
|
|
76
|
+
defaults.merge(configured.transform_keys(&:to_s).transform_values(&:to_s))
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def normalize_lang(lang)
|
|
80
|
+
lang.to_s.downcase.split("-").first.to_s.then { |value| value.empty? ? "en" : value }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def add_classes(node, *classes)
|
|
84
|
+
current = node["class"].to_s.split
|
|
85
|
+
node["class"] = (current + classes).uniq.join(" ")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def add_title(blockquote, label)
|
|
89
|
+
existing = blockquote.element_children.first
|
|
90
|
+
return if existing && existing["class"].to_s.split.include?("uw-callout-title")
|
|
91
|
+
|
|
92
|
+
title = Nokogiri::XML::Node.new("p", blockquote.document)
|
|
93
|
+
title["class"] = "uw-callout-title"
|
|
94
|
+
title["data-unaltraweb-callout-title"] = "true"
|
|
95
|
+
title.content = label
|
|
96
|
+
blockquote.prepend_child(title)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
Jekyll::Hooks.register %i[documents pages], :post_convert do |doc|
|
|
102
|
+
lang = Unaltraweb::Callouts.detect_lang(doc)
|
|
103
|
+
doc.content = Unaltraweb::Callouts.transform_html(doc.content, site: doc.site, lang: lang)
|
|
104
|
+
end
|