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
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The Pandorga contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Pandorga
|
|
2
|
+
|
|
3
|
+
[](https://github.com/alexandrelheinen/pandorga/actions/workflows/validate.yml)
|
|
4
|
+
[](https://github.com/alexandrelheinen/pandorga/releases/latest)
|
|
5
|
+
[](https://rubygems.org/gems/pandorga)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
<img src="docs/images/family_link_64dp_5084C1_FILL0_wght400_GRAD0_opsz48.svg" alt="Pandorga Logo" width="120" align="left" style="margin-right: 10%;">
|
|
9
|
+
An aesthetic Jekyll publishing platform for creative and technical writing. The site is your paper, your portfolio, and an extension of your own thoughts.
|
|
10
|
+
|
|
11
|
+
- **Headless and S3-compatible.** Your content lives independently of the Pandorga shell — write, store, and move it on your own terms.
|
|
12
|
+
- **Studio CMS.** Manage everything from quick notes to full diagrams without touching the repo.
|
|
13
|
+
- **Fully configurable.** Portfolio, CV, blog, articles, and bibliography — each with its own presentation.
|
|
14
|
+
|
|
15
|
+
## Quickstart
|
|
16
|
+
|
|
17
|
+
Scaffold a site (Ada Example defaults, `content.backend: static`):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
gem install pandorga # once 1.1 is on RubyGems; or use a local checkout
|
|
21
|
+
pandorga new my-site
|
|
22
|
+
cd my-site
|
|
23
|
+
bundle install
|
|
24
|
+
bundle exec pandorga doctor
|
|
25
|
+
bundle exec pandorga serve
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or run the packaged minimal example from a clone:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone https://github.com/alexandrelheinen/pandorga.git
|
|
32
|
+
cd pandorga
|
|
33
|
+
git submodule update --init .guidelines # agent/prose guidelines (optional for runtime)
|
|
34
|
+
mise install # or use Ruby >= 3.3
|
|
35
|
+
bundle install
|
|
36
|
+
cd examples/minimal && bundle install && cd ../..
|
|
37
|
+
bundle exec pandorga export examples/minimal/content examples/minimal/_content_json
|
|
38
|
+
bundle exec pandorga doctor examples/minimal
|
|
39
|
+
mise exec -- ./scripts/validate.sh
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Serve from the example directory:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd examples/minimal
|
|
46
|
+
bundle exec pandorga serve
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## CLI
|
|
50
|
+
|
|
51
|
+
| Command | Purpose |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `pandorga new PATH` | Scaffold a site from `examples/minimal` |
|
|
54
|
+
| `pandorga doctor` | Validate `pandorga:` config |
|
|
55
|
+
| `pandorga export` | Content → JSON (`manifest.json` includes `schema_version`) |
|
|
56
|
+
| `pandorga serve` | Export + `jekyll serve` |
|
|
57
|
+
| `pandorga publish` | S3-compatible object-store sync (`S3_*` or `R2_*`) |
|
|
58
|
+
| `pandorga install-functions` | Copy `functions/` + `studio/` into the site root |
|
|
59
|
+
| `pandorga studio-schema` | Compose Studio schema from templates |
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
| Doc | Topic |
|
|
64
|
+
|---|---|
|
|
65
|
+
| [docs/getting-started.md](docs/getting-started.md) | Minimal example locally |
|
|
66
|
+
| [docs/configuration.md](docs/configuration.md) | `pandorga:` reference |
|
|
67
|
+
| [docs/pages-and-templates.md](docs/pages-and-templates.md) | Registry and seven templates |
|
|
68
|
+
| [docs/theming.md](docs/theming.md) | `_data/themes` and tokens |
|
|
69
|
+
| [docs/extending.md](docs/extending.md) | Site overrides, hero art, Studio overrides |
|
|
70
|
+
| [docs/architecture.md](docs/architecture.md) | Shell, JSON, runtime, Studio |
|
|
71
|
+
| [docs/upgrading.md](docs/upgrading.md) | Semver, `schema_version`, gem pins |
|
|
72
|
+
| [docs/studio.md](docs/studio.md) | Studio env and schema compose |
|
|
73
|
+
| [docs/studio-android.md](docs/studio-android.md) | Optional Expo Android WebView shell |
|
|
74
|
+
| [docs/deploy/static.md](docs/deploy/static.md) | Static backend |
|
|
75
|
+
| [docs/deploy/cloudflare.md](docs/deploy/cloudflare.md) | Pages + object store |
|
|
76
|
+
| [docs/spec.md](docs/spec.md) | Migration plan and acceptance criteria |
|
|
77
|
+
| [docs/decisions.md](docs/decisions.md) | Frozen decisions |
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT — Copyright (c) The Pandorga contributors.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Brazilian Ledger — dark theme (runtime toggle companion to light.yml).
|
|
2
|
+
#
|
|
3
|
+
# 2026-09 vivid pass: same Ledger hues as light, chroma raised so accents
|
|
4
|
+
# read on the near-black ladder (Stitch Home Dark Mode intent: pigment on
|
|
5
|
+
# near-black, not a new triad).
|
|
6
|
+
|
|
7
|
+
colors:
|
|
8
|
+
primary: "#a4c8da"
|
|
9
|
+
secondary: "#95c8a6"
|
|
10
|
+
tertiary: "#ddd8a8"
|
|
11
|
+
primary_container: "#4a5c66"
|
|
12
|
+
secondary_container: "#435c4c"
|
|
13
|
+
tertiary_container: "#6a684f"
|
|
14
|
+
on_primary_container: "#c0d8e6"
|
|
15
|
+
on_secondary_container: "#b5d9c2"
|
|
16
|
+
on_tertiary_container: "#e8e4c0"
|
|
17
|
+
chart_project: "#98c8ac"
|
|
18
|
+
|
|
19
|
+
neutrals:
|
|
20
|
+
on_surface: "#ffffff"
|
|
21
|
+
on_surface_variant: "#b8b7ae"
|
|
22
|
+
on_background: "#ffffff"
|
|
23
|
+
outline: "#93938d"
|
|
24
|
+
# Neutralised with the rest of the ramp: this was #44453f (green highest),
|
|
25
|
+
# and every hairline in the build is an opacity step of it.
|
|
26
|
+
outline_variant: "#45454c"
|
|
27
|
+
background: "#0c0c0e"
|
|
28
|
+
background_secondary: "#141418"
|
|
29
|
+
surface: "#111114"
|
|
30
|
+
surface_container_low: "#17171b"
|
|
31
|
+
surface_container: "#1f1f24"
|
|
32
|
+
surface_container_high: "#26262b"
|
|
33
|
+
surface_variant: "#2e2e34"
|
|
34
|
+
# Architectural Ledger ladder. Depth comes from tonal steps, not shadow:
|
|
35
|
+
# canvas (background) -> panel -> card (transparent at rest) -> hover.
|
|
36
|
+
#
|
|
37
|
+
# Cards rest transparent so the panel/canvas and shards show through; the
|
|
38
|
+
# hover rung still lifts. Widened 2026-09: canvas near-black buys headroom
|
|
39
|
+
# the reference mockup uses (#0a0a0a canvas). Panel and hover keep the
|
|
40
|
+
# ~+4 L* / ~+6 L* steps; the resting card no longer inserts a mid plate.
|
|
41
|
+
panel_contrast: "#141418"
|
|
42
|
+
surface_card: "#0c0c0e"
|
|
43
|
+
surface_card_contrast: "#141418"
|
|
44
|
+
surface_high: "#26262b"
|
|
45
|
+
surface_high_contrast: "#26262b"
|
|
46
|
+
|
|
47
|
+
links:
|
|
48
|
+
default: "#b0d0e0"
|
|
49
|
+
hover: "#c4dce8"
|
|
50
|
+
|
|
51
|
+
# Fonts, motion, and geometry live in shared.yml — colour themes do not
|
|
52
|
+
# redeclare them.
|
|
53
|
+
|
|
54
|
+
static:
|
|
55
|
+
on_primary: "#0f1a22"
|
|
56
|
+
on_secondary: "#141a15"
|
|
57
|
+
on_tertiary: "#1b1c12"
|
|
58
|
+
surface_container_lowest: "#08080a"
|
|
59
|
+
surface_dim: "#060607"
|
|
60
|
+
inverse_primary: "#1c5a7a"
|
|
61
|
+
inverse_surface: "#ffffff"
|
|
62
|
+
inverse_on_surface: "#000000"
|
|
63
|
+
primary_fixed: "#a8c5d4"
|
|
64
|
+
primary_fixed_dim: "#a4c8da"
|
|
65
|
+
secondary_fixed: "#b4d4c0"
|
|
66
|
+
secondary_fixed_dim: "#95c8a6"
|
|
67
|
+
tertiary_fixed: "#d0ceb0"
|
|
68
|
+
tertiary_fixed_dim: "#ddd8a8"
|
|
69
|
+
on_primary_fixed: "#0a1419"
|
|
70
|
+
on_primary_fixed_variant: "#c0d8e6"
|
|
71
|
+
on_secondary_fixed: "#0c1710"
|
|
72
|
+
on_secondary_fixed_variant: "#b5d9c2"
|
|
73
|
+
on_tertiary_fixed: "#17160c"
|
|
74
|
+
on_tertiary_fixed_variant: "#e8e4c0"
|
|
75
|
+
error: "#ffb4ab"
|
|
76
|
+
on_error: "#690005"
|
|
77
|
+
error_container: "#93000a"
|
|
78
|
+
on_error_container: "#ffdad6"
|
|
79
|
+
res_youtube: "#de6461"
|
|
80
|
+
res_podcast: "#5dc462"
|
|
81
|
+
res_doc: "#e4b268"
|
|
82
|
+
|
|
83
|
+
sidebar_thumbnail:
|
|
84
|
+
background: "#1f1f24"
|
|
85
|
+
overlay_gradient_start: "rgba(23, 23, 27, 0.35)"
|
|
86
|
+
overlay_gradient_end: "rgba(12, 12, 14, 0.45)"
|
|
87
|
+
|
|
88
|
+
# Timeline lane palette — see light.yml for the rationale. Same six hues,
|
|
89
|
+
# lifted in lightness and eased in saturation so they carry against the
|
|
90
|
+
# near-black canvas instead of sinking into it. Chroma raised with the triad.
|
|
91
|
+
timeline:
|
|
92
|
+
employment: "#a4c8da" # petrol
|
|
93
|
+
education: "#95c8a6" # forest
|
|
94
|
+
product: "#d5b46e" # tobacco
|
|
95
|
+
project: "#a9a5dd" # indigo
|
|
96
|
+
article: "#da987e" # terracotta
|
|
97
|
+
post: "#7cc7b5" # sage teal
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Brazilian Ledger — light theme (production default).
|
|
2
|
+
# Add sibling files (e.g. dark.yml) and set shell_theme.active in _config.yml to switch palettes.
|
|
3
|
+
#
|
|
4
|
+
# 2026-09 vivid pass (second cut): slate / forest / ochre chroma raised again
|
|
5
|
+
# so brand ink reads on white paper without grey wash. Canvas and cards stay
|
|
6
|
+
# pure white; contrast bands are near-white paper rhythm (Stitch "Editorial
|
|
7
|
+
# Detour" intent, without adopting its alabaster #fcf9f6 canvas). Card margins
|
|
8
|
+
# use a darker outline_variant so hairlines read closer to Stitch paper rules.
|
|
9
|
+
|
|
10
|
+
colors:
|
|
11
|
+
primary: "#1c5a7a"
|
|
12
|
+
secondary: "#287445"
|
|
13
|
+
tertiary: "#746f30"
|
|
14
|
+
primary_container: "#a8c5d4"
|
|
15
|
+
secondary_container: "#b4d4c0"
|
|
16
|
+
tertiary_container: "#d0ceb0"
|
|
17
|
+
on_primary_container: "#0a1419"
|
|
18
|
+
on_secondary_container: "#0c1710"
|
|
19
|
+
on_tertiary_container: "#17160c"
|
|
20
|
+
chart_project: "#6fb387"
|
|
21
|
+
|
|
22
|
+
neutrals:
|
|
23
|
+
on_surface: "#000000"
|
|
24
|
+
on_surface_variant: "#5e5d59"
|
|
25
|
+
on_background: "#000000"
|
|
26
|
+
# Hairlines. Every border in the build is an opacity step of
|
|
27
|
+
# `outline_variant`. Stitch-like paper rules need a mid-grey base so the
|
|
28
|
+
# opacity ladder does not vanish on white cards. Neutral grey — no cream
|
|
29
|
+
# warmth and no slate cast in the fills.
|
|
30
|
+
outline: "#5c5c5c"
|
|
31
|
+
outline_variant: "#b8b8b8"
|
|
32
|
+
# Architectural Ledger ladder — white paper edition.
|
|
33
|
+
#
|
|
34
|
+
# Canvas is pure white. Depth is hairline + a near-neutral grey panel band
|
|
35
|
+
# for alternating rhythm. Cards rest transparent (panel/canvas shows
|
|
36
|
+
# through; shards stay visible) and only take a fill on hover. Cream washed
|
|
37
|
+
# ochre into the page; the blue-grey step still read as slate — this ladder
|
|
38
|
+
# is practically grey (equal RGB) so highlights stay quiet paper.
|
|
39
|
+
#
|
|
40
|
+
# Canvas (#ffffff) -> Panel contrast (#f4f4f4) -> Card (transparent)
|
|
41
|
+
# -> Hover (#ebebeb). Contrast-band cards stay transparent too, so they
|
|
42
|
+
# never cut a white plate out of the grey band.
|
|
43
|
+
background: "#ffffff"
|
|
44
|
+
background_secondary: "#f4f4f4"
|
|
45
|
+
panel_contrast: "#f4f4f4"
|
|
46
|
+
surface_card: "#ffffff"
|
|
47
|
+
surface_card_contrast: "#f4f4f4"
|
|
48
|
+
surface_high: "#ebebeb"
|
|
49
|
+
surface_high_contrast: "#e2e2e2"
|
|
50
|
+
surface: "#ffffff"
|
|
51
|
+
surface_container_low: "#f4f4f4"
|
|
52
|
+
surface_container: "#ebebeb"
|
|
53
|
+
surface_container_high: "#e2e2e2"
|
|
54
|
+
surface_variant: "#d8d8d8"
|
|
55
|
+
|
|
56
|
+
links:
|
|
57
|
+
default: "#1c5a7a"
|
|
58
|
+
hover: "#2a6f92"
|
|
59
|
+
|
|
60
|
+
# Fonts, motion, and geometry live in shared.yml — colour themes do not
|
|
61
|
+
# redeclare them.
|
|
62
|
+
|
|
63
|
+
# Static tokens shared across Tailwind and scoped CSS (not derived from the brand triad).
|
|
64
|
+
static:
|
|
65
|
+
on_primary: "#ffffff"
|
|
66
|
+
on_secondary: "#ffffff"
|
|
67
|
+
on_tertiary: "#ffffff"
|
|
68
|
+
surface_container_lowest: "#ffffff"
|
|
69
|
+
surface_dim: "#d8d8d8"
|
|
70
|
+
inverse_primary: "#a4c8da"
|
|
71
|
+
inverse_surface: "#000000"
|
|
72
|
+
inverse_on_surface: "#ffffff"
|
|
73
|
+
primary_fixed: "#a8c5d4"
|
|
74
|
+
primary_fixed_dim: "#7fa8bc"
|
|
75
|
+
secondary_fixed: "#b4d4c0"
|
|
76
|
+
secondary_fixed_dim: "#6fb387"
|
|
77
|
+
tertiary_fixed: "#d0ceb0"
|
|
78
|
+
tertiary_fixed_dim: "#c0bc90"
|
|
79
|
+
on_primary_fixed: "#0a1419"
|
|
80
|
+
on_primary_fixed_variant: "#163040"
|
|
81
|
+
on_secondary_fixed: "#0c1710"
|
|
82
|
+
on_secondary_fixed_variant: "#24382a"
|
|
83
|
+
on_tertiary_fixed: "#17160c"
|
|
84
|
+
on_tertiary_fixed_variant: "#3a381c"
|
|
85
|
+
error: "#ba1a1a"
|
|
86
|
+
on_error: "#ffffff"
|
|
87
|
+
error_container: "#ffdad6"
|
|
88
|
+
on_error_container: "#93000a"
|
|
89
|
+
res_youtube: "#c62828"
|
|
90
|
+
res_podcast: "#2e7d32"
|
|
91
|
+
res_doc: "#b45309"
|
|
92
|
+
|
|
93
|
+
# Detail-page sidebar thumbnail. Light had no block of its own and fell through
|
|
94
|
+
# to _config.yml, whose #eeeeee plate and grey scrim are cold neutrals from
|
|
95
|
+
# before the ramp was warmed (DESIGN.md known inconsistency 14). Same three
|
|
96
|
+
# keys as dark.yml; width, opacity and the filters still fall through.
|
|
97
|
+
#
|
|
98
|
+
# The plate sits a step below the card because a photo is inset into the page,
|
|
99
|
+
# not lifted off it, and the scrim runs from card-white down to deep paper so
|
|
100
|
+
# the image settles onto the sheet instead of floating. Dark can afford 0.35 /
|
|
101
|
+
# 0.45 on its scrim; a light scrim that heavy would wash the photograph out,
|
|
102
|
+
# which is the failure this palette pass exists to undo.
|
|
103
|
+
sidebar_thumbnail:
|
|
104
|
+
background: "#ebebeb"
|
|
105
|
+
overlay_gradient_start: "rgba(255, 255, 255, 0.18)"
|
|
106
|
+
overlay_gradient_end: "rgba(226, 226, 226, 0.28)"
|
|
107
|
+
|
|
108
|
+
# Timeline lane palette — a categorical scale for the CV chart, not part of
|
|
109
|
+
# the UI triad. Six kinds of event are drawn at once and have to be told
|
|
110
|
+
# apart, so this is the one place the site carries more than three inks.
|
|
111
|
+
# Held separately from `colors:` on purpose: a `.page-accent--*` class
|
|
112
|
+
# rebinds --color-primary, and the CV reads green, but a green chart is an
|
|
113
|
+
# unreadable chart. Same hues as before, chroma raised with the triad.
|
|
114
|
+
timeline:
|
|
115
|
+
employment: "#1c5a7a" # petrol — the triad primary, the anchor lane
|
|
116
|
+
education: "#287445" # forest — triad secondary
|
|
117
|
+
product: "#906c2a" # tobacco — deepened off the ochre tertiary
|
|
118
|
+
project: "#534da1" # indigo
|
|
119
|
+
article: "#a95031" # terracotta
|
|
120
|
+
post: "#478576" # sage teal
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Tokens shared by every colour theme. Light and dark only differ on colour
|
|
2
|
+
# roles (see light.yml / dark.yml); fonts, motion, and geometry live here so
|
|
3
|
+
# a palette swap cannot drift the type stack.
|
|
4
|
+
#
|
|
5
|
+
# Consumed by theme-context.liquid → theme-vars-block.liquid / font-loader.
|
|
6
|
+
|
|
7
|
+
fonts:
|
|
8
|
+
title: "Cinzel Decorative"
|
|
9
|
+
subtitle: "Newsreader"
|
|
10
|
+
label: "Marcellus SC"
|
|
11
|
+
body: "Newsreader"
|
|
12
|
+
mono: "Courier Prime"
|
|
13
|
+
code: "Courier Prime"
|
|
14
|
+
cv_body: "Newsreader"
|
|
15
|
+
cv_body_weight: 400
|
|
16
|
+
# Generic CSS fallback after the named face (serif | sans-serif | monospace).
|
|
17
|
+
body_fallback: "sans-serif"
|
|
18
|
+
subtitle_fallback: "serif"
|
|
19
|
+
title_fallback: "serif"
|
|
20
|
+
label_fallback: "serif"
|
|
21
|
+
google_title_spec: "wght@400;700;900"
|
|
22
|
+
google_subtitle_spec: "ital,opsz,wght@0,6..72,300;0,6..72,400;0,6..72,500;0,6..72,600;0,6..72,700;1,6..72,300;1,6..72,400;1,6..72,500"
|
|
23
|
+
google_label_spec: "wght@400;700"
|
|
24
|
+
google_body_spec: "wght@300;400;500;600;700"
|
|
25
|
+
google_mono_spec: "ital,wght@0,400;0,700;1,400;1,700"
|
|
26
|
+
google_code_spec: "ital,wght@0,300;0,400;0,700;1,400;1,700"
|
|
27
|
+
google_cv_body_spec: "wght@300;400;500;600;700"
|
|
28
|
+
|
|
29
|
+
motion:
|
|
30
|
+
duration_fast: "0.15s"
|
|
31
|
+
duration_base: "0.4s"
|
|
32
|
+
duration_slow: "0.7s"
|
|
33
|
+
ease_default: "ease"
|
|
34
|
+
ease_out: "ease-out"
|
|
35
|
+
|
|
36
|
+
geometry:
|
|
37
|
+
radius_card: "0"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
updated:
|
|
2
|
+
enus: "Updated"
|
|
3
|
+
ptbr: "Atualizado"
|
|
4
|
+
frfr: "Mis à jour"
|
|
5
|
+
eses: "Actualizado"
|
|
6
|
+
published:
|
|
7
|
+
enus: "Published"
|
|
8
|
+
ptbr: "Publicado"
|
|
9
|
+
frfr: "Publié"
|
|
10
|
+
eses: "Publicado"
|
|
11
|
+
months:
|
|
12
|
+
enus: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
|
13
|
+
ptbr: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"]
|
|
14
|
+
frfr: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembro", "décembre"]
|
|
15
|
+
eses: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"]
|
|
16
|
+
back:
|
|
17
|
+
enus: "Back"
|
|
18
|
+
ptbr: "Voltar"
|
|
19
|
+
frfr: "Retour"
|
|
20
|
+
eses: "Volver"
|
|
21
|
+
back_to_drafts:
|
|
22
|
+
enus: "Back to drafts"
|
|
23
|
+
ptbr: "Voltar aos rascunhos"
|
|
24
|
+
frfr: "Retour aux brouillons"
|
|
25
|
+
eses: "Volver a los borradores"
|
|
26
|
+
back_to_articles:
|
|
27
|
+
enus: "Back to articles"
|
|
28
|
+
ptbr: "Voltar aos artigos"
|
|
29
|
+
frfr: "Retour aux articles"
|
|
30
|
+
eses: "Volver a los artículos"
|
|
31
|
+
back_to_portfolio:
|
|
32
|
+
enus: "Back to portfolio"
|
|
33
|
+
ptbr: "Voltar ao portfólio"
|
|
34
|
+
frfr: "Retour au portfolio"
|
|
35
|
+
eses: "Volver al portafolio"
|
|
36
|
+
back_to_projects:
|
|
37
|
+
enus: "Back to projects"
|
|
38
|
+
ptbr: "Voltar aos projetos"
|
|
39
|
+
frfr: "Retour aux projets"
|
|
40
|
+
eses: "Volver a los proyectos"
|
|
41
|
+
back_to_cv:
|
|
42
|
+
enus: "Back to CV"
|
|
43
|
+
ptbr: "Voltar ao CV"
|
|
44
|
+
frfr: "Retour au CV"
|
|
45
|
+
eses: "Volver al CV"
|
|
46
|
+
previous_text:
|
|
47
|
+
enus: "Previous"
|
|
48
|
+
ptbr: "Anterior"
|
|
49
|
+
frfr: "Précédent"
|
|
50
|
+
eses: "Anterior"
|
|
51
|
+
next_text:
|
|
52
|
+
enus: "Next"
|
|
53
|
+
ptbr: "Próximo"
|
|
54
|
+
frfr: "Suivant"
|
|
55
|
+
eses: "Siguiente"
|
|
56
|
+
random_text:
|
|
57
|
+
enus: "Random"
|
|
58
|
+
ptbr: "Aleatório"
|
|
59
|
+
frfr: "Aléatoire"
|
|
60
|
+
eses: "Aleatorio"
|
|
61
|
+
toc_title:
|
|
62
|
+
enus: "In this text"
|
|
63
|
+
ptbr: "Neste texto"
|
|
64
|
+
frfr: "Dans ce texte"
|
|
65
|
+
eses: "En este texto"
|
|
66
|
+
cite_this_text:
|
|
67
|
+
enus: "Cite this text"
|
|
68
|
+
ptbr: "Citar este texto"
|
|
69
|
+
frfr: "Citer ce texte"
|
|
70
|
+
eses: "Citar este texto"
|
|
71
|
+
related_texts:
|
|
72
|
+
enus: "Related texts"
|
|
73
|
+
ptbr: "Textos relacionados"
|
|
74
|
+
frfr: "Textes liés"
|
|
75
|
+
eses: "Textos relacionados"
|
|
76
|
+
cites:
|
|
77
|
+
enus: "Cites"
|
|
78
|
+
ptbr: "Cita"
|
|
79
|
+
frfr: "Cite"
|
|
80
|
+
eses: "Cita"
|
|
81
|
+
cited_by:
|
|
82
|
+
enus: "Cited by"
|
|
83
|
+
ptbr: "Citado por"
|
|
84
|
+
frfr: "Cité par"
|
|
85
|
+
eses: "Citado por"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{% comment %}
|
|
2
|
+
chord-tab.html
|
|
3
|
+
Exibe uma cifra estruturada em N colunas monoespaçadas, usando toda a largura disponível.
|
|
4
|
+
Cada coluna respeita o limite de 79 caracteres por linha.
|
|
5
|
+
Uso: {% include chord-tab.html tab=tab_data %}
|
|
6
|
+
Onde tab_data tem:
|
|
7
|
+
intro: "linha de acordes do intro (opcional)"
|
|
8
|
+
sections:
|
|
9
|
+
- label: "rótulo da seção (opcional)"
|
|
10
|
+
content: |
|
|
11
|
+
linhas de cifra/letra
|
|
12
|
+
{% endcomment %}
|
|
13
|
+
|
|
14
|
+
<div class="chord-tab-container mt-16 mb-8"
|
|
15
|
+
style="width: 100%; box-sizing: border-box; padding-left: 0; padding-right: 0;">
|
|
16
|
+
<h2>Cifra</h2>
|
|
17
|
+
|
|
18
|
+
{% if include.tab.intro %}
|
|
19
|
+
<div class="mt-3 mb-6">
|
|
20
|
+
<pre class="font-mono text-tertiary text-[0.8em] leading-relaxed whitespace-pre m-0 p-0 bg-transparent border-0">{{ include.tab.intro }}</pre>
|
|
21
|
+
</div>
|
|
22
|
+
{% endif %}
|
|
23
|
+
|
|
24
|
+
<div class="mt-4 font-mono text-[0.8em] grid gap-x-2"
|
|
25
|
+
style="display: grid; grid-template-columns: repeat(auto-fill, min(79ch, 100%)); gap: 0 0.5rem; width: 100%;">
|
|
26
|
+
{% for section in include.tab.sections %}
|
|
27
|
+
<div style="overflow-y: auto;">
|
|
28
|
+
{% if section.label and section.label != '' %}
|
|
29
|
+
<div class="font-body text-[0.9em] uppercase tracking-widest text-tertiary mb-[0.35rem]">
|
|
30
|
+
{{ section.label }}</div>
|
|
31
|
+
{% endif %}
|
|
32
|
+
<pre
|
|
33
|
+
class="m-0 p-0 bg-transparent border-0 whitespace-pre overflow-x-auto leading-[1.55] text-on-surface">{{ section.content }}</pre>
|
|
34
|
+
<hr class="border-0 border-t border-gentle-divider my-[1.55em]" />
|
|
35
|
+
</div>
|
|
36
|
+
{% endfor %}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@15.0.7/marked.min.js"></script>
|
|
2
|
+
<script>
|
|
3
|
+
window.ContentRuntimeConfig = {
|
|
4
|
+
contentBase: '{{ site.content_api_base_url | default: "" }}',
|
|
5
|
+
includeUnpublished: {{ site.content_include_unpublished | default: false | jsonify }},
|
|
6
|
+
defaultAuthor: {{ site.pandorga.identity.name | default: site.author | jsonify }},
|
|
7
|
+
siteSuffix: {% assign _short = site.pandorga.identity.short_name | default: site.pandorga.identity.name | default: site.author %}{{ _short | prepend: ' | ' | jsonify }},
|
|
8
|
+
translations: {{ site.data.translations | jsonify }},
|
|
9
|
+
tocMinHeadings: 3,
|
|
10
|
+
expectedSchemaVersion: 1
|
|
11
|
+
};
|
|
12
|
+
// Template modules register listing/detail handlers here (PLT Phase 2).
|
|
13
|
+
window.ContentRuntime = window.ContentRuntime || {};
|
|
14
|
+
window.ContentRuntime.templates = window.ContentRuntime.templates || {
|
|
15
|
+
_map: Object.create(null),
|
|
16
|
+
register: function (name, api) {
|
|
17
|
+
if (!name) throw new Error('ContentRuntime.templates.register: name required');
|
|
18
|
+
this._map[name] = api || {};
|
|
19
|
+
},
|
|
20
|
+
get: function (name) { return this._map[name] || null; }
|
|
21
|
+
};
|
|
22
|
+
</script>
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
{% raw %}
|
|
2
|
+
var contentBase = (window.ContentRuntimeConfig && window.ContentRuntimeConfig.contentBase);
|
|
3
|
+
if (contentBase == null) contentBase = '';
|
|
4
|
+
contentBase = String(contentBase).replace(/\/$/, '');
|
|
5
|
+
|
|
6
|
+
function escapeHtml(value) {
|
|
7
|
+
return String(value == null ? '' : value)
|
|
8
|
+
.replace(/&/g, '&')
|
|
9
|
+
.replace(/</g, '<')
|
|
10
|
+
.replace(/>/g, '>')
|
|
11
|
+
.replace(/"/g, '"')
|
|
12
|
+
.replace(/'/g, ''');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function escapeAttr(value) {
|
|
16
|
+
return escapeHtml(value).replace(/`/g, '`');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function shellOrigin() {
|
|
20
|
+
return (window.ContentRuntimeConfig && window.ContentRuntimeConfig.shellOrigin) || window.location.origin || '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function buildUrl(path) {
|
|
24
|
+
var value = unwrapMediaSrc(path);
|
|
25
|
+
if (!value) return '';
|
|
26
|
+
if (/^https?:\/\//.test(value)) return value;
|
|
27
|
+
if (value.charAt(0) === '/') return encodeURI(contentBase + value);
|
|
28
|
+
return encodeURI(contentBase + '/' + value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Pages CMS rich-text (Editor mode) rewrites bare URLs inside quoted
|
|
32
|
+
* Liquid attributes into Markdown autolinks, e.g.
|
|
33
|
+
* src="https://example.com/a.png"
|
|
34
|
+
* becomes
|
|
35
|
+
* src="[https://example.com/a.png](https://example.com/a.png)"
|
|
36
|
+
* which then breaks <img src>. Prefer the Markdown href when the whole
|
|
37
|
+
* attribute value is a single link; leave real captions alone. */
|
|
38
|
+
function unwrapMediaSrc(path) {
|
|
39
|
+
var value = String(path == null ? '' : path).trim();
|
|
40
|
+
if (!value) return '';
|
|
41
|
+
var md = value.match(/^\[([^\]]*)\]\(([^)\s]+)\)\s*$/);
|
|
42
|
+
if (md) return String(md[2] || '').trim();
|
|
43
|
+
var angle = value.match(/^<([^>\s]+)>\s*$/);
|
|
44
|
+
if (angle) return String(angle[1] || '').trim();
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveAssetUrl(path) {
|
|
49
|
+
if (!path) return '';
|
|
50
|
+
var value = unwrapMediaSrc(path);
|
|
51
|
+
if (!value) return '';
|
|
52
|
+
if (/^https?:\/\//i.test(value)) return value;
|
|
53
|
+
if (value.charAt(0) === '/') {
|
|
54
|
+
if (value.indexOf('/media/') === 0) {
|
|
55
|
+
return encodeURI(contentBase.replace(/\/$/, '') + value);
|
|
56
|
+
}
|
|
57
|
+
return encodeURI(shellOrigin().replace(/\/$/, '') + value);
|
|
58
|
+
}
|
|
59
|
+
if (value.indexOf('media/') === 0) {
|
|
60
|
+
return encodeURI(contentBase.replace(/\/$/, '') + '/' + value);
|
|
61
|
+
}
|
|
62
|
+
return encodeURI(contentBase.replace(/\/$/, '') + '/' + value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseIncludeAttrs(raw) {
|
|
66
|
+
var attrs = {};
|
|
67
|
+
var text = String(raw || '');
|
|
68
|
+
// Allow newlines inside quoted values (dict-card def=, tweet body=/note=).
|
|
69
|
+
text = text.replace(/([\w-]+)\s*=\s*(?:"([\s\S]*?)"|'([\s\S]*?)')/g, function (_, key, dbl, sgl) {
|
|
70
|
+
attrs[key] = dbl != null ? dbl : sgl;
|
|
71
|
+
return '';
|
|
72
|
+
});
|
|
73
|
+
text.replace(/([\w-]+)\s*=\s*([^\s]+)/g, function (_, key, val) {
|
|
74
|
+
if (!(key in attrs)) attrs[key] = val;
|
|
75
|
+
return '';
|
|
76
|
+
});
|
|
77
|
+
return attrs;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseScalar(value) {
|
|
81
|
+
var raw = String(value || '').trim();
|
|
82
|
+
if ((raw.charAt(0) === '"' && raw.charAt(raw.length - 1) === '"') ||
|
|
83
|
+
(raw.charAt(0) === "'" && raw.charAt(raw.length - 1) === "'")) {
|
|
84
|
+
return raw.slice(1, -1);
|
|
85
|
+
}
|
|
86
|
+
if (raw === 'true') return true;
|
|
87
|
+
if (raw === 'false') return false;
|
|
88
|
+
return raw;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hydrateFrontMatter(item) {
|
|
92
|
+
var markdown = String(item.body_markdown || '').replace(/^\uFEFF/, '');
|
|
93
|
+
var match = markdown.match(/^---\s*\n([\s\S]*?)\n---\s*\n?/);
|
|
94
|
+
|
|
95
|
+
// The export strips the front-matter block out of body_markdown, so this
|
|
96
|
+
// never matches for exported content. The date promotion below therefore
|
|
97
|
+
// has to happen first: when it sat after the early return, no detail
|
|
98
|
+
// page ever received a date. The parse itself still matters for raw
|
|
99
|
+
// Markdown that has not been through the exporter.
|
|
100
|
+
item.front_matter = item.front_matter || {};
|
|
101
|
+
if (item.date) item.front_matter.date = item.date;
|
|
102
|
+
if (item.last_updated) item.front_matter.last_updated = item.last_updated;
|
|
103
|
+
|
|
104
|
+
if (!match) return item;
|
|
105
|
+
|
|
106
|
+
var parsed = {};
|
|
107
|
+
match[1].split(/\n/).forEach(function (line) {
|
|
108
|
+
var m = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
109
|
+
if (m) parsed[m[1]] = parseScalar(m[2]);
|
|
110
|
+
});
|
|
111
|
+
item.front_matter = Object.assign({}, parsed, item.front_matter);
|
|
112
|
+
item.body_markdown = markdown.slice(match[0].length);
|
|
113
|
+
return item;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function stripFrontMatter(markdown) {
|
|
117
|
+
return String(markdown || '').replace(/^\uFEFF/, '').replace(/^---\s*\n[\s\S]*?\n---\s*\n?/, '');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function endsWithSentencePunctuation(text) {
|
|
121
|
+
var value = String(text || '').trim();
|
|
122
|
+
return /[.!?](\s*<\/[^>]+>)*\s*$/.test(value);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ensureCaptionPeriod(text) {
|
|
126
|
+
var value = String(text || '').trim();
|
|
127
|
+
if (!value || endsWithSentencePunctuation(value)) return value;
|
|
128
|
+
return value + '.';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* The opening sentence of a longer piece of copy, for the places that need
|
|
132
|
+
* one sentence and are given a paragraph. A project's `tagline` is the
|
|
133
|
+
* case that forced this: it is a standfirst on the page, and it is also
|
|
134
|
+
* what `_layouts/projects.html` hands to the meta description and the
|
|
135
|
+
* social card, where a search result truncated mid-clause reads worse than
|
|
136
|
+
* a shorter one that finishes its thought.
|
|
137
|
+
*
|
|
138
|
+
* 160 characters is roughly what a desktop search result renders; Open
|
|
139
|
+
* Graph is more generous and takes the same string. A first sentence longer
|
|
140
|
+
* than the budget is cut on a word boundary rather than mid-word, and any
|
|
141
|
+
* punctuation left dangling at the cut goes with it.
|
|
142
|
+
*/
|
|
143
|
+
var LEAD_SENTENCE_MAX = 160;
|
|
144
|
+
|
|
145
|
+
function leadSentence(text, limit) {
|
|
146
|
+
var value = String(text || '').trim();
|
|
147
|
+
if (!value) return '';
|
|
148
|
+
var max = limit || LEAD_SENTENCE_MAX;
|
|
149
|
+
var match = value.match(/^[\s\S]*?[.!?](?=\s|$)/);
|
|
150
|
+
var lead = match ? match[0] : value;
|
|
151
|
+
if (lead.length <= max) return lead;
|
|
152
|
+
var cut = lead.slice(0, max);
|
|
153
|
+
var space = cut.lastIndexOf(' ');
|
|
154
|
+
if (space > 0) cut = cut.slice(0, space);
|
|
155
|
+
return cut.replace(/[\s,;:.]+$/, '');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function figureSourceHtml(raw) {
|
|
159
|
+
raw = String(raw || '').trim();
|
|
160
|
+
if (!raw) return '';
|
|
161
|
+
if (/<a\s/i.test(raw)) {
|
|
162
|
+
return ' Source: ' + raw;
|
|
163
|
+
}
|
|
164
|
+
// Captions already parse Markdown; sources do too so
|
|
165
|
+
// `[Parrot Website](https://…)` renders as a link, not escaped brackets.
|
|
166
|
+
return ' Source: ' + stripSingleParagraph(parseInlineMarkdown(raw));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function includeCaptionHtml(caption) {
|
|
170
|
+
var trimmed = ensureCaptionPeriod(String(caption || '').trim());
|
|
171
|
+
if (!trimmed) return '';
|
|
172
|
+
if (/<[a-z][\s\S]*>/i.test(trimmed)) return trimmed;
|
|
173
|
+
return stripSingleParagraph(parseInlineMarkdown(trimmed));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
{% endraw %}
|