pandorga 1.2.1

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 (376) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +77 -0
  3. data/DESIGN.md +1434 -0
  4. data/LICENSE +21 -0
  5. data/README.md +81 -0
  6. data/_data/themes/dark.yml +97 -0
  7. data/_data/themes/light.yml +120 -0
  8. data/_data/themes/shared.yml +37 -0
  9. data/_data/translations.yml +85 -0
  10. data/_includes/chord-tab.html +38 -0
  11. data/_includes/content-runtime/00-config.html +22 -0
  12. data/_includes/content-runtime/10-utils.html +176 -0
  13. data/_includes/content-runtime/20-markdown.html +264 -0
  14. data/_includes/content-runtime/25-code-blocks.html +315 -0
  15. data/_includes/content-runtime/30-includes-bib.html +190 -0
  16. data/_includes/content-runtime/30-includes-xcite.html +122 -0
  17. data/_includes/content-runtime/30-includes.html +365 -0
  18. data/_includes/content-runtime/40-listing.html +225 -0
  19. data/_includes/content-runtime/41-listing-helpers.html +71 -0
  20. data/_includes/content-runtime/42-listing-filter.html +208 -0
  21. data/_includes/content-runtime/43-blocks.html +379 -0
  22. data/_includes/content-runtime/50-detail.html +861 -0
  23. data/_includes/content-runtime/55-toc.html +176 -0
  24. data/_includes/content-runtime/60-fragments.html +567 -0
  25. data/_includes/content-runtime/90-bootstrap.html +76 -0
  26. data/_includes/cut-in.html +10 -0
  27. data/_includes/cv/cv-box.html +18 -0
  28. data/_includes/dict-card.html +24 -0
  29. data/_includes/figure.html +36 -0
  30. data/_includes/home/band-index.html +43 -0
  31. data/_includes/home/band-listing.html +49 -0
  32. data/_includes/mathjax.html +10 -0
  33. data/_includes/ongoing-product.html +1 -0
  34. data/_includes/page/content-runtime.html +20 -0
  35. data/_includes/page/date_evolution.html +19 -0
  36. data/_includes/page/figure-lightbox.html +102 -0
  37. data/_includes/page/formatted_date.html +15 -0
  38. data/_includes/page/hero-default.html +18 -0
  39. data/_includes/page/listing-runtime-attrs.html +8 -0
  40. data/_includes/page/mermaid.html +101 -0
  41. data/_includes/page/network-graph.html +1253 -0
  42. data/_includes/page/page-header.html +41 -0
  43. data/_includes/page/professional-connections.html +2 -0
  44. data/_includes/page/site-footer.html +101 -0
  45. data/_includes/page/timeline-section.html +868 -0
  46. data/_includes/plotly.html +22 -0
  47. data/_includes/theme/dev-reexport.html +100 -0
  48. data/_includes/theme/favicons.html +4 -0
  49. data/_includes/theme/font-loader.html +55 -0
  50. data/_includes/theme/shell-theme-boot.html +115 -0
  51. data/_includes/theme/site-logo.html +6 -0
  52. data/_includes/theme/tailwind-theme-colors.json.liquid +65 -0
  53. data/_includes/theme/tailwind-theme-fonts.json.liquid +6 -0
  54. data/_includes/theme/theme-context.liquid +20 -0
  55. data/_includes/theme/theme-toggle.html +94 -0
  56. data/_includes/theme/theme-vars-block.liquid +161 -0
  57. data/_includes/theme/theme-vars.html +16 -0
  58. data/_includes/transcription.html +80 -0
  59. data/_includes/tweet.html +22 -0
  60. data/_includes/video.html +11 -0
  61. data/_includes/xcite.html +3 -0
  62. data/_includes/youtube-short.html +26 -0
  63. data/_includes/youtube.html +12 -0
  64. data/_layouts/article.html +27 -0
  65. data/_layouts/articles.html +534 -0
  66. data/_layouts/bibliography.html +417 -0
  67. data/_layouts/blog.html +544 -0
  68. data/_layouts/cv.html +393 -0
  69. data/_layouts/home.html +319 -0
  70. data/_layouts/network.html +9 -0
  71. data/_layouts/pandorga/articles.html +4 -0
  72. data/_layouts/pandorga/bibliography.html +4 -0
  73. data/_layouts/pandorga/blog.html +4 -0
  74. data/_layouts/pandorga/cv.html +4 -0
  75. data/_layouts/pandorga/media.html +4 -0
  76. data/_layouts/pandorga/network.html +4 -0
  77. data/_layouts/pandorga/portfolio.html +4 -0
  78. data/_layouts/post.html +7 -0
  79. data/_layouts/product.html +5 -0
  80. data/_layouts/project.html +27 -0
  81. data/_layouts/projects.html +534 -0
  82. data/_layouts/resources.html +387 -0
  83. data/_layouts/shell.html +203 -0
  84. data/_layouts/text.html +246 -0
  85. data/_plugins/bibliography_artifact.rb +57 -0
  86. data/_plugins/content_backend.rb +37 -0
  87. data/_plugins/content_collections.rb +51 -0
  88. data/_plugins/content_detail_paths.rb +58 -0
  89. data/_plugins/content_headers.rb +73 -0
  90. data/_plugins/content_keys.rb +310 -0
  91. data/_plugins/content_local_serve.rb +168 -0
  92. data/_plugins/content_site_adapter.rb +159 -0
  93. data/_plugins/content_validators_hook.rb +20 -0
  94. data/_plugins/content_writing_index.rb +52 -0
  95. data/_plugins/content_writing_paths.rb +55 -0
  96. data/_plugins/force_utf8_encoding.rb +13 -0
  97. data/_plugins/git_chronology.rb +211 -0
  98. data/_plugins/git_metadata.rb +43 -0
  99. data/_plugins/job_sections.rb +25 -0
  100. data/_plugins/lib/content_validators.rb +27 -0
  101. data/_plugins/lib/resource_validator.rb +56 -0
  102. data/_plugins/lib/tag_validator.rb +153 -0
  103. data/_plugins/lib/text_excerpt.rb +56 -0
  104. data/_plugins/lib/writing_entry.rb +107 -0
  105. data/_plugins/local_detail_rewrites.rb +194 -0
  106. data/_plugins/timeline.rb +507 -0
  107. data/_plugins/writing_slug_limits.rb +70 -0
  108. data/assets/css/article.css +1330 -0
  109. data/assets/css/base.css +1432 -0
  110. data/assets/css/cv.css +13 -0
  111. data/assets/css/global-link.css +94 -0
  112. data/assets/css/ledger/bibliography.css +307 -0
  113. data/assets/css/ledger/chrome.css +118 -0
  114. data/assets/css/ledger/cv.css +836 -0
  115. data/assets/css/ledger/detail.css +1270 -0
  116. data/assets/css/ledger/footer.css +298 -0
  117. data/assets/css/ledger/home.css +1490 -0
  118. data/assets/css/ledger/network.css +106 -0
  119. data/assets/css/ledger/projects.css +716 -0
  120. data/assets/css/ledger/rascunhos.css +379 -0
  121. data/assets/css/ledger/sources.css +327 -0
  122. data/assets/css/ledger/writing.css +754 -0
  123. data/assets/tailwind-play.js +15 -0
  124. data/examples/full/Gemfile +7 -0
  125. data/examples/full/_config.yml +92 -0
  126. data/examples/full/_redirects +3 -0
  127. data/examples/full/content/collections/articles/2026-01-01-welcome.md +9 -0
  128. data/examples/full/content/collections/data/contacts.yml +3 -0
  129. data/examples/full/content/collections/data/education.yml +4 -0
  130. data/examples/full/content/collections/jobs/research-fellow.md +12 -0
  131. data/examples/full/content/collections/posts/2026-01-02-note.md +9 -0
  132. data/examples/full/content/collections/products/ledger-tool.md +6 -0
  133. data/examples/full/content/collections/projects/demo-kit.md +10 -0
  134. data/examples/full/content/collections/resources/style-guide.md +7 -0
  135. data/examples/full/content/pages/cv/summary.md +1 -0
  136. data/examples/full/content/pages/headers.yml +20 -0
  137. data/examples/full/index.html +4 -0
  138. data/examples/minimal/Gemfile +7 -0
  139. data/examples/minimal/_config.yml +47 -0
  140. data/examples/minimal/_redirects +3 -0
  141. data/examples/minimal/content/collections/articles/2026-01-01-hello.md +10 -0
  142. data/examples/minimal/content/collections/articles/2026-01-02-second.md +9 -0
  143. data/examples/minimal/content/pages/headers.yml +6 -0
  144. data/examples/minimal/index.html +4 -0
  145. data/exe/pandorga +7 -0
  146. data/functions/api/studio/[[path]].js +562 -0
  147. data/functions/api/studio/_lib/auth.js +131 -0
  148. data/functions/api/studio/_lib/blocks.js +156 -0
  149. data/functions/api/studio/_lib/gemini.js +62 -0
  150. data/functions/api/studio/_lib/github.js +278 -0
  151. data/functions/api/studio/_lib/guidelines.js +143 -0
  152. data/functions/api/studio/_lib/paths.js +76 -0
  153. data/functions/api/studio/_lib/prompts.js +165 -0
  154. data/functions/api/studio/_lib/rate-limit.js +40 -0
  155. data/functions/api/studio/_lib/rewrite.js +136 -0
  156. data/functions/api/studio/_lib/sanitize.js +143 -0
  157. data/lib/pandorga/cli.rb +66 -0
  158. data/lib/pandorga/commands/doctor.rb +66 -0
  159. data/lib/pandorga/commands/export.rb +30 -0
  160. data/lib/pandorga/commands/install_functions.rb +41 -0
  161. data/lib/pandorga/commands/new.rb +113 -0
  162. data/lib/pandorga/commands/publish.rb +53 -0
  163. data/lib/pandorga/commands/serve.rb +34 -0
  164. data/lib/pandorga/commands/studio_schema.rb +309 -0
  165. data/lib/pandorga/jekyll/generator.rb +74 -0
  166. data/lib/pandorga/jekyll/plugins/bibliography_artifact.rb +57 -0
  167. data/lib/pandorga/jekyll/plugins/content_backend.rb +37 -0
  168. data/lib/pandorga/jekyll/plugins/content_collections.rb +51 -0
  169. data/lib/pandorga/jekyll/plugins/content_detail_paths.rb +58 -0
  170. data/lib/pandorga/jekyll/plugins/content_headers.rb +73 -0
  171. data/lib/pandorga/jekyll/plugins/content_keys.rb +310 -0
  172. data/lib/pandorga/jekyll/plugins/content_local_serve.rb +168 -0
  173. data/lib/pandorga/jekyll/plugins/content_site_adapter.rb +159 -0
  174. data/lib/pandorga/jekyll/plugins/content_validators_hook.rb +20 -0
  175. data/lib/pandorga/jekyll/plugins/content_writing_index.rb +52 -0
  176. data/lib/pandorga/jekyll/plugins/content_writing_paths.rb +55 -0
  177. data/lib/pandorga/jekyll/plugins/force_utf8_encoding.rb +13 -0
  178. data/lib/pandorga/jekyll/plugins/git_chronology.rb +211 -0
  179. data/lib/pandorga/jekyll/plugins/git_metadata.rb +43 -0
  180. data/lib/pandorga/jekyll/plugins/job_sections.rb +25 -0
  181. data/lib/pandorga/jekyll/plugins/lib/content_validators.rb +27 -0
  182. data/lib/pandorga/jekyll/plugins/lib/resource_validator.rb +56 -0
  183. data/lib/pandorga/jekyll/plugins/lib/tag_validator.rb +153 -0
  184. data/lib/pandorga/jekyll/plugins/lib/text_excerpt.rb +56 -0
  185. data/lib/pandorga/jekyll/plugins/lib/writing_entry.rb +107 -0
  186. data/lib/pandorga/jekyll/plugins/local_detail_rewrites.rb +194 -0
  187. data/lib/pandorga/jekyll/plugins/timeline.rb +507 -0
  188. data/lib/pandorga/jekyll/plugins/writing_slug_limits.rb +70 -0
  189. data/lib/pandorga/jekyll.rb +15 -0
  190. data/lib/pandorga/object_store_env.rb +51 -0
  191. data/lib/pandorga/registry/schema.yml +115 -0
  192. data/lib/pandorga/registry.rb +279 -0
  193. data/lib/pandorga/version.rb +5 -0
  194. data/lib/pandorga.rb +19 -0
  195. data/scripts/cdn-allowlist.json +19 -0
  196. data/scripts/content/backfill-content-keys.rb +99 -0
  197. data/scripts/content/band_art.rb +362 -0
  198. data/scripts/content/export-content-json.rb +741 -0
  199. data/scripts/content/flatten-ansi-capture.mjs +153 -0
  200. data/scripts/content/hero_portraits.rb +28 -0
  201. data/scripts/content/publish-content-to-object-store.sh +78 -0
  202. data/scripts/content/publish-content-to-r2.sh +5 -0
  203. data/scripts/content/sync-content-json-to-r2.rb +167 -0
  204. data/scripts/content/sync-content-redirects.rb +12 -0
  205. data/scripts/generate-configuration-doc.rb +127 -0
  206. data/scripts/lib/content_license.rb +50 -0
  207. data/scripts/lib/content_storage_config.rb +70 -0
  208. data/scripts/lib/normalize-display-math.mjs +52 -0
  209. data/scripts/lib/r2_json_sync.rb +76 -0
  210. data/scripts/lib/withdrawn_public_objects.rb +23 -0
  211. data/scripts/lib/writing_index_contract.rb +61 -0
  212. data/scripts/pdf/md-to-pdf.mjs +1400 -0
  213. data/scripts/pdf/md-to-pdf.sh +27 -0
  214. data/scripts/test/fixtures/dual-template/_config.yml +32 -0
  215. data/scripts/test/fixtures/dual-template/index.html +4 -0
  216. data/scripts/test/render-parity/article-note.json +5 -0
  217. data/scripts/test/render-parity/blockquote.json +5 -0
  218. data/scripts/test/render-parity/blocks/ansi-basic.json +7 -0
  219. data/scripts/test/render-parity/blocks/ansi-bold-is-bright.json +7 -0
  220. data/scripts/test/render-parity/blocks/ansi-drops-cursor-moves.json +7 -0
  221. data/scripts/test/render-parity/blocks/ansi-escapes-markup.json +7 -0
  222. data/scripts/test/render-parity/blocks/ansi-extended-colour.json +7 -0
  223. data/scripts/test/render-parity/blocks/ansi-real-control-byte.json +7 -0
  224. data/scripts/test/render-parity/blocks/archive-card-date-once.json +19 -0
  225. data/scripts/test/render-parity/blocks/archive-card-empty-foot.json +7 -0
  226. data/scripts/test/render-parity/blocks/archive-card-footer-dates.json +22 -0
  227. data/scripts/test/render-parity/blocks/archive-card-meta-parts.json +26 -0
  228. data/scripts/test/render-parity/blocks/archive-card.json +32 -0
  229. data/scripts/test/render-parity/blocks/cta-link.json +13 -0
  230. data/scripts/test/render-parity/blocks/lang-pill-pt.json +8 -0
  231. data/scripts/test/render-parity/blocks/lang-pill.json +8 -0
  232. data/scripts/test/render-parity/blocks/ledger-row-meta-parts.json +29 -0
  233. data/scripts/test/render-parity/blocks/ledger-row.json +35 -0
  234. data/scripts/test/render-parity/blocks/meta-strip.json +27 -0
  235. data/scripts/test/render-parity/blocks/poster-media-image.json +8 -0
  236. data/scripts/test/render-parity/blocks/poster-media-video.json +9 -0
  237. data/scripts/test/render-parity/blocks/section-banner.json +13 -0
  238. data/scripts/test/render-parity/blocks/system-card-custom-meta.json +22 -0
  239. data/scripts/test/render-parity/blocks/system-card.json +48 -0
  240. data/scripts/test/render-parity/blocks/tag-chips-links.json +12 -0
  241. data/scripts/test/render-parity/blocks/tag-chips.json +9 -0
  242. data/scripts/test/render-parity/cut-in-blank-line.json +9 -0
  243. data/scripts/test/render-parity/cut-in-right.json +9 -0
  244. data/scripts/test/render-parity/cut-in.json +8 -0
  245. data/scripts/test/render-parity/figure.json +5 -0
  246. data/scripts/test/render-parity/load-runtime.mjs +337 -0
  247. data/scripts/test/render-parity/ongoing-product.json +5 -0
  248. data/scripts/test/render-parity/plotly.json +5 -0
  249. data/scripts/test/render-parity/poem.json +5 -0
  250. data/scripts/test/render-parity/run-absent-field-checks.mjs +232 -0
  251. data/scripts/test/render-parity/run-block-fixture.mjs +86 -0
  252. data/scripts/test/render-parity/run-detail-parity-checks.mjs +123 -0
  253. data/scripts/test/render-parity/run-field-flow-checks.mjs +227 -0
  254. data/scripts/test/render-parity/run-fixture.mjs +159 -0
  255. data/scripts/test/render-parity/selectors.mjs +43 -0
  256. data/scripts/test/render-parity/video.json +5 -0
  257. data/scripts/test/render-parity/youtube-short.json +10 -0
  258. data/scripts/test/render-parity/youtube.json +8 -0
  259. data/scripts/test/test-absent-field-absent-element.rb +43 -0
  260. data/scripts/test/test-cdn-pins.rb +44 -0
  261. data/scripts/test/test-cloudflare-watch-paths-doc.rb +31 -0
  262. data/scripts/test/test-configuration-doc.rb +36 -0
  263. data/scripts/test/test-content-detail-urls.rb +346 -0
  264. data/scripts/test/test-content-keys.rb +110 -0
  265. data/scripts/test/test-content-license.rb +45 -0
  266. data/scripts/test/test-content-render-parity.rb +38 -0
  267. data/scripts/test/test-content-validators.rb +12 -0
  268. data/scripts/test/test-css-structure.rb +72 -0
  269. data/scripts/test/test-cv-export-contract.rb +158 -0
  270. data/scripts/test/test-detail-render-parity.rb +40 -0
  271. data/scripts/test/test-dev-reexport.rb +122 -0
  272. data/scripts/test/test-doctor.rb +39 -0
  273. data/scripts/test/test-dual-template-instances.rb +87 -0
  274. data/scripts/test/test-dual-template-runtime.rb +167 -0
  275. data/scripts/test/test-examples-build.rb +60 -0
  276. data/scripts/test/test-export-content-json-incremental.rb +138 -0
  277. data/scripts/test/test-export.rb +53 -0
  278. data/scripts/test/test-exported-fields-reach-the-view.rb +60 -0
  279. data/scripts/test/test-form-control-theming.rb +143 -0
  280. data/scripts/test/test-git-chronology.rb +414 -0
  281. data/scripts/test/test-hero-portraits.mjs +97 -0
  282. data/scripts/test/test-hero-portraits.rb +162 -0
  283. data/scripts/test/test-home-band-art.rb +135 -0
  284. data/scripts/test/test-install-functions.rb +39 -0
  285. data/scripts/test/test-language-export.rb +79 -0
  286. data/scripts/test/test-listing-filter-contract.rb +119 -0
  287. data/scripts/test/test-math-row-breaks.mjs +79 -0
  288. data/scripts/test/test-math-row-breaks.rb +18 -0
  289. data/scripts/test/test-new.rb +113 -0
  290. data/scripts/test/test-no-personal-data.rb +85 -0
  291. data/scripts/test/test-public-cv-export.rb +164 -0
  292. data/scripts/test/test-r2-config-consistency.rb +57 -0
  293. data/scripts/test/test-r2-json-sync.rb +193 -0
  294. data/scripts/test/test-registry-home.rb +34 -0
  295. data/scripts/test/test-runtime-js-syntax.rb +64 -0
  296. data/scripts/test/test-slim-writing-index.rb +126 -0
  297. data/scripts/test/test-studio-api-contract.rb +99 -0
  298. data/scripts/test/test-studio-content-files.rb +79 -0
  299. data/scripts/test/test-studio-liquid-roundtrip.mjs +179 -0
  300. data/scripts/test/test-studio-rate-limit.mjs +70 -0
  301. data/scripts/test/test-studio-rewrite-api-contract.rb +59 -0
  302. data/scripts/test/test-studio-rewrite-sanitize.mjs +210 -0
  303. data/scripts/test/test-studio-schema-composition.rb +126 -0
  304. data/scripts/test/test-studio-slug-config.rb +167 -0
  305. data/scripts/test/test-template-packages.rb +51 -0
  306. data/scripts/test/test-text-excerpt.rb +51 -0
  307. data/scripts/test/test-unwrap-media-src.mjs +39 -0
  308. data/scripts/test/test-unwrap-media-src.rb +19 -0
  309. data/scripts/test/test-withdrawn-content-export.rb +69 -0
  310. data/scripts/test/test-writing-index-export-slugs.rb +84 -0
  311. data/scripts/test/test-writing-slug-limits.rb +61 -0
  312. data/scripts/test/test-xcite-chronology.rb +106 -0
  313. data/scripts/validate.sh +74 -0
  314. data/scripts/visual/build-cv-pages-json.js +33 -0
  315. data/scripts/visual/build-site-pages-json.js +94 -0
  316. data/scripts/visual/publish-visual-inspection-to-r2.sh +42 -0
  317. data/scripts/visual/take-screenshots.js +88 -0
  318. data/scripts/visual/visual-inspection-pages.json +113 -0
  319. data/studio/assets/index-B_j0pMD5.css +1 -0
  320. data/studio/assets/index-Ch4YEv9g.js +285 -0
  321. data/studio/index.html +27 -0
  322. data/studio/schema.yml +869 -0
  323. data/studio-app/README.md +27 -0
  324. data/studio-app/index.html +26 -0
  325. data/studio-app/package-lock.json +2499 -0
  326. data/studio-app/package.json +26 -0
  327. data/studio-app/skills-lock.json +47 -0
  328. data/studio-app/src/api/client.js +71 -0
  329. data/studio-app/src/editor/body-editor.js +70 -0
  330. data/studio-app/src/editor/liquid-core.js +382 -0
  331. data/studio-app/src/editor/liquid.js +77 -0
  332. data/studio-app/src/lib/document.js +207 -0
  333. data/studio-app/src/lib/list-controls.js +317 -0
  334. data/studio-app/src/lib/schema.js +66 -0
  335. data/studio-app/src/lib/yaml-doc.js +100 -0
  336. data/studio-app/src/main.js +3693 -0
  337. data/studio-app/src/media/browser.js +578 -0
  338. data/studio-app/src/preview/render.js +430 -0
  339. data/studio-app/src/styles/studio.css +2826 -0
  340. data/studio-app/vite.config.js +25 -0
  341. data/templates/articles/README.md +40 -0
  342. data/templates/articles/fixtures/article.md +9 -0
  343. data/templates/articles/screenshots/README.md +6 -0
  344. data/templates/articles/studio.yml +73 -0
  345. data/templates/articles/template.yml +21 -0
  346. data/templates/bibliography/README.md +41 -0
  347. data/templates/bibliography/fixtures/references.json +9 -0
  348. data/templates/bibliography/screenshots/README.md +6 -0
  349. data/templates/bibliography/studio.yml +66 -0
  350. data/templates/bibliography/template.yml +18 -0
  351. data/templates/blog/README.md +38 -0
  352. data/templates/blog/fixtures/post.md +9 -0
  353. data/templates/blog/screenshots/README.md +6 -0
  354. data/templates/blog/studio.yml +69 -0
  355. data/templates/blog/template.yml +20 -0
  356. data/templates/cv/README.md +34 -0
  357. data/templates/cv/fixtures/job.md +12 -0
  358. data/templates/cv/screenshots/README.md +6 -0
  359. data/templates/cv/studio.yml +200 -0
  360. data/templates/cv/template.yml +25 -0
  361. data/templates/media/README.md +38 -0
  362. data/templates/media/fixtures/resource.md +7 -0
  363. data/templates/media/screenshots/README.md +6 -0
  364. data/templates/media/studio.yml +58 -0
  365. data/templates/media/template.yml +17 -0
  366. data/templates/network/README.md +34 -0
  367. data/templates/network/fixtures/sources.json +3 -0
  368. data/templates/network/screenshots/README.md +6 -0
  369. data/templates/network/studio.yml +28 -0
  370. data/templates/network/template.yml +10 -0
  371. data/templates/portfolio/README.md +39 -0
  372. data/templates/portfolio/fixtures/project.md +10 -0
  373. data/templates/portfolio/screenshots/README.md +6 -0
  374. data/templates/portfolio/studio.yml +89 -0
  375. data/templates/portfolio/template.yml +18 -0
  376. metadata +505 -0
@@ -0,0 +1,24 @@
1
+ {% if include.lemma %}
2
+ {% assign _locale = include.locale | default: '' | strip | downcase %}
3
+ {% assign _label = include.country | default: include.meta | default: _locale %}
4
+ <article class="sov-card{% if _locale != '' %} sov-card--{{ _locale }}{% endif %}" role="listitem">
5
+ <div class="sov-card__head">
6
+ {% if _locale != '' %}
7
+ <span class="sov-card__flag" title="{{ _label | escape }}"><span class="fi fi-{{ _locale }}" role="img" aria-label="{{ _label | escape }}"></span></span>
8
+ {% endif %}
9
+ {% if include.meta and include.meta != '' %}
10
+ <span class="sov-card__meta">{{ include.meta | escape }}</span>
11
+ {% endif %}
12
+ </div>
13
+ <p class="sov-card__lemma">{{ include.lemma | escape }}</p>
14
+ {% if include.def and include.def != '' %}
15
+ <div class="sov-card__def">{{ include.def | strip | newline_to_br }}</div>
16
+ {% endif %}
17
+ {% if include.note and include.note != '' %}
18
+ <p class="sov-card__note">{{ include.note }}</p>
19
+ {% endif %}
20
+ {% if include.source and include.source != '' %}
21
+ <p class="sov-card__cite">{{ include.source | escape }}, s.v. &ldquo;{{ include.lemma | escape }},&rdquo;{% if include.url and include.url != '' %} <a href="{{ include.url }}">{% if include.link_label and include.link_label != '' %}{{ include.link_label | escape }}{% else %}{{ include.url | escape }}{% endif %}</a>{% endif %}{% if include.accessed and include.accessed != '' %}, accessed {{ include.accessed | escape }}{% endif %}.{% if include.cite_extra and include.cite_extra != '' %} {{ include.cite_extra | escape }}{% endif %}</p>
22
+ {% endif %}
23
+ </article>
24
+ {% endif %}
@@ -0,0 +1,36 @@
1
+ {% if include.src %}
2
+ {% assign _raw_src = include.src | strip %}
3
+ {% comment %}Pages CMS Editor mode turns bare URLs into Markdown autolinks inside attrs.{% endcomment %}
4
+ {% if _raw_src contains '](' and _raw_src contains ')' %}
5
+ {% assign _src_parts = _raw_src | split: '](' %}
6
+ {% assign _src_tail = _src_parts | last %}
7
+ {% assign _href_parts = _src_tail | split: ')' %}
8
+ {% assign _src = _href_parts | first %}
9
+ {% elsif _raw_src contains '<' and _raw_src contains '>' %}
10
+ {% assign _src = _raw_src | remove: '<' | remove: '>' %}
11
+ {% else %}
12
+ {% assign _src = _raw_src %}
13
+ {% endif %}
14
+ <figure style="margin: 1.5rem auto; text-align: center; max-width: {% if include.width %}{{ include.width }}{% else %}100{% endif %}%;">
15
+ {% assign _cap = include.caption | strip %}
16
+ {% if _cap != "" %}
17
+ {% assign _last = _cap | slice: -1, 1 %}
18
+ {% unless _last == '.' or _last == '!' or _last == '?' %}
19
+ {% assign _cap = _cap | append: '.' %}
20
+ {% endunless %}
21
+ {% endif %}
22
+ {% assign _lb_caption = _cap %}
23
+ {% if include.source %}
24
+ {% assign _src_part = include.source | strip %}
25
+ {% if _lb_caption != "" %}
26
+ {% assign _lb_caption = _lb_caption | append: ' Source: ' | append: _src_part %}
27
+ {% else %}
28
+ {% assign _lb_caption = 'Source: ' | append: _src_part %}
29
+ {% endif %}
30
+ {% endif %}
31
+ <img class="figure-lightbox-trigger" src="{{ _src }}" alt="{{ include.alt | default: include.caption }}" style="max-width: 100%; border-radius: 0;" tabindex="0" role="button" aria-label="Enlarge image"{% if _lb_caption != "" %} data-lightbox-caption="{{ _lb_caption | strip_html | escape }}"{% endif %}/>
32
+ {% if include.caption or include.source %}
33
+ <figcaption>{% if _cap != "" %}{{ _cap | markdownify | remove: '<p>' | remove: '</p>' }}{% endif %}{% if include.source %} Source: {{ include.source | strip | markdownify | remove: '<p>' | remove: '</p>' }}{% endif %}</figcaption>
34
+ {% endif %}
35
+ </figure>
36
+ {% endif %}
@@ -0,0 +1,43 @@
1
+ {%- comment -%}
2
+ Grouped index band (sources / network / bibliography). Expects `band` with
3
+ kind=index and a pages array from PandorgaRegistry.home_bands.
4
+ {%- endcomment -%}
5
+ <section
6
+ id="home-{{ band.group }}"
7
+ class="home-band home-band--contrast home-band--index"
8
+ data-home-band
9
+ data-home-kind="index"
10
+ data-home-group="{{ band.group }}"
11
+ >
12
+ <div class="home-band-inner">
13
+ <div class="ledger-section-banner" data-content-home-section="{{ band.section_key }}">
14
+ <div class="ledger-section-lead">
15
+ <span class="ledger-kicker" data-content-section-kicker></span>
16
+ <h2 class="section-title" data-content-section-title></h2>
17
+ <p class="home-section-note font-body" data-content-section-note></p>
18
+ </div>
19
+ </div>
20
+ <div class="home-index-split">
21
+ {%- for panel in band.pages -%}
22
+ {%- assign _panel_page = site.pages | where: "key", panel.key | first -%}
23
+ {%- assign _panel_title = panel.title | default: _panel_page.title | default: panel.key -%}
24
+ {%- assign _panel_path = panel.path | default: _panel_page.url -%}
25
+ {%- assign _art_key = panel.key -%}
26
+ {%- if panel.key == "resources" -%}{%- assign _art_key = "sources" -%}{%- endif -%}
27
+ <article class="home-index-panel"{% if panel.template == "bibliography" %} id="home-bib-panel"{% endif %}>
28
+ <span class="shard-accent home-index-shard" aria-hidden="true"></span>
29
+ {%- if panel.template == "bibliography" -%}
30
+ <figure class="home-index-plate" id="home-bib-plate" hidden></figure>
31
+ {%- else -%}
32
+ <figure class="home-index-plate" data-content-band-art="{{ _art_key }}" hidden></figure>
33
+ {%- endif -%}
34
+ <h3 class="section-title home-index-title">{{ _panel_title }}</h3>
35
+ <a class="ledger-cta" href="{{ _panel_path }}">
36
+ <span>Open</span>
37
+ <span class="material-symbols-outlined ledger-cta-arrow" aria-hidden="true">chevron_right</span>
38
+ </a>
39
+ </article>
40
+ {%- endfor -%}
41
+ </div>
42
+ </div>
43
+ </section>
@@ -0,0 +1,49 @@
1
+ {%- comment -%}
2
+ One homepage listing band. Expects `band` from site.data.pandorga_home_bands.
3
+ Markup slots are filled by the home layout script from writing_index.json.
4
+ {%- endcomment -%}
5
+ {%- assign _accent = band.accent -%}
6
+ {%- assign _limit = band.home.limit | default: 3 -%}
7
+ {%- assign _featured = band.home.featured -%}
8
+ {%- assign _lang = band.language | default: site.pandorga.identity.locale | default: "en" -%}
9
+ {%- assign _path = band.path -%}
10
+ {%- assign _cta = band.home.cta | default: "View all" -%}
11
+ {%- assign _slot_id = "home-band-" | append: band.key -%}
12
+ <section
13
+ id="home-{{ band.key }}"
14
+ class="home-band{% if band.contrast %} home-band--contrast{% endif %}{% if _accent != blank %} page-accent--{{ _accent }}{% endif %}"
15
+ {% if _lang != blank %}lang="{{ _lang }}"{% endif %}
16
+ data-home-band
17
+ data-home-kind="{{ band.kind }}"
18
+ data-home-key="{{ band.key }}"
19
+ data-home-collection="{{ band.collection }}"
20
+ data-home-path="{{ _path }}"
21
+ data-home-limit="{{ _limit }}"
22
+ data-home-featured="{{ _featured }}"
23
+ data-home-language="{{ _lang }}"
24
+ >
25
+ <div class="home-band-inner">
26
+ <div class="ledger-section-banner" data-content-home-section="{{ band.section_key }}">
27
+ <div class="ledger-section-lead">
28
+ <span class="ledger-kicker" data-content-section-kicker></span>
29
+ <h2 class="section-title" data-content-section-title></h2>
30
+ <p class="home-section-note font-body" data-content-section-note></p>
31
+ </div>
32
+ <div class="home-section-aside">
33
+ <a class="ledger-cta" href="{{ _path }}">
34
+ <span>{{ _cta }}</span>
35
+ <span class="material-symbols-outlined ledger-cta-arrow" aria-hidden="true">chevron_right</span>
36
+ </a>
37
+ </div>
38
+ </div>
39
+ {%- if _featured -%}
40
+ <div id="{{ _slot_id }}-featured" data-home-featured-slot data-tag-base="{{ _path }}"></div>
41
+ {%- endif -%}
42
+ <div
43
+ id="{{ _slot_id }}"
44
+ class="{% if band.kind == 'blog' %}home-draft-list{% elsif band.kind == 'portfolio' %}home-system-grid{% else %}home-card-grid{% endif %}"
45
+ data-home-list
46
+ data-tag-base="{{ _path }}"
47
+ ></div>
48
+ </div>
49
+ </section>
@@ -0,0 +1,10 @@
1
+ <!-- MathJax configuration for Jekyll with inline math support -->
2
+ <script>
3
+ window.MathJax = {
4
+ tex: {
5
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
6
+ displayMath: [['$$', '$$'], ['\\[', '\\]']]
7
+ }
8
+ };
9
+ </script>
10
+ <script src="https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-mml-chtml.js"></script>
@@ -0,0 +1 @@
1
+ <span class="ongoing-product-badge" style="display: inline-block; padding: 0.15rem 0.5rem; background: var(--color-surface-container-low); border-radius: 0.25rem; font-size: 0.8rem; color: var(--color-on-surface-variant);">Currently active</span>
@@ -0,0 +1,20 @@
1
+ {% include content-runtime/00-config.html %}
2
+ <script>
3
+ window.ContentRuntime = (function () {
4
+ 'use strict';
5
+ {% include content-runtime/10-utils.html %}
6
+ {% include content-runtime/30-includes.html %}
7
+ {% include content-runtime/30-includes-bib.html %}
8
+ {% include content-runtime/30-includes-xcite.html %}
9
+ {% include content-runtime/20-markdown.html %}
10
+ {% include content-runtime/25-code-blocks.html %}
11
+ {% include content-runtime/50-detail.html %}
12
+ {% include content-runtime/55-toc.html %}
13
+ {% include content-runtime/40-listing.html %}
14
+ {% include content-runtime/60-fragments.html %}
15
+ {% include content-runtime/41-listing-helpers.html %}
16
+ {% include content-runtime/42-listing-filter.html %}
17
+ {% include content-runtime/43-blocks.html %}
18
+ {% include content-runtime/90-bootstrap.html %}
19
+ })();
20
+ </script>
@@ -0,0 +1,19 @@
1
+ {% assign lang = include.lang | default: page.language | default: "enus" %}
2
+ {% assign t = site.data.translations %}
3
+ {% assign creation = include.date | default: page.date %}
4
+ {% assign update = include.last_updated | default: page.last_updated %}
5
+
6
+ <div class="date-evolution {% if include.stacked %}flex flex-col {{ include.gap | default: 'gap-1' }}{% if include.align == 'right' %} items-end{% endif %}{% else %}flex items-center gap-1{% endif %}">
7
+ <span title="{{ t.published[lang] }}">
8
+ {% if include.show_labels %}{{ t.published[lang] }}: {% endif %}
9
+ {% include page/formatted_date.html date=creation lang=lang %}
10
+ </span>
11
+
12
+ {% if update and update != creation %}
13
+ {% unless include.stacked %}<span class="opacity-40 mx-0.5">–</span>{% endunless %}
14
+ <span class="opacity-60" title="{{ t.updated[lang] }}">
15
+ {% if include.show_labels %}{{ t.updated[lang] }}: {% endif %}
16
+ {% include page/formatted_date.html date=update lang=lang %}
17
+ </span>
18
+ {% endif %}
19
+ </div>
@@ -0,0 +1,102 @@
1
+ <!-- Shared figure lightbox: one overlay per page (shell). See docs/content/elements.md -->
2
+ <div id="figure-lightbox" class="figure-lightbox" hidden aria-hidden="true" role="dialog" aria-modal="true" aria-label="Enlarged figure">
3
+ <div class="figure-lightbox-backdrop" data-lightbox-close tabindex="-1"></div>
4
+ <div class="figure-lightbox-panel">
5
+ <button type="button" class="figure-lightbox-close" data-lightbox-close aria-label="Close">
6
+ <span class="material-symbols-outlined" aria-hidden="true">close</span>
7
+ </button>
8
+ <img class="figure-lightbox-img" alt="" />
9
+ <p class="figure-lightbox-caption" hidden></p>
10
+ </div>
11
+ </div>
12
+ <script>
13
+ (function () {
14
+ var root = document.getElementById('figure-lightbox');
15
+ if (!root) return;
16
+
17
+ var imgEl = root.querySelector('.figure-lightbox-img');
18
+ var captionEl = root.querySelector('.figure-lightbox-caption');
19
+ var closeBtn = root.querySelector('.figure-lightbox-close');
20
+ var lastTrigger = null;
21
+ var open = false;
22
+
23
+ function setOpen(isOpen) {
24
+ open = isOpen;
25
+ root.hidden = !isOpen;
26
+ root.setAttribute('aria-hidden', String(!isOpen));
27
+ document.documentElement.classList.toggle('figure-lightbox-open', isOpen);
28
+ document.body.classList.toggle('figure-lightbox-open', isOpen);
29
+ }
30
+
31
+ function closeLightbox() {
32
+ if (!open) return;
33
+ setOpen(false);
34
+ if (imgEl) {
35
+ imgEl.removeAttribute('src');
36
+ imgEl.alt = '';
37
+ }
38
+ if (captionEl) {
39
+ captionEl.textContent = '';
40
+ captionEl.hidden = true;
41
+ }
42
+ if (lastTrigger && typeof lastTrigger.focus === 'function') {
43
+ try { lastTrigger.focus(); } catch (e) { /* ignore */ }
44
+ }
45
+ lastTrigger = null;
46
+ }
47
+
48
+ function openLightbox(trigger) {
49
+ if (!trigger || !imgEl) return;
50
+ var src = trigger.getAttribute('src');
51
+ if (!src) return;
52
+ lastTrigger = trigger;
53
+ imgEl.src = src;
54
+ imgEl.alt = trigger.getAttribute('alt') || '';
55
+ var caption = trigger.getAttribute('data-lightbox-caption') || '';
56
+ if (captionEl) {
57
+ if (caption) {
58
+ captionEl.textContent = caption;
59
+ captionEl.hidden = false;
60
+ } else {
61
+ captionEl.textContent = '';
62
+ captionEl.hidden = true;
63
+ }
64
+ }
65
+ setOpen(true);
66
+ if (closeBtn) closeBtn.focus();
67
+ }
68
+
69
+ function isTrigger(el) {
70
+ return el && el.classList && el.classList.contains('figure-lightbox-trigger');
71
+ }
72
+
73
+ document.addEventListener('click', function (event) {
74
+ var closeTarget = event.target.closest('[data-lightbox-close]');
75
+ if (closeTarget && open) {
76
+ event.preventDefault();
77
+ closeLightbox();
78
+ return;
79
+ }
80
+ var trigger = event.target.closest('img.figure-lightbox-trigger');
81
+ if (isTrigger(trigger)) {
82
+ event.preventDefault();
83
+ openLightbox(trigger);
84
+ }
85
+ });
86
+
87
+ document.addEventListener('keydown', function (event) {
88
+ if (open && event.key === 'Escape') {
89
+ event.preventDefault();
90
+ closeLightbox();
91
+ return;
92
+ }
93
+ if (!open && (event.key === 'Enter' || event.key === ' ')) {
94
+ var trigger = event.target;
95
+ if (isTrigger(trigger)) {
96
+ event.preventDefault();
97
+ openLightbox(trigger);
98
+ }
99
+ }
100
+ });
101
+ })();
102
+ </script>
@@ -0,0 +1,15 @@
1
+ {% assign lang = include.lang | default: page.language | default: "enus" %}
2
+ {% assign date = include.date %}
3
+ {% if lang == "enus" %}
4
+ {{ date | date: "%B %-d, %Y" }}
5
+ {% else %}
6
+ {% assign m_idx = date | date: "%-m" | minus: 1 %}
7
+ {% assign month = site.data.translations.months[lang][m_idx] %}
8
+ {% assign day = date | date: "%-d" %}
9
+ {% assign year = date | date: "%Y" %}
10
+ {% if lang == "ptbr" or lang == "eses" %}
11
+ {{ day }} de {{ month }} de {{ year }}
12
+ {% elsif lang == "frfr" %}
13
+ {{ day }} {{ month }} {{ year }}
14
+ {% endif %}
15
+ {% endif %}
@@ -0,0 +1,18 @@
1
+ {% comment %}
2
+ Neutral hero art slot. Sites override via pandorga.home.hero_art or by
3
+ replacing this include. The website kite art stays outside the gem.
4
+ {% endcomment %}
5
+ <svg class="home-hero-art-svg" viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
6
+ <defs>
7
+ <linearGradient id="heroDefaultGrad" x1="0" y1="0" x2="1" y2="1">
8
+ <stop offset="0%" stop-color="var(--color-primary, #3d4a5c)" stop-opacity="0.35"/>
9
+ <stop offset="100%" stop-color="var(--color-tertiary, #8a6a4a)" stop-opacity="0.2"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect width="1200" height="800" fill="url(#heroDefaultGrad)"/>
13
+ <g fill="none" stroke="var(--color-outline, #5c6570)" stroke-opacity="0.35" stroke-width="2">
14
+ <path d="M120 640 L420 220 L780 220 L1080 640"/>
15
+ <path d="M420 220 L600 520 L780 220"/>
16
+ <circle cx="600" cy="360" r="48"/>
17
+ </g>
18
+ </svg>
@@ -0,0 +1,8 @@
1
+ {%- comment -%}
2
+ Registry-backed listing runtime config for inline page scripts.
3
+ Defaults keep English platform paths when a hand-authored page omits fields.
4
+ {%- endcomment -%}
5
+ {%- assign listing_collection = page.collection | default: include.default_collection -%}
6
+ {%- assign listing_path = page.listing_path | default: page.permalink | default: include.default_path -%}
7
+ {%- assign listing_detail = page.detail | default: include.default_detail -%}
8
+ data-listing-collection="{{ listing_collection }}" data-listing-path="{{ listing_path }}" data-listing-detail="{{ listing_detail }}"
@@ -0,0 +1,101 @@
1
+ <script type="module">
2
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
3
+
4
+ /* Mermaid resolves its palette once, when initialize() runs, and bakes the
5
+ values into the SVG it emits. Reading the theme at load therefore left a
6
+ diagram painted in whatever palette happened to be active at that moment:
7
+ toggling to dark kept the light node fills and cluster backgrounds, which
8
+ is why diagrams showed pale blocks on a dark page. The palette is re-read
9
+ and the diagrams re-rendered whenever the theme changes. */
10
+
11
+ function themeFont() {
12
+ var value = getComputedStyle(document.documentElement).getPropertyValue('--font-sans').trim();
13
+ return value || "'Lato', sans-serif";
14
+ }
15
+
16
+ function themeColor(name, fallback) {
17
+ var value = getComputedStyle(document.documentElement).getPropertyValue('--color-' + name).trim();
18
+ return value || fallback;
19
+ }
20
+
21
+ function config() {
22
+ return {
23
+ startOnLoad: false,
24
+ theme: 'base',
25
+ darkMode: document.documentElement.getAttribute('data-theme') === 'dark',
26
+ themeVariables: {
27
+ fontFamily: themeFont(),
28
+ background: themeColor('background', '#ffffff'),
29
+ mainBkg: themeColor('surface', '#f1f1ef'),
30
+ primaryColor: themeColor('surface', '#f1f1ef'),
31
+ primaryTextColor: themeColor('on-surface', '#1b1c15'),
32
+ primaryBorderColor: themeColor('outline-variant', '#c4ccc6'),
33
+ secondaryColor: themeColor('panel-contrast', '#f7f7f5'),
34
+ secondaryTextColor: themeColor('on-surface', '#1b1c15'),
35
+ secondaryBorderColor: themeColor('outline-variant', '#c4ccc6'),
36
+ tertiaryColor: themeColor('surface-high', '#e8e8e4'),
37
+ tertiaryTextColor: themeColor('on-surface', '#1b1c15'),
38
+ tertiaryBorderColor: themeColor('outline-variant', '#c4ccc6'),
39
+ lineColor: themeColor('outline', '#6b7569'),
40
+ textColor: themeColor('on-surface', '#1b1c15'),
41
+ nodeBorder: themeColor('outline-variant', '#c4ccc6'),
42
+ nodeTextColor: themeColor('on-surface', '#1b1c15'),
43
+ clusterBkg: themeColor('panel-contrast', '#f7f7f5'),
44
+ clusterBorder: themeColor('outline-variant', '#c4ccc6'),
45
+ titleColor: themeColor('on-surface', '#1b1c15'),
46
+ edgeLabelBackground: themeColor('background', '#ffffff'),
47
+ labelBackground: themeColor('background', '#ffffff'),
48
+ labelTextColor: themeColor('on-surface', '#1b1c15'),
49
+ fontSize: '14px'
50
+ },
51
+ flowchart: {
52
+ diagramPadding: 16,
53
+ padding: 16,
54
+ subGraphTitleMargin: { top: 8, bottom: 0 }
55
+ }
56
+ };
57
+ }
58
+
59
+ /* Kramdown renders ```mermaid as <pre><code class="language-mermaid">.
60
+ Convert those to <div class="mermaid"> so Mermaid can process them. The
61
+ source is kept on the node so the diagram can be drawn again from scratch
62
+ after a theme change, since rendering replaces the text with an SVG. */
63
+ function collect() {
64
+ document.querySelectorAll('pre code.language-mermaid').forEach(function (code) {
65
+ var div = document.createElement('div');
66
+ div.className = 'mermaid';
67
+ div.textContent = code.textContent;
68
+ div.dataset.mermaidSource = code.textContent;
69
+ code.closest('pre').replaceWith(div);
70
+ });
71
+ return Array.from(document.querySelectorAll('.mermaid'));
72
+ }
73
+
74
+ async function draw(nodes) {
75
+ if (!nodes.length) return;
76
+ mermaid.initialize(config());
77
+ try {
78
+ await mermaid.run({ nodes: nodes });
79
+ } catch (error) {
80
+ console.error('Mermaid render failed', error);
81
+ }
82
+ }
83
+
84
+ var nodes = collect();
85
+ nodes.forEach(function (node) {
86
+ if (!node.dataset.mermaidSource) node.dataset.mermaidSource = node.textContent;
87
+ });
88
+ draw(nodes);
89
+
90
+ document.addEventListener('shell-theme-change', function () {
91
+ var existing = Array.from(document.querySelectorAll('.mermaid'));
92
+ if (!existing.length) return;
93
+ existing.forEach(function (node) {
94
+ if (!node.dataset.mermaidSource) return;
95
+ node.removeAttribute('data-processed');
96
+ node.innerHTML = '';
97
+ node.textContent = node.dataset.mermaidSource;
98
+ });
99
+ draw(existing);
100
+ });
101
+ </script>