datalog-theme 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +125 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +23 -17
  5. data/_data/cdn-integrity.yml +0 -30
  6. data/_includes/analytics/dashboard.html +3 -1
  7. data/_includes/components/api-function.html +20 -1
  8. data/_includes/components/enhanced-code-block.html +1 -1
  9. data/_includes/csp-meta.html +115 -11
  10. data/_includes/footer.html +19 -20
  11. data/_includes/head.html +60 -23
  12. data/_includes/header/navigation.html +12 -15
  13. data/_includes/header.html +28 -19
  14. data/_includes/layouts/default/article.html +5 -1
  15. data/_includes/meta/math-config.html +9 -5
  16. data/_includes/meta/schema.html +5 -2
  17. data/_includes/meta/scripts-loader.html +16 -32
  18. data/_includes/post/related-posts.html +4 -7
  19. data/_includes/search/index-data.json +9 -34
  20. data/_layouts/dataset.html +1 -0
  21. data/_layouts/default.html +16 -8
  22. data/_layouts/notebook.html +1 -0
  23. data/_layouts/package.html +1 -0
  24. data/_layouts/portfolio.html +1 -0
  25. data/_layouts/post.html +20 -5
  26. data/_layouts/project.html +2 -1
  27. data/_plugins/analytics_dashboard.rb +9 -3
  28. data/_plugins/config_validator.rb +12 -7
  29. data/_plugins/csp_generator.rb +18 -28
  30. data/_plugins/datalog_bibliography.rb +9 -7
  31. data/_plugins/datalog_comments.rb +8 -5
  32. data/_plugins/datalog_slides.rb +9 -8
  33. data/_plugins/i18n.rb +7 -8
  34. data/_plugins/image_optimizer.rb +17 -6
  35. data/_plugins/math_preprocessor.rb +33 -3
  36. data/_plugins/notebook_converter.rb +23 -4
  37. data/_plugins/plugin_loader.rb +3 -1
  38. data/_plugins/publications_generator.rb +8 -2
  39. data/_plugins/rouge_highlight_filter.rb +42 -0
  40. data/_plugins/search_code_blocks.rb +30 -0
  41. data/_plugins/search_normalizer.rb +15 -53
  42. data/_plugins/search_pages.rb +3 -4
  43. data/_sass/_academic-dashboard.scss +262 -0
  44. data/_sass/_base.scss +12 -0
  45. data/_sass/_components.scss +64 -1153
  46. data/_sass/_features.scss +17 -0
  47. data/_sass/_layout.scss +1 -1
  48. data/_sass/_notebooks.scss +322 -0
  49. data/_sass/_open-science-badges.scss +56 -0
  50. data/_sass/{_phase1-enhancements.scss → _post-components.scss} +1 -1
  51. data/_sass/_search-page.scss +530 -0
  52. data/_sass/_search.scss +46 -0
  53. data/_sass/_syntax-highlighting.scss +212 -97
  54. data/_sass/_theme.scss +29 -19
  55. data/_sass/_typography.scss +14 -0
  56. data/assets/css/main.scss +14 -0
  57. data/assets/js/dist/academic.js +1 -1
  58. data/assets/js/dist/analytics-dashboard.js +1 -1
  59. data/assets/js/dist/chunks/chunk-225H5YXE.js +1 -0
  60. data/assets/js/dist/core.js +1 -1
  61. data/assets/js/dist/loader.js +1 -1
  62. data/assets/js/dist/notebook.js +1 -1
  63. data/assets/js/dist/search.js +1 -1
  64. data/assets/js/dist/visualizations.js +11 -2
  65. data/assets/js/loader.js +3 -1
  66. data/datalog-theme.gemspec +36 -23
  67. data/lib/datalog/cli.rb +34 -14
  68. data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
  69. data/lib/datalog/theme/package.rb +57 -0
  70. data/lib/datalog/theme/repository_checkout.rb +90 -0
  71. data/lib/datalog/theme/version.rb +1 -1
  72. data/lib/datalog/warning_filter.rb +5 -11
  73. data/lib/datalog-theme.rb +5 -0
  74. metadata +48 -133
  75. data/_data/academic.yml +0 -217
  76. data/_data/config/author.yml +0 -121
  77. data/_data/datasets.yml +0 -28
  78. data/_data/js_meta.json +0 -371
  79. data/_data/navigation.yml +0 -145
  80. data/_data/projects.yml +0 -41
  81. data/_data/publications.yml +0 -28
  82. data/_data/social.yml +0 -73
  83. data/_data/visualizations.yml +0 -51
  84. data/_includes/components/advanced-search.html +0 -682
  85. data/_includes/components/bookmark-system.html +0 -96
  86. data/_includes/components/comments.html +0 -244
  87. data/_includes/components/content-recommendations.html +0 -228
  88. data/_includes/components/email-preferences.html +0 -200
  89. data/_includes/components/enhanced-metadata.html +0 -228
  90. data/_includes/components/language-switcher.html +0 -396
  91. data/_includes/components/navigation-enhancements.html +0 -454
  92. data/_includes/components/newsletter-signup.html +0 -178
  93. data/_includes/components/popular-posts.html +0 -233
  94. data/_includes/components/reading-progress.html +0 -133
  95. data/_includes/components/reading-time.html +0 -121
  96. data/_includes/components/series-navigation.html +0 -124
  97. data/_includes/components/social-proof.html +0 -34
  98. data/_includes/components/user-preferences.html +0 -566
  99. data/_includes/meta/syntax-config.html +0 -19
  100. data/_layouts/archive.html +0 -282
  101. data/_layouts/post-sidebar.html +0 -183
  102. data/_sass/_phase3-enhancements.scss +0 -874
  103. data/_sass/_phase4-enhancements.scss +0 -1214
  104. data/_sass/_phase5-enhancements.scss +0 -414
  105. data/assets/js/academic.js +0 -262
  106. data/assets/js/analytics-dashboard.js +0 -382
  107. data/assets/js/core/dark-mode.js +0 -79
  108. data/assets/js/core/github-cards.js +0 -123
  109. data/assets/js/core/language-filter.js +0 -69
  110. data/assets/js/core/navigation.js +0 -184
  111. data/assets/js/core/scroll-progress.js +0 -45
  112. data/assets/js/core/search-hotkeys.js +0 -62
  113. data/assets/js/core/skip-links.js +0 -62
  114. data/assets/js/dist/manifest.json +0 -22
  115. data/assets/js/dist/meta.json +0 -371
  116. data/assets/js/main.js +0 -23
  117. data/assets/js/math.js +0 -818
  118. data/assets/js/notebook.js +0 -158
  119. data/assets/js/search/analytics.js +0 -91
  120. data/assets/js/search/app.js +0 -271
  121. data/assets/js/search/autocomplete.js +0 -120
  122. data/assets/js/search/engine.js +0 -260
  123. data/assets/js/search/filters.js +0 -45
  124. data/assets/js/search/render.js +0 -217
  125. data/assets/js/search/utils.js +0 -99
  126. data/assets/js/search.js +0 -354
  127. data/assets/js/visualizations.js +0 -816
  128. data/assets/publications/datalog-publications.bib +0 -8
  129. data/assets/publications/datalog-publications.ris +0 -9
  130. data/assets/publications/publications.bib +0 -30
  131. data/assets/templates/diogo-ribeiro-cv.md +0 -31
  132. data/assets/templates/diogo-ribeiro-cv.tex +0 -32
  133. data/lib/datalog/theme/theme.rb +0 -18
@@ -1 +1 @@
1
- var j="datalog-search-analytics";function K({panel:e,list:n,empty:t,onSelect:o}){if(!e||!n||!t)return{record(){},render(){}};let r=g(),f="";function g(){let v=Object.create(null);try{let s=window.localStorage.getItem(j);if(s){let i=JSON.parse(s);i&&typeof i=="object"&&Object.entries(i).forEach(([d,u])=>{typeof u=="number"&&Number.isFinite(u)&&(v[d]=u)})}}catch(s){}return v}function w(){try{window.localStorage.setItem(j,JSON.stringify(r))}catch(v){}}function c(v){let s=(v||"").trim();!s||s===f||(f=s,r[s]=(r[s]||0)+1,w(),h())}function h(){let v=Object.entries(r).filter(([i])=>i&&i.trim().length>1).sort((i,d)=>d[1]-i[1]).slice(0,5);if(n.replaceChildren(),v.length===0){t.hidden=!1;return}t.hidden=!0;let s=document.createDocumentFragment();v.forEach(([i,d])=>{let u=document.createElement("li"),p=document.createElement("button");p.type="button",p.className="search-analytics__query",p.textContent=`${i} (${d})`,p.addEventListener("click",()=>{typeof o=="function"&&o(i)}),u.appendChild(p),s.appendChild(u)}),n.appendChild(s)}return{record:c,render:h}}function z(e=""){let n=e==null?"":String(e);try{return n.toLowerCase().normalize("NFKD").replace(new RegExp("\\p{Diacritic}","gu"),"")}catch(t){return n.toLowerCase()}}function F(e=""){return z(e).replace(/\s+/g,"")}function P(e=""){return z(e).split(/[^a-z0-9\\._]+/).filter(Boolean)}function H(e=""){return/\\|\^|_|\{|\}|\$/.test(e)}function B(e=""){return/`|::|->|=>|\(|\)|\{|\}|\[|\]|=|\bdef\b|\bfunction\b|\bclass\b/.test(e)}function X(e,n){if(!e||!n)return!1;let t=0;for(let o=0;o<e.length&&t<n.length;o+=1)e[o]===n[t]&&(t+=1);return t===n.length}function oe(e){if(!e)return"";let n=document.createElement("div");return n.innerHTML=e,n.textContent||n.innerText||""}function O(e,n,t){if(!e)return"";let o=oe(e),r=Math.max(0,n-80),f=Math.min(o.length,n+t+80);return`${o.slice(r,f)}${f<o.length?"\u2026":""}`}function se(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _(e,n){if(!e||!n)return e;let t=Array.from(new Set(P(n))).sort((r,f)=>f.length-r.length),o=e;return t.forEach(r=>{if(!r)return;let f=new RegExp(`(${se(r)})`,"gi");o=o.replace(f,"<mark>$1</mark>")}),o}function M(e){return(e||"").toString().split(/[-_\s]+/).map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join(" ")}function J(e){switch(e){case"post":return"Tutorial & Blog";case"project":return"Project";case"research":return"Research";case"dataset":return"Dataset";default:return M(e||"Page")}}function Y({panel:e,limit:n=8,onSelect:t}){if(!e)return{setSuggestions(){},update(){},close(){},handleNavigation(){}};let o=[],r=-1;function f(s){o=Array.isArray(s)?[...s]:[]}function g(s){r=-1;let i=(s||"").trim().toLowerCase();if(!i){h();return}let d=o.filter(p=>p&&p.toLowerCase().includes(i)).slice(0,n);if(d.length===0){h();return}let u=document.createDocumentFragment();d.forEach((p,E)=>{let y=document.createElement("button");y.type="button",y.className="search-autocomplete__option",y.setAttribute("role","option"),y.dataset.autocompleteOption="",y.dataset.value=p,y.setAttribute("aria-selected",E===r?"true":"false"),y.replaceChildren(),y.insertAdjacentHTML("beforeend",_(p,i)),u.appendChild(y)}),e.replaceChildren(),e.appendChild(u),e.hidden=!1}function w(s,i){if(e.hidden)return;let d=Array.from(e.querySelectorAll("[data-autocomplete-option]"));if(d.length!==0){if(s.key==="ArrowDown")s.preventDefault(),r=(r+1)%d.length,c(d);else if(s.key==="ArrowUp")s.preventDefault(),r=(r-1+d.length)%d.length,c(d);else if(s.key==="Enter"&&r>=0){s.preventDefault();let u=d[r],p=u?u.dataset.value:"";p&&i&&(i.value=p),typeof t=="function"&&t(p),v()}}}function c(s){s.forEach((i,d)=>{let u=d===r;i.setAttribute("aria-selected",u?"true":"false"),i.classList.toggle("is-active",u)})}function h(){e.replaceChildren(),e.hidden=!0,r=-1}function v(){h()}return e.addEventListener("click",s=>{let i=s.target.closest("[data-autocomplete-option]");if(!i)return;let d=i.dataset.value||"";d&&typeof t=="function"&&t(d),v()}),{setSuggestions:f,update:g,close:v,handleNavigation:w}}function V(e=[]){let n=Array.isArray(e)?[...e]:[];function t(g){n=Array.isArray(g)?[...g]:[]}function o(g,w={}){let c=(g||"").trim();if(!c)return[];let h=z(c),v=P(c),s=H(c),i=B(c),{type:d="",language:u="",difficulty:p="",tags:E=new Set}=w;return n.map(y=>le(y,{rawQuery:c,normalizedQuery:h,queryTokens:v,mathQuery:s,codeQuery:i,typeFilter:d,languageFilter:u,difficultyFilter:p,selectedTags:E})).filter(y=>y&&y.score>0).sort((y,C)=>C.score-y.score||y.title.localeCompare(C.title))}function r(g=150){return ce(n,g)}function f(){return[...n]}return{setDocuments:t,search:o,suggestions:r,getDocuments:f}}function ce(e=[],n=150){let t=new Set;return e.forEach(o=>{o.title&&t.add(o.title),Array.isArray(o.languages)&&o.languages.forEach(r=>t.add(r)),Array.isArray(o.tags)&&o.tags.forEach(r=>t.add(`#${r}`)),Array.isArray(o.math)&&o.math.slice(0,3).forEach(r=>t.add(r))}),Array.from(t).slice(0,n)}function le(e,n){let{rawQuery:t,normalizedQuery:o,queryTokens:r,mathQuery:f,codeQuery:g,typeFilter:w,languageFilter:c,difficultyFilter:h,selectedTags:v}=n;if(w&&e.type!==w)return null;let s=Array.isArray(e.languages)?e.languages:[];if(c&&!s.includes(c))return null;if(h){let a=String(e.difficulty||"").toLowerCase();if(!a||a!==h)return null}if(v&&v.size>0){let a=ue(e,"tags");for(let S of v)if(!a.has(S))return null}if(!t)return null;let i=e.normalized||{},d=i.content||z(e.content||""),u=i.summary||z(e.summary||""),p=i.title||z(e.title||""),E=G(i.tags,e.tags),y=G(i.languages,e.languages),C=i.difficulty||z(e.difficulty||""),T=Array.isArray(e.code)?e.code:[],k=Array.isArray(e.math)?e.math:[],m=0,q="",x=null,L=null;if(p.includes(o)&&(m+=40),r.forEach(a=>{a&&(p.includes(a)&&(m+=12),u.includes(a)&&(m+=8),d.includes(a)&&(m+=6),E.forEach(S=>{S.includes(a)&&(m+=4)}),y.forEach(S=>{S.includes(a)&&(m+=4)}),C.includes(a)&&(m+=2))}),T.length>0){let a=F(t);for(let S of T){let b=String(S.language||"").toLowerCase(),I=S.code||"",N=F(I);if(N.includes(a)){m+=30,x={language:b,code:I};break}if(g&&X(N,a)){m+=18,x={language:b,code:I};break}}!x&&T[0]&&(x={language:String(T[0].language||"").toLowerCase(),code:T[0].code||""})}if(k.length>0){let a=o.replace(/\\/g,"");for(let S of k)if(z(String(S)).includes(a)){m+=26,L=S;break}f&&!L&&k[0]&&(L=k[0],m+=10)}if(d.includes(o)){let a=d.indexOf(o);q=O(e.content||"",a,t.length),m+=10}else if(u.includes(o)){let a=u.indexOf(o);q=O(e.summary||"",a,t.length),m+=6}return m===0?null:{id:`${e.url}`,title:e.title,url:e.url,summary:e.summary,snippet:q,codeSnippet:x,mathSnippet:L,tags:e.tags||[],languages:e.languages||[],difficulty:e.difficulty||"",type:e.type||"page",date:e.date,readingTime:e.reading_time,score:m}}function G(e,n){return Array.isArray(e)&&e.length>0?e:Array.isArray(n)?n.map(t=>z(t)):[]}function ue(e,n){let o=(e.normalized||{})[n];if(Array.isArray(o)&&o.length>0)return new Set(o);let r=Array.isArray(e[n])?e[n]:[];return new Set(r.map(f=>z(f)))}function W(e,n,t){if(!e)return;let o=new Set;n.forEach(g=>{(g.tags||g.topics||[]).forEach(c=>{if(!c)return;let h=String(c).trim().toLowerCase();h&&o.add(h)})});let r=Array.from(o).sort();if(r.length===0){let g=document.createElement("p");g.className="search-filter__empty",g.textContent="No tags available yet.",e.replaceChildren(g);return}let f=document.createDocumentFragment();r.forEach(g=>{let w=document.createElement("button");w.type="button",w.className="search-filter__tag",w.textContent=g,w.dataset.filterTag=g,w.setAttribute("aria-pressed",t.has(g)?"true":"false"),f.appendChild(w)}),e.replaceChildren(),e.appendChild(f)}function Z(e,n,t){let{resultsList:o,resultsMeta:r,emptyState:f,template:g}=t;if(!o||!r||!f||!g)return;if(o.replaceChildren(),!n){r.textContent="Enter a query to begin.",f.hidden=!0;return}if(e.length===0){r.textContent=`No matches for \u201C${n}\u201D.`,f.hidden=!1;return}f.hidden=!0,r.textContent=`${e.length} result${e.length===1?"":"s"} for \u201C${n}\u201D.`;let w=document.createDocumentFragment();e.forEach(c=>{let h=g.content.cloneNode(!0),v=h.querySelector("[data-result-type]"),s=h.querySelector("[data-result-difficulty]"),i=h.querySelector("[data-result-languages]"),d=h.querySelector("[data-result-link]"),u=h.querySelector("[data-result-summary]"),p=h.querySelector("[data-result-code]"),E=p?p.querySelector("code"):null,y=h.querySelector("[data-result-math]"),C=h.querySelector("[data-result-math-preview]"),T=h.querySelector("[data-result-math-code]"),k=h.querySelector("[data-result-math-copy]"),m=h.querySelector("[data-result-excerpt]"),q=h.querySelector("[data-result-tags]"),x=h.querySelector("[data-result-date]");if(v&&(v.textContent=J(c.type)),s&&(c.difficulty?(s.textContent=`Difficulty: ${M(c.difficulty)}`,s.hidden=!1):s.hidden=!0),i&&(c.languages&&c.languages.length>0?(i.textContent=`Languages: ${c.languages.map(L=>M(L)).join(", ")}`,i.hidden=!1):i.hidden=!0),d&&(d.textContent=c.title||c.url,d.setAttribute("href",c.url)),u&&(u.replaceChildren(),u.insertAdjacentHTML("beforeend",_(c.summary||"",n))),y&&T&&(c.mathSnippet?(y.hidden=!1,T.textContent=c.mathSnippet,C&&(window.DatalogMath&&typeof window.DatalogMath.renderLatex=="function"?window.DatalogMath.renderLatex(C,c.mathSnippet,{display:!1,enhance:!1}):window.MathJax&&typeof window.MathJax.typesetPromise=="function"?(C.innerHTML=`\\(${c.mathSnippet}\\)`,window.MathJax.typesetPromise([C]).catch(()=>{C.textContent=c.mathSnippet})):C.textContent=c.mathSnippet),k&&k.addEventListener("click",()=>de(c.mathSnippet,y))):y.hidden=!0),m&&(c.snippet?(m.replaceChildren(),m.insertAdjacentHTML("beforeend",_(c.snippet,n)),m.hidden=!1):m.hidden=!0),p&&E)if(c.codeSnippet&&c.codeSnippet.code){let L=c.codeSnippet.language||"text";p.classList.remove("language-none"),p.classList.add(`language-${L}`),E.className=`language-${L}`;let a=c.codeSnippet.code;if(window.Prism&&window.Prism.languages){let S=window.Prism.languages[L]||window.Prism.languages.markup;E.innerHTML=window.Prism.highlight(a,S,L)}else E.textContent=a;p.hidden=!1}else p.hidden=!0;if(q&&(q.replaceChildren(),(c.tags||[]).forEach(L=>{let a=document.createElement("li");a.textContent=`#${L}`,q.appendChild(a)})),x)if(c.date){let L=new Date(c.date);Number.isNaN(L.getTime())?x.hidden=!0:(x.textContent=L.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}),x.hidden=!1)}else x.hidden=!0;w.appendChild(h)}),o.appendChild(w)}function de(e,n){if(!e)return;let t=()=>{if(!n)return;let r=n.querySelector("[data-result-math-copy]"),f=r?r.querySelector(".visually-hidden"):null;if(r&&f){let g=r.getAttribute("data-sr-original")||f.textContent;r.getAttribute("data-sr-original")||r.setAttribute("data-sr-original",g||"Copy LaTeX"),f.textContent="Copied LaTeX",r.classList.add("is-copied"),window.setTimeout(()=>{f.textContent=r.getAttribute("data-sr-original")||"Copy LaTeX",r.classList.remove("is-copied")},2e3)}},o=()=>{let r=document.createElement("textarea");r.value=e,r.setAttribute("aria-hidden","true"),r.style.position="fixed",r.style.opacity="0",document.body.appendChild(r),r.select();try{document.execCommand("copy"),t()}catch(f){}document.body.removeChild(r)};navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(e).then(()=>t()).catch(()=>o()):o()}var fe=8;function ee(){let e=document.querySelector("[data-search-app]");if(!e)return;let n=e.querySelector("[data-search-form]"),t=e.querySelector("[data-search-input]"),o=e.querySelector("[data-search-results]"),r=e.querySelector("[data-search-meta]"),f=e.querySelector("[data-search-empty]"),g=e.querySelector("[data-search-autocomplete]"),w=e.querySelector("[data-search-analytics]"),c=w?w.querySelector(".search-app__analytics-list"):null,h=w?w.querySelector(".search-app__analytics-empty"):null,v=document.getElementById("search-result-template"),s=e.querySelector("[data-filter-type]"),i=e.querySelector("[data-filter-language]"),d=e.querySelector("[data-filter-difficulty]"),u=e.querySelector("[data-filter-tags]"),p=e.getAttribute("data-search-index")||"/search.json",E=new Set,y=V(),C=K({panel:w,list:c,empty:h,onSelect:a=>{t&&(t.value=a,x())}}),T=Y({panel:g,limit:fe,onSelect:a=>{a&&t&&(t.value=a,t.focus(),x())}}),k=!1,m=new URLSearchParams(window.location.search);t&&m.has("q")&&(t.value=m.get("q")||""),s&&m.has("type")&&(s.value=m.get("type")),i&&m.has("language")&&(i.value=m.get("language")),d&&m.has("difficulty")&&(d.value=m.get("difficulty")),m.has("tags")&&m.get("tags").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean).forEach(a=>E.add(a)),he(t,()=>{T.close(),x()}),ge(p).then(a=>{let S=a.documents||[];y.setDocuments(S),T.setSuggestions(y.suggestions()),W(u,S,E),k=!0,q()}).catch(a=>{r&&(r.textContent="Unable to load the search index. Please try again later.")}),n&&n.addEventListener("submit",a=>{a.preventDefault(),x()}),t&&(t.addEventListener("input",()=>{T.update(t.value)}),t.addEventListener("keydown",a=>{T.handleNavigation(a,t)}),t.addEventListener("focus",()=>{T.update(t.value)})),s&&s.addEventListener("change",x),i&&i.addEventListener("change",x),d&&d.addEventListener("change",x),e.addEventListener("click",a=>{let S=a.target;if(S.matches("[data-filter-tag]")){let b=S.getAttribute("data-filter-tag");b&&(E.has(b)?(E.delete(b),S.setAttribute("aria-pressed","false")):(E.add(b),S.setAttribute("aria-pressed","true")),x())}}),document.addEventListener("click",a=>{!g||g.hidden||e.contains(a.target)||T.close()}),document.addEventListener("keydown",a=>{let S=document.activeElement?document.activeElement.tagName:"";["INPUT","TEXTAREA"].includes(S)||(a.key==="/"&&!a.ctrlKey&&!a.metaKey&&!a.altKey||(a.key==="k"||a.key==="K")&&(a.ctrlKey||a.metaKey))&&(a.preventDefault(),t&&(t.focus(),t.select()))}),C.render();function q(){t&&t.value.trim()?x():L()}function x(){if(!t)return;if(!k){r&&(r.textContent="Loading technical index\u2026");return}let a=t.value.trim(),S={type:s?s.value:"",language:i?i.value:"",difficulty:d?d.value:"",tags:E},b=y.search(a,S);Z(b,a,{resultsList:o,resultsMeta:r,emptyState:f,template:v}),L(a),C.record(a)}function L(a){let S=new URL(window.location.href),b=S.searchParams;a?b.set("q",a):b.delete("q"),s&&s.value?b.set("type",s.value):b.delete("type"),i&&i.value?b.set("language",i.value):b.delete("language"),d&&d.value?b.set("difficulty",d.value):b.delete("difficulty"),E.size>0?b.set("tags",Array.from(E).join(",")):b.delete("tags");let I=b.toString(),N=I?`${S.pathname}?${I}`:S.pathname;window.history.replaceState({},"",N)}}function ge(e){return fetch(e,{credentials:"same-origin"}).then(n=>{if(!n.ok)throw new Error(`HTTP ${n.status}`);return n.json()})}function he(e,n){e&&e.addEventListener("keydown",t=>{t.key==="Escape"&&(e.value="",typeof n=="function"&&n())})}var pe=300,me="search-result-",U=500;function ye(e,n=pe){let t,o=(...r)=>{t&&window.clearTimeout(t),t=window.setTimeout(()=>{t=void 0,e.apply(null,r)},n)};return o.cancel=()=>{t&&(window.clearTimeout(t),t=void 0)},o}function $(e,n){if(!e)return;let t=String(n||"");e.textContent===t?e.textContent=`${t}\xA0`:e.textContent=t,t.trim()?e.removeAttribute("hidden"):e.setAttribute("hidden","")}function Se(){let e=document.querySelector("[data-search-app]");if(!e)return;let n=e.querySelector("[data-search-form]"),t=e.querySelector("[data-search-input]"),o=e.querySelector("[data-search-results]"),r=e.querySelector("[data-search-empty]"),f=e.querySelector("[data-search-loading]"),g=e.querySelector("[data-search-region]"),w=e.querySelector('[data-search-live="count"]'),c=e.querySelector('[data-search-live="selection"]'),h=e.querySelector('[data-search-live="status"]'),v=e.querySelector("[data-search-filters]"),s=e.querySelector("[data-filter-tags]");if(!t||!o)return;let i=-1,d=0,u=[],p=!1,E=[],y=0,C=null,T=ye(()=>{n&&(p=!0,Q(),$(h,"Loading results\u2026"),n.dispatchEvent(new Event("submit",{cancelable:!0})))});new MutationObserver(()=>{I()}).observe(o,{childList:!0}),I(),q(),s&&new MutationObserver(()=>{q()}).observe(s,{childList:!0}),t.addEventListener("input",()=>{S(!1),T()}),t.addEventListener("keydown",l=>{if(!x(l)&&l.key==="Tab"&&E.length>0){l.preventDefault();let A=l.shiftKey?E.length-1:0;E[A].focus()}});function m(l){if(l.key!=="Tab"||E.length===0)return;l.preventDefault();let A=E.indexOf(l.currentTarget);if(A===-1)return;let D=l.shiftKey?-1:1,R=(A+D+E.length)%E.length;E[R].focus()}function q(){if(!v)return;let l=Array.from(v.querySelectorAll("select")),A=s?Array.from(s.querySelectorAll("[data-filter-tag]")):[];E=[...l,...A],E.forEach(D=>{D.removeEventListener("keydown",m),D.addEventListener("keydown",m)})}function x(l){if(!u.length&&["ArrowDown","ArrowUp","Enter"].includes(l.key))return!1;switch(l.key){case"ArrowDown":return l.preventDefault(),L(1),!0;case"ArrowUp":return l.preventDefault(),L(-1),!0;case"Enter":return i>=0?(l.preventDefault(),re(),!0):!1;case"Escape":return l.preventDefault(),ae(),!0;default:return!1}}function L(l){if(!u.length)return;let A=i===-1?l>0?0:u.length-1:(i+l+u.length)%u.length;a(A)}function a(l){if(!(l<-1||l>=u.length)&&i!==l)if(i>=0&&u[i]&&u[i].classList.remove("is-active"),i=l,i>=0){let A=u[i];if(!A)return;A.classList.add("is-active");let D=b(A);t.setAttribute("aria-activedescendant",D);let R=ie(A);$(c,`Result ${i+1} of ${u.length}: ${R}`),A.scrollIntoView({block:"nearest"})}else t.removeAttribute("aria-activedescendant"),$(c,"Search results selection cleared.")}function S(l=!0){i>=0&&u[i]&&u[i].classList.remove("is-active"),i=-1,t.removeAttribute("aria-activedescendant"),l&&$(c,"Search results selection cleared.")}function b(l){if(l.id)return l.id;d+=1;let A=`${me}${d}`;return l.id=A,A}function I(){u=Array.from(o.querySelectorAll(".search-result")),u.forEach(l=>{b(l),l.setAttribute("role","option"),l.setAttribute("tabindex","-1")}),i>=u.length&&S(!1),p&&(p=!1,$(h,"Results updated.")),ne(),N()}function N(){if(!w)return;let l=t.value.trim();if(!l){$(w,"Enter a query to begin.");return}if(r&&!r.hidden&&u.length===0){$(w,`No results found for \u201C${l}\u201D.`);return}$(w,`${u.length} result${u.length===1?"":"s"} found for \u201C${l}\u201D.`)}function Q(){g&&g.setAttribute("aria-busy","true"),f&&(C&&(window.clearTimeout(C),C=null),y=Date.now(),f.hidden=!1,f.removeAttribute("hidden"))}function ne(){if(g&&g.setAttribute("aria-busy","false"),f){let l=()=>{f.hidden=!0,f.setAttribute("hidden",""),C=null,y=0},A=y?Date.now()-y:U;if(A<U){let D=U-A;C&&window.clearTimeout(C),C=window.setTimeout(l,D)}else l()}}function re(){let l=i>=0?u[i]:null;if(!l)return;let A=l.querySelector("[data-result-link]");A&&A.href&&window.location.assign(A.href)}function ae(){T.cancel(),t.value="",S(),$(h,"Search cleared."),n&&(p=!0,Q(),n.dispatchEvent(new Event("submit",{cancelable:!0})))}function ie(l){let A=l.querySelector("[data-result-link]");if(A&&A.textContent)return A.textContent.trim();let D=l.querySelector(".search-result__title");return D&&D.textContent?D.textContent.trim():"Result"}}var we=typeof process!="undefined"&&process.env&&process.env.VITEST==="true";function te(){ee(),Se()}we||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",te):te());export{ye as debounce,Se as setupSearchEnhancements,$ as updateLiveRegion};
1
+ import"./chunks/chunk-225H5YXE.js";var Q="datalog-search-analytics";function j({panel:e,list:n,empty:t,onSelect:i}){if(!e||!n||!t)return{record(){},render(){}};let r=d(),f="";function d(){let u=Object.create(null);try{let c=window.localStorage.getItem(Q);if(c){let a=JSON.parse(c);a&&typeof a=="object"&&Object.entries(a).forEach(([l,S])=>{typeof S=="number"&&Number.isFinite(S)&&(u[l]=S)})}}catch(c){}return u}function m(){try{window.localStorage.setItem(Q,JSON.stringify(r))}catch(u){}}function s(u){let c=(u||"").trim();!c||c===f||(f=c,r[c]=(r[c]||0)+1,m(),p())}function p(){let u=Object.entries(r).filter(([a])=>a&&a.trim().length>1).sort((a,l)=>l[1]-a[1]).slice(0,5);if(n.replaceChildren(),u.length===0){t.hidden=!1;return}t.hidden=!0;let c=document.createDocumentFragment();u.forEach(([a,l])=>{let S=document.createElement("li"),g=document.createElement("button");g.type="button",g.className="search-analytics__query",g.textContent=`${a} (${l})`,g.addEventListener("click",()=>{typeof i=="function"&&i(a)}),S.appendChild(g),c.appendChild(S)}),n.appendChild(c)}return{record:s,render:p}}function k(e=""){let n=e==null?"":String(e);try{return n.toLowerCase().normalize("NFKD").replace(new RegExp("\\p{Diacritic}","gu"),"")}catch(t){return n.toLowerCase()}}function F(e=""){return k(e).replace(/\s+/g,"")}function P(e=""){return k(e).split(/[^\p{L}\p{N}\\._]+/u).filter(Boolean)}function H(e=""){return/\\|\^|_|\{|\}|\$/.test(e)}function B(e=""){return/`|::|->|=>|\(|\)|\{|\}|\[|\]|=|\bdef\b|\bfunction\b|\bclass\b/.test(e)}function K(e,n){if(!e||!n)return!1;let t=0;for(let i=0;i<e.length&&t<n.length;i+=1)e[i]===n[t]&&(t+=1);return t===n.length}function ae(e){return e&&new DOMParser().parseFromString(String(e),"text/html").body.textContent||""}function O(e,n,t){if(!e)return"";let i=ae(e),r=Math.max(0,n-80),f=Math.min(i.length,n+t+80);return`${i.slice(r,f)}${f<i.length?"\u2026":""}`}function ie(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var oe={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function _(e){return String(e).replace(/[&<>"']/g,n=>oe[n])}function N(e,n){if(!e)return"";let t=String(e),i=Array.from(new Set(P(n||""))).sort((s,p)=>p.length-s.length);if(!i.length)return _(t);let r=new RegExp(i.map(ie).join("|"),"giu"),f="",d=0,m;for(;(m=r.exec(t))!==null;)f+=`${_(t.slice(d,m.index))}<mark>${_(m[0])}</mark>`,d=m.index+m[0].length;return f+_(t.slice(d))}function M(e){return(e||"").toString().split(/[-_\s]+/).map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join(" ")}function X(e){switch(e){case"post":return"Tutorial & Blog";case"project":return"Project";case"research":return"Research";case"dataset":return"Dataset";default:return M(e||"Page")}}function J({panel:e,limit:n=8,onSelect:t}){if(!e)return{setSuggestions(){},update(){},close(){},handleNavigation(){}};let i=[],r=-1;function f(c){i=Array.isArray(c)?[...c]:[]}function d(c){r=-1;let a=(c||"").trim().toLowerCase();if(!a){p();return}let l=i.filter(g=>g&&g.toLowerCase().includes(a)).slice(0,n);if(l.length===0){p();return}let S=document.createDocumentFragment();l.forEach((g,C)=>{let E=document.createElement("button");E.type="button",E.className="search-autocomplete__option",E.setAttribute("role","option"),E.dataset.autocompleteOption="",E.dataset.value=g,E.setAttribute("aria-selected",C===r?"true":"false"),E.replaceChildren(),E.insertAdjacentHTML("beforeend",N(g,a)),S.appendChild(E)}),e.replaceChildren(),e.appendChild(S),e.hidden=!1}function m(c,a){if(e.hidden)return;let l=Array.from(e.querySelectorAll("[data-autocomplete-option]"));if(l.length!==0){if(c.key==="ArrowDown")c.preventDefault(),r=(r+1)%l.length,s(l);else if(c.key==="ArrowUp")c.preventDefault(),r=(r-1+l.length)%l.length,s(l);else if(c.key==="Enter"&&r>=0){c.preventDefault();let S=l[r],g=S?S.dataset.value:"";g&&a&&(a.value=g),typeof t=="function"&&t(g),u()}}}function s(c){c.forEach((a,l)=>{let S=l===r;a.setAttribute("aria-selected",S?"true":"false"),a.classList.toggle("is-active",S)})}function p(){e.replaceChildren(),e.hidden=!0,r=-1}function u(){p()}return e.addEventListener("click",c=>{let a=c.target.closest("[data-autocomplete-option]");if(!a)return;let l=a.dataset.value||"";l&&typeof t=="function"&&t(l),u()}),{setSuggestions:f,update:d,close:u,handleNavigation:m}}function W(e=[]){let n=Array.isArray(e)?[...e]:[];function t(d){n=Array.isArray(d)?[...d]:[]}function i(d,m={}){let s=(d||"").trim();if(!s)return[];let p=k(s),u=P(s),c=H(s),a=B(s),{type:l="",language:S="",difficulty:g="",tags:C=new Set}=m;return n.map(E=>ce(E,{rawQuery:s,normalizedQuery:p,queryTokens:u,mathQuery:c,codeQuery:a,typeFilter:l,languageFilter:S,difficultyFilter:g,selectedTags:C})).filter(E=>E&&E.score>0).sort((E,T)=>T.score-E.score||E.title.localeCompare(T.title))}function r(d=150){return se(n,d)}function f(){return[...n]}return{setDocuments:t,search:i,suggestions:r,getDocuments:f}}function se(e=[],n=150){let t=new Set;return e.forEach(i=>{i.title&&t.add(i.title),Array.isArray(i.languages)&&i.languages.forEach(r=>t.add(r)),Array.isArray(i.tags)&&i.tags.forEach(r=>t.add(`#${r}`)),Array.isArray(i.math)&&i.math.slice(0,3).forEach(r=>t.add(r))}),Array.from(t).slice(0,n)}function ce(e,n){let{rawQuery:t,normalizedQuery:i,queryTokens:r,mathQuery:f,codeQuery:d,typeFilter:m,languageFilter:s,difficultyFilter:p,selectedTags:u}=n;if(m&&e.type!==m)return null;let c=Array.isArray(e.languages)?e.languages:[];if(s&&!c.includes(s))return null;if(p){let y=String(e.difficulty||"").toLowerCase();if(!y||y!==p)return null}if(u&&u.size>0){let y=new Set(G(e).tags);for(let o of u)if(!y.has(o))return null}if(!t)return null;let{title:a,summary:l,content:S,tags:g,languages:C,difficulty:E}=G(e),T=Array.isArray(e.code)?e.code:[],q=Array.isArray(e.math)?e.math:[],x=0,w="",D=null,A=null;if(a.includes(i)&&(x+=40),r.forEach(y=>{y&&(a.includes(y)&&(x+=12),l.includes(y)&&(x+=8),S.includes(y)&&(x+=6),g.forEach(o=>{o.includes(y)&&(x+=4)}),C.forEach(o=>{o.includes(y)&&(x+=4)}),E.includes(y)&&(x+=2))}),T.length>0){let y=F(t);for(let o of T){let b=String(o.language||"").toLowerCase(),v=o.code||"",z=F(v);if(z.includes(y)){x+=30,D={language:b,code:v};break}if(d&&K(z,y)){x+=18,D={language:b,code:v};break}}!D&&T[0]&&(D={language:String(T[0].language||"").toLowerCase(),code:T[0].code||""})}if(q.length>0){let y=i.replace(/\\/g,"");for(let o of q)if(k(String(o)).includes(y)){x+=26,A=o;break}f&&!A&&q[0]&&(A=q[0],x+=10)}if(S.includes(i)){let y=S.indexOf(i);w=O(e.content||"",y,t.length),x+=10}else if(l.includes(i)){let y=l.indexOf(i);w=O(e.summary||"",y,t.length),x+=6}return x===0?null:{id:`${e.url}`,title:e.title,url:e.url,summary:e.summary,snippet:w,codeSnippet:D,mathSnippet:A,tags:e.tags||[],languages:e.languages||[],difficulty:e.difficulty||"",type:e.type||"page",date:e.date,readingTime:e.reading_time,score:x}}var Y=new WeakMap;function G(e){let n=Y.get(e);if(n)return n;let t=e.normalized||{},i={title:t.title||k(e.title||""),summary:t.summary||k(e.summary||""),content:t.content||k(e.content||""),tags:V(t.tags,e.tags),languages:V(t.languages,e.languages),difficulty:t.difficulty||k(e.difficulty||"")};return Y.set(e,i),i}function V(e,n){return Array.isArray(e)&&e.length>0?e:Array.isArray(n)?n.map(t=>k(t)):[]}function Z(e,n,t){if(!e)return;let i=new Set;n.forEach(d=>{(d.tags||d.topics||[]).forEach(s=>{if(!s)return;let p=String(s).trim().toLowerCase();p&&i.add(p)})});let r=Array.from(i).sort();if(r.length===0){let d=document.createElement("p");d.className="search-filter__empty",d.textContent="No tags available yet.",e.replaceChildren(d);return}let f=document.createDocumentFragment();r.forEach(d=>{let m=document.createElement("button");m.type="button",m.className="search-filter__tag",m.textContent=d,m.dataset.filterTag=d,m.setAttribute("aria-pressed",t.has(d)?"true":"false"),f.appendChild(m)}),e.replaceChildren(),e.appendChild(f)}function ee(e,n,t){let{resultsList:i,resultsMeta:r,emptyState:f,template:d}=t;if(!i||!r||!f||!d)return;if(i.replaceChildren(),!n){r.textContent="Enter a query to begin.",f.hidden=!0;return}if(e.length===0){r.textContent=`No matches for \u201C${n}\u201D.`,f.hidden=!1;return}f.hidden=!0,r.textContent=`${e.length} result${e.length===1?"":"s"} for \u201C${n}\u201D.`;let m=document.createDocumentFragment();e.forEach(s=>{let p=d.content.cloneNode(!0),u=p.querySelector("[data-result-type]"),c=p.querySelector("[data-result-difficulty]"),a=p.querySelector("[data-result-languages]"),l=p.querySelector("[data-result-link]"),S=p.querySelector("[data-result-summary]"),g=p.querySelector("[data-result-code]"),C=g?g.querySelector("code"):null,E=p.querySelector("[data-result-math]"),T=p.querySelector("[data-result-math-preview]"),q=p.querySelector("[data-result-math-code]"),x=p.querySelector("[data-result-math-copy]"),w=p.querySelector("[data-result-excerpt]"),D=p.querySelector("[data-result-tags]"),A=p.querySelector("[data-result-date]");if(u&&(u.textContent=X(s.type)),c&&(s.difficulty?(c.textContent=`Difficulty: ${M(s.difficulty)}`,c.hidden=!1):c.hidden=!0),a&&(s.languages&&s.languages.length>0?(a.textContent=`Languages: ${s.languages.map(y=>M(y)).join(", ")}`,a.hidden=!1):a.hidden=!0),l&&(l.textContent=s.title||s.url,l.setAttribute("href",s.url)),S&&(S.replaceChildren(),S.insertAdjacentHTML("beforeend",N(s.summary||"",n))),E&&q&&(s.mathSnippet?(E.hidden=!1,q.textContent=s.mathSnippet,T&&(window.DatalogMath&&typeof window.DatalogMath.renderLatex=="function"?window.DatalogMath.renderLatex(T,s.mathSnippet,{display:!1,enhance:!1}):window.MathJax&&typeof window.MathJax.typesetPromise=="function"?(T.textContent=`\\(${s.mathSnippet}\\)`,window.MathJax.typesetPromise([T]).catch(()=>{T.textContent=s.mathSnippet})):T.textContent=s.mathSnippet),x&&x.addEventListener("click",()=>le(s.mathSnippet,E))):E.hidden=!0),w&&(s.snippet?(w.replaceChildren(),w.insertAdjacentHTML("beforeend",N(s.snippet,n)),w.hidden=!1):w.hidden=!0),g&&C)if(s.codeSnippet&&s.codeSnippet.code){let y=s.codeSnippet.language||"text";g.classList.remove("language-none"),g.classList.add(`language-${y}`),C.className=`language-${y}`,C.textContent=s.codeSnippet.code,g.hidden=!1}else g.hidden=!0;if(D&&(D.replaceChildren(),(s.tags||[]).forEach(y=>{let o=document.createElement("li");o.textContent=`#${y}`,D.appendChild(o)})),A)if(s.date){let y=new Date(s.date);Number.isNaN(y.getTime())?A.hidden=!0:(A.textContent=y.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}),A.hidden=!1)}else A.hidden=!0;m.appendChild(p)}),i.appendChild(m)}function le(e,n){if(!e)return;let t=()=>{if(!n)return;let r=n.querySelector("[data-result-math-copy]"),f=r?r.querySelector(".visually-hidden"):null;if(r&&f){let d=r.getAttribute("data-sr-original")||f.textContent;r.getAttribute("data-sr-original")||r.setAttribute("data-sr-original",d||"Copy LaTeX"),f.textContent="Copied LaTeX",r.classList.add("is-copied"),window.setTimeout(()=>{f.textContent=r.getAttribute("data-sr-original")||"Copy LaTeX",r.classList.remove("is-copied")},2e3)}},i=()=>{let r=document.createElement("textarea");r.value=e,r.setAttribute("aria-hidden","true"),r.style.position="fixed",r.style.opacity="0",document.body.appendChild(r),r.select();try{document.execCommand("copy"),t()}catch(f){}document.body.removeChild(r)};navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(e).then(()=>t()).catch(()=>i()):i()}var ue=8;function te(){let e=document.querySelector("[data-search-app]");if(!e)return;let n=e.querySelector("[data-search-form]"),t=e.querySelector("[data-search-input]"),i=e.querySelector("[data-search-results]"),r=e.querySelector("[data-search-meta]"),f=e.querySelector("[data-search-empty]"),d=e.querySelector("[data-search-autocomplete]"),m=e.querySelector("[data-search-analytics]"),s=m?m.querySelector(".search-app__analytics-list"):null,p=m?m.querySelector(".search-app__analytics-empty"):null,u=document.getElementById("search-result-template"),c=e.querySelector("[data-filter-type]"),a=e.querySelector("[data-filter-language]"),l=e.querySelector("[data-filter-difficulty]"),S=e.querySelector("[data-filter-tags]"),g=e.getAttribute("data-search-index")||"/search.json",C=new Set,E=W(),T=j({panel:m,list:s,empty:p,onSelect:o=>{t&&(t.value=o,A())}}),q=J({panel:d,limit:ue,onSelect:o=>{o&&t&&(t.value=o,t.focus(),A())}}),x=!1,w=new URLSearchParams(window.location.search);t&&w.has("q")&&(t.value=w.get("q")||""),c&&w.has("type")&&(c.value=w.get("type")),a&&w.has("language")&&(a.value=w.get("language")),l&&w.has("difficulty")&&(l.value=w.get("difficulty")),w.has("tags")&&w.get("tags").split(",").map(o=>o.trim().toLowerCase()).filter(Boolean).forEach(o=>C.add(o)),fe(t,()=>{q.close(),A()}),de(g).then(o=>{let b=o.documents||[];E.setDocuments(b),q.setSuggestions(E.suggestions()),Z(S,b,C),x=!0,D()}).catch(o=>{r&&(r.textContent="Unable to load the search index. Please try again later.")}),n&&n.addEventListener("submit",o=>{o.preventDefault(),A()}),t&&(t.addEventListener("input",()=>{q.update(t.value)}),t.addEventListener("keydown",o=>{q.handleNavigation(o,t)}),t.addEventListener("focus",()=>{q.update(t.value)})),c&&c.addEventListener("change",A),a&&a.addEventListener("change",A),l&&l.addEventListener("change",A),e.addEventListener("click",o=>{let b=o.target;if(b.matches("[data-filter-tag]")){let v=b.getAttribute("data-filter-tag");v&&(C.has(v)?(C.delete(v),b.setAttribute("aria-pressed","false")):(C.add(v),b.setAttribute("aria-pressed","true")),A())}}),document.addEventListener("click",o=>{!d||d.hidden||e.contains(o.target)||q.close()}),document.addEventListener("keydown",o=>{let b=document.activeElement?document.activeElement.tagName:"";["INPUT","TEXTAREA"].includes(b)||(o.key==="/"&&!o.ctrlKey&&!o.metaKey&&!o.altKey||(o.key==="k"||o.key==="K")&&(o.ctrlKey||o.metaKey))&&(o.preventDefault(),t&&(t.focus(),t.select()))}),T.render();function D(){t&&t.value.trim()?A():y()}function A(){if(!t)return;if(!x){r&&(r.textContent="Loading technical index\u2026");return}let o=t.value.trim(),b={type:c?c.value:"",language:a?a.value:"",difficulty:l?l.value:"",tags:C},v=E.search(o,b);ee(v,o,{resultsList:i,resultsMeta:r,emptyState:f,template:u}),y(o),T.record(o)}function y(o){let b=new URL(window.location.href),v=b.searchParams;o?v.set("q",o):v.delete("q"),c&&c.value?v.set("type",c.value):v.delete("type"),a&&a.value?v.set("language",a.value):v.delete("language"),l&&l.value?v.set("difficulty",l.value):v.delete("difficulty"),C.size>0?v.set("tags",Array.from(C).join(",")):v.delete("tags");let z=v.toString(),R=z?`${b.pathname}?${z}`:b.pathname;window.history.replaceState({},"",R)}}function de(e){return fetch(e,{credentials:"same-origin"}).then(n=>{if(!n.ok)throw new Error(`HTTP ${n.status}`);return n.json()})}function fe(e,n){e&&e.addEventListener("keydown",t=>{t.key==="Escape"&&(e.value="",typeof n=="function"&&n())})}var pe=300,ge="search-result-",U=500;function he(e,n=pe){let t,i=(...r)=>{t&&window.clearTimeout(t),t=window.setTimeout(()=>{t=void 0,e.apply(null,r)},n)};return i.cancel=()=>{t&&(window.clearTimeout(t),t=void 0)},i}function $(e,n){if(!e)return;let t=String(n||"");e.textContent===t?e.textContent=`${t}\xA0`:e.textContent=t,t.trim()?e.removeAttribute("hidden"):e.setAttribute("hidden","")}function me(){let e=document.querySelector("[data-search-app]");if(!e)return;let n=e.querySelector("[data-search-form]"),t=e.querySelector("[data-search-input]"),i=e.querySelector("[data-search-results]"),r=e.querySelector("[data-search-empty]"),f=e.querySelector("[data-search-loading]"),d=e.querySelector("[data-search-region]"),m=e.querySelector('[data-search-live="count"]'),s=e.querySelector('[data-search-live="selection"]'),p=e.querySelector('[data-search-live="status"]');if(!t||!i)return;let u=-1,c=0,a=[],l=!1,S=0,g=null,C=he(()=>{n&&(l=!0,o(),$(p,"Loading results\u2026"),n.dispatchEvent(new Event("submit",{cancelable:!0})))});new MutationObserver(()=>{A()}).observe(i,{childList:!0}),A(),t.addEventListener("input",()=>{w(!1),C()}),t.addEventListener("keydown",T);function T(h){if(!a.length&&["ArrowDown","ArrowUp","Enter"].includes(h.key))return!1;switch(h.key){case"ArrowDown":return h.preventDefault(),q(1),!0;case"ArrowUp":return h.preventDefault(),q(-1),!0;case"Enter":return u>=0?(h.preventDefault(),v(),!0):!1;case"Escape":return h.preventDefault(),z(),!0;default:return!1}}function q(h){if(!a.length)return;let L=u===-1?h>0?0:a.length-1:(u+h+a.length)%a.length;x(L)}function x(h){if(!(h<-1||h>=a.length)&&u!==h)if(u>=0&&a[u]&&a[u].classList.remove("is-active"),u=h,u>=0){let L=a[u];if(!L)return;L.classList.add("is-active");let I=D(L);t.setAttribute("aria-activedescendant",I);let re=R(L);$(s,`Result ${u+1} of ${a.length}: ${re}`),L.scrollIntoView({block:"nearest"})}else t.removeAttribute("aria-activedescendant"),$(s,"Search results selection cleared.")}function w(h=!0){u>=0&&a[u]&&a[u].classList.remove("is-active"),u=-1,t.removeAttribute("aria-activedescendant"),h&&$(s,"Search results selection cleared.")}function D(h){if(h.id)return h.id;c+=1;let L=`${ge}${c}`;return h.id=L,L}function A(){a=Array.from(i.querySelectorAll(".search-result")),a.forEach(h=>{D(h),h.setAttribute("role","option"),h.setAttribute("tabindex","-1")}),u>=a.length&&w(!1),l&&(l=!1,$(p,"Results updated.")),b(),y()}function y(){if(!m)return;let h=t.value.trim();if(!h){$(m,"Enter a query to begin.");return}if(r&&!r.hidden&&a.length===0){$(m,`No results found for \u201C${h}\u201D.`);return}$(m,`${a.length} result${a.length===1?"":"s"} found for \u201C${h}\u201D.`)}function o(){d&&d.setAttribute("aria-busy","true"),f&&(g&&(window.clearTimeout(g),g=null),S=Date.now(),f.hidden=!1,f.removeAttribute("hidden"))}function b(){if(d&&d.setAttribute("aria-busy","false"),f){let h=()=>{f.hidden=!0,f.setAttribute("hidden",""),g=null,S=0},L=S?Date.now()-S:U;if(L<U){let I=U-L;g&&window.clearTimeout(g),g=window.setTimeout(h,I)}else h()}}function v(){let h=u>=0?a[u]:null;if(!h)return;let L=h.querySelector("[data-result-link]");L&&L.href&&window.location.assign(L.href)}function z(){C.cancel(),t.value="",w(),$(p,"Search cleared."),n&&(l=!0,o(),n.dispatchEvent(new Event("submit",{cancelable:!0})))}function R(h){let L=h.querySelector("[data-result-link]");if(L&&L.textContent)return L.textContent.trim();let I=h.querySelector(".search-result__title");return I&&I.textContent?I.textContent.trim():"Result"}}var ye=typeof process!="undefined"&&process.env&&process.env.VITEST==="true";function ne(){te(),me()}ye||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ne):ne());export{he as debounce,me as setupSearchEnhancements,$ as updateLiveRegion};
@@ -1,2 +1,11 @@
1
- (function(){let Y=typeof process!="undefined"&&process.env&&process.env.VITEST==="true",T="[data-viz-type]",O='script[type="application/json"]',F='script[type="application/vnd.jupyter.widget-state+json"]',H='script[type="application/vnd.jupyter.widget-view+json"]',C=new Map,_=new Set,k="viz-table-fallback-template",v=(t,r={})=>{if(!t)return Promise.reject(new Error("Missing script source"));if(C.has(t))return C.get(t);let e=new Promise((n,s)=>{let o=document.createElement("script");o.src=t,o.async=r.async!==!1,r.integrity&&(o.integrity=r.integrity,o.crossOrigin=r.crossOrigin||"anonymous"),o.onload=()=>n(o),o.onerror=a=>s(a),document.head.appendChild(o)});return C.set(t,e),e},I=t=>!t||_.has(t)?Promise.resolve():new Promise((r,e)=>{let n=document.createElement("link");n.rel="stylesheet",n.href=t,n.onload=()=>{_.add(t),r(n)},n.onerror=s=>e(s),document.head.appendChild(n)}),g=t=>Object.prototype.toString.call(t)==="[object Object]",f=t=>t===null||typeof t=="undefined"?"":t instanceof Date?t.toISOString():Array.isArray(t)?t.map(r=>f(r)).join(", "):g(t)?Object.entries(t).map(([r,e])=>`${r}: ${f(e)}`).join("; "):typeof t=="boolean"?t?"Yes":"No":typeof t=="number"?Number.isFinite(t)?`${t}`:"":String(t),j=(t,r=[])=>g(t)?Object.entries(t).reduce((e,[n,s])=>{let o=r.concat([n]);return g(s)?Object.assign(e,j(s,o)):Array.isArray(s)?e[o.join(" \u203A ")]=s.map(a=>f(a)).join(", "):e[o.join(" \u203A ")]=s,e},{}):{[r.join(" \u203A ")||"Value"]:t},m=t=>{if(!t)return[];if(Array.isArray(t)){if(!t.length)return[];if(t.every(r=>g(r)))return t.map(r=>j(r));if(Array.isArray(t[0])){let r=t[0],e=r.every(o=>typeof o=="string"||typeof o=="number"),n=r.map((o,a)=>e?f(o):`Column ${a+1}`),s=e?1:0;return t.slice(s).map((o,a)=>{let i={};return Array.isArray(o)?(n.forEach((c,l)=>{i[c]=o[l]}),n.length||o.forEach((c,l)=>{i[`Column ${l+1}`]=c})):i[`Row ${a+1}`]=o,i})}return t.map((r,e)=>({Index:e+1,Value:r}))}return g(t)?Array.isArray(t.data)?m(t.data):Array.isArray(t.values)?m(t.values):Array.isArray(t.rows)?m(t.rows):[j(t)]:[{Value:t}]},X=t=>{let r=["Series","Trace","Group","Category","Index","X","Y","Z","Value","Text"],e=[];return r.forEach(n=>{t.includes(n)&&e.push(n)}),t.filter(n=>!r.includes(n)).sort().forEach(n=>e.push(n)),e},Z=t=>{let r=t.getAttribute("data-viz-title");if(r)return r;let e=t.querySelector(".viz-title");return e&&e.textContent?e.textContent.trim():t.getAttribute("data-viz-slug")||"Visualization data"},U=()=>{let t=document.getElementById(k);if(t)return t;t=document.createElement("template"),t.id=k;let r=document.createElement("div");return r.insertAdjacentHTML("afterbegin",'<div class="viz-table-container" data-viz-table-container><button type="button" class="viz-table-toggle" data-viz-table-toggle aria-expanded="false">Show data table</button><div class="viz-table-wrapper" data-viz-table-wrapper hidden><table class="viz-table" data-viz-table><caption data-viz-table-caption></caption><thead data-viz-table-head></thead><tbody data-viz-table-body></tbody></table></div></div>'),t.content.appendChild(r.firstElementChild),document.body.appendChild(t),t},E=(t,r={})=>{let{caption:e,rows:n}=r,s=m(n);if(!s.length)return;let o=Array.from(s.reduce((p,y)=>(Object.keys(y).forEach(P=>p.add(P)),p),new Set));if(!o.length)return;let a=X(o),c=U().content.firstElementChild.cloneNode(!0),l=c.querySelector("[data-viz-table-toggle]"),u=c.querySelector("[data-viz-table-wrapper]"),w=c.querySelector("[data-viz-table]"),S=c.querySelector("[data-viz-table-caption]"),h=c.querySelector("[data-viz-table-head]"),A=c.querySelector("[data-viz-table-body]"),z=`${t.getAttribute("data-viz-slug")||t.id||"viz"}-table`;w.id=z,l.setAttribute("aria-controls",z),S.textContent=e||Z(t);let x=document.createElement("tr");a.forEach(p=>{let y=document.createElement("th");y.scope="col",y.textContent=p,x.appendChild(y)}),h.appendChild(x),s.forEach(p=>{let y=document.createElement("tr");a.forEach((P,lt)=>{let J=f(p[P]);if(lt===0){let b=document.createElement("th");b.scope="row",b.textContent=J,y.appendChild(b)}else{let b=document.createElement("td");b.textContent=J,y.appendChild(b)}}),A.appendChild(y)}),l.addEventListener("click",()=>{let p=l.getAttribute("aria-expanded")==="true";l.setAttribute("aria-expanded",String(!p)),l.textContent=p?"Show data table":"Hide data table",p?u.setAttribute("hidden",""):u.removeAttribute("hidden")});let G=t.querySelector("[data-viz-table-container]");G&&G.remove(),t.appendChild(c),(t.querySelector("[data-viz-canvas]")||t).setAttribute("aria-describedby",z)},N=(t=[])=>{let r=[];return t.forEach((e,n)=>{let s=e.name||`Series ${n+1}`,o=Array.isArray(e.x)?e.x:[],a=Array.isArray(e.y)?e.y:[],i=Array.isArray(e.text)?e.text:[],c=e.z;if(Array.isArray(c)&&c.length&&Array.isArray(c[0])){let u=o.length?o:c[0].map((S,h)=>h+1);(a.length?a:c.map((S,h)=>h+1)).forEach((S,h)=>{let A=c[h]||[];u.forEach((z,x)=>{r.push({Series:s,Y:S,X:z,Value:Array.isArray(A)?A[x]:A,Text:i[h]?f(i[h]):""})})});return}let l=Math.max(o.length,a.length,i.length);for(let u=0;u<l;u+=1)r.push({Series:s,X:o[u],Y:a[u],Text:i[u]})}),r.length?r:null},L=t=>t?Array.isArray(t)?t:g(t)&&Array.isArray(t.data)?t.data:t:null,V=t=>{let r=t.querySelector("script[data-observable-data]");if(!r)return null;try{return JSON.parse(r.textContent||"null")}catch(e){return null}},D=()=>(typeof window.Plotly!="undefined"?Promise.resolve():v("https://cdn.plot.ly/plotly-2.27.0.min.js")).then(()=>window.Plotly),K=()=>typeof window.d3!="undefined"?Promise.resolve(window.d3):v("https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js").then(()=>window.d3),Q=()=>Promise.all([v("https://cdn.bokeh.org/bokeh/release/bokeh-3.3.3.min.js"),I("https://cdn.bokeh.org/bokeh/release/bokeh-3.3.3.min.css")]).then(()=>window.Bokeh),tt=()=>typeof window.requirejs!="undefined"?Promise.resolve(window.requirejs):v("https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js",{async:!1}).then(()=>window.requirejs),et=()=>tt().then(t=>{let r=window.__datalogWidgetManagerPromise;if(r)return r;let e=new Promise((n,s)=>{t.config({paths:{"@jupyter-widgets/html-manager":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@1.0.8/dist/embed-amd","@jupyter-widgets/base":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/base@6.0.7/dist/index","@jupyter-widgets/controls":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/controls@5.0.7/dist/index","@lumino/coreutils":"https://cdn.jsdelivr.net/npm/@lumino/coreutils@2.1.1/dist/index","@lumino/widgets":"https://cdn.jsdelivr.net/npm/@lumino/widgets@2.3.1/dist/index"}}),t(["@jupyter-widgets/html-manager"],o=>n(o),o=>s(o))});return window.__datalogWidgetManagerPromise=e,e}),rt=(t,r)=>{let e=document.createElement("button");return e.type="button",e.className="viz-toolbar__button",e.textContent=t,e.addEventListener("click",n=>{n.preventDefault(),r(n)}),e},d=(t,r,e="info")=>{let n=t.querySelector("[data-viz-status]");n&&(n.textContent=r,n.dataset.tone=e)},M=t=>{let r=t.getAttribute("data-viz-version"),e=t.getAttribute("data-viz-updated"),n=t.querySelector("[data-viz-meta]");if(!n)return;let s=[];r&&s.push(`v${r}`),e&&s.push(`Updated ${e}`),n.textContent=s.join(" \xB7 ")},nt=t=>{let r=t.querySelector("[data-viz-canvas]")||t,e=t.querySelector(O);if(!e)return d(t,"Missing Plotly specification","error"),Promise.resolve();let n={};try{n=JSON.parse(e.textContent||"{}")}catch(a){return d(t,"Invalid Plotly specification","error"),Promise.resolve()}let s=Array.isArray(n.data)?n.data:[],o=Object.assign({autosize:!0},n.layout||{});return D().then(a=>a.newPlot(r,s,o,{responsive:!0,displaylogo:!1})).then(()=>{d(t,"Interactive");let a=t.querySelector("[data-viz-export]");a&&(a.replaceChildren(),a.appendChild(rt("Download PNG",()=>{D().then(c=>{c.downloadImage(r,{format:"png",filename:t.getAttribute("data-viz-slug")||"visualization"})})})));let i=N(s);i&&E(t,{caption:o&&o.title?f(o.title.text||o.title):void 0,rows:i})}).catch(()=>{d(t,"Plotly failed to load","error")})},ot=t=>{let r=t.querySelector("[data-d3-script]");return r?K().then(e=>{let n=r.textContent||"",s=t.querySelector("[data-viz-canvas]")||t;s.replaceChildren();let o=[],a=i=>{typeof i!="undefined"&&o.push(i)};try{let i=`${n}
2
- ;try { if (typeof data !== 'undefined') captureData(data); } catch (instrumentationError) {}`,l=new Function("d3","element","captureData",i)(e,s,a);typeof l!="undefined"&&a(l);let u=o.length?o[o.length-1]:null,w=L(u);w&&E(t,{rows:w}),d(t,"Interactive")}catch(i){s.replaceChildren(),d(t,"D3 rendering error","error")}}).catch(()=>d(t,"D3 assets failed to load","error")):(d(t,"Missing D3 rendering instructions","error"),Promise.resolve())},st=t=>{let r=t.getAttribute("data-observable-src");if(!r)return d(t,"Missing Observable notebook source","error"),Promise.resolve();let e=document.createElement("iframe");e.src=r,e.loading="lazy",e.title=t.getAttribute("data-viz-title")||"Observable visualization",e.setAttribute("allowfullscreen",""),e.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),e.className="viz-embed",(t.querySelector("[data-viz-canvas]")||t).replaceChildren(e),d(t,"Embedded");let s=V(t);return s&&E(t,{rows:s}),Promise.resolve()},at=t=>{let r=t.querySelector(O),e=t.querySelector("[data-bokeh-script]"),n=t.querySelector("[data-viz-canvas]")||t;return!r&&!e?(d(t,"Missing Bokeh specification","error"),Promise.resolve()):Q().then(s=>{if(r){let o={};try{o=JSON.parse(r.textContent||"{}")}catch(i){d(t,"Invalid Bokeh specification","error");return}let a=n.id||`bokeh-${Math.random().toString(36).slice(2)}`;n.id=a;try{s.embed.embed_item(o,a),d(t,"Interactive")}catch(i){d(t,"Bokeh rendering error","error")}return}if(e){let o=e.textContent||"";n.replaceChildren();try{new Function("Bokeh","element",o)(s,n),d(t,"Interactive")}catch(a){d(t,"Bokeh rendering error","error")}}}).catch(()=>{d(t,"Bokeh assets failed to load","error")})},it=t=>{let r=t.getAttribute("data-shiny-src");if(!r)return d(t,"Missing Shiny application source","error"),Promise.resolve();let e=document.createElement("iframe");e.src=r,e.loading="lazy",e.title=t.getAttribute("data-viz-title")||"R Shiny application",e.className="viz-embed",e.setAttribute("allow","fullscreen"),e.setAttribute("sandbox","allow-scripts allow-forms allow-same-origin");let n=t.getAttribute("data-shiny-height");return e.style.height=n||"640px",(t.querySelector("[data-viz-canvas]")||t).replaceChildren(e),d(t,"Embedded"),Promise.resolve()},ct=t=>{let r=t.querySelector(F),e=t.querySelector(H);if(!r||!e)return d(t,"Missing widget state payload","error"),Promise.resolve();let n,s;try{n=JSON.parse(r.textContent||"{}"),s=JSON.parse(e.textContent||"{}")}catch(a){return d(t,"Invalid widget payload","error"),Promise.resolve()}let o=t.querySelector("[data-viz-canvas]")||t;return o.replaceChildren(),et().then(a=>{let i=new a.WidgetManager;return i.set_state(n).then(()=>i.get_model(s.model_id)).then(c=>i.create_view(c)).then(c=>i.display_view(void 0,c,{el:o})).then(()=>d(t,"Interactive")).catch(c=>{d(t,"Widget rendering error","error")})}).catch(()=>d(t,"Widget assets failed to load","error"))},q=t=>{let r=t.getAttribute("data-viz-type");switch(M(t),r){case"plotly":return nt(t);case"observable":return st(t);case"d3":return ot(t);case"bokeh":return at(t);case"shiny":return it(t);case"ipywidgets":return ct(t);default:return d(t,"Unsupported visualization type","error"),Promise.resolve()}},B=()=>{if(!("IntersectionObserver"in window)){document.querySelectorAll(T).forEach(r=>{q(r)});return}let t=new IntersectionObserver((r,e)=>{r.filter(n=>n.isIntersecting).forEach(n=>{let s=n.target;e.unobserve(s),q(s)})},{rootMargin:"200px 0px"});document.querySelectorAll(T).forEach(r=>{t.observe(r)})},R=t=>{document.querySelectorAll("[data-viz-card]").forEach(e=>{let n=!t.tech||e.dataset.vizTech===t.tech,s=(e.dataset.vizTags||"").split(",").map(a=>a.trim()).filter(Boolean),o=!t.tag||s.includes(t.tag);e.hidden=!(n&&o)})},$=()=>{let t=document.querySelector("[data-viz-gallery]");if(!t)return;let r=t.querySelector('[data-viz-filter="tech"]'),e=t.querySelector('[data-viz-filter="tag"]'),n=()=>{R({tech:r&&r.value!=="all"?r.value:"",tag:e&&e.value!=="all"?e.value:""})};r&&r.addEventListener("change",n),e&&e.addEventListener("change",n),n()},W=()=>{B(),$()},dt={loadScript:v,loadStyle:I,normalizeRecords:m,stringifyValue:f,buildDataTable:E,annotateVersionMetadata:M,buildPlotlyRecords:N,buildD3Records:L,buildObservableRecords:V,filterGallery:R,renderVisualization:q,initializeVisualizations:B,initializeGallery:$};typeof globalThis!="undefined"&&(globalThis.__DATALOG_VIZ_INTERNALS__=dt),Y||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",W):W())})();
1
+ (function(){let Z=typeof process!="undefined"&&process.env&&process.env.VITEST==="true",_="[data-viz-type]",I='script[type="application/json"]',F='script[type="application/vnd.jupyter.widget-state+json"]',K='script[type="application/vnd.jupyter.widget-view+json"]',q=new Map,L=new Set,k="viz-table-fallback-template",z=(t,e={})=>{if(!t)return Promise.reject(new Error("Missing script source"));if(q.has(t))return q.get(t);let r=new Promise((n,s)=>{let o=document.createElement("script");o.src=t,o.async=e.async!==!1,e.integrity&&(o.integrity=e.integrity,o.crossOrigin=e.crossOrigin||"anonymous"),o.onload=()=>n(o),o.onerror=a=>s(a),document.head.appendChild(o)});return q.set(t,r),r},Q=t=>!t||L.has(t)?Promise.resolve():new Promise((e,r)=>{let n=document.createElement("link");n.rel="stylesheet",n.href=t,n.onload=()=>{L.add(t),e(n)},n.onerror=s=>r(s),document.head.appendChild(n)}),b=t=>Object.prototype.toString.call(t)==="[object Object]",y=t=>t===null||typeof t=="undefined"?"":t instanceof Date?t.toISOString():Array.isArray(t)?t.map(e=>y(e)).join(", "):b(t)?Object.entries(t).map(([e,r])=>`${e}: ${y(r)}`).join("; "):typeof t=="boolean"?t?"Yes":"No":typeof t=="number"?Number.isFinite(t)?`${t}`:"":String(t),T=(t,e=[])=>b(t)?Object.entries(t).reduce((r,[n,s])=>{let o=e.concat([n]);return b(s)?Object.assign(r,T(s,o)):Array.isArray(s)?r[o.join(" \u203A ")]=s.map(a=>y(a)).join(", "):r[o.join(" \u203A ")]=s,r},{}):{[e.join(" \u203A ")||"Value"]:t},m=t=>{if(!t)return[];if(Array.isArray(t)){if(!t.length)return[];if(t.every(e=>b(e)))return t.map(e=>T(e));if(Array.isArray(t[0])){let e=t[0],r=e.every(o=>typeof o=="string"||typeof o=="number"),n=e.map((o,a)=>r?y(o):`Column ${a+1}`),s=r?1:0;return t.slice(s).map((o,a)=>{let c={};return Array.isArray(o)?(n.forEach((i,l)=>{c[i]=o[l]}),n.length||o.forEach((i,l)=>{c[`Column ${l+1}`]=i})):c[`Row ${a+1}`]=o,c})}return t.map((e,r)=>({Index:r+1,Value:e}))}return b(t)?Array.isArray(t.data)?m(t.data):Array.isArray(t.values)?m(t.values):Array.isArray(t.rows)?m(t.rows):[T(t)]:[{Value:t}]},tt=t=>{let e=["Series","Trace","Group","Category","Index","X","Y","Z","Value","Text"],r=[];return e.forEach(n=>{t.includes(n)&&r.push(n)}),t.filter(n=>!e.includes(n)).sort().forEach(n=>r.push(n)),r},et=t=>{let e=t.getAttribute("data-viz-title");if(e)return e;let r=t.querySelector(".viz-title");return r&&r.textContent?r.textContent.trim():t.getAttribute("data-viz-slug")||"Visualization data"},rt=()=>{let t=document.getElementById(k);if(t)return t;t=document.createElement("template"),t.id=k;let e=document.createElement("div");return e.insertAdjacentHTML("afterbegin",'<div class="viz-table-container" data-viz-table-container><button type="button" class="viz-table-toggle" data-viz-table-toggle aria-expanded="false">Show data table</button><div class="viz-table-wrapper" data-viz-table-wrapper hidden><table class="viz-table" data-viz-table><caption data-viz-table-caption></caption><thead data-viz-table-head></thead><tbody data-viz-table-body></tbody></table></div></div>'),t.content.appendChild(e.firstElementChild),document.body.appendChild(t),t},E=(t,e={})=>{let{caption:r,rows:n}=e,s=m(n);if(!s.length)return;let o=Array.from(s.reduce((p,f)=>(Object.keys(f).forEach(O=>p.add(O)),p),new Set));if(!o.length)return;let a=tt(o),i=rt().content.firstElementChild.cloneNode(!0),l=i.querySelector("[data-viz-table-toggle]"),u=i.querySelector("[data-viz-table-wrapper]"),H=i.querySelector("[data-viz-table]"),w=i.querySelector("[data-viz-table-caption]"),h=i.querySelector("[data-viz-table-head]"),S=i.querySelector("[data-viz-table-body]"),A=`${t.getAttribute("data-viz-slug")||t.id||"viz"}-table`;H.id=A,l.setAttribute("aria-controls",A),w.textContent=r||et(t);let x=document.createElement("tr");a.forEach(p=>{let f=document.createElement("th");f.scope="col",f.textContent=p,x.appendChild(f)}),h.appendChild(x),s.forEach(p=>{let f=document.createElement("tr");a.forEach((O,yt)=>{let X=y(p[O]);if(yt===0){let v=document.createElement("th");v.scope="row",v.textContent=X,f.appendChild(v)}else{let v=document.createElement("td");v.textContent=X,f.appendChild(v)}}),S.appendChild(f)}),l.addEventListener("click",()=>{let p=l.getAttribute("aria-expanded")==="true";l.setAttribute("aria-expanded",String(!p)),l.textContent=p?"Show data table":"Hide data table",p?u.setAttribute("hidden",""):u.removeAttribute("hidden")});let Y=t.querySelector("[data-viz-table-container]");Y&&Y.remove(),t.appendChild(i),(t.querySelector("[data-viz-canvas]")||t).setAttribute("aria-describedby",A)},N=(t=[])=>{let e=[];return t.forEach((r,n)=>{let s=r.name||`Series ${n+1}`,o=Array.isArray(r.x)?r.x:[],a=Array.isArray(r.y)?r.y:[],c=Array.isArray(r.text)?r.text:[],i=r.z;if(Array.isArray(i)&&i.length&&Array.isArray(i[0])){let u=o.length?o:i[0].map((w,h)=>h+1);(a.length?a:i.map((w,h)=>h+1)).forEach((w,h)=>{let S=i[h]||[];u.forEach((A,x)=>{e.push({Series:s,Y:w,X:A,Value:Array.isArray(S)?S[x]:S,Text:c[h]?y(c[h]):""})})});return}let l=Math.max(o.length,a.length,c.length);for(let u=0;u<l;u+=1)e.push({Series:s,X:o[u],Y:a[u],Text:c[u]})}),e.length?e:null},M=t=>t?Array.isArray(t)?t:b(t)&&Array.isArray(t.data)?t.data:t:null,V=t=>{let e=t.querySelector("script[data-observable-data]");if(!e)return null;try{return JSON.parse(e.textContent||"null")}catch(r){return null}},g=null,j=new Set,C=(t,e)=>{if(typeof window[e]!="undefined")return Promise.resolve(window[e]);let r=()=>z(t).then(()=>window[e]);if(g)return g.then(o=>new Promise((a,c)=>{o([t],i=>a(i||window[e]),c)}),r);let n=r();j.add(n);let s=()=>j.delete(n);return n.then(s,s),n},D=()=>C("https://cdn.jsdelivr.net/npm/plotly.js-dist-min@2.27.0/plotly.min.js","Plotly"),nt=()=>C("https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js","d3"),ot=()=>C("https://cdn.jsdelivr.net/npm/@bokeh/bokehjs@3.3.3/build/js/bokeh.min.js","Bokeh").then(t=>t&&t.Plotting?t:z("https://cdn.jsdelivr.net/npm/@bokeh/bokehjs@3.3.3/build/js/bokeh-api.min.js").then(()=>window.Bokeh)),R=()=>(g||(g=Promise.allSettled([...j]).then(()=>typeof window.requirejs!="undefined"?window.requirejs:z("https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js",{async:!1}).then(()=>window.requirejs))),g),st=()=>R().then(t=>{let e=window.__datalogWidgetManagerPromise;if(e)return e;let r=new Promise((n,s)=>{t.config({paths:{"@jupyter-widgets/html-manager":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@1.0.8/dist/embed-amd","@jupyter-widgets/base":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/base@6.0.7/dist/index","@jupyter-widgets/controls":"https://cdn.jsdelivr.net/npm/@jupyter-widgets/controls@5.0.7/dist/index","@lumino/coreutils":"https://cdn.jsdelivr.net/npm/@lumino/coreutils@2.1.1/dist/index","@lumino/widgets":"https://cdn.jsdelivr.net/npm/@lumino/widgets@2.3.1/dist/index"}}),t(["@jupyter-widgets/html-manager"],o=>n(o),o=>s(o))});return window.__datalogWidgetManagerPromise=r,r}),at=(t,e)=>{let r=document.createElement("button");return r.type="button",r.className="viz-toolbar__button",r.textContent=t,r.addEventListener("click",n=>{n.preventDefault(),e(n)}),r},d=(t,e,r="info")=>{let n=t.querySelector("[data-viz-status]");n&&(n.textContent=e,n.dataset.tone=r)},$=t=>{let e=t.getAttribute("data-viz-version"),r=t.getAttribute("data-viz-updated"),n=t.querySelector("[data-viz-meta]");if(!n)return;let s=[];e&&s.push(`v${e}`),r&&s.push(`Updated ${r}`),n.textContent=s.join(" \xB7 ")},it=t=>{let e=t.querySelector("[data-viz-canvas]")||t,r=t.querySelector(I);if(!r)return d(t,"Missing Plotly specification","error"),Promise.resolve();let n={};try{n=JSON.parse(r.textContent||"{}")}catch(a){return d(t,"Invalid Plotly specification","error"),Promise.resolve()}let s=Array.isArray(n.data)?n.data:[],o=Object.assign({autosize:!0},n.layout||{});return D().then(a=>a.newPlot(e,s,o,{responsive:!0,displaylogo:!1})).then(()=>{d(t,"Interactive");let a=t.querySelector("[data-viz-export]");a&&(a.replaceChildren(),a.appendChild(at("Download PNG",()=>{D().then(i=>{i.downloadImage(e,{format:"png",filename:t.getAttribute("data-viz-slug")||"visualization"})})})));let c=N(s);c&&E(t,{caption:o&&o.title?y(o.title.text||o.title):void 0,rows:c})}).catch(()=>{d(t,"Plotly failed to load","error")})},B=(t,e,r,n)=>{let s={args:n,done:!1,error:null,result:void 0},o=document.createElement("script"),a=t.nonce||t.getAttribute("nonce");a&&(o.nonce=a),o.datalogRun=s,o.textContent=`(function (run) {
2
+ try {
3
+ run.result = (function (${e.join(", ")}) {
4
+ ${r}
5
+ }).apply(null, run.args);
6
+ run.done = true;
7
+ } catch (error) {
8
+ run.error = error;
9
+ }
10
+ })(document.currentScript.datalogRun);`;try{document.head.appendChild(o)}finally{o.remove()}if(s.error)throw s.error;if(!s.done)throw new Error("The Content Security Policy did not allow the visualization script to run");return s.result},ct=t=>{let e=t.querySelector("[data-d3-script]");return e?nt().then(r=>{let n=e.textContent||"",s=t.querySelector("[data-viz-canvas]")||t;s.replaceChildren();let o=[],a=c=>{typeof c!="undefined"&&o.push(c)};try{let c=`${n}
11
+ ;try { if (typeof data !== 'undefined') captureData(data); } catch (instrumentationError) {}`,i=B(e,["d3","element","captureData"],c,[r,s,a]);typeof i!="undefined"&&a(i);let l=o.length?o[o.length-1]:null,u=M(l);u&&E(t,{rows:u}),d(t,"Interactive")}catch(c){s.replaceChildren(),d(t,"D3 rendering error","error")}}).catch(()=>d(t,"D3 assets failed to load","error")):(d(t,"Missing D3 rendering instructions","error"),Promise.resolve())},dt=t=>{try{let e=new URL(t,"https://observablehq.com");if(e.origin!=="https://observablehq.com")return null;let r=Array.from(e.searchParams,([n,s])=>`${encodeURIComponent(n)}=${encodeURIComponent(s)}`).join("&");return"https://observablehq.com"+e.pathname+(r?"?"+r:"")}catch(e){return null}},lt=t=>{let e=t.getAttribute("data-observable-src")||t.getAttribute("data-viz-src");if(!e)return d(t,"Missing Observable notebook source","error"),Promise.resolve();let r=dt(e);if(!r)return d(t,"Observable embeds must come from observablehq.com","error"),Promise.resolve();let n=document.createElement("iframe");n.src=r,n.loading="lazy",n.title=t.getAttribute("data-viz-title")||"Observable visualization",n.setAttribute("allowfullscreen",""),n.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups allow-forms"),n.className="viz-embed",(t.querySelector("[data-viz-canvas]")||t).replaceChildren(n),d(t,"Embedded");let o=V(t);return o&&E(t,{rows:o}),Promise.resolve()},ut=t=>{let e=t.querySelector(I),r=t.querySelector("[data-bokeh-script]"),n=t.querySelector("[data-viz-canvas]")||t;return!e&&!r?(d(t,"Missing Bokeh specification","error"),Promise.resolve()):ot().then(s=>{if(e){let o={};try{o=JSON.parse(e.textContent||"{}")}catch(c){d(t,"Invalid Bokeh specification","error");return}let a=n.id||`bokeh-${Math.random().toString(36).slice(2)}`;n.id=a;try{s.embed.embed_item(o,a),d(t,"Interactive")}catch(c){d(t,"Bokeh rendering error","error")}return}if(r){let o=r.textContent||"";n.replaceChildren();try{B(r,["Bokeh","element"],o,[s,n]),d(t,"Interactive")}catch(a){d(t,"Bokeh rendering error","error")}}}).catch(s=>{d(t,"Bokeh assets failed to load","error")})},pt=t=>{let e=t.getAttribute("data-shiny-src");if(!e)return d(t,"Missing Shiny application source","error"),Promise.resolve();let r=document.createElement("iframe");r.src=e,r.loading="lazy",r.title=t.getAttribute("data-viz-title")||"R Shiny application",r.className="viz-embed",r.setAttribute("allow","fullscreen"),r.setAttribute("sandbox","allow-scripts allow-forms allow-same-origin");let n=t.getAttribute("data-shiny-height");return r.style.height=n||"640px",(t.querySelector("[data-viz-canvas]")||t).replaceChildren(r),d(t,"Embedded"),Promise.resolve()},ht=t=>{let e=t.querySelector(F),r=t.querySelector(K);if(!e||!r)return d(t,"Missing widget state payload","error"),Promise.resolve();let n,s;try{n=JSON.parse(e.textContent||"{}"),s=JSON.parse(r.textContent||"{}")}catch(a){return d(t,"Invalid widget payload","error"),Promise.resolve()}let o=t.querySelector("[data-viz-canvas]")||t;return o.replaceChildren(),st().then(a=>{let c=new a.HTMLManager({loader:a.requireLoader});return c.set_state(n).then(()=>c.get_model(s.model_id)).then(i=>c.create_view(i)).then(i=>c.display_view(i,o)).then(()=>d(t,"Interactive")).catch(i=>{d(t,"Widget rendering error","error")})}).catch(a=>{d(t,"Widget assets failed to load","error")})},P=t=>{let e=t.getAttribute("data-viz-type");switch($(t),e){case"plotly":return it(t);case"observable":return lt(t);case"d3":return ct(t);case"bokeh":return ut(t);case"shiny":return pt(t);case"ipywidgets":return ht(t);default:return d(t,"Unsupported visualization type","error"),Promise.resolve()}},W=()=>{if(!("IntersectionObserver"in window)){document.querySelectorAll(_).forEach(e=>{P(e)});return}let t=new IntersectionObserver((e,r)=>{e.filter(n=>n.isIntersecting).forEach(n=>{let s=n.target;r.unobserve(s),P(s)})},{rootMargin:"200px 0px"});document.querySelectorAll(_).forEach(e=>{t.observe(e)})},U=t=>{document.querySelectorAll("[data-viz-card]").forEach(r=>{let n=!t.tech||r.dataset.vizTech===t.tech,s=(r.dataset.vizTags||"").split(",").map(a=>a.trim()).filter(Boolean),o=!t.tag||s.includes(t.tag);r.hidden=!(n&&o)})},G=()=>{let t=document.querySelector("[data-viz-gallery]");if(!t)return;let e=t.querySelector('[data-viz-filter="tech"]'),r=t.querySelector('[data-viz-filter="tag"]'),n=()=>{U({tech:e&&e.value!=="all"?e.value:"",tag:r&&r.value!=="all"?r.value:""})};e&&e.addEventListener("change",n),r&&r.addEventListener("change",n),n()},J=()=>{W(),G()},ft={loadScript:z,loadStyle:Q,loadUmd:C,ensureRequire:R,resetRequireLoading:()=>{g=null,j.clear()},normalizeRecords:m,stringifyValue:y,buildDataTable:E,annotateVersionMetadata:$,buildPlotlyRecords:N,buildD3Records:M,buildObservableRecords:V,filterGallery:U,renderVisualization:P,initializeVisualizations:W,initializeGallery:G};typeof globalThis!="undefined"&&(globalThis.__DATALOG_VIZ_INTERNALS__=ft),Z||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",J):J())})();
data/assets/js/loader.js CHANGED
@@ -61,7 +61,9 @@ async function importModule(url) {
61
61
  const FEATURE_CONFIG = [
62
62
  {
63
63
  name: "search",
64
- test: () => document.querySelector("[data-search-app]") || document.querySelector(".site-search")
64
+ // Only the search page renders the app. The header's search form is a
65
+ // plain form on every page, and matching it loaded the bundle everywhere.
66
+ test: () => document.querySelector("[data-search-app]")
65
67
  },
66
68
  {
67
69
  name: "visualizations",
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "lib/datalog/theme/version"
4
+ require_relative "lib/datalog/theme/package"
4
5
 
5
6
  Gem::Specification.new do |spec|
6
7
  spec.name = "datalog-theme"
@@ -23,7 +24,9 @@ Gem::Specification.new do |spec|
23
24
  spec.metadata["plugin_type"] = "theme"
24
25
  spec.metadata["orcid"] = "https://orcid.org/0009-0001-2022-7072"
25
26
 
26
- spec.required_ruby_version = ">= 3.0"
27
+ # The sass-embedded and nokogiri releases the theme is tested with need Ruby
28
+ # 3.2; the gemspec said 3.0.
29
+ spec.required_ruby_version = ">= 3.2"
27
30
  spec.require_paths = ["lib"]
28
31
  spec.bindir = "bin"
29
32
  spec.executables = ["datalog"]
@@ -31,10 +34,13 @@ Gem::Specification.new do |spec|
31
34
  # Ship only theme infrastructure — not demo content (_posts, _pages, _portfolio,
32
35
  # _datasets, _packages, _notebooks, tests, docs, scripts, CI configs, frontend
33
36
  # tooling, Dockerfiles, etc.). Theme consumers get layouts/includes/sass/assets/
34
- # plugins/data/lib/bin and the licensing/changelog metadata.
37
+ # plugins/data/lib/bin and the licensing/changelog metadata. Within _data and
38
+ # assets, the demo site's own files (its navigation, social profiles, author
39
+ # profile, CV and publication exports) stay out: see Datalog::Theme::Package.
35
40
  spec.files = Dir.chdir(__dir__) do
36
41
  tracked = `git ls-files -z`.split("\x0").select do |f|
37
- f.match?(%r{\A(?:_layouts|_includes|_sass|_plugins|_data|assets|lib|bin)/}) ||
42
+ (f.match?(%r{\A(?:_layouts|_includes|_sass|_plugins|_data|assets|lib|bin)/}) &&
43
+ Datalog::Theme::Package.theme_file?(f)) ||
38
44
  %w[
39
45
  LICENSE
40
46
  README.md
@@ -47,32 +53,39 @@ Gem::Specification.new do |spec|
47
53
  # The browser bundles are build output, so git does not track them, but
48
54
  # _data/js_manifest.json points every page at them: a gem without them
49
55
  # gives consumers a site whose scripts all 404. Run `npm run build:js`
50
- # before packaging; scripts/verify_gem_package.rb checks the result.
51
- built = Dir.glob("assets/js/dist/**/*").select { |f| File.file?(f) }
56
+ # before packaging; scripts/verify_gem_package.rb checks the result. The
57
+ # esbuild metafile and the copy of the manifest written next to the bundles
58
+ # are records of the build that no page loads, so they stay out.
59
+ built = Dir.glob("assets/js/dist/**/*").select { |f| File.file?(f) } -
60
+ %w[assets/js/dist/manifest.json assets/js/dist/meta.json]
52
61
 
53
62
  (tracked + built).uniq.sort
54
63
  end
55
64
 
65
+ # Each dependency stops below its next major version, so a breaking release
66
+ # reaches sites through a pull request that updates this file rather than an
67
+ # untested `bundle update`.
56
68
  spec.add_runtime_dependency "jekyll", "~> 4.3"
57
69
  spec.add_runtime_dependency "jekyll-sass-converter", "~> 3.0"
58
- spec.add_runtime_dependency "jekyll-feed", ">= 0.16"
59
- spec.add_runtime_dependency "jekyll-seo-tag", ">= 2.8"
60
- spec.add_runtime_dependency "jekyll-sitemap", ">= 1.4"
61
- spec.add_runtime_dependency "sass-embedded", ">= 1.71"
62
- spec.add_runtime_dependency "jekyll-paginate", ">= 1.1"
63
- spec.add_runtime_dependency "jekyll-include-cache", ">= 0.2"
64
- spec.add_runtime_dependency "jekyll-archives", ">= 2.2"
65
- spec.add_runtime_dependency "jekyll-remote-theme", ">= 0.4"
66
- spec.add_runtime_dependency "jekyll-redirect-from", ">= 0.16"
67
- spec.add_runtime_dependency "kramdown-parser-gfm", ">= 1.1"
68
- spec.add_runtime_dependency "webrick", ">= 1.8"
69
- spec.add_runtime_dependency "fastimage", ">= 2.2"
70
- spec.add_runtime_dependency "loofah", ">= 2.19"
71
- spec.add_runtime_dependency "nokogiri", ">= 1.15"
72
- spec.add_runtime_dependency "mini_magick", ">= 4.12"
73
- spec.add_runtime_dependency "logger", ">= 1.6"
74
- spec.add_runtime_dependency "thor", ">= 1.3"
75
- spec.add_runtime_dependency "googleauth", ">= 1.9"
70
+ spec.add_runtime_dependency "jekyll-feed", "~> 0.16"
71
+ spec.add_runtime_dependency "jekyll-seo-tag", "~> 2.8"
72
+ spec.add_runtime_dependency "jekyll-sitemap", "~> 1.4"
73
+ spec.add_runtime_dependency "sass-embedded", "~> 1.71"
74
+ spec.add_runtime_dependency "jekyll-paginate", "~> 1.1"
75
+ spec.add_runtime_dependency "jekyll-include-cache", "~> 0.2"
76
+ spec.add_runtime_dependency "jekyll-redirect-from", "~> 0.16"
77
+ spec.add_runtime_dependency "kramdown-parser-gfm", "~> 1.1"
78
+ spec.add_runtime_dependency "webrick", "~> 1.8"
79
+ spec.add_runtime_dependency "fastimage", "~> 2.2"
80
+ spec.add_runtime_dependency "loofah", "~> 2.19"
81
+ spec.add_runtime_dependency "nokogiri", "~> 1.15"
82
+ spec.add_runtime_dependency "mini_magick", ">= 4.12", "< 6"
83
+ spec.add_runtime_dependency "logger", "~> 1.6"
84
+ spec.add_runtime_dependency "thor", "~> 1.3"
85
+ # googleauth, with the Google Cloud gems it brings, is needed only by the
86
+ # analytics dashboard with a GA4 property configured, and such a site adds it
87
+ # to its own Gemfile. jekyll-archives and jekyll-remote-theme were listed here
88
+ # but used by nothing in the theme.
76
89
 
77
90
  spec.add_development_dependency "bundler", ">= 2.4"
78
91
  spec.add_development_dependency "rake", ">= 13.0"
data/lib/datalog/cli.rb CHANGED
@@ -83,19 +83,27 @@ module Datalog
83
83
  branch = options[:branch]
84
84
  message = options[:message] || "Publish DataLog site on #{Time.now.utc.strftime('%Y-%m-%d %H:%M UTC')}"
85
85
 
86
- say_status :build, "bundle exec jekyll build", :blue
87
- unless system({ "BUNDLE_GEMFILE" => gemfile_path(root) }, "bundle exec jekyll build", chdir: root)
86
+ # A deployment is a production build: without JEKYLL_ENV the published
87
+ # site left out the analytics tag and shipped the development CSP logger.
88
+ build_env = { "BUNDLE_GEMFILE" => gemfile_path(root), "JEKYLL_ENV" => "production" }
89
+ say_status :build, "JEKYLL_ENV=production bundle exec jekyll build", :blue
90
+ unless system(build_env, "bundle exec jekyll build", chdir: root)
88
91
  say_error "Jekyll build failed. Resolve the error above and try again."
89
92
  exit 1
90
93
  end
91
94
 
95
+ published = false
92
96
  Dir.mktmpdir("datalog-publish") do |tmp|
93
97
  worktree_path = File.join(tmp, "deploy")
94
98
  prepare_worktree(root, branch, worktree_path)
95
- copy_site_output(root, worktree_path)
96
- commit_and_push(worktree_path, branch, message)
97
- cleanup_worktree(root, worktree_path)
99
+ begin
100
+ copy_site_output(root, worktree_path)
101
+ published = commit_and_push(worktree_path, branch, message)
102
+ ensure
103
+ cleanup_worktree(root, worktree_path)
104
+ end
98
105
  end
106
+ exit 1 unless published
99
107
  end
100
108
 
101
109
  desc "update", "Update the DataLog theme and related assets to the latest version"
@@ -182,23 +190,26 @@ module Datalog
182
190
  exit 1
183
191
  end
184
192
 
193
+ # Values go in as JSON strings, which YAML reads as double-quoted scalars.
194
+ # Interpolated between plain quotes, a title containing a double quote
195
+ # or a tag containing a colon produced front matter that did not parse.
185
196
  tags_yaml = if tags.empty?
186
197
  "[]"
187
198
  else
188
- "\n" + tags.map { |tag| " - #{tag}" }.join("\n")
199
+ "\n" + tags.map { |tag| " - #{tag.to_json}" }.join("\n")
189
200
  end
190
201
  front_matter = <<~YAML
191
202
  ---
192
203
  layout: post
193
- title: "#{title}"
194
- description: "#{summary}"
195
- author: "#{author}"
204
+ title: #{title.to_json}
205
+ description: #{summary.to_json}
206
+ author: #{author.to_json}
196
207
  date: #{date.strftime('%Y-%m-%d')}
197
208
  tags:#{tags_yaml}
198
- difficulty: "#{difficulty}"
209
+ difficulty: #{difficulty.to_json}
199
210
  hero:
200
211
  image: /assets/images/#{slug}.jpg
201
- alt: "Hero image for #{title}"
212
+ alt: #{"Hero image for #{title}".to_json}
202
213
  callouts:
203
214
  - label: Key takeaway
204
215
  content: Highlight the most important insight from the post.
@@ -553,17 +564,26 @@ module Datalog
553
564
  end
554
565
  end
555
566
 
567
+ # Returns whether the branch now holds the site. The exit status of commit
568
+ # and push used to be ignored, so a rejected push still ended as a publish.
556
569
  def commit_and_push(worktree_path, branch, message)
557
570
  Dir.chdir(worktree_path) do
558
571
  system("git", "add", "--all")
559
572
  if system("git", "diff", "--cached", "--quiet")
560
573
  say_status :skip, "No changes to publish", :yellow
561
- return
574
+ return true
575
+ end
576
+
577
+ unless system("git", "commit", "-m", message)
578
+ say_error "git commit failed, so nothing was published."
579
+ return false
562
580
  end
563
581
 
564
- system("git", "commit", "-m", message)
565
582
  say_status :git, "git push origin #{branch}", :blue
566
- system("git", "push", "origin", branch)
583
+ return true if system("git", "push", "origin", branch)
584
+
585
+ say_error "git push to #{branch} failed, so the site was not published."
586
+ false
567
587
  end
568
588
  end
569
589
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
-
5
3
  module Datalog
6
4
  module PluginSystem
7
5
  class DependencyResolver
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datalog
4
+ module Theme
5
+ # The repository is both the theme and the theme's demo site, and the demo
6
+ # keeps some of its files in directories a theme also uses. These lists say
7
+ # which of those files belong to the theme. The gemspec packages only those,
8
+ # and RepositoryCheckout applies the same split to sites that install the
9
+ # theme from a Git checkout or a local path, which see the whole repository.
10
+ module Package
11
+ # The _data files the layouts need in order to render. The rest of _data
12
+ # (navigation, social profiles, publications, the author profile) is the
13
+ # demo site's own; a site using the theme supplies its own versions.
14
+ DATA_FILES = %w[
15
+ _data/i18n
16
+ _data/js_manifest.json
17
+ _data/cdn-integrity.yml
18
+ ].freeze
19
+
20
+ # Downloads the demo site links to from assets/: the maintainer's CV
21
+ # templates and publication exports.
22
+ DEMO_ASSETS = %w[
23
+ assets/publications
24
+ assets/templates
25
+ ].freeze
26
+
27
+ # Pages load the bundles in assets/js/dist, which scripts/build_js.mjs
28
+ # builds from the sources beside them, and the loader that picks among
29
+ # the bundles. No page loads the sources themselves, and a site copies
30
+ # every theme asset into its output, so the gem leaves them out.
31
+ SCRIPTS_PAGES_LOAD = %w[
32
+ assets/js/dist
33
+ assets/js/loader.js
34
+ ].freeze
35
+
36
+ module_function
37
+
38
+ # Whether a repository-relative path is part of the theme rather than
39
+ # demo content that happens to live in a theme directory.
40
+ def theme_file?(path)
41
+ return DATA_FILES.any? { |entry| inside?(path, entry) } if inside?(path, "_data")
42
+ return SCRIPTS_PAGES_LOAD.any? { |entry| inside?(path, entry) } if inside?(path, "assets/js")
43
+
44
+ DEMO_ASSETS.none? { |entry| inside?(path, entry) }
45
+ end
46
+
47
+ # The site.data keys the theme's own data files are read into.
48
+ def data_keys
49
+ DATA_FILES.map { |entry| File.basename(entry, ".*") }
50
+ end
51
+
52
+ def inside?(path, entry)
53
+ path == entry || path.start_with?("#{entry}/")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll"
4
+ require_relative "package"
5
+
6
+ module Datalog
7
+ module Theme
8
+ # A site that installs the theme from a Git checkout or a local path
9
+ # (`gem "datalog-theme", github: ...` or `path: ...`) gets the whole
10
+ # repository as its theme, and the repository is also the demo site. Jekyll
11
+ # merges the demo's _config.yml into the site's configuration, reads the
12
+ # demo's _data as theme data and copies the demo's downloads from assets/.
13
+ # The site then inherits the maintainer's name, contact addresses and social
14
+ # profiles, and jekyll-feed stops the build on a datasets feed for a
15
+ # collection the site does not have. The packaged gem contains none of those
16
+ # files; these hooks give a checkout the same contents.
17
+ module RepositoryCheckout
18
+ module_function
19
+
20
+ # The packaged gem ships no _config.yml, so one at the theme root means
21
+ # the theme is a copy of the repository.
22
+ def applies_to?(site)
23
+ theme = site.theme
24
+ !theme.nil? && theme.name == "datalog-theme" && File.file?(File.join(theme.root, "_config.yml"))
25
+ end
26
+
27
+ # Jekyll merges the theme configuration before any theme code runs, so it
28
+ # cannot be taken back out here: Jekyll's own `ignore_theme_config` switch
29
+ # is the only way to keep it out. A site that sets the switch to false has
30
+ # chosen to inherit the demo configuration.
31
+ def check_configuration(site)
32
+ return unless applies_to?(site)
33
+ return if site.config.key?("ignore_theme_config")
34
+
35
+ raise Jekyll::Errors::FatalException, <<~MESSAGE
36
+ datalog-theme is installed from a copy of its repository (#{site.theme.root}),
37
+ which is also the theme's demo site. Jekyll merges the demo's _config.yml into
38
+ your configuration, so your site would carry the demo's author, contact
39
+ addresses, social profiles and feeds.
40
+
41
+ Add this line to your _config.yml:
42
+
43
+ ignore_theme_config: true
44
+
45
+ The theme then also leaves out the demo's _data files and downloads. Set it to
46
+ false instead only if you mean to inherit the demo configuration.
47
+ MESSAGE
48
+ end
49
+
50
+ def remove_demo_content(site)
51
+ return unless applies_to?(site) && site.config["ignore_theme_config"] == true
52
+
53
+ remove_demo_assets(site)
54
+ remove_demo_data(site)
55
+ end
56
+
57
+ def remove_demo_assets(site)
58
+ demo_dirs = Package::DEMO_ASSETS.map { |entry| File.join(site.theme.root, entry, "") }
59
+ site.static_files.reject! { |file| demo_dirs.any? { |dir| file.path.start_with?(dir) } }
60
+ end
61
+
62
+ # site.data holds the theme's data with the site's merged over it. Each key
63
+ # the demo contributed goes back to the site's own value, or away.
64
+ def remove_demo_data(site)
65
+ theme_data_dir = File.join(site.theme.root, "_data")
66
+ return unless File.directory?(theme_data_dir)
67
+
68
+ demo_keys = Dir.children(theme_data_dir).map { |name| File.basename(name, ".*") } - Package.data_keys
69
+ return if demo_keys.empty?
70
+
71
+ own = Jekyll::DataReader.new(site).read(site.config["data_dir"])
72
+ demo_keys.each do |key|
73
+ if own.key?(key)
74
+ site.data[key] = own[key]
75
+ else
76
+ site.data.delete(key)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ Jekyll::Hooks.register :site, :after_init do |site|
85
+ Datalog::Theme::RepositoryCheckout.check_configuration(site)
86
+ end
87
+
88
+ Jekyll::Hooks.register :site, :post_read do |site|
89
+ Datalog::Theme::RepositoryCheckout.remove_demo_content(site)
90
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Datalog
4
4
  module Theme
5
- VERSION = "0.7.0" unless const_defined?(:VERSION)
5
+ VERSION = "0.8.0" unless const_defined?(:VERSION)
6
6
  end
7
7
  end
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Datalog
4
+ # Silences two warnings that every build repeats. Kernel#warn reports through
5
+ # Warning.warn, so prepending here covers both. A Kernel#warn override used to
6
+ # sit alongside it, and it printed keyword arguments such as `uplevel:` and
7
+ # `category:` as a hash after the message instead of honouring them.
4
8
  module WarningFilter
5
9
  FILTERS = [
6
10
  /literal string will be frozen/,
7
11
  /already initialized constant Datalog::Theme::VERSION/
8
12
  ].freeze
9
13
 
10
- def warn(message)
14
+ def warn(message, **options)
11
15
  return if FILTERS.any? { |pattern| pattern.match?(message) }
12
16
 
13
17
  super
@@ -16,13 +20,3 @@ module Datalog
16
20
  end
17
21
 
18
22
  Warning.singleton_class.prepend(Datalog::WarningFilter) if defined?(Warning)
19
-
20
- module Kernel
21
- alias __datalog_warn warn
22
-
23
- def warn(message = nil, *args)
24
- return if message && Datalog::WarningFilter::FILTERS.any? { |pattern| pattern.match?(message) }
25
-
26
- __datalog_warn(message, *args)
27
- end
28
- end
data/lib/datalog-theme.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "datalog/theme/version"
4
+ # The layouts render their page-independent includes with {% include_cached %},
5
+ # which comes from jekyll-include-cache rather than Jekyll itself.
6
+ require "jekyll-include-cache"
4
7
 
5
8
  module Datalog
6
9
  module Theme
@@ -31,3 +34,5 @@ module Datalog
31
34
  end
32
35
 
33
36
  Datalog::Theme.load_plugins
37
+
38
+ require_relative "datalog/theme/repository_checkout"