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.
Files changed (444) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/Makefile +412 -0
  4. data/README.md +226 -0
  5. data/_config.yml +842 -0
  6. data/_data/i18n/ca.yml +278 -0
  7. data/_data/i18n/en.yml +278 -0
  8. data/_data/i18n/es.yml +278 -0
  9. data/_includes/audio.liquid +30 -0
  10. data/_includes/bib_search.liquid +5 -0
  11. data/_includes/blog-list.liquid +66 -0
  12. data/_includes/book-citation.liquid +33 -0
  13. data/_includes/citation.liquid +26 -0
  14. data/_includes/custom_head.liquid +3 -0
  15. data/_includes/custom_scripts.liquid +5 -0
  16. data/_includes/cv/list.liquid +5 -0
  17. data/_includes/cv/list_groups.liquid +51 -0
  18. data/_includes/cv/map.liquid +29 -0
  19. data/_includes/cv/nested_list.liquid +16 -0
  20. data/_includes/cv/time_table.liquid +118 -0
  21. data/_includes/cv-download-card.liquid +26 -0
  22. data/_includes/developer-mode-switcher.liquid +24 -0
  23. data/_includes/disqus.liquid +13 -0
  24. data/_includes/distill_scripts.liquid +298 -0
  25. data/_includes/documentation-download-detail.liquid +76 -0
  26. data/_includes/documentation-downloads.liquid +71 -0
  27. data/_includes/documentation-profile-attributes.liquid +4 -0
  28. data/_includes/documentation-section-toc.liquid +9 -0
  29. data/_includes/documentation-sidebar.liquid +112 -0
  30. data/_includes/figure.liquid +87 -0
  31. data/_includes/footer.liquid +66 -0
  32. data/_includes/giscus.liquid +25 -0
  33. data/_includes/head.liquid +220 -0
  34. data/_includes/header.liquid +544 -0
  35. data/_includes/latest_posts.liquid +61 -0
  36. data/_includes/localized-date.liquid +5 -0
  37. data/_includes/manual-bibliography.liquid +2 -0
  38. data/_includes/manual-featured-readings.liquid +12 -0
  39. data/_includes/manual-other-readings.liquid +12 -0
  40. data/_includes/manual-page-toc.liquid +11 -0
  41. data/_includes/manual-sidebar.liquid +58 -0
  42. data/_includes/manual-teachers.liquid +74 -0
  43. data/_includes/metadata.liquid +278 -0
  44. data/_includes/news.liquid +48 -0
  45. data/_includes/newsletter.liquid +68 -0
  46. data/_includes/page-hero.liquid +96 -0
  47. data/_includes/page-link.liquid +8 -0
  48. data/_includes/pagination.liquid +22 -0
  49. data/_includes/post-reading-time.liquid +29 -0
  50. data/_includes/previous-next.liquid +37 -0
  51. data/_includes/profile-card.liquid +49 -0
  52. data/_includes/profile-feature-matrix.liquid +75 -0
  53. data/_includes/profile-highlights.liquid +122 -0
  54. data/_includes/project-grid.liquid +26 -0
  55. data/_includes/project-resource-link.liquid +45 -0
  56. data/_includes/project-resources.liquid +21 -0
  57. data/_includes/projects.liquid +38 -0
  58. data/_includes/projects_horizontal.liquid +37 -0
  59. data/_includes/publications-metrics-summary.liquid +69 -0
  60. data/_includes/publications-summary.liquid +127 -0
  61. data/_includes/reading-biblio-controls.liquid +65 -0
  62. data/_includes/reading-cover-card.liquid +93 -0
  63. data/_includes/reading-rating.liquid +11 -0
  64. data/_includes/recommended-readings.liquid +30 -0
  65. data/_includes/related_posts.liquid +39 -0
  66. data/_includes/repository/repo.liquid +48 -0
  67. data/_includes/repository/repo_trophies.liquid +44 -0
  68. data/_includes/repository/repo_user.liquid +35 -0
  69. data/_includes/resume/awards.liquid +19 -0
  70. data/_includes/resume/basics.liquid +28 -0
  71. data/_includes/resume/certificates.liquid +35 -0
  72. data/_includes/resume/education.liquid +54 -0
  73. data/_includes/resume/interests.liquid +34 -0
  74. data/_includes/resume/languages.liquid +31 -0
  75. data/_includes/resume/projects.liquid +32 -0
  76. data/_includes/resume/publications.liquid +28 -0
  77. data/_includes/resume/references.liquid +31 -0
  78. data/_includes/resume/skills.liquid +33 -0
  79. data/_includes/resume/volunteer.liquid +52 -0
  80. data/_includes/resume/work.liquid +52 -0
  81. data/_includes/scripts.liquid +364 -0
  82. data/_includes/search-data.js.liquid +341 -0
  83. data/_includes/selected_papers.liquid +3 -0
  84. data/_includes/t.liquid +31 -0
  85. data/_includes/team-grid.liquid +172 -0
  86. data/_includes/video.liquid +97 -0
  87. data/_layouts/about.liquid +93 -0
  88. data/_layouts/archive.liquid +45 -0
  89. data/_layouts/bib.liquid +677 -0
  90. data/_layouts/book-review.liquid +225 -0
  91. data/_layouts/book-shelf.liquid +66 -0
  92. data/_layouts/cv.liquid +127 -0
  93. data/_layouts/default.liquid +70 -0
  94. data/_layouts/distill.liquid +132 -0
  95. data/_layouts/documentation-download-detail.liquid +5 -0
  96. data/_layouts/documentation-home.liquid +100 -0
  97. data/_layouts/documentation-page.liquid +45 -0
  98. data/_layouts/manual-bib.liquid +73 -0
  99. data/_layouts/manual-chapter.liquid +99 -0
  100. data/_layouts/manual-featured-bib.liquid +100 -0
  101. data/_layouts/manual-home.liquid +120 -0
  102. data/_layouts/none.liquid +1 -0
  103. data/_layouts/outputs.liquid +29 -0
  104. data/_layouts/page.liquid +52 -0
  105. data/_layouts/post.liquid +95 -0
  106. data/_layouts/profile.liquid +36 -0
  107. data/_layouts/profiles.liquid +36 -0
  108. data/_layouts/project.liquid +7 -0
  109. data/_layouts/repositories.liquid +58 -0
  110. data/_layouts/theses.liquid +126 -0
  111. data/_plugins/bibliography_profiles.rb +164 -0
  112. data/_plugins/callouts.rb +104 -0
  113. data/_plugins/code_blocks.rb +277 -0
  114. data/_plugins/computation_figure_images.rb +266 -0
  115. data/_plugins/computation_sources.rb +42 -0
  116. data/_plugins/content_search_index.rb +210 -0
  117. data/_plugins/details.rb +23 -0
  118. data/_plugins/external-posts.rb +124 -0
  119. data/_plugins/figure_captions.rb +800 -0
  120. data/_plugins/file-exists.rb +22 -0
  121. data/_plugins/google-scholar-citations.rb +86 -0
  122. data/_plugins/hide-custom-bibtex.rb +18 -0
  123. data/_plugins/inspirehep-citations.rb +57 -0
  124. data/_plugins/localized_visual_sources.rb +145 -0
  125. data/_plugins/manual_release_metadata.rb +47 -0
  126. data/_plugins/mermaid_mmd_images.rb +233 -0
  127. data/_plugins/profile-pages.rb +28 -0
  128. data/_plugins/remove-accents.rb +32 -0
  129. data/_plugins/reproducible_build_time.rb +55 -0
  130. data/_plugins/search-data.rb +83 -0
  131. data/_plugins/theme-cache-bust.rb +56 -0
  132. data/_plugins/vega_visual_images.rb +290 -0
  133. data/_plugins/web_capture_images.rb +154 -0
  134. data/_sass/_base.scss +2133 -0
  135. data/_sass/_blog.scss +67 -0
  136. data/_sass/_callouts.scss +100 -0
  137. data/_sass/_custom.scss +437 -0
  138. data/_sass/_cv.scss +274 -0
  139. data/_sass/_developer.scss +97 -0
  140. data/_sass/_distill.scss +185 -0
  141. data/_sass/_documentation.scss +2220 -0
  142. data/_sass/_layout.scss +218 -0
  143. data/_sass/_manual.scss +2691 -0
  144. data/_sass/_profile.scss +323 -0
  145. data/_sass/_projects.scss +163 -0
  146. data/_sass/_reading.scss +465 -0
  147. data/_sass/_site-custom.scss +3 -0
  148. data/_sass/_tabs.scss +48 -0
  149. data/_sass/_team.scss +230 -0
  150. data/_sass/_themes.scss +254 -0
  151. data/_sass/_typograms.scss +132 -0
  152. data/_sass/_variables.scss +52 -0
  153. data/_sass/font-awesome/_animated.scss +152 -0
  154. data/_sass/font-awesome/_bordered-pulled.scss +20 -0
  155. data/_sass/font-awesome/_core.scss +49 -0
  156. data/_sass/font-awesome/_fixed-width.scss +7 -0
  157. data/_sass/font-awesome/_functions.scss +57 -0
  158. data/_sass/font-awesome/_icons.scss +13 -0
  159. data/_sass/font-awesome/_list.scss +18 -0
  160. data/_sass/font-awesome/_mixins.scss +65 -0
  161. data/_sass/font-awesome/_rotated-flipped.scss +31 -0
  162. data/_sass/font-awesome/_screen-reader.scss +14 -0
  163. data/_sass/font-awesome/_shims.scss +1578 -0
  164. data/_sass/font-awesome/_sizing.scss +16 -0
  165. data/_sass/font-awesome/_stacked.scss +32 -0
  166. data/_sass/font-awesome/_variables.scss +5044 -0
  167. data/_sass/font-awesome/brands.scss +30 -0
  168. data/_sass/font-awesome/fontawesome.scss +21 -0
  169. data/_sass/font-awesome/regular.scss +27 -0
  170. data/_sass/font-awesome/solid.scss +27 -0
  171. data/_sass/font-awesome/v4-shims.scss +11 -0
  172. data/_sass/tabler-icons/tabler-icons-filled.scss +1646 -0
  173. data/_sass/tabler-icons/tabler-icons-outline.scss +9859 -0
  174. data/_sass/tabler-icons/tabler-icons.scss +11463 -0
  175. data/_scripts/cronitor-analytics-setup.js +9 -0
  176. data/_scripts/giscus-setup.js +48 -0
  177. data/_scripts/google-analytics-setup.js +9 -0
  178. data/_scripts/open-panel-analytics-setup.js +14 -0
  179. data/_scripts/photoswipe-setup.js +11 -0
  180. data/assets/audio/epicaly-short-113909.mp3 +0 -0
  181. data/assets/bibliography/2018-12-22-distill.bib +7 -0
  182. data/assets/css/academicons.min.css +1 -0
  183. data/assets/css/bootstrap-toc.min.css +4 -0
  184. data/assets/css/bootstrap.min.css +7 -0
  185. data/assets/css/bootstrap.min.css.map +1 -0
  186. data/assets/css/jekyll-pygments-themes-github.css +209 -0
  187. data/assets/css/jekyll-pygments-themes-native.css +232 -0
  188. data/assets/css/jupyter-grade3.css +3758 -0
  189. data/assets/css/jupyter-monokai.css +3758 -0
  190. data/assets/css/jupyter.css +383 -0
  191. data/assets/css/main.scss +36 -0
  192. data/assets/css/mdb.min.css +48 -0
  193. data/assets/css/mdb.min.css.map +1 -0
  194. data/assets/css/scholar-icons.css +386 -0
  195. data/assets/fonts/academicons.ttf +0 -0
  196. data/assets/fonts/academicons.woff +0 -0
  197. data/assets/fonts/scholar-icons.ttf +0 -0
  198. data/assets/fonts/scholar-icons.woff +0 -0
  199. data/assets/fonts/tabler-icons-filled.ttf +0 -0
  200. data/assets/fonts/tabler-icons-filled.woff +0 -0
  201. data/assets/fonts/tabler-icons-filled.woff2 +0 -0
  202. data/assets/fonts/tabler-icons-outline.ttf +0 -0
  203. data/assets/fonts/tabler-icons-outline.woff +0 -0
  204. data/assets/fonts/tabler-icons-outline.woff2 +0 -0
  205. data/assets/fonts/tabler-icons.ttf +0 -0
  206. data/assets/fonts/tabler-icons.woff +0 -0
  207. data/assets/fonts/tabler-icons.woff2 +0 -0
  208. data/assets/html/relativity.html +15 -0
  209. data/assets/img/1.jpg +0 -0
  210. data/assets/img/10.jpg +0 -0
  211. data/assets/img/11.jpg +0 -0
  212. data/assets/img/12.jpg +0 -0
  213. data/assets/img/2.jpg +0 -0
  214. data/assets/img/3.jpg +0 -0
  215. data/assets/img/4.jpg +0 -0
  216. data/assets/img/5.jpg +0 -0
  217. data/assets/img/6.jpg +0 -0
  218. data/assets/img/7.jpg +0 -0
  219. data/assets/img/8.jpg +0 -0
  220. data/assets/img/9.jpg +0 -0
  221. data/assets/img/book_covers/the_godfather.jpg +0 -0
  222. data/assets/img/brand/dosquartsdedocs-logo-cafe.svg +31 -0
  223. data/assets/img/brand/dosquartsdedocs-logo-footer-cafe.svg +31 -0
  224. data/assets/img/brand/dosquartsdedocs-logo-white.svg +31 -0
  225. data/assets/img/brand/dosquartsdedocs-logo.svg +31 -0
  226. data/assets/img/prof_pic.jpg +0 -0
  227. data/assets/img/prof_pic_color.png +0 -0
  228. data/assets/img/profile-placeholder.svg +8 -0
  229. data/assets/img/publication_preview/brownian-motion.gif +0 -0
  230. data/assets/img/publication_preview/goodchild1992-gis-cover.jpg +0 -0
  231. data/assets/img/publication_preview/gutierrez2020-jtrg-preview.jpg +0 -0
  232. data/assets/img/publication_preview/harvey1989-postmodernity-cover.jpg +0 -0
  233. data/assets/img/publication_preview/tobler1970-economic-geography-cover.jpg +0 -0
  234. data/assets/img/publication_preview/tuan1977-space-place-cover.jpg +0 -0
  235. data/assets/img/publication_preview/wave-mechanics.gif +0 -0
  236. data/assets/img/publication_preview/zaragozi2025-rooftop-pv-preview.jpg +0 -0
  237. data/assets/img/rhino.png +0 -0
  238. data/assets/img/team/aaron-gutierrez.png +0 -0
  239. data/assets/img/team/alba-font.png +0 -0
  240. data/assets/img/team/alba-viana.png +0 -0
  241. data/assets/img/team/alejandro-gonzalez.png +0 -0
  242. data/assets/img/team/ana-pastor.png +0 -0
  243. data/assets/img/team/antoni-domenech.png +0 -0
  244. data/assets/img/team/benito-zaragozi.png +0 -0
  245. data/assets/img/team/cinta-sanz.png +0 -0
  246. data/assets/img/team/daniel-miravet.png +0 -0
  247. data/assets/img/team/eugenia-altamirano.png +0 -0
  248. data/assets/img/team/fiammetta-brandajs.png +0 -0
  249. data/assets/img/team/francesc-gonzalez.png +0 -0
  250. data/assets/img/team/isabel-paulino.png +0 -0
  251. data/assets/img/team/joan-borras.png +0 -0
  252. data/assets/img/team/julie-wilson.png +0 -0
  253. data/assets/img/team/liliana-sole.png +0 -0
  254. data/assets/img/team/maria-casado.png +0 -0
  255. data/assets/img/team/maria-medina.png +0 -0
  256. data/assets/img/team/marta-nello.png +0 -0
  257. data/assets/img/team/mogrify +1 -0
  258. data/assets/img/team/oscar-saladie.png +0 -0
  259. data/assets/img/team/paolo-russo.png +0 -0
  260. data/assets/img/team/raquel-santos.png +0 -0
  261. data/assets/img/team/salvador-anton.png +0 -0
  262. data/assets/img/team/sunsi-huertas.png +0 -0
  263. data/assets/img/team/user-placeholder.png +0 -0
  264. data/assets/img/team/wilbert-den-hoed.png +0 -0
  265. data/assets/img/team/xavier-delclos.png +0 -0
  266. data/assets/img/template_error.png +0 -0
  267. data/assets/js/bibsearch.js +70 -0
  268. data/assets/js/bootstrap-toc.min.js +5 -0
  269. data/assets/js/bootstrap.bundle.min.js +7 -0
  270. data/assets/js/bootstrap.bundle.min.js.map +1 -0
  271. data/assets/js/callouts.js +115 -0
  272. data/assets/js/chartjs-setup.js +14 -0
  273. data/assets/js/common.js +117 -0
  274. data/assets/js/content-search-match.js +159 -0
  275. data/assets/js/content-search.js +441 -0
  276. data/assets/js/copy_code.js +60 -0
  277. data/assets/js/custom.js +6 -0
  278. data/assets/js/developer-mode.js +103 -0
  279. data/assets/js/diff2html-setup.js +20 -0
  280. data/assets/js/distillpub/overrides.js +27 -0
  281. data/assets/js/distillpub/template.v2.js +9616 -0
  282. data/assets/js/distillpub/template.v2.js.map +1 -0
  283. data/assets/js/distillpub/transforms.v2.js +14557 -0
  284. data/assets/js/distillpub/transforms.v2.js.map +1 -0
  285. data/assets/js/documentation.js +435 -0
  286. data/assets/js/echarts-setup.js +29 -0
  287. data/assets/js/highlight-search-term.js +110 -0
  288. data/assets/js/jupyter_new_tab.js +18 -0
  289. data/assets/js/leaflet-setup.js +22 -0
  290. data/assets/js/manual.js +308 -0
  291. data/assets/js/masonry.js +12 -0
  292. data/assets/js/mathjax-setup.js +46 -0
  293. data/assets/js/mermaid-setup.js +37 -0
  294. data/assets/js/newsletter.js +105 -0
  295. data/assets/js/no_defer.js +24 -0
  296. data/assets/js/plotly-setup.js +52 -0
  297. data/assets/js/profile-nav.js +92 -0
  298. data/assets/js/progress-bar.js +73 -0
  299. data/assets/js/pseudocode-setup.js +18 -0
  300. data/assets/js/search/base-styles.min.js +286 -0
  301. data/assets/js/search/command-score.min.js +7 -0
  302. data/assets/js/search/hotkeys-js/hotkeys.esm.min.js +18 -0
  303. data/assets/js/search/lit/decorators.min.js +7 -0
  304. data/assets/js/search/lit/directives/class-map.min.js +7 -0
  305. data/assets/js/search/lit/directives/join.min.js +7 -0
  306. data/assets/js/search/lit/directives/live.min.js +7 -0
  307. data/assets/js/search/lit/directives/ref.min.js +7 -0
  308. data/assets/js/search/lit/directives/repeat.min.js +7 -0
  309. data/assets/js/search/lit/directives/unsafe-html.min.js +7 -0
  310. data/assets/js/search/lit/index.min.js +7 -0
  311. data/assets/js/search/lit-element/lit-element.min.js +12 -0
  312. data/assets/js/search/lit-html/directives/class-map.min.js +22 -0
  313. data/assets/js/search/lit-html/directives/join.min.js +12 -0
  314. data/assets/js/search/lit-html/directives/live.min.js +28 -0
  315. data/assets/js/search/lit-html/directives/ref.min.js +32 -0
  316. data/assets/js/search/lit-html/directives/repeat.min.js +27 -0
  317. data/assets/js/search/lit-html/directives/unsafe-html.min.js +22 -0
  318. data/assets/js/search/lit-html/is-server.min.js +12 -0
  319. data/assets/js/search/lit-html/lit-html.min.js +12 -0
  320. data/assets/js/search/ninja-action.min.js +101 -0
  321. data/assets/js/search/ninja-footer.min.js +62 -0
  322. data/assets/js/search/ninja-header.min.js +78 -0
  323. data/assets/js/search/ninja-keys.min.js +39 -0
  324. data/assets/js/search/reactive-element/decorators/custom-element.min.js +12 -0
  325. data/assets/js/search/reactive-element/decorators/event-options.min.js +12 -0
  326. data/assets/js/search/reactive-element/decorators/property.min.js +22 -0
  327. data/assets/js/search/reactive-element/decorators/query-all.min.js +17 -0
  328. data/assets/js/search/reactive-element/decorators/query-assigned-elements.min.js +17 -0
  329. data/assets/js/search/reactive-element/decorators/query-assigned-nodes.min.js +17 -0
  330. data/assets/js/search/reactive-element/decorators/query-async.min.js +17 -0
  331. data/assets/js/search/reactive-element/decorators/query.min.js +17 -0
  332. data/assets/js/search/reactive-element/decorators/state.min.js +27 -0
  333. data/assets/js/search/reactive-element/reactive-element.min.js +17 -0
  334. data/assets/js/search-setup.js +17 -0
  335. data/assets/js/shortcut-key.js +11 -0
  336. data/assets/js/tabs.min.js +5 -0
  337. data/assets/js/theme.js +314 -0
  338. data/assets/js/tooltips-setup.js +3 -0
  339. data/assets/js/typograms.js +1341 -0
  340. data/assets/js/vanilla-back-to-top.min.js +1 -0
  341. data/assets/js/vega-setup.js +24 -0
  342. data/assets/js/venobox-setup.js +5 -0
  343. data/assets/js/wechat.js +14 -0
  344. data/assets/js/zoom.js +15 -0
  345. data/assets/json/resume.json +98 -0
  346. data/assets/json/table_data.json +128 -0
  347. data/assets/jupyter/blog.ipynb +48 -0
  348. data/assets/pdf/example_pdf.pdf +0 -0
  349. data/assets/plotly/demo.html +72 -0
  350. data/assets/video/pexels-engin-akyurt-6069112-960x540-30fps.mp4 +0 -0
  351. data/assets/webfonts/fa-brands-400.ttf +0 -0
  352. data/assets/webfonts/fa-brands-400.woff2 +0 -0
  353. data/assets/webfonts/fa-regular-400.ttf +0 -0
  354. data/assets/webfonts/fa-regular-400.woff2 +0 -0
  355. data/assets/webfonts/fa-solid-900.ttf +0 -0
  356. data/assets/webfonts/fa-solid-900.woff2 +0 -0
  357. data/assets/webfonts/fa-v4compatibility.ttf +0 -0
  358. data/assets/webfonts/fa-v4compatibility.woff2 +0 -0
  359. data/docs/Gemfile +5 -0
  360. data/docs/_config.yml +83 -0
  361. data/docs/_documentation/en/01-quick-start.md +115 -0
  362. data/docs/_documentation/en/02-tools.md +146 -0
  363. data/docs/_documentation/en/03-usage.md +107 -0
  364. data/docs/_documentation/en/04-jekyll-basics.md +51 -0
  365. data/docs/_documentation/en/05-pages-collections.md +68 -0
  366. data/docs/_documentation/en/06-github-web-editing.md +92 -0
  367. data/docs/_documentation/en/10-profiles.md +125 -0
  368. data/docs/_documentation/en/11-unaltreselfie.md +39 -0
  369. data/docs/_documentation/en/12-unaltreprojecte.md +38 -0
  370. data/docs/_documentation/en/13-unaltremanual.md +237 -0
  371. data/docs/_documentation/en/14-unaltredocs.md +92 -0
  372. data/docs/_documentation/en/15-profile-checklist.md +39 -0
  373. data/docs/_documentation/en/20-syntax.md +353 -0
  374. data/docs/_documentation/en/21-themes.md +103 -0
  375. data/docs/_documentation/en/22-feature-reference.md +56 -0
  376. data/docs/_documentation/en/23-front-matter.md +51 -0
  377. data/docs/_documentation/en/24-data-files.md +28 -0
  378. data/docs/_documentation/en/30-customization.md +448 -0
  379. data/docs/_documentation/en/31-template.md +55 -0
  380. data/docs/_documentation/en/32-development.md +108 -0
  381. data/docs/_documentation/en/33-reusable-workflows.md +136 -0
  382. data/docs/_documentation/en/40-distribution.md +164 -0
  383. data/docs/_documentation/en/41-bibliometrics.md +137 -0
  384. data/docs/_documentation/en/42-docker-image.md +185 -0
  385. data/docs/_documentation/en/50-faq.md +33 -0
  386. data/docs/_pages/ca/index.md +35 -0
  387. data/docs/_pages/en/index.md +35 -0
  388. data/docs/_pages/es/index.md +35 -0
  389. data/docs/agents/action-prompts/00-start-site-session.txt +10 -0
  390. data/docs/agents/action-prompts/05-create-new-web.txt +5 -0
  391. data/docs/agents/action-prompts/10-content-update.txt +9 -0
  392. data/docs/agents/action-prompts/15-edit-default-content.txt +8 -0
  393. data/docs/agents/action-prompts/20-manual-teaching-materials.txt +18 -0
  394. data/docs/agents/action-prompts/22-manual-style-audit.txt +14 -0
  395. data/docs/agents/action-prompts/23-manual-structure-audit.txt +17 -0
  396. data/docs/agents/action-prompts/25-translation-prepublish.txt +8 -0
  397. data/docs/agents/action-prompts/30-project-site-update.txt +7 -0
  398. data/docs/agents/action-prompts/40-documentation-update.txt +7 -0
  399. data/docs/agents/action-prompts/50-bibliography-entry.txt +7 -0
  400. data/docs/agents/action-prompts/60-bibliometrics-refresh.txt +7 -0
  401. data/docs/agents/action-prompts/70-build-and-review.txt +12 -0
  402. data/docs/agents/manual-authoring-components.md +255 -0
  403. data/docs/agents/mcp-contract.md +162 -0
  404. data/docs/agents/quarto-computation-adoption.md +102 -0
  405. data/docs/assets/img/unaltraweb-docs-hero.svg +36 -0
  406. data/lib/unaltraweb/version.rb +8 -0
  407. data/lib/unaltraweb.rb +31 -0
  408. data/requirements.txt +5 -0
  409. data/scripts/biblio/fetch_scimago_csv.sh +126 -0
  410. data/scripts/biblio/metrics_common.py +154 -0
  411. data/scripts/biblio/metrics_merge_meta.py +73 -0
  412. data/scripts/biblio/metrics_update.py +826 -0
  413. data/scripts/computations/python/Dockerfile +37 -0
  414. data/scripts/computations/r/Dockerfile +31 -0
  415. data/scripts/computations/render.py +1267 -0
  416. data/scripts/cv/render_pdf_preview.sh +36 -0
  417. data/scripts/deploy/publish_branch.sh +80 -0
  418. data/scripts/generate_logo_variants.py +47 -0
  419. data/scripts/manual/Dockerfile +31 -0
  420. data/scripts/manual/build_pdf.py +1780 -0
  421. data/scripts/manual/filters/bibliography.lua +164 -0
  422. data/scripts/manual/filters/code-blocks.lua +102 -0
  423. data/scripts/manual/filters/figure-captions.lua +35 -0
  424. data/scripts/manual/publish_release.sh +281 -0
  425. data/scripts/manual/templates/manual.tex +494 -0
  426. data/scripts/manual/verify_release_assets.py +650 -0
  427. data/scripts/test_gem_build.py +128 -0
  428. data/scripts/test_reproducible_jekyll_build.py +191 -0
  429. data/scripts/test_wheel_install.py +282 -0
  430. data/scripts/unaltraweb-docker-mount.sh +36 -0
  431. data/scripts/unaltraweb-mcp-bootstrap.sh +105 -0
  432. data/scripts/unaltraweb-mcp-cleanup.sh +73 -0
  433. data/scripts/unaltraweb-mcp-project-id.sh +34 -0
  434. data/scripts/validate_distribution.py +563 -0
  435. data/scripts/validate_workflows.py +1285 -0
  436. data/scripts/web_captures/Dockerfile +31 -0
  437. data/scripts/web_captures/capture.mjs +157 -0
  438. data/scripts/web_captures/package-lock.json +56 -0
  439. data/scripts/web_captures/package.json +9 -0
  440. data/scripts/web_captures/render.py +867 -0
  441. data/src/unaltraweb_mcp/component-contract.json +153 -0
  442. data/src/unaltraweb_mcp/component-contract.schema.json +87 -0
  443. data/src/unaltraweb_mcp/docker_mount.py +19 -0
  444. metadata +861 -0
@@ -0,0 +1,441 @@
1
+ (function () {
2
+ "use strict";
3
+
4
+ var matcher = window.UnaltrawebContentSearchMatch;
5
+ var searchIndexPromises = {};
6
+ var DOCUMENTATION_PROFILE_STORAGE_KEY = "unaltrawebDocumentationProfile";
7
+ var DOCUMENTATION_PROFILE_PARAM = "doc_profile";
8
+ var MAX_RENDERED_RESULTS = 24;
9
+ var MAX_QUERY_LENGTH = 120;
10
+ var BLOCK_TAGS = ["address", "article", "aside", "blockquote", "div", "dl", "dt", "dd", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hr", "li", "main", "ol", "p", "pre", "section", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "ul"];
11
+ var DYNAMIC_SOURCE_CLASSES = ["language-mermaid", "language-vega_lite", "language-plotly", "language-echarts", "language-geojson", "language-diff2html"];
12
+
13
+ if (!matcher) return;
14
+
15
+ function defaultSearchUrl() {
16
+ var input = document.querySelector("[data-content-search]");
17
+ if (input && input.dataset.contentSearchUrl) return input.dataset.contentSearchUrl;
18
+ if (window.unaltrawebContentSearchUrl) return window.unaltrawebContentSearchUrl;
19
+ return "/assets/js/content-search-index.json";
20
+ }
21
+
22
+ function loadSearchIndex(url) {
23
+ var resolvedUrl = url || defaultSearchUrl();
24
+ if (!searchIndexPromises[resolvedUrl]) {
25
+ searchIndexPromises[resolvedUrl] = fetch(resolvedUrl, { credentials: "same-origin" }).then(function (response) {
26
+ if (!response.ok) throw new Error("Content search index unavailable");
27
+ return response.json();
28
+ }).catch(function () { return []; });
29
+ }
30
+ return searchIndexPromises[resolvedUrl];
31
+ }
32
+
33
+ function normalizeProfileToken(value) {
34
+ return (value || "").toString().trim().toLowerCase();
35
+ }
36
+
37
+ function storedDocumentationProfile() {
38
+ try {
39
+ return localStorage.getItem(DOCUMENTATION_PROFILE_STORAGE_KEY);
40
+ } catch (_error) {
41
+ return "";
42
+ }
43
+ }
44
+
45
+ function readDocumentationProfile() {
46
+ var switcher = document.querySelector("[data-documentation-profile-switcher]");
47
+ if (!switcher) return "";
48
+ var params = new URLSearchParams(window.location.search);
49
+ var profile = params.has(DOCUMENTATION_PROFILE_PARAM)
50
+ ? normalizeProfileToken(params.get(DOCUMENTATION_PROFILE_PARAM))
51
+ : normalizeProfileToken(storedDocumentationProfile());
52
+ if (!profile) return "";
53
+ var hasProfileOption = Array.prototype.slice.call(switcher.querySelectorAll("[data-documentation-profile-select] option")).some(function (option) {
54
+ return normalizeProfileToken(option.value) === profile;
55
+ });
56
+ return hasProfileOption ? profile : "";
57
+ }
58
+
59
+ function documentationSearchProfileEnabled() {
60
+ return (document.documentElement.getAttribute("data-site-profile") || "") === "unaltredocs";
61
+ }
62
+
63
+ function entryMatchesDocumentationProfile(entry, activeProfile) {
64
+ if (!activeProfile) return true;
65
+ var profiles = entry && Array.isArray(entry.documentation_profile_slugs) ? entry.documentation_profile_slugs : [];
66
+ return profiles.length === 0 || profiles.indexOf(activeProfile) !== -1;
67
+ }
68
+
69
+ function filteredEntries(entries) {
70
+ var lang = (document.documentElement.getAttribute("lang") || "").toLowerCase();
71
+ var activeProfile = documentationSearchProfileEnabled() ? readDocumentationProfile() : "";
72
+ return entries.filter(function (entry) {
73
+ if (entry.lang && lang && entry.lang.toLowerCase() !== lang) return false;
74
+ return !activeProfile || entryMatchesDocumentationProfile(entry, activeProfile);
75
+ });
76
+ }
77
+
78
+ function occurrenceResults(entries, query) {
79
+ var pageResultSets = [];
80
+ filteredEntries(entries).forEach(function (entry) {
81
+ var pageResults = [];
82
+ var segments = Array.isArray(entry.segments) && entry.segments.length ? entry.segments : [entry.body || ""];
83
+ segments.forEach(function (source) {
84
+ matcher.findOccurrences(source, query).forEach(function (occurrence) {
85
+ pageResults.push({
86
+ source: source,
87
+ entry: entry,
88
+ occurrence: occurrence
89
+ });
90
+ });
91
+ });
92
+ pageResults.forEach(function (result, index) {
93
+ Object.assign(result, {
94
+ entry: entry,
95
+ occurrenceNumber: index + 1,
96
+ pageOccurrenceTotal: pageResults.length
97
+ });
98
+ });
99
+ if (pageResults.length) pageResultSets.push(pageResults);
100
+ });
101
+ var results = [];
102
+ for (var occurrenceIndex = 0; pageResultSets.some(function (pageResults) { return occurrenceIndex < pageResults.length; }); occurrenceIndex += 1) {
103
+ pageResultSets.forEach(function (pageResults) {
104
+ if (pageResults[occurrenceIndex]) results.push(pageResults[occurrenceIndex]);
105
+ });
106
+ }
107
+ return results;
108
+ }
109
+
110
+ function searchBox(input) {
111
+ return input.closest("[data-content-search-box]") || input.parentElement;
112
+ }
113
+
114
+ function setPanelOpen(input, panel, open) {
115
+ panel.hidden = !open;
116
+ input.setAttribute("aria-expanded", open ? "true" : "false");
117
+ }
118
+
119
+ function resultUrl(value, query, occurrenceNumber) {
120
+ var target;
121
+ try {
122
+ target = new URL(value || "#", window.location.origin);
123
+ } catch (_error) {
124
+ return "#";
125
+ }
126
+ if (target.origin !== window.location.origin) return "#";
127
+ target.searchParams.set("h", query);
128
+ target.searchParams.set("hit", occurrenceNumber.toString());
129
+ var current = new URLSearchParams(window.location.search);
130
+ if (current.has(DOCUMENTATION_PROFILE_PARAM) && !target.searchParams.has(DOCUMENTATION_PROFILE_PARAM)) {
131
+ target.searchParams.set(DOCUMENTATION_PROFILE_PARAM, current.get(DOCUMENTATION_PROFILE_PARAM));
132
+ }
133
+ return target.pathname + target.search + target.hash;
134
+ }
135
+
136
+ function entryMeta(entry) {
137
+ return [entry.section, entry.subsection].filter(Boolean).join(" / ");
138
+ }
139
+
140
+ function formatLabel(template, current, total) {
141
+ return (template || "Match {current} of {total}")
142
+ .replace("{current}", current.toString())
143
+ .replace("{total}", total.toString());
144
+ }
145
+
146
+ function appendExcerpt(parent, body, occurrence) {
147
+ var parts = matcher.excerptParts(body, occurrence);
148
+ parent.appendChild(document.createTextNode(parts.before));
149
+ var mark = document.createElement("mark");
150
+ mark.textContent = parts.match;
151
+ parent.appendChild(mark);
152
+ parent.appendChild(document.createTextNode(parts.after));
153
+ }
154
+
155
+ function renderSearchResults(input, entries, query) {
156
+ var box = searchBox(input);
157
+ if (!box) return;
158
+ var panel = box.querySelector("[data-content-search-results]");
159
+ var list = box.querySelector("[data-content-search-list]");
160
+ if (!panel || !list) return;
161
+
162
+ query = (query || "").toString().slice(0, MAX_QUERY_LENGTH);
163
+ list.replaceChildren();
164
+ if (!query || query.trim().length < 2) {
165
+ setPanelOpen(input, panel, false);
166
+ return;
167
+ }
168
+
169
+ var matches = occurrenceResults(entries, query);
170
+ matches.slice(0, MAX_RENDERED_RESULTS).forEach(function (result) {
171
+ var item = document.createElement("li");
172
+ var link = document.createElement("a");
173
+ link.href = resultUrl(result.entry.url, query, result.occurrenceNumber);
174
+ link.textContent = result.entry.title;
175
+ item.appendChild(link);
176
+
177
+ var metaParts = [entryMeta(result.entry), formatLabel(
178
+ input.dataset.contentSearchMatch,
179
+ result.occurrenceNumber,
180
+ result.pageOccurrenceTotal
181
+ )].filter(Boolean);
182
+ var meta = document.createElement("small");
183
+ meta.className = "content-search-meta";
184
+ meta.textContent = metaParts.join(" / ");
185
+ item.appendChild(meta);
186
+
187
+ var text = document.createElement("p");
188
+ appendExcerpt(text, result.source, result.occurrence);
189
+ item.appendChild(text);
190
+ list.appendChild(item);
191
+ });
192
+
193
+ if (!matches.length) {
194
+ var empty = document.createElement("li");
195
+ empty.className = "content-search-empty";
196
+ empty.textContent = input.dataset.contentSearchEmpty || panel.dataset.contentSearchEmpty || "No results";
197
+ list.appendChild(empty);
198
+ }
199
+ setPanelOpen(input, panel, true);
200
+ }
201
+
202
+ function setupSearch() {
203
+ document.querySelectorAll("[data-content-search]").forEach(function (input) {
204
+ if (input.dataset.contentSearchReady) return;
205
+ input.dataset.contentSearchReady = "true";
206
+ var run = function () {
207
+ var query = input.value;
208
+ loadSearchIndex(input.dataset.contentSearchUrl).then(function (entries) {
209
+ renderSearchResults(input, entries, query);
210
+ });
211
+ };
212
+ input.addEventListener("input", run);
213
+ input.addEventListener("focus", run);
214
+ input.addEventListener("keydown", function (event) {
215
+ if (event.key !== "Escape") return;
216
+ var box = searchBox(input);
217
+ var panel = box && box.querySelector("[data-content-search-results]");
218
+ if (panel) setPanelOpen(input, panel, false);
219
+ });
220
+ });
221
+ }
222
+
223
+ function closeSearchPanels(event) {
224
+ document.querySelectorAll("[data-content-search-box]").forEach(function (box) {
225
+ if (box.contains(event.target)) return;
226
+ var input = box.querySelector("[data-content-search]");
227
+ var panel = box.querySelector("[data-content-search-results]");
228
+ if (input && panel) setPanelOpen(input, panel, false);
229
+ });
230
+ }
231
+
232
+ function rerenderSearchResults() {
233
+ document.querySelectorAll("[data-content-search]").forEach(function (input) {
234
+ if (!input.dataset.contentSearchReady || !input.value || input.value.trim().length < 2) return;
235
+ loadSearchIndex(input.dataset.contentSearchUrl).then(function (entries) {
236
+ renderSearchResults(input, entries, input.value);
237
+ });
238
+ });
239
+ }
240
+
241
+ function contentRoot() {
242
+ var configured = window.unaltrawebContentSearchTarget;
243
+ var configuredRoot = configured ? document.querySelector(configured) : null;
244
+ if (configuredRoot) return configuredRoot;
245
+ var input = document.querySelector("[data-content-search-target]");
246
+ var inputRoot = input && input.dataset.contentSearchTarget ? document.querySelector(input.dataset.contentSearchTarget) : null;
247
+ if (inputRoot) return inputRoot;
248
+ return document.querySelector("[data-content-search-root], .manual-content, .documentation-content");
249
+ }
250
+
251
+ function dynamicSource(element) {
252
+ return element.tagName.toLowerCase() === "code" && DYNAMIC_SOURCE_CLASSES.some(function (className) {
253
+ return element.classList.contains(className);
254
+ });
255
+ }
256
+
257
+ function excludedElement(element) {
258
+ return element.matches("script, style, template, noscript, textarea, input, select, button, nav, [hidden], [inert], [aria-hidden='true'], .content-search-navigation, .documentation-index, .mermaid, .vega-lite, .echarts, .map, .diff2html, .js-plotly-plot") || dynamicSource(element);
259
+ }
260
+
261
+ function searchableTextStream(content) {
262
+ var rawText = "";
263
+ var rawRanges = [];
264
+
265
+ function appendSpace() {
266
+ if (rawText && !/\s$/u.test(rawText)) rawText += " ";
267
+ }
268
+
269
+ function visit(node) {
270
+ Array.prototype.forEach.call(node.childNodes, function (child) {
271
+ if (child.nodeType === Node.TEXT_NODE) {
272
+ if (!child.nodeValue) return;
273
+ var start = rawText.length;
274
+ rawText += child.nodeValue;
275
+ rawRanges.push({ node: child, start: start, end: rawText.length });
276
+ return;
277
+ }
278
+ if (child.nodeType !== Node.ELEMENT_NODE || excludedElement(child)) return;
279
+ var tagName = child.tagName.toLowerCase();
280
+ var block = BLOCK_TAGS.indexOf(tagName) !== -1 || tagName === "br";
281
+ if (block) appendSpace();
282
+ if (tagName !== "br") visit(child);
283
+ if (block) appendSpace();
284
+ });
285
+ }
286
+
287
+ visit(content);
288
+ var collapsed = matcher.collapseWhitespaceWithMap(rawText);
289
+ return { text: collapsed.text, ranges: rawRanges, starts: collapsed.starts, ends: collapsed.ends };
290
+ }
291
+
292
+ function markContentOccurrences(content, query, requestedHit) {
293
+ var stream = searchableTextStream(content);
294
+ var occurrences = matcher.findOccurrences(stream.text, query);
295
+ if (!occurrences.length) return null;
296
+ var groups = [];
297
+ occurrences.forEach(function (occurrence, occurrenceIndex) {
298
+ var rawOccurrenceStart = stream.starts[occurrence.start];
299
+ var rawOccurrenceEnd = stream.ends[occurrence.end - 1];
300
+ stream.ranges.forEach(function (range) {
301
+ var overlapStart = Math.max(rawOccurrenceStart, range.start);
302
+ var overlapEnd = Math.min(rawOccurrenceEnd, range.end);
303
+ if (overlapStart >= overlapEnd) return;
304
+ var localStart = overlapStart - range.start;
305
+ var localEnd = overlapEnd - range.start;
306
+ while (localStart < localEnd && /\s/u.test(range.node.nodeValue[localStart])) localStart += 1;
307
+ while (localEnd > localStart && /\s/u.test(range.node.nodeValue[localEnd - 1])) localEnd -= 1;
308
+ if (localStart >= localEnd) return;
309
+ var group = groups.find(function (candidate) { return candidate.node === range.node; });
310
+ if (!group) {
311
+ group = { node: range.node, parts: [] };
312
+ groups.push(group);
313
+ }
314
+ group.parts.push({
315
+ start: localStart,
316
+ end: localEnd,
317
+ hitNumber: occurrenceIndex + 1
318
+ });
319
+ });
320
+ });
321
+
322
+ var activeHit = Math.min(Math.max(requestedHit, 1), occurrences.length);
323
+ var activeMark = null;
324
+ groups.forEach(function (group) {
325
+ var fragment = document.createDocumentFragment();
326
+ var cursor = 0;
327
+ group.parts.forEach(function (part) {
328
+ fragment.appendChild(document.createTextNode(group.node.nodeValue.slice(cursor, part.start)));
329
+ var mark = document.createElement("mark");
330
+ mark.className = "content-search-hit";
331
+ mark.textContent = group.node.nodeValue.slice(part.start, part.end);
332
+ if (part.hitNumber === activeHit) {
333
+ mark.classList.add("content-search-hit-active");
334
+ if (!activeMark) {
335
+ mark.setAttribute("aria-current", "true");
336
+ mark.setAttribute("tabindex", "-1");
337
+ activeMark = mark;
338
+ }
339
+ }
340
+ fragment.appendChild(mark);
341
+ cursor = part.end;
342
+ });
343
+ fragment.appendChild(document.createTextNode(group.node.nodeValue.slice(cursor)));
344
+ group.node.parentNode.replaceChild(fragment, group.node);
345
+ });
346
+ return { activeHit: activeHit, activeMark: activeMark, total: occurrences.length };
347
+ }
348
+
349
+ function revealActiveOccurrence(mark) {
350
+ var ancestor = mark && mark.parentElement;
351
+ while (ancestor) {
352
+ if (ancestor.tagName && ancestor.tagName.toLowerCase() === "details") ancestor.open = true;
353
+ if (ancestor.classList.contains("hidden")) ancestor.classList.add("open");
354
+ if (ancestor.classList.contains("collapse")) ancestor.classList.add("show");
355
+ if (ancestor.classList.contains("unloaded")) ancestor.classList.remove("unloaded");
356
+ if (ancestor.tagName && ancestor.tagName.toLowerCase() === "li" && ancestor.parentElement && ancestor.parentElement.classList.contains("tab-content")) {
357
+ ancestor.classList.add("active");
358
+ }
359
+ ancestor = ancestor.parentElement;
360
+ }
361
+ }
362
+
363
+ function normalizedPath(value) {
364
+ var url = new URL(value, window.location.origin);
365
+ return url.pathname.replace(/index\.html$/, "").replace(/\/$/, "") || "/";
366
+ }
367
+
368
+ function addNavigationLink(container, className, label, result, query) {
369
+ if (!result) return;
370
+ var link = document.createElement("a");
371
+ link.className = className;
372
+ link.href = resultUrl(result.entry.url, query, result.occurrenceNumber);
373
+ link.textContent = label;
374
+ container.appendChild(link);
375
+ }
376
+
377
+ function addOccurrenceNavigation(content, entries, query, marked, input) {
378
+ var results = occurrenceResults(entries, query);
379
+ var currentPath = normalizedPath(window.location.href);
380
+ var resultIndex = results.findIndex(function (result) {
381
+ return normalizedPath(result.entry.url) === currentPath && result.occurrenceNumber === marked.activeHit;
382
+ });
383
+ var current = resultIndex >= 0 ? resultIndex + 1 : marked.activeHit;
384
+ var total = resultIndex >= 0 ? results.length : marked.total;
385
+ var navigation = document.createElement("nav");
386
+ navigation.className = "content-search-navigation";
387
+ navigation.setAttribute("aria-label", input.dataset.contentSearchResultsLabel || "Search results");
388
+
389
+ var status = document.createElement("span");
390
+ status.className = "content-search-navigation-status";
391
+ status.setAttribute("aria-live", "polite");
392
+ status.textContent = formatLabel(input.dataset.contentSearchMatch, current, total);
393
+ navigation.appendChild(status);
394
+
395
+ var links = document.createElement("span");
396
+ links.className = "content-search-navigation-links";
397
+ if (resultIndex >= 0) {
398
+ addNavigationLink(links, "content-search-previous", input.dataset.contentSearchPrevious || "Previous match", results[resultIndex - 1], query);
399
+ addNavigationLink(links, "content-search-next", input.dataset.contentSearchNext || "Next match", results[resultIndex + 1], query);
400
+ }
401
+ navigation.appendChild(links);
402
+ content.insertBefore(navigation, content.firstChild);
403
+ }
404
+
405
+ function highlightQuery() {
406
+ var params = new URLSearchParams(window.location.search);
407
+ var query = (params.get("h") || "").slice(0, MAX_QUERY_LENGTH);
408
+ if (!query || query.trim().length < 2) return;
409
+ var content = contentRoot();
410
+ if (!content || content.dataset.contentSearchHighlighted) return;
411
+ content.dataset.contentSearchHighlighted = "true";
412
+
413
+ var requestedHit = parseInt(params.get("hit") || "1", 10);
414
+ var marked = markContentOccurrences(content, query, Number.isFinite(requestedHit) ? requestedHit : 1);
415
+ if (!marked) return;
416
+ var input = document.querySelector("[data-content-search]");
417
+ if (input) {
418
+ loadSearchIndex(input.dataset.contentSearchUrl).then(function (entries) {
419
+ addOccurrenceNavigation(content, entries, query, marked, input);
420
+ });
421
+ }
422
+ revealActiveOccurrence(marked.activeMark);
423
+ var reducedMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
424
+ marked.activeMark.scrollIntoView({ block: "center", behavior: reducedMotion ? "auto" : "smooth" });
425
+ marked.activeMark.focus({ preventScroll: true });
426
+ }
427
+
428
+ function enhanceContentSearch() {
429
+ setupSearch();
430
+ highlightQuery();
431
+ }
432
+
433
+ if (document.readyState === "loading") {
434
+ document.addEventListener("DOMContentLoaded", enhanceContentSearch);
435
+ } else {
436
+ enhanceContentSearch();
437
+ }
438
+ document.addEventListener("click", closeSearchPanels);
439
+ document.addEventListener("unaltraweb:contentchange", enhanceContentSearch);
440
+ document.addEventListener("unaltraweb:documentationprofilechange", rerenderSearchResults);
441
+ })();
@@ -0,0 +1,60 @@
1
+ // create element for copy button in code blocks
2
+ var codeBlocks = document.querySelectorAll("pre");
3
+ codeBlocks.forEach(function (codeBlock) {
4
+ if (
5
+ (codeBlock.querySelector("pre:not(.lineno)") || codeBlock.querySelector("code")) &&
6
+ codeBlock.querySelector("code:not(.language-chartjs)") &&
7
+ codeBlock.querySelector("code:not(.language-diff2html)") &&
8
+ codeBlock.querySelector("code:not(.language-echarts)") &&
9
+ codeBlock.querySelector("code:not(.language-geojson)") &&
10
+ codeBlock.querySelector("code:not(.language-mermaid)") &&
11
+ codeBlock.querySelector("code:not(.language-plotly)") &&
12
+ codeBlock.querySelector("code:not(.language-vega_lite)")
13
+ ) {
14
+ // create copy button
15
+ var copyButton = document.createElement("button");
16
+ copyButton.className = "copy";
17
+ copyButton.type = "button";
18
+ copyButton.ariaLabel = "Copy code to clipboard";
19
+ copyButton.innerText = "Copy";
20
+ copyButton.innerHTML = '<i class="fa-solid fa-clipboard"></i>';
21
+
22
+ // get code from code block and copy to clipboard
23
+ copyButton.addEventListener("click", function () {
24
+ // check if code block has line numbers
25
+ // i.e. `kramdown.syntax_highlighter_opts.block.line_numbers` set to true in _config.yml
26
+ // or using `jekyll highlight` liquid tag with `linenos` option
27
+ if (codeBlock.querySelector("pre:not(.lineno)")) {
28
+ // get code from code block ignoring line numbers
29
+ var code = codeBlock.querySelector("pre:not(.lineno)").innerText.trim();
30
+ } else {
31
+ // if (codeBlock.querySelector('code')) {
32
+ // get code from code block when line numbers are not displayed
33
+ var code = codeBlock.querySelector("code").innerText.trim();
34
+ }
35
+ window.navigator.clipboard.writeText(code);
36
+ copyButton.innerText = "Copied";
37
+ copyButton.innerHTML = '<i class="fa-solid fa-clipboard-check"></i>';
38
+ var waitFor = 3000;
39
+
40
+ setTimeout(function () {
41
+ copyButton.innerText = "Copy";
42
+ copyButton.innerHTML = '<i class="fa-solid fa-clipboard"></i>';
43
+ }, waitFor);
44
+ });
45
+
46
+ var manualBlock = codeBlock.closest(".uw-code-block");
47
+ var manualHeader = manualBlock ? manualBlock.querySelector(".uw-code-header") : null;
48
+ if (manualHeader) {
49
+ manualHeader.append(copyButton);
50
+ } else {
51
+ // Preserve the generic overlay for preformatted blocks outside manual panels.
52
+ var wrapper = document.createElement("div");
53
+ wrapper.className = "code-display-wrapper";
54
+ const parent = codeBlock.parentElement;
55
+ parent.insertBefore(wrapper, codeBlock);
56
+ wrapper.append(codeBlock);
57
+ wrapper.append(copyButton);
58
+ }
59
+ }
60
+ });
@@ -0,0 +1,6 @@
1
+ /* CUSTOM: site-specific JavaScript lives here */
2
+
3
+ document.addEventListener("DOMContentLoaded", () => {
4
+ // Example: console.log("custom.js loaded");
5
+ });
6
+
@@ -0,0 +1,103 @@
1
+ (function () {
2
+ var STORAGE_KEY = "unaltrawebDeveloperSwitcherPosition";
3
+
4
+ function clamp(value, min, max) {
5
+ return Math.min(Math.max(value, min), max);
6
+ }
7
+
8
+ function viewportPosition(element, left, top) {
9
+ var margin = 8;
10
+ var width = element.offsetWidth;
11
+ var height = element.offsetHeight;
12
+ return {
13
+ left: clamp(left, margin, Math.max(margin, window.innerWidth - width - margin)),
14
+ top: clamp(top, margin, Math.max(margin, window.innerHeight - height - margin)),
15
+ };
16
+ }
17
+
18
+ function applyPosition(element, position) {
19
+ var next = viewportPosition(element, position.left, position.top);
20
+ element.style.left = next.left + "px";
21
+ element.style.top = next.top + "px";
22
+ element.style.right = "auto";
23
+ element.style.bottom = "auto";
24
+ }
25
+
26
+ function setupDeveloperSwitcher() {
27
+ var switcher = document.querySelector("[data-developer-mode-switcher]");
28
+ if (!switcher || switcher.dataset.developerModeReady) return;
29
+ switcher.dataset.developerModeReady = "true";
30
+
31
+ var handle = switcher.querySelector("[data-developer-mode-handle]") || switcher;
32
+ var saved = null;
33
+ try {
34
+ saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || "null");
35
+ } catch (error) {
36
+ saved = null;
37
+ }
38
+ if (saved && Number.isFinite(saved.left) && Number.isFinite(saved.top)) {
39
+ applyPosition(switcher, saved);
40
+ }
41
+
42
+ switcher.querySelectorAll("[data-developer-profile-link]").forEach(function (link) {
43
+ link.setAttribute("target", "_self");
44
+ link.addEventListener("click", function (event) {
45
+ event.preventDefault();
46
+ window.location.assign(link.href);
47
+ });
48
+ });
49
+
50
+ handle.addEventListener("dblclick", function () {
51
+ localStorage.removeItem(STORAGE_KEY);
52
+ switcher.style.left = "";
53
+ switcher.style.top = "";
54
+ switcher.style.right = "";
55
+ switcher.style.bottom = "";
56
+ });
57
+
58
+ handle.addEventListener("pointerdown", function (event) {
59
+ if (event.button !== 0) return;
60
+ event.preventDefault();
61
+ var rect = switcher.getBoundingClientRect();
62
+ var offsetX = event.clientX - rect.left;
63
+ var offsetY = event.clientY - rect.top;
64
+ switcher.classList.add("is-dragging");
65
+ handle.setPointerCapture(event.pointerId);
66
+
67
+ function move(moveEvent) {
68
+ applyPosition(switcher, {
69
+ left: moveEvent.clientX - offsetX,
70
+ top: moveEvent.clientY - offsetY,
71
+ });
72
+ }
73
+
74
+ function finish(upEvent) {
75
+ switcher.classList.remove("is-dragging");
76
+ handle.releasePointerCapture(upEvent.pointerId);
77
+ document.removeEventListener("pointermove", move);
78
+ document.removeEventListener("pointerup", finish);
79
+ document.removeEventListener("pointercancel", finish);
80
+ var finalRect = switcher.getBoundingClientRect();
81
+ localStorage.setItem(STORAGE_KEY, JSON.stringify({ left: finalRect.left, top: finalRect.top }));
82
+ }
83
+
84
+ document.addEventListener("pointermove", move);
85
+ document.addEventListener("pointerup", finish);
86
+ document.addEventListener("pointercancel", finish);
87
+ });
88
+
89
+ window.addEventListener("resize", function () {
90
+ if (!switcher.style.left || !switcher.style.top) return;
91
+ applyPosition(switcher, {
92
+ left: switcher.getBoundingClientRect().left,
93
+ top: switcher.getBoundingClientRect().top,
94
+ });
95
+ });
96
+ }
97
+
98
+ if (document.readyState === "loading") {
99
+ document.addEventListener("DOMContentLoaded", setupDeveloperSwitcher);
100
+ } else {
101
+ setupDeveloperSwitcher();
102
+ }
103
+ })();
@@ -0,0 +1,20 @@
1
+ let diff2HtmlTheme = determineComputedTheme();
2
+
3
+ /* Create diff2html as another node and hide the code block, appending the diff2html node after it
4
+ this is done to enable retrieving the code again when changing theme between light/dark */
5
+ document.addEventListener("readystatechange", () => {
6
+ if (document.readyState === "complete") {
7
+ document.querySelectorAll("pre>code.language-diff2html").forEach((elem) => {
8
+ const textData = elem.textContent;
9
+ const backup = elem.parentElement;
10
+ backup.classList.add("unloaded");
11
+ /* create diff node */
12
+ let diffElement = document.createElement("div");
13
+ diffElement.classList.add("diff2html");
14
+ backup.after(diffElement);
15
+ const configuration = { colorScheme: diff2HtmlTheme, drawFileList: true, highlight: true, matching: "lines" };
16
+ const diff2htmlUi = new Diff2HtmlUI(diffElement, textData, configuration);
17
+ diff2htmlUi.draw();
18
+ });
19
+ }
20
+ });
@@ -0,0 +1,27 @@
1
+ $(window).on("load", function () {
2
+ document.querySelectorAll("d-footnote").forEach(function (footnote) {
3
+ footnote.shadowRoot.querySelector("sup > span").setAttribute("style", "color: var(--global-theme-color);");
4
+ footnote.shadowRoot
5
+ .querySelector("d-hover-box")
6
+ .shadowRoot.querySelector("style")
7
+ .sheet.insertRule(".panel {background-color: var(--global-bg-color) !important;}");
8
+ footnote.shadowRoot
9
+ .querySelector("d-hover-box")
10
+ .shadowRoot.querySelector("style")
11
+ .sheet.insertRule(".panel {border-color: var(--global-divider-color) !important;}");
12
+ });
13
+ // Override styles of the citations.
14
+ document.querySelectorAll("d-cite").forEach(function (cite) {
15
+ cite.shadowRoot.querySelector("div > span").setAttribute("style", "color: var(--global-theme-color);");
16
+ cite.shadowRoot.querySelector("style").sheet.insertRule("ul li a {color: var(--global-text-color) !important; text-decoration: none;}");
17
+ cite.shadowRoot.querySelector("style").sheet.insertRule("ul li a:hover {color: var(--global-theme-color) !important;}");
18
+ cite.shadowRoot
19
+ .querySelector("d-hover-box")
20
+ .shadowRoot.querySelector("style")
21
+ .sheet.insertRule(".panel {background-color: var(--global-bg-color) !important;}");
22
+ cite.shadowRoot
23
+ .querySelector("d-hover-box")
24
+ .shadowRoot.querySelector("style")
25
+ .sheet.insertRule(".panel {border-color: var(--global-divider-color) !important;}");
26
+ });
27
+ });