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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +77 -0
- data/DESIGN.md +1434 -0
- data/LICENSE +21 -0
- data/README.md +81 -0
- data/_data/themes/dark.yml +97 -0
- data/_data/themes/light.yml +120 -0
- data/_data/themes/shared.yml +37 -0
- data/_data/translations.yml +85 -0
- data/_includes/chord-tab.html +38 -0
- data/_includes/content-runtime/00-config.html +22 -0
- data/_includes/content-runtime/10-utils.html +176 -0
- data/_includes/content-runtime/20-markdown.html +264 -0
- data/_includes/content-runtime/25-code-blocks.html +315 -0
- data/_includes/content-runtime/30-includes-bib.html +190 -0
- data/_includes/content-runtime/30-includes-xcite.html +122 -0
- data/_includes/content-runtime/30-includes.html +365 -0
- data/_includes/content-runtime/40-listing.html +225 -0
- data/_includes/content-runtime/41-listing-helpers.html +71 -0
- data/_includes/content-runtime/42-listing-filter.html +208 -0
- data/_includes/content-runtime/43-blocks.html +379 -0
- data/_includes/content-runtime/50-detail.html +861 -0
- data/_includes/content-runtime/55-toc.html +176 -0
- data/_includes/content-runtime/60-fragments.html +567 -0
- data/_includes/content-runtime/90-bootstrap.html +76 -0
- data/_includes/cut-in.html +10 -0
- data/_includes/cv/cv-box.html +18 -0
- data/_includes/dict-card.html +24 -0
- data/_includes/figure.html +36 -0
- data/_includes/home/band-index.html +43 -0
- data/_includes/home/band-listing.html +49 -0
- data/_includes/mathjax.html +10 -0
- data/_includes/ongoing-product.html +1 -0
- data/_includes/page/content-runtime.html +20 -0
- data/_includes/page/date_evolution.html +19 -0
- data/_includes/page/figure-lightbox.html +102 -0
- data/_includes/page/formatted_date.html +15 -0
- data/_includes/page/hero-default.html +18 -0
- data/_includes/page/listing-runtime-attrs.html +8 -0
- data/_includes/page/mermaid.html +101 -0
- data/_includes/page/network-graph.html +1253 -0
- data/_includes/page/page-header.html +41 -0
- data/_includes/page/professional-connections.html +2 -0
- data/_includes/page/site-footer.html +101 -0
- data/_includes/page/timeline-section.html +868 -0
- data/_includes/plotly.html +22 -0
- data/_includes/theme/dev-reexport.html +100 -0
- data/_includes/theme/favicons.html +4 -0
- data/_includes/theme/font-loader.html +55 -0
- data/_includes/theme/shell-theme-boot.html +115 -0
- data/_includes/theme/site-logo.html +6 -0
- data/_includes/theme/tailwind-theme-colors.json.liquid +65 -0
- data/_includes/theme/tailwind-theme-fonts.json.liquid +6 -0
- data/_includes/theme/theme-context.liquid +20 -0
- data/_includes/theme/theme-toggle.html +94 -0
- data/_includes/theme/theme-vars-block.liquid +161 -0
- data/_includes/theme/theme-vars.html +16 -0
- data/_includes/transcription.html +80 -0
- data/_includes/tweet.html +22 -0
- data/_includes/video.html +11 -0
- data/_includes/xcite.html +3 -0
- data/_includes/youtube-short.html +26 -0
- data/_includes/youtube.html +12 -0
- data/_layouts/article.html +27 -0
- data/_layouts/articles.html +534 -0
- data/_layouts/bibliography.html +417 -0
- data/_layouts/blog.html +544 -0
- data/_layouts/cv.html +393 -0
- data/_layouts/home.html +319 -0
- data/_layouts/network.html +9 -0
- data/_layouts/pandorga/articles.html +4 -0
- data/_layouts/pandorga/bibliography.html +4 -0
- data/_layouts/pandorga/blog.html +4 -0
- data/_layouts/pandorga/cv.html +4 -0
- data/_layouts/pandorga/media.html +4 -0
- data/_layouts/pandorga/network.html +4 -0
- data/_layouts/pandorga/portfolio.html +4 -0
- data/_layouts/post.html +7 -0
- data/_layouts/product.html +5 -0
- data/_layouts/project.html +27 -0
- data/_layouts/projects.html +534 -0
- data/_layouts/resources.html +387 -0
- data/_layouts/shell.html +203 -0
- data/_layouts/text.html +246 -0
- data/_plugins/bibliography_artifact.rb +57 -0
- data/_plugins/content_backend.rb +37 -0
- data/_plugins/content_collections.rb +51 -0
- data/_plugins/content_detail_paths.rb +58 -0
- data/_plugins/content_headers.rb +73 -0
- data/_plugins/content_keys.rb +310 -0
- data/_plugins/content_local_serve.rb +168 -0
- data/_plugins/content_site_adapter.rb +159 -0
- data/_plugins/content_validators_hook.rb +20 -0
- data/_plugins/content_writing_index.rb +52 -0
- data/_plugins/content_writing_paths.rb +55 -0
- data/_plugins/force_utf8_encoding.rb +13 -0
- data/_plugins/git_chronology.rb +211 -0
- data/_plugins/git_metadata.rb +43 -0
- data/_plugins/job_sections.rb +25 -0
- data/_plugins/lib/content_validators.rb +27 -0
- data/_plugins/lib/resource_validator.rb +56 -0
- data/_plugins/lib/tag_validator.rb +153 -0
- data/_plugins/lib/text_excerpt.rb +56 -0
- data/_plugins/lib/writing_entry.rb +107 -0
- data/_plugins/local_detail_rewrites.rb +194 -0
- data/_plugins/timeline.rb +507 -0
- data/_plugins/writing_slug_limits.rb +70 -0
- data/assets/css/article.css +1330 -0
- data/assets/css/base.css +1432 -0
- data/assets/css/cv.css +13 -0
- data/assets/css/global-link.css +94 -0
- data/assets/css/ledger/bibliography.css +307 -0
- data/assets/css/ledger/chrome.css +118 -0
- data/assets/css/ledger/cv.css +836 -0
- data/assets/css/ledger/detail.css +1270 -0
- data/assets/css/ledger/footer.css +298 -0
- data/assets/css/ledger/home.css +1490 -0
- data/assets/css/ledger/network.css +106 -0
- data/assets/css/ledger/projects.css +716 -0
- data/assets/css/ledger/rascunhos.css +379 -0
- data/assets/css/ledger/sources.css +327 -0
- data/assets/css/ledger/writing.css +754 -0
- data/assets/tailwind-play.js +15 -0
- data/examples/full/Gemfile +7 -0
- data/examples/full/_config.yml +92 -0
- data/examples/full/_redirects +3 -0
- data/examples/full/content/collections/articles/2026-01-01-welcome.md +9 -0
- data/examples/full/content/collections/data/contacts.yml +3 -0
- data/examples/full/content/collections/data/education.yml +4 -0
- data/examples/full/content/collections/jobs/research-fellow.md +12 -0
- data/examples/full/content/collections/posts/2026-01-02-note.md +9 -0
- data/examples/full/content/collections/products/ledger-tool.md +6 -0
- data/examples/full/content/collections/projects/demo-kit.md +10 -0
- data/examples/full/content/collections/resources/style-guide.md +7 -0
- data/examples/full/content/pages/cv/summary.md +1 -0
- data/examples/full/content/pages/headers.yml +20 -0
- data/examples/full/index.html +4 -0
- data/examples/minimal/Gemfile +7 -0
- data/examples/minimal/_config.yml +47 -0
- data/examples/minimal/_redirects +3 -0
- data/examples/minimal/content/collections/articles/2026-01-01-hello.md +10 -0
- data/examples/minimal/content/collections/articles/2026-01-02-second.md +9 -0
- data/examples/minimal/content/pages/headers.yml +6 -0
- data/examples/minimal/index.html +4 -0
- data/exe/pandorga +7 -0
- data/functions/api/studio/[[path]].js +562 -0
- data/functions/api/studio/_lib/auth.js +131 -0
- data/functions/api/studio/_lib/blocks.js +156 -0
- data/functions/api/studio/_lib/gemini.js +62 -0
- data/functions/api/studio/_lib/github.js +278 -0
- data/functions/api/studio/_lib/guidelines.js +143 -0
- data/functions/api/studio/_lib/paths.js +76 -0
- data/functions/api/studio/_lib/prompts.js +165 -0
- data/functions/api/studio/_lib/rate-limit.js +40 -0
- data/functions/api/studio/_lib/rewrite.js +136 -0
- data/functions/api/studio/_lib/sanitize.js +143 -0
- data/lib/pandorga/cli.rb +66 -0
- data/lib/pandorga/commands/doctor.rb +66 -0
- data/lib/pandorga/commands/export.rb +30 -0
- data/lib/pandorga/commands/install_functions.rb +41 -0
- data/lib/pandorga/commands/new.rb +113 -0
- data/lib/pandorga/commands/publish.rb +53 -0
- data/lib/pandorga/commands/serve.rb +34 -0
- data/lib/pandorga/commands/studio_schema.rb +309 -0
- data/lib/pandorga/jekyll/generator.rb +74 -0
- data/lib/pandorga/jekyll/plugins/bibliography_artifact.rb +57 -0
- data/lib/pandorga/jekyll/plugins/content_backend.rb +37 -0
- data/lib/pandorga/jekyll/plugins/content_collections.rb +51 -0
- data/lib/pandorga/jekyll/plugins/content_detail_paths.rb +58 -0
- data/lib/pandorga/jekyll/plugins/content_headers.rb +73 -0
- data/lib/pandorga/jekyll/plugins/content_keys.rb +310 -0
- data/lib/pandorga/jekyll/plugins/content_local_serve.rb +168 -0
- data/lib/pandorga/jekyll/plugins/content_site_adapter.rb +159 -0
- data/lib/pandorga/jekyll/plugins/content_validators_hook.rb +20 -0
- data/lib/pandorga/jekyll/plugins/content_writing_index.rb +52 -0
- data/lib/pandorga/jekyll/plugins/content_writing_paths.rb +55 -0
- data/lib/pandorga/jekyll/plugins/force_utf8_encoding.rb +13 -0
- data/lib/pandorga/jekyll/plugins/git_chronology.rb +211 -0
- data/lib/pandorga/jekyll/plugins/git_metadata.rb +43 -0
- data/lib/pandorga/jekyll/plugins/job_sections.rb +25 -0
- data/lib/pandorga/jekyll/plugins/lib/content_validators.rb +27 -0
- data/lib/pandorga/jekyll/plugins/lib/resource_validator.rb +56 -0
- data/lib/pandorga/jekyll/plugins/lib/tag_validator.rb +153 -0
- data/lib/pandorga/jekyll/plugins/lib/text_excerpt.rb +56 -0
- data/lib/pandorga/jekyll/plugins/lib/writing_entry.rb +107 -0
- data/lib/pandorga/jekyll/plugins/local_detail_rewrites.rb +194 -0
- data/lib/pandorga/jekyll/plugins/timeline.rb +507 -0
- data/lib/pandorga/jekyll/plugins/writing_slug_limits.rb +70 -0
- data/lib/pandorga/jekyll.rb +15 -0
- data/lib/pandorga/object_store_env.rb +51 -0
- data/lib/pandorga/registry/schema.yml +115 -0
- data/lib/pandorga/registry.rb +279 -0
- data/lib/pandorga/version.rb +5 -0
- data/lib/pandorga.rb +19 -0
- data/scripts/cdn-allowlist.json +19 -0
- data/scripts/content/backfill-content-keys.rb +99 -0
- data/scripts/content/band_art.rb +362 -0
- data/scripts/content/export-content-json.rb +741 -0
- data/scripts/content/flatten-ansi-capture.mjs +153 -0
- data/scripts/content/hero_portraits.rb +28 -0
- data/scripts/content/publish-content-to-object-store.sh +78 -0
- data/scripts/content/publish-content-to-r2.sh +5 -0
- data/scripts/content/sync-content-json-to-r2.rb +167 -0
- data/scripts/content/sync-content-redirects.rb +12 -0
- data/scripts/generate-configuration-doc.rb +127 -0
- data/scripts/lib/content_license.rb +50 -0
- data/scripts/lib/content_storage_config.rb +70 -0
- data/scripts/lib/normalize-display-math.mjs +52 -0
- data/scripts/lib/r2_json_sync.rb +76 -0
- data/scripts/lib/withdrawn_public_objects.rb +23 -0
- data/scripts/lib/writing_index_contract.rb +61 -0
- data/scripts/pdf/md-to-pdf.mjs +1400 -0
- data/scripts/pdf/md-to-pdf.sh +27 -0
- data/scripts/test/fixtures/dual-template/_config.yml +32 -0
- data/scripts/test/fixtures/dual-template/index.html +4 -0
- data/scripts/test/render-parity/article-note.json +5 -0
- data/scripts/test/render-parity/blockquote.json +5 -0
- data/scripts/test/render-parity/blocks/ansi-basic.json +7 -0
- data/scripts/test/render-parity/blocks/ansi-bold-is-bright.json +7 -0
- data/scripts/test/render-parity/blocks/ansi-drops-cursor-moves.json +7 -0
- data/scripts/test/render-parity/blocks/ansi-escapes-markup.json +7 -0
- data/scripts/test/render-parity/blocks/ansi-extended-colour.json +7 -0
- data/scripts/test/render-parity/blocks/ansi-real-control-byte.json +7 -0
- data/scripts/test/render-parity/blocks/archive-card-date-once.json +19 -0
- data/scripts/test/render-parity/blocks/archive-card-empty-foot.json +7 -0
- data/scripts/test/render-parity/blocks/archive-card-footer-dates.json +22 -0
- data/scripts/test/render-parity/blocks/archive-card-meta-parts.json +26 -0
- data/scripts/test/render-parity/blocks/archive-card.json +32 -0
- data/scripts/test/render-parity/blocks/cta-link.json +13 -0
- data/scripts/test/render-parity/blocks/lang-pill-pt.json +8 -0
- data/scripts/test/render-parity/blocks/lang-pill.json +8 -0
- data/scripts/test/render-parity/blocks/ledger-row-meta-parts.json +29 -0
- data/scripts/test/render-parity/blocks/ledger-row.json +35 -0
- data/scripts/test/render-parity/blocks/meta-strip.json +27 -0
- data/scripts/test/render-parity/blocks/poster-media-image.json +8 -0
- data/scripts/test/render-parity/blocks/poster-media-video.json +9 -0
- data/scripts/test/render-parity/blocks/section-banner.json +13 -0
- data/scripts/test/render-parity/blocks/system-card-custom-meta.json +22 -0
- data/scripts/test/render-parity/blocks/system-card.json +48 -0
- data/scripts/test/render-parity/blocks/tag-chips-links.json +12 -0
- data/scripts/test/render-parity/blocks/tag-chips.json +9 -0
- data/scripts/test/render-parity/cut-in-blank-line.json +9 -0
- data/scripts/test/render-parity/cut-in-right.json +9 -0
- data/scripts/test/render-parity/cut-in.json +8 -0
- data/scripts/test/render-parity/figure.json +5 -0
- data/scripts/test/render-parity/load-runtime.mjs +337 -0
- data/scripts/test/render-parity/ongoing-product.json +5 -0
- data/scripts/test/render-parity/plotly.json +5 -0
- data/scripts/test/render-parity/poem.json +5 -0
- data/scripts/test/render-parity/run-absent-field-checks.mjs +232 -0
- data/scripts/test/render-parity/run-block-fixture.mjs +86 -0
- data/scripts/test/render-parity/run-detail-parity-checks.mjs +123 -0
- data/scripts/test/render-parity/run-field-flow-checks.mjs +227 -0
- data/scripts/test/render-parity/run-fixture.mjs +159 -0
- data/scripts/test/render-parity/selectors.mjs +43 -0
- data/scripts/test/render-parity/video.json +5 -0
- data/scripts/test/render-parity/youtube-short.json +10 -0
- data/scripts/test/render-parity/youtube.json +8 -0
- data/scripts/test/test-absent-field-absent-element.rb +43 -0
- data/scripts/test/test-cdn-pins.rb +44 -0
- data/scripts/test/test-cloudflare-watch-paths-doc.rb +31 -0
- data/scripts/test/test-configuration-doc.rb +36 -0
- data/scripts/test/test-content-detail-urls.rb +346 -0
- data/scripts/test/test-content-keys.rb +110 -0
- data/scripts/test/test-content-license.rb +45 -0
- data/scripts/test/test-content-render-parity.rb +38 -0
- data/scripts/test/test-content-validators.rb +12 -0
- data/scripts/test/test-css-structure.rb +72 -0
- data/scripts/test/test-cv-export-contract.rb +158 -0
- data/scripts/test/test-detail-render-parity.rb +40 -0
- data/scripts/test/test-dev-reexport.rb +122 -0
- data/scripts/test/test-doctor.rb +39 -0
- data/scripts/test/test-dual-template-instances.rb +87 -0
- data/scripts/test/test-dual-template-runtime.rb +167 -0
- data/scripts/test/test-examples-build.rb +60 -0
- data/scripts/test/test-export-content-json-incremental.rb +138 -0
- data/scripts/test/test-export.rb +53 -0
- data/scripts/test/test-exported-fields-reach-the-view.rb +60 -0
- data/scripts/test/test-form-control-theming.rb +143 -0
- data/scripts/test/test-git-chronology.rb +414 -0
- data/scripts/test/test-hero-portraits.mjs +97 -0
- data/scripts/test/test-hero-portraits.rb +162 -0
- data/scripts/test/test-home-band-art.rb +135 -0
- data/scripts/test/test-install-functions.rb +39 -0
- data/scripts/test/test-language-export.rb +79 -0
- data/scripts/test/test-listing-filter-contract.rb +119 -0
- data/scripts/test/test-math-row-breaks.mjs +79 -0
- data/scripts/test/test-math-row-breaks.rb +18 -0
- data/scripts/test/test-new.rb +113 -0
- data/scripts/test/test-no-personal-data.rb +85 -0
- data/scripts/test/test-public-cv-export.rb +164 -0
- data/scripts/test/test-r2-config-consistency.rb +57 -0
- data/scripts/test/test-r2-json-sync.rb +193 -0
- data/scripts/test/test-registry-home.rb +34 -0
- data/scripts/test/test-runtime-js-syntax.rb +64 -0
- data/scripts/test/test-slim-writing-index.rb +126 -0
- data/scripts/test/test-studio-api-contract.rb +99 -0
- data/scripts/test/test-studio-content-files.rb +79 -0
- data/scripts/test/test-studio-liquid-roundtrip.mjs +179 -0
- data/scripts/test/test-studio-rate-limit.mjs +70 -0
- data/scripts/test/test-studio-rewrite-api-contract.rb +59 -0
- data/scripts/test/test-studio-rewrite-sanitize.mjs +210 -0
- data/scripts/test/test-studio-schema-composition.rb +126 -0
- data/scripts/test/test-studio-slug-config.rb +167 -0
- data/scripts/test/test-template-packages.rb +51 -0
- data/scripts/test/test-text-excerpt.rb +51 -0
- data/scripts/test/test-unwrap-media-src.mjs +39 -0
- data/scripts/test/test-unwrap-media-src.rb +19 -0
- data/scripts/test/test-withdrawn-content-export.rb +69 -0
- data/scripts/test/test-writing-index-export-slugs.rb +84 -0
- data/scripts/test/test-writing-slug-limits.rb +61 -0
- data/scripts/test/test-xcite-chronology.rb +106 -0
- data/scripts/validate.sh +74 -0
- data/scripts/visual/build-cv-pages-json.js +33 -0
- data/scripts/visual/build-site-pages-json.js +94 -0
- data/scripts/visual/publish-visual-inspection-to-r2.sh +42 -0
- data/scripts/visual/take-screenshots.js +88 -0
- data/scripts/visual/visual-inspection-pages.json +113 -0
- data/studio/assets/index-B_j0pMD5.css +1 -0
- data/studio/assets/index-Ch4YEv9g.js +285 -0
- data/studio/index.html +27 -0
- data/studio/schema.yml +869 -0
- data/studio-app/README.md +27 -0
- data/studio-app/index.html +26 -0
- data/studio-app/package-lock.json +2499 -0
- data/studio-app/package.json +26 -0
- data/studio-app/skills-lock.json +47 -0
- data/studio-app/src/api/client.js +71 -0
- data/studio-app/src/editor/body-editor.js +70 -0
- data/studio-app/src/editor/liquid-core.js +382 -0
- data/studio-app/src/editor/liquid.js +77 -0
- data/studio-app/src/lib/document.js +207 -0
- data/studio-app/src/lib/list-controls.js +317 -0
- data/studio-app/src/lib/schema.js +66 -0
- data/studio-app/src/lib/yaml-doc.js +100 -0
- data/studio-app/src/main.js +3693 -0
- data/studio-app/src/media/browser.js +578 -0
- data/studio-app/src/preview/render.js +430 -0
- data/studio-app/src/styles/studio.css +2826 -0
- data/studio-app/vite.config.js +25 -0
- data/templates/articles/README.md +40 -0
- data/templates/articles/fixtures/article.md +9 -0
- data/templates/articles/screenshots/README.md +6 -0
- data/templates/articles/studio.yml +73 -0
- data/templates/articles/template.yml +21 -0
- data/templates/bibliography/README.md +41 -0
- data/templates/bibliography/fixtures/references.json +9 -0
- data/templates/bibliography/screenshots/README.md +6 -0
- data/templates/bibliography/studio.yml +66 -0
- data/templates/bibliography/template.yml +18 -0
- data/templates/blog/README.md +38 -0
- data/templates/blog/fixtures/post.md +9 -0
- data/templates/blog/screenshots/README.md +6 -0
- data/templates/blog/studio.yml +69 -0
- data/templates/blog/template.yml +20 -0
- data/templates/cv/README.md +34 -0
- data/templates/cv/fixtures/job.md +12 -0
- data/templates/cv/screenshots/README.md +6 -0
- data/templates/cv/studio.yml +200 -0
- data/templates/cv/template.yml +25 -0
- data/templates/media/README.md +38 -0
- data/templates/media/fixtures/resource.md +7 -0
- data/templates/media/screenshots/README.md +6 -0
- data/templates/media/studio.yml +58 -0
- data/templates/media/template.yml +17 -0
- data/templates/network/README.md +34 -0
- data/templates/network/fixtures/sources.json +3 -0
- data/templates/network/screenshots/README.md +6 -0
- data/templates/network/studio.yml +28 -0
- data/templates/network/template.yml +10 -0
- data/templates/portfolio/README.md +39 -0
- data/templates/portfolio/fixtures/project.md +10 -0
- data/templates/portfolio/screenshots/README.md +6 -0
- data/templates/portfolio/studio.yml +89 -0
- data/templates/portfolio/template.yml +18 -0
- metadata +505 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
{% raw %}
|
|
2
|
+
function plainTextFromMarkup(value) {
|
|
3
|
+
return String(value || '')
|
|
4
|
+
.replace(/<[^>]+>/g, ' ')
|
|
5
|
+
.replace(/ /gi, ' ')
|
|
6
|
+
.replace(/&/g, '&')
|
|
7
|
+
.replace(/</g, '<')
|
|
8
|
+
.replace(/>/g, '>')
|
|
9
|
+
.replace(/"/g, '"')
|
|
10
|
+
.replace(/'/g, "'")
|
|
11
|
+
.replace(/\s+/g, ' ')
|
|
12
|
+
.trim();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function figureLightboxCaption(caption, source) {
|
|
16
|
+
var parts = [];
|
|
17
|
+
var cap = plainTextFromMarkup(ensureCaptionPeriod(String(caption || '').trim()));
|
|
18
|
+
if (cap) parts.push(cap);
|
|
19
|
+
var src = plainTextFromMarkup(String(source || '').trim());
|
|
20
|
+
if (src) parts.push('Source: ' + src);
|
|
21
|
+
return parts.join(' ');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function cutInHtml(attrs) {
|
|
25
|
+
if (!attrs.src) return '';
|
|
26
|
+
var src = resolveAssetUrl(attrs.src);
|
|
27
|
+
var sideClass = attrs.side === 'right' ? ' article-cut-in--right' : '';
|
|
28
|
+
return '<figure class="article-cut-in-plate' + sideClass + '">' +
|
|
29
|
+
'<img class="article-cut-in' + sideClass + '" src="' + escapeAttr(src) + '" alt="' + escapeAttr(attrs.alt || '') + '" width="120" loading="lazy">' +
|
|
30
|
+
'</figure>';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function figureHtml(attrs) {
|
|
34
|
+
var width = attrs.width ? 'max-width:' + escapeAttr(attrs.width) + '%;' : 'max-width:100%;';
|
|
35
|
+
var src = resolveAssetUrl(attrs.src);
|
|
36
|
+
var caption = attrs.caption || '';
|
|
37
|
+
var lbCaption = figureLightboxCaption(caption, attrs.source);
|
|
38
|
+
var lbAttr = lbCaption ? ' data-lightbox-caption="' + escapeAttr(lbCaption) + '"' : '';
|
|
39
|
+
return [
|
|
40
|
+
'<figure class="my-8 mx-auto text-center w-full" style="display:block;margin-left:auto;margin-right:auto;' + width + '">',
|
|
41
|
+
'<img src="' + escapeAttr(src) + '" alt="' + escapeAttr(attrs.alt || caption) + '" class="figure-lightbox-trigger mx-auto max-w-full h-auto block" loading="lazy" tabindex="0" role="button" aria-label="Enlarge image"' + lbAttr + '>',
|
|
42
|
+
caption || attrs.source ? '<figcaption class="mt-3 font-body">' + includeCaptionHtml(caption) + figureSourceHtml(attrs.source) + '</figcaption>' : '',
|
|
43
|
+
'</figure>'
|
|
44
|
+
].join('');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function plotlyHtml(attrs) {
|
|
48
|
+
if (!attrs.src) return '';
|
|
49
|
+
var width = attrs.width ? String(attrs.width).trim() : '100';
|
|
50
|
+
var height = attrs.height ? String(attrs.height).trim() : '480';
|
|
51
|
+
if (!/^\d+$/.test(height)) height = '480';
|
|
52
|
+
var src = resolveAssetUrl(attrs.src);
|
|
53
|
+
var caption = attrs.caption || '';
|
|
54
|
+
var title = attrs.alt || caption || 'Interactive chart';
|
|
55
|
+
return [
|
|
56
|
+
'<figure class="plotly-figure my-8 mx-auto text-center w-full" style="display:block;margin-left:auto;margin-right:auto;max-width:' + escapeAttr(width) + '%;">',
|
|
57
|
+
'<iframe class="plotly-embed-frame" src="' + escapeAttr(src) + '" title="' + escapeAttr(title) + '" loading="lazy" scrolling="no" style="width:100%;height:' + escapeAttr(height) + 'px;border:0;display:block;border-radius:0;background:transparent;"></iframe>',
|
|
58
|
+
caption || attrs.source ? '<figcaption class="mt-3 font-body">' + includeCaptionHtml(caption) + figureSourceHtml(attrs.source) + '</figcaption>' : '',
|
|
59
|
+
'</figure>'
|
|
60
|
+
].join('');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function youtubeHtml(attrs, isShort) {
|
|
64
|
+
var id = attrs.id || attrs.youtube_id || (isShort ? attrs.src : '');
|
|
65
|
+
if (!id) return '';
|
|
66
|
+
var caption = attrs.caption || '';
|
|
67
|
+
if (isShort) {
|
|
68
|
+
return '<figure class="article-youtube-short-wrap my-8 mx-auto text-center w-full" style="margin:1.5rem auto;max-width:45%;">' +
|
|
69
|
+
'<div class="article-youtube-short" style="display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;">' +
|
|
70
|
+
youtubeShortEmbed(id, false) +
|
|
71
|
+
'</div>' +
|
|
72
|
+
(caption ? '<figcaption class="mt-3 font-body">' + includeCaptionHtml(caption) + '</figcaption>' : '') +
|
|
73
|
+
'</figure>';
|
|
74
|
+
}
|
|
75
|
+
return '<figure class="article-youtube-landscape my-8 mx-auto text-center w-full" style="margin:1.5rem auto;max-width:100%;">' +
|
|
76
|
+
'<div style="aspect-ratio:16 / 9;">' +
|
|
77
|
+
'<iframe src="https://www.youtube.com/embed/' + escapeAttr(id) + '" title="YouTube video" loading="lazy" allowfullscreen class="w-full h-full" style="width:100%;height:100%;border:0;"></iframe>' +
|
|
78
|
+
'</div>' +
|
|
79
|
+
(caption ? '<figcaption class="mt-3 font-body">' + includeCaptionHtml(caption) + '</figcaption>' : '') +
|
|
80
|
+
'</figure>';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function youtubeShortEmbed(id, paired) {
|
|
84
|
+
var width = paired ? '45%' : '100%';
|
|
85
|
+
return '<iframe width="315" height="560" src="https://www.youtube.com/embed/' + escapeAttr(id) + '" title="YouTube short" loading="lazy" allowfullscreen style="width:' + width + ';max-width:' + (paired ? '45%' : '100%') + ';aspect-ratio:9 / 16;height:auto;border-radius:0.25rem;"></iframe>';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function youtubeShortHtml(attrs) {
|
|
89
|
+
var src = attrs.src || attrs.id || attrs.id1;
|
|
90
|
+
var src2 = attrs.src2 || attrs.id2;
|
|
91
|
+
if (!src) return '';
|
|
92
|
+
var paired = !!src2;
|
|
93
|
+
return '<figure class="article-youtube-short-wrap' + (paired ? ' article-youtube-short-wrap--pair' : '') + ' my-8 mx-auto text-center w-full" style="margin:1.5rem auto;max-width:' + (paired ? '100%' : '45%') + ';">' +
|
|
94
|
+
'<div class="article-youtube-short' + (paired ? ' article-youtube-short--pair' : '') + '" style="display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;">' +
|
|
95
|
+
youtubeShortEmbed(src, paired) +
|
|
96
|
+
(src2 ? youtubeShortEmbed(src2, paired) : '') +
|
|
97
|
+
'</div>' +
|
|
98
|
+
'</figure>';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function formatDefHtml(def) {
|
|
102
|
+
return escapeHtml(String(def || '').trim()).replace(/\r\n|\r|\n/g, '<br>');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function dictCardHtml(attrs) {
|
|
106
|
+
var lemma = String(attrs.lemma || '').trim();
|
|
107
|
+
if (!lemma) return '';
|
|
108
|
+
var locale = String(attrs.locale || '').trim().toLowerCase();
|
|
109
|
+
var meta = String(attrs.meta || '').trim();
|
|
110
|
+
var label = String(attrs.country || meta || locale).trim();
|
|
111
|
+
var note = String(attrs.note || '').trim();
|
|
112
|
+
var source = String(attrs.source || '').trim();
|
|
113
|
+
var url = String(attrs.url || '').trim();
|
|
114
|
+
var accessed = String(attrs.accessed || '').trim();
|
|
115
|
+
var citeExtra = String(attrs.cite_extra || '').trim();
|
|
116
|
+
var linkLabel = String(attrs.link_label || url).trim();
|
|
117
|
+
var parts = [
|
|
118
|
+
'<article class="sov-card' + (locale ? ' sov-card--' + escapeAttr(locale) : '') + '" role="listitem">',
|
|
119
|
+
'<div class="sov-card__head">'
|
|
120
|
+
];
|
|
121
|
+
if (locale) {
|
|
122
|
+
parts.push(
|
|
123
|
+
'<span class="sov-card__flag" title="' + escapeAttr(label) + '">' +
|
|
124
|
+
'<span class="fi fi-' + escapeAttr(locale) + '" role="img" aria-label="' + escapeAttr(label) + '"></span>' +
|
|
125
|
+
'</span>'
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (meta) parts.push('<span class="sov-card__meta">' + escapeHtml(meta) + '</span>');
|
|
129
|
+
parts.push('</div>');
|
|
130
|
+
parts.push('<p class="sov-card__lemma">' + escapeHtml(lemma) + '</p>');
|
|
131
|
+
if (attrs.def) parts.push('<div class="sov-card__def">' + formatDefHtml(attrs.def) + '</div>');
|
|
132
|
+
if (note) parts.push('<p class="sov-card__note">' + note + '</p>');
|
|
133
|
+
if (source) {
|
|
134
|
+
var cite = escapeHtml(source) + ', s.v. “' + escapeHtml(lemma) + ',”';
|
|
135
|
+
if (url) cite += ' <a href="' + escapeAttr(url) + '">' + escapeHtml(linkLabel) + '</a>';
|
|
136
|
+
if (accessed) cite += ', accessed ' + escapeHtml(accessed);
|
|
137
|
+
cite += '.';
|
|
138
|
+
if (citeExtra) cite += ' ' + escapeHtml(citeExtra);
|
|
139
|
+
parts.push('<p class="sov-card__cite">' + cite + '</p>');
|
|
140
|
+
}
|
|
141
|
+
parts.push('</article>');
|
|
142
|
+
return parts.join('');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function tweetHtml(attrs) {
|
|
146
|
+
var body = String(attrs.body || '').trim();
|
|
147
|
+
if (!body) return '';
|
|
148
|
+
var handle = String(attrs.handle || '').trim().replace(/^@/, '');
|
|
149
|
+
var icon = String(attrs.icon || 'chat').trim() || 'chat';
|
|
150
|
+
var url = String(attrs.url || '').trim();
|
|
151
|
+
var date = String(attrs.date || '').trim();
|
|
152
|
+
var note = String(attrs.note || '').trim();
|
|
153
|
+
var name = String(attrs.name || '').trim();
|
|
154
|
+
var linkLabel = url.replace(/^https?:\/\//, '');
|
|
155
|
+
var parts = [
|
|
156
|
+
'<article class="sov-tweet article-tweet">',
|
|
157
|
+
'<div class="sov-tweet__head article-tweet__head">',
|
|
158
|
+
'<span class="sov-tweet__avatar article-tweet__avatar" aria-hidden="true"><span class="material-symbols-outlined">' + escapeHtml(icon) + '</span></span>',
|
|
159
|
+
'<span class="sov-tweet__id article-tweet__id">'
|
|
160
|
+
];
|
|
161
|
+
if (name) parts.push('<span class="sov-tweet__name article-tweet__name">' + escapeHtml(name) + '</span>');
|
|
162
|
+
if (handle) parts.push('<span class="sov-tweet__handle article-tweet__handle">@' + escapeHtml(handle) + '</span>');
|
|
163
|
+
parts.push('</span></div>');
|
|
164
|
+
parts.push('<p class="sov-tweet__body article-tweet__body">' + body + '</p>');
|
|
165
|
+
if (url || date) {
|
|
166
|
+
var cite = '';
|
|
167
|
+
if (url) cite += '<a href="' + escapeAttr(url) + '">' + escapeHtml(linkLabel) + '</a>';
|
|
168
|
+
if (url && date) cite += ' · ';
|
|
169
|
+
if (date) cite += escapeHtml(date);
|
|
170
|
+
parts.push('<p class="sov-tweet__cite article-tweet__cite">' + cite + '</p>');
|
|
171
|
+
}
|
|
172
|
+
if (note) parts.push('<p class="sov-tweet__note article-tweet__note">' + note + '</p>');
|
|
173
|
+
parts.push('</article>');
|
|
174
|
+
return parts.join('');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function wrapDictCardGrid(html) {
|
|
178
|
+
return String(html || '').replace(
|
|
179
|
+
/(?:<article\b[^>]*\bsov-card\b[\s\S]*?<\/article>\s*){2,}/g,
|
|
180
|
+
function (block) {
|
|
181
|
+
if (/\bsov-grid\b/.test(block)) return block;
|
|
182
|
+
return '<div class="sov-grid" role="list">' + block.trim() + '</div>\n';
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function videoHtml(attrs) {
|
|
188
|
+
if (!attrs.src) return '';
|
|
189
|
+
var caption = attrs.caption || '';
|
|
190
|
+
return '<figure class="article-video-landscape my-8 mx-auto text-center" style="display:block;margin-left:auto;margin-right:auto;max-width:100%;">' +
|
|
191
|
+
'<video controls src="' + escapeAttr(buildUrl(attrs.src)) + '" class="mx-auto max-w-full" style="width:100%;"></video>' +
|
|
192
|
+
(caption ? '<figcaption class="mt-3 font-body">' + includeCaptionHtml(caption) + '</figcaption>' : '') +
|
|
193
|
+
'</figure>';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function placeholderHtml() {
|
|
197
|
+
return '<div class="w-full h-full flex items-center justify-center opacity-30"><span class="material-symbols-outlined text-5xl">article</span></div>';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function normalizeDataPath(path, fallbackPrefix) {
|
|
201
|
+
var value = String(path || '').trim();
|
|
202
|
+
if (!value) return '';
|
|
203
|
+
value = value.replace(/^content\/collections\/data\//, 'data/');
|
|
204
|
+
value = value.replace(/^_data\//, 'data/');
|
|
205
|
+
value = value.replace(/\.(ya?ml)$/, '.json');
|
|
206
|
+
if (value.indexOf('/') === -1 && fallbackPrefix) {
|
|
207
|
+
value = fallbackPrefix + '/' + value + '.json';
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function preprocessTranscriptionAssigns(markdown) {
|
|
213
|
+
var assignMap = {};
|
|
214
|
+
var text = String(markdown || '').replace(
|
|
215
|
+
/\{%-?\s*assign\s+(\w+)\s*=\s*site\.data\.transcriptions\[([^\]]+)\]\.transcription\s*-?%\}\s*/g,
|
|
216
|
+
function (_, varName, keyExpr) {
|
|
217
|
+
keyExpr = String(keyExpr || '').trim();
|
|
218
|
+
if ((keyExpr.charAt(0) === "'" && keyExpr.charAt(keyExpr.length - 1) === "'") ||
|
|
219
|
+
(keyExpr.charAt(0) === '"' && keyExpr.charAt(keyExpr.length - 1) === '"')) {
|
|
220
|
+
assignMap[varName] = keyExpr.slice(1, -1);
|
|
221
|
+
} else if (keyExpr === 'page.transcription') {
|
|
222
|
+
assignMap[varName] = null;
|
|
223
|
+
} else {
|
|
224
|
+
assignMap[varName] = keyExpr;
|
|
225
|
+
}
|
|
226
|
+
return '';
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
return { text: text, assignMap: assignMap };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function resolveTranscriptionPath(attrs, fm, assignMap) {
|
|
233
|
+
var path = normalizeDataPath(attrs.path || attrs.file || attrs.src, '');
|
|
234
|
+
if (path) return path;
|
|
235
|
+
|
|
236
|
+
var transcriptionVar = attrs.transcription;
|
|
237
|
+
if (transcriptionVar && Object.prototype.hasOwnProperty.call(assignMap, transcriptionVar)) {
|
|
238
|
+
var assignedKey = assignMap[transcriptionVar];
|
|
239
|
+
if (assignedKey) {
|
|
240
|
+
return normalizeDataPath(assignedKey, 'data/transcriptions');
|
|
241
|
+
}
|
|
242
|
+
if (fm.transcription) {
|
|
243
|
+
return normalizeDataPath(fm.transcription, 'data/transcriptions');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (fm.transcription) {
|
|
248
|
+
return normalizeDataPath(fm.transcription, 'data/transcriptions');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return '';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function transcriptionSpeakerLabel(name) {
|
|
255
|
+
return String(name || '')
|
|
256
|
+
.trim()
|
|
257
|
+
.toLowerCase()
|
|
258
|
+
.replace(/(^|\s)\S/g, function (ch) { return ch.toUpperCase(); });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function transcriptionHtml(data, attrs) {
|
|
262
|
+
var rows = Array.isArray(data) ? data : (data && data.transcription) || [];
|
|
263
|
+
var speakers = [];
|
|
264
|
+
rows.forEach(function (line) {
|
|
265
|
+
var character = String(line.character || '').trim();
|
|
266
|
+
if (character && speakers.indexOf(character) === -1) speakers.push(character);
|
|
267
|
+
});
|
|
268
|
+
var colors = ['primary', 'secondary', 'tertiary', 'outline'];
|
|
269
|
+
var header = attrs.youtube_id ? youtubeHtml({ id: attrs.youtube_id }, false) : '';
|
|
270
|
+
return [
|
|
271
|
+
'<div class="mt-16 mb-8">',
|
|
272
|
+
'<hr class="border-t border-gentle-divider mb-6">',
|
|
273
|
+
header,
|
|
274
|
+
'<span class="font-label text-xs text-on-surface-variant">Transcrição</span>',
|
|
275
|
+
'</div>',
|
|
276
|
+
'<div class="transcription-block space-y-4">',
|
|
277
|
+
rows.map(function (line) {
|
|
278
|
+
var character = String(line.character || '').trim();
|
|
279
|
+
var side = '';
|
|
280
|
+
if (line.timestamp) {
|
|
281
|
+
side = '<span class="font-mono text-xs text-on-surface-variant whitespace-nowrap" style="flex-basis:15%; flex-shrink:0; flex-grow:0; max-width:15%; text-align:left; align-self:flex-start;">[' + escapeHtml(line.timestamp) + ']</span>';
|
|
282
|
+
} else if (line.scene) {
|
|
283
|
+
side = '<span class="font-mono text-xs text-on-surface-variant whitespace-nowrap align-top" style="flex-basis:15%; flex-shrink:0; flex-grow:0; max-width:15%; writing-mode:vertical-lr; text-align:left; align-self:flex-start;">' + escapeHtml(line.scene) + '</span>';
|
|
284
|
+
} else {
|
|
285
|
+
side = '<span class="font-mono text-xs text-on-surface-variant opacity-0 whitespace-nowrap align-top" style="flex-basis:15%; flex-shrink:0; flex-grow:0; max-width:15%;"> </span>';
|
|
286
|
+
}
|
|
287
|
+
if (!character) {
|
|
288
|
+
return '<div class="flex items-start gap-0 w-full" style="justify-content:flex-start;">' + side + '<span class="font-body text-on-surface italic opacity-60" style="flex-basis:85%; flex-shrink:1; flex-grow:1; max-width:85%; min-width:0;">' + escapeHtml(line.content || '') + '</span></div>';
|
|
289
|
+
}
|
|
290
|
+
var color = colors[speakers.indexOf(character)] || 'outline';
|
|
291
|
+
return '<div class="flex items-start gap-0 w-full" style="justify-content:flex-start;">' + side + '<span class="transcription-speaker text-' + color + '">' + escapeHtml(transcriptionSpeakerLabel(character)) + '</span><span class="font-body text-on-surface" style="flex-basis:65%; flex-shrink:1; flex-grow:1; max-width:65%; min-width:0;">' + escapeHtml(line.content || '') + '</span></div>';
|
|
292
|
+
}).join(''),
|
|
293
|
+
'</div>'
|
|
294
|
+
].join('');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function themeFont() {
|
|
298
|
+
var value = getComputedStyle(document.documentElement).getPropertyValue('--font-sans').trim();
|
|
299
|
+
return value || "'Lato', sans-serif";
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function themeColor(name, fallback) {
|
|
303
|
+
var value = getComputedStyle(document.documentElement).getPropertyValue('--color-' + name).trim();
|
|
304
|
+
return value || fallback;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function ongoingProductHtml() {
|
|
308
|
+
return '<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>';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function chordTabHtml(data) {
|
|
312
|
+
var sections = (data && data.sections) || [];
|
|
313
|
+
return [
|
|
314
|
+
'<div class="chord-tab-container mt-16 mb-8" style="width:100%; box-sizing:border-box; padding-left:0; padding-right:0;">',
|
|
315
|
+
'<h2>Cifra</h2>',
|
|
316
|
+
data && data.intro ? '<div class="mt-3 mb-6"><pre class="font-mono text-tertiary text-[0.8em] leading-relaxed whitespace-pre m-0 p-0 bg-transparent border-0">' + escapeHtml(data.intro) + '</pre></div>' : '',
|
|
317
|
+
"<div class=\"mt-4 font-mono text-[0.8em]\" style=\"display:grid; grid-template-columns:repeat(auto-fill, min(79ch, 100%)); gap:0 0.5rem; width:100%;\">",
|
|
318
|
+
sections.map(function (section) {
|
|
319
|
+
return '<div style="overflow-y:auto;">' +
|
|
320
|
+
(section.label ? '<div class="font-body text-[0.9em] uppercase tracking-widest text-tertiary mb-[0.35rem]">' + escapeHtml(section.label) + '</div>' : '') +
|
|
321
|
+
'<pre class="m-0 p-0 bg-transparent border-0 whitespace-pre overflow-x-auto leading-[1.55] text-on-surface">' + escapeHtml(section.content || '') + '</pre>' +
|
|
322
|
+
'<hr class="border-0 border-t border-gentle-divider my-[1.55em]">' +
|
|
323
|
+
'</div>';
|
|
324
|
+
}).join(''),
|
|
325
|
+
'</div>',
|
|
326
|
+
'</div>'
|
|
327
|
+
].join('');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function preprocessLiquid(markdown, xciteIndex) {
|
|
331
|
+
var text = stripFrontMatter(markdown)
|
|
332
|
+
.replace(/\{%-?\s*include\s+cut-in\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
333
|
+
return cutInHtml(parseIncludeAttrs(raw));
|
|
334
|
+
})
|
|
335
|
+
.replace(/\{%-?\s*include\s+figure\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
336
|
+
return figureHtml(parseIncludeAttrs(raw));
|
|
337
|
+
})
|
|
338
|
+
.replace(/\{%-?\s*include\s+plotly\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
339
|
+
return plotlyHtml(parseIncludeAttrs(raw));
|
|
340
|
+
})
|
|
341
|
+
.replace(/\{%-?\s*include\s+youtube-short\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
342
|
+
return youtubeShortHtml(parseIncludeAttrs(raw));
|
|
343
|
+
})
|
|
344
|
+
.replace(/\{%-?\s*include\s+youtube\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
345
|
+
return youtubeHtml(parseIncludeAttrs(raw), false);
|
|
346
|
+
})
|
|
347
|
+
.replace(/\{%-?\s*include\s+video\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
348
|
+
return videoHtml(parseIncludeAttrs(raw));
|
|
349
|
+
})
|
|
350
|
+
.replace(/\{%-?\s*include\s+dict-card\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
351
|
+
return dictCardHtml(parseIncludeAttrs(raw));
|
|
352
|
+
})
|
|
353
|
+
.replace(/\{%-?\s*include\s+tweet\.html\s+([\s\S]*?)-?%\}/g, function (_, raw) {
|
|
354
|
+
return tweetHtml(parseIncludeAttrs(raw));
|
|
355
|
+
})
|
|
356
|
+
.replace(/\{%-?\s*include\s+ongoing-product\.html\s*-?%\}/g, function () {
|
|
357
|
+
return ongoingProductHtml();
|
|
358
|
+
})
|
|
359
|
+
.replace(/\{%-?\s*include\s+xcite\.html\s+key=["']([^"']+)["'][\s\S]*?-?%\}/g, function (_, key) {
|
|
360
|
+
return xciteIndex ? xciteHtml(key, xciteIndex) : '%%CONTENT_RUNTIME_XCITE_' + key + '%%';
|
|
361
|
+
});
|
|
362
|
+
return wrapDictCardGrid(text);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
{% endraw %}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
{% raw %}
|
|
2
|
+
function extractExcerptText(root) {
|
|
3
|
+
var parts = [];
|
|
4
|
+
var skipTags = { script: true, style: true, iframe: true, svg: true, hr: true, noscript: true, video: true };
|
|
5
|
+
var blockTags = { p: true, li: true, blockquote: true, tr: true, pre: true, td: true, th: true, dd: true, dt: true };
|
|
6
|
+
|
|
7
|
+
function lastChar() {
|
|
8
|
+
return parts.length ? parts[parts.length - 1].slice(-1) : '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ensureSpace() {
|
|
12
|
+
if (parts.length && lastChar() && !/\s/.test(lastChar())) {
|
|
13
|
+
parts.push(' ');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function append(text) {
|
|
18
|
+
if (text) parts.push(text);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hasClass(node, name) {
|
|
22
|
+
return node.classList && node.classList.contains(name);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function visit(node) {
|
|
26
|
+
if (!node) return;
|
|
27
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
28
|
+
append(node.textContent);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
32
|
+
|
|
33
|
+
var tag = node.tagName.toLowerCase();
|
|
34
|
+
|
|
35
|
+
if (skipTags[tag]) return;
|
|
36
|
+
|
|
37
|
+
if (tag === 'div' && hasClass(node, 'article-references')) return;
|
|
38
|
+
|
|
39
|
+
if (tag === 'br') {
|
|
40
|
+
ensureSpace();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (tag === 'img') {
|
|
45
|
+
var alt = (node.getAttribute('alt') || '').trim();
|
|
46
|
+
if (alt) {
|
|
47
|
+
ensureSpace();
|
|
48
|
+
append(alt);
|
|
49
|
+
ensureSpace();
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (tag === 'pre') {
|
|
55
|
+
ensureSpace();
|
|
56
|
+
var codeText = (node.textContent || '').replace(/\s+/g, ' ').trim();
|
|
57
|
+
if (codeText) append(codeText);
|
|
58
|
+
ensureSpace();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (tag === 'figcaption') {
|
|
63
|
+
ensureSpace();
|
|
64
|
+
Array.prototype.forEach.call(node.childNodes, visit);
|
|
65
|
+
ensureSpace();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (/^h[1-6]$/.test(tag)) {
|
|
70
|
+
ensureSpace();
|
|
71
|
+
var heading = (node.textContent || '').trim();
|
|
72
|
+
if (heading) {
|
|
73
|
+
append(heading.replace(/:+\s*$/, '') + ': ');
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var isBlock = !!blockTags[tag];
|
|
79
|
+
|
|
80
|
+
if (isBlock) ensureSpace();
|
|
81
|
+
|
|
82
|
+
Array.prototype.forEach.call(node.childNodes, visit);
|
|
83
|
+
|
|
84
|
+
if (isBlock) ensureSpace();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
visit(root);
|
|
88
|
+
return parts.join('')
|
|
89
|
+
.replace(/%%CONTENT_RUNTIME_XCITE_[^%]+%%/g, '')
|
|
90
|
+
.replace(/\$\$[\s\S]*?\$\$/g, ' ')
|
|
91
|
+
.replace(/\$[^$\n]+\$/g, ' ')
|
|
92
|
+
.replace(/\\\[[\s\S]*?\\\]/g, ' ')
|
|
93
|
+
.replace(/\\\([\s\S]*?\\\)/g, ' ')
|
|
94
|
+
.replace(/\{%-?[\s\S]*?-?%\}/g, ' ')
|
|
95
|
+
.replace(/\s+/g, ' ')
|
|
96
|
+
.trim();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function textExcerpt(markdown) {
|
|
100
|
+
var html = renderMarkdown(markdown);
|
|
101
|
+
var el = document.createElement('div');
|
|
102
|
+
el.innerHTML = html;
|
|
103
|
+
var text = extractExcerptText(el);
|
|
104
|
+
return text.length > 220 ? text.slice(0, 217).trim() + '...' : text;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function listingPreview(item) {
|
|
108
|
+
var fm = (item && item.front_matter) || {};
|
|
109
|
+
var editorial = String(fm.description || '').trim();
|
|
110
|
+
if (editorial) return editorial;
|
|
111
|
+
var excerpt = String(fm.excerpt || '').trim();
|
|
112
|
+
if (excerpt) return excerpt;
|
|
113
|
+
return textExcerpt((item && item.body_markdown) || '');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function formatDate(value, locale) {
|
|
117
|
+
if (!value) return '';
|
|
118
|
+
var parts = String(value).slice(0, 10).split('-').map(Number);
|
|
119
|
+
if (parts.length !== 3 || parts.some(isNaN)) return value;
|
|
120
|
+
return new Intl.DateTimeFormat(locale || 'en', {
|
|
121
|
+
day: '2-digit',
|
|
122
|
+
month: 'short',
|
|
123
|
+
year: 'numeric'
|
|
124
|
+
}).format(new Date(parts[0], parts[1] - 1, parts[2]));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function chronologySortKey(item) {
|
|
128
|
+
var fm = item.front_matter || {};
|
|
129
|
+
var primary = item.last_updated || fm.last_updated || item.date || fm.date || '';
|
|
130
|
+
var tiebreaker = item.date || fm.date || item.slug || '';
|
|
131
|
+
return String(primary) + '\0' + String(tiebreaker);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getSessionRandomSeed(namespace) {
|
|
135
|
+
var key = 'listing-random-seed-' + (namespace || 'global');
|
|
136
|
+
var seed = null;
|
|
137
|
+
try {
|
|
138
|
+
seed = window.sessionStorage.getItem(key);
|
|
139
|
+
if (!seed) {
|
|
140
|
+
seed = String(Math.random()) + '-' + Date.now();
|
|
141
|
+
window.sessionStorage.setItem(key, seed);
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
seed = 'static-seed';
|
|
145
|
+
}
|
|
146
|
+
return seed;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function hashString(str) {
|
|
150
|
+
var h = 2166136261 >>> 0;
|
|
151
|
+
for (var i = 0; i < str.length; i++) {
|
|
152
|
+
h ^= str.charCodeAt(i);
|
|
153
|
+
h = Math.imul(h, 16777619);
|
|
154
|
+
}
|
|
155
|
+
h += h << 13;
|
|
156
|
+
h ^= h >>> 7;
|
|
157
|
+
h += h << 3;
|
|
158
|
+
h ^= h >>> 17;
|
|
159
|
+
h += h << 5;
|
|
160
|
+
return h >>> 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sessionRandomCompare(aKey, bKey, namespace) {
|
|
164
|
+
var seed = getSessionRandomSeed(namespace);
|
|
165
|
+
var ha = hashString(seed + ':' + aKey);
|
|
166
|
+
var hb = hashString(seed + ':' + bKey);
|
|
167
|
+
if (ha !== hb) return ha < hb ? -1 : 1;
|
|
168
|
+
return String(aKey).localeCompare(String(bKey));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function dateKey(value) {
|
|
172
|
+
if (value == null || value === '') return '';
|
|
173
|
+
return String(value).slice(0, 10);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function renderDateEvolution(date, lastUpdated, locale, options) {
|
|
177
|
+
options = options || {};
|
|
178
|
+
var created = formatDate(date, locale);
|
|
179
|
+
var updated = formatDate(lastUpdated, locale);
|
|
180
|
+
var hasUpdate = dateKey(lastUpdated) && dateKey(lastUpdated) !== dateKey(date);
|
|
181
|
+
if (!created && !(hasUpdate && updated)) return '';
|
|
182
|
+
var align = options.align === 'right' ? ' items-end' : '';
|
|
183
|
+
var gap = options.gap || 'gap-1';
|
|
184
|
+
var metaClass = options.metaClass ? ' ' + options.metaClass : '';
|
|
185
|
+
var nowrap = options.nowrap === false ? '' : ' whitespace-nowrap';
|
|
186
|
+
var publishedTitle = options.publishedLabel || 'Published';
|
|
187
|
+
var updatedTitle = options.updatedLabel || 'Updated';
|
|
188
|
+
var html = '<div class="date-evolution flex flex-col ' + gap + align + metaClass + '">';
|
|
189
|
+
if (created) {
|
|
190
|
+
html += '<span class="' + nowrap.trim() + '"' + (options.showLabels ? '' : ' title="' + escapeAttr(publishedTitle) + '"') + '>';
|
|
191
|
+
if (options.showLabels) html += escapeHtml(publishedTitle) + ': ';
|
|
192
|
+
html += escapeHtml(created) + '</span>';
|
|
193
|
+
}
|
|
194
|
+
if (hasUpdate && updated) {
|
|
195
|
+
html += '<span class="opacity-60' + nowrap + '"' + (options.showLabels ? '' : ' title="' + escapeAttr(updatedTitle) + '"') + '>';
|
|
196
|
+
if (options.showLabels) html += escapeHtml(updatedTitle) + ': ';
|
|
197
|
+
html += escapeHtml(updated) + '</span>';
|
|
198
|
+
}
|
|
199
|
+
html += '</div>';
|
|
200
|
+
return html;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function renderCardMetaBlock(category) {
|
|
204
|
+
if (!category) return '';
|
|
205
|
+
return [
|
|
206
|
+
'<div class="card-meta-block">',
|
|
207
|
+
'<span class="card-meta px-2 py-0.5 border border-gentle text-tertiary">',
|
|
208
|
+
escapeHtml(category),
|
|
209
|
+
'</span></div>'
|
|
210
|
+
].join('');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function renderCardFooterDates(date, lastUpdated, locale, options) {
|
|
214
|
+
options = options || {};
|
|
215
|
+
return renderDateEvolution(date, lastUpdated, locale, {
|
|
216
|
+
align: 'right',
|
|
217
|
+
gap: options.gap || 'gap-0.5',
|
|
218
|
+
publishedLabel: options.publishedLabel,
|
|
219
|
+
updatedLabel: options.updatedLabel,
|
|
220
|
+
showLabels: options.showLabels,
|
|
221
|
+
metaClass: 'card-meta text-on-surface-variant'
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
{% endraw %}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{% raw %}
|
|
2
|
+
|
|
3
|
+
var Listing = {
|
|
4
|
+
setActive: function (el) {
|
|
5
|
+
if (!el) return;
|
|
6
|
+
el.classList.add('text-secondary');
|
|
7
|
+
el.classList.remove('text-on-surface-variant');
|
|
8
|
+
},
|
|
9
|
+
clearActive: function (el) {
|
|
10
|
+
if (!el) return;
|
|
11
|
+
el.classList.remove('text-secondary');
|
|
12
|
+
el.classList.add('text-on-surface-variant');
|
|
13
|
+
},
|
|
14
|
+
buildFilterUrl: function (updates) {
|
|
15
|
+
var p = new URLSearchParams(window.location.search);
|
|
16
|
+
Object.keys(updates || {}).forEach(function (key) {
|
|
17
|
+
var val = updates[key];
|
|
18
|
+
if (val == null || val === '') p.delete(key);
|
|
19
|
+
else p.set(key, val);
|
|
20
|
+
});
|
|
21
|
+
p.delete('page');
|
|
22
|
+
var qs = p.toString();
|
|
23
|
+
return window.location.pathname + (qs ? '?' + qs : '');
|
|
24
|
+
},
|
|
25
|
+
pageUrl: function (pageNumber) {
|
|
26
|
+
var p = new URLSearchParams(window.location.search);
|
|
27
|
+
p.set('page', pageNumber);
|
|
28
|
+
return window.location.pathname + '?' + p.toString();
|
|
29
|
+
},
|
|
30
|
+
renderPagination: function (controls, currentPage, totalPages, labels) {
|
|
31
|
+
labels = labels || {};
|
|
32
|
+
if (!controls) return;
|
|
33
|
+
controls.innerHTML = '';
|
|
34
|
+
if (totalPages <= 1) {
|
|
35
|
+
controls.classList.add('hidden');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
controls.classList.remove('hidden');
|
|
39
|
+
var prevLabel = labels.prev || 'Previous';
|
|
40
|
+
var nextLabel = labels.next || 'Next';
|
|
41
|
+
// Styled by .pagination-nav-btn in base.css. Handing out utilities
|
|
42
|
+
// here forced every page sheet to out-specify them.
|
|
43
|
+
var btnClass = 'pagination-nav-btn';
|
|
44
|
+
var prevBtn = document.createElement('button');
|
|
45
|
+
prevBtn.textContent = prevLabel;
|
|
46
|
+
prevBtn.disabled = currentPage === 1;
|
|
47
|
+
prevBtn.className = btnClass;
|
|
48
|
+
if (currentPage > 1) prevBtn.addEventListener('click', function () { window.location.href = Listing.pageUrl(currentPage - 1); });
|
|
49
|
+
controls.appendChild(prevBtn);
|
|
50
|
+
var indicator = document.createElement('span');
|
|
51
|
+
indicator.className = 'pagination-count';
|
|
52
|
+
indicator.textContent = currentPage + ' / ' + totalPages;
|
|
53
|
+
controls.appendChild(indicator);
|
|
54
|
+
var nextBtn = document.createElement('button');
|
|
55
|
+
nextBtn.textContent = nextLabel;
|
|
56
|
+
nextBtn.disabled = currentPage === totalPages;
|
|
57
|
+
nextBtn.className = btnClass;
|
|
58
|
+
if (currentPage < totalPages) nextBtn.addEventListener('click', function () { window.location.href = Listing.pageUrl(currentPage + 1); });
|
|
59
|
+
controls.appendChild(nextBtn);
|
|
60
|
+
},
|
|
61
|
+
showLoadingState: function (element, message) {
|
|
62
|
+
if (!element) return;
|
|
63
|
+
element.innerHTML = '<p class="font-body text-on-surface-variant italic col-span-full">' + escapeHtml(message) + '</p>';
|
|
64
|
+
},
|
|
65
|
+
showErrorState: function (element, message) {
|
|
66
|
+
if (!element) return;
|
|
67
|
+
element.innerHTML = '<p class="font-body text-on-surface-variant italic col-span-full">' + escapeHtml(message) + '</p>';
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
{% endraw %}
|