Repository: HugoBlox/kit Branch: main Commit: e02d32190aa4 Files: 779 Total size: 6.8 MB Directory structure: gitextract_4a7sb44i/ ├── .cursorindexingignore ├── .devcontainer/ │ └── base.Dockerfile ├── .editorconfig ├── .github/ │ ├── CLA.md │ ├── CODEOWNERS │ ├── CODE_OF_CONDUCT.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.yml │ │ ├── config.yml │ │ └── feature-request.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── SECURITY.md │ ├── SUPPORT.md │ ├── dependabot.yml │ ├── labeler.yml │ └── workflows/ │ ├── ci-build-starters-matrix.yml │ ├── ci-lint.yml │ ├── ci-pr-labeler.yml │ ├── codeql.yml │ ├── community-welcome.yml │ ├── devcontainer-image.yml │ ├── maintenance-stale.yml │ ├── release-hugoblox-modules.yml │ ├── release-package-splitter.yml │ └── security-codeql.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── CITATION.cff ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── README.zh.md ├── biome.json ├── hugoblox.code-workspace ├── modules/ │ ├── README.md │ ├── analytics/ │ │ ├── README.md │ │ ├── go.mod │ │ ├── hugo.yaml │ │ └── layouts/ │ │ └── _partials/ │ │ └── blox-analytics/ │ │ ├── index.html │ │ ├── services/ │ │ │ ├── baidu_tongji.html │ │ │ ├── fathom.html │ │ │ ├── google_analytics.html │ │ │ ├── google_tag_manager.html │ │ │ ├── index.html │ │ │ ├── microsoft_clarity.html │ │ │ ├── pirsch.html │ │ │ └── plausible.html │ │ └── verification.html │ ├── blox/ │ │ ├── .npmrc │ │ ├── README.md │ │ ├── archetypes/ │ │ │ ├── faq.md │ │ │ └── questions.md │ │ ├── assets/ │ │ │ ├── css/ │ │ │ │ ├── README.md │ │ │ │ ├── animations.css │ │ │ │ ├── blox/ │ │ │ │ │ ├── all.css │ │ │ │ │ ├── biography.css │ │ │ │ │ ├── navbar.css │ │ │ │ │ └── skills.css │ │ │ │ ├── chroma.css │ │ │ │ ├── color-utilities.css │ │ │ │ ├── components/ │ │ │ │ │ ├── all.css │ │ │ │ │ ├── author-notes.css │ │ │ │ │ ├── cards.css │ │ │ │ │ ├── charts.css │ │ │ │ │ ├── copy.css │ │ │ │ │ ├── cover.css │ │ │ │ │ ├── glassmorphism.css │ │ │ │ │ ├── math.css │ │ │ │ │ ├── notebook.css │ │ │ │ │ ├── page.css │ │ │ │ │ ├── sidebar-left.css │ │ │ │ │ ├── steps.css │ │ │ │ │ └── task-list.css │ │ │ │ ├── config/ │ │ │ │ │ ├── safelist.css │ │ │ │ │ ├── tailwind.css │ │ │ │ │ └── theme.css │ │ │ │ ├── framework/ │ │ │ │ │ ├── base.css │ │ │ │ │ └── components.css │ │ │ │ ├── hb-search.css │ │ │ │ ├── layout-utilities.css │ │ │ │ ├── libs/ │ │ │ │ │ └── chroma/ │ │ │ │ │ ├── dark.css │ │ │ │ │ └── light.css │ │ │ │ ├── main.css │ │ │ │ ├── themes/ │ │ │ │ │ ├── amber.css │ │ │ │ │ ├── blue.css │ │ │ │ │ ├── cyan.css │ │ │ │ │ ├── emerald.css │ │ │ │ │ ├── fuchsia.css │ │ │ │ │ ├── green.css │ │ │ │ │ ├── indigo.css │ │ │ │ │ ├── lime.css │ │ │ │ │ ├── orange.css │ │ │ │ │ ├── pink.css │ │ │ │ │ ├── purple.css │ │ │ │ │ ├── red.css │ │ │ │ │ ├── rose.css │ │ │ │ │ ├── sky.css │ │ │ │ │ ├── slate.css │ │ │ │ │ ├── stone.css │ │ │ │ │ ├── teal.css │ │ │ │ │ ├── violet.css │ │ │ │ │ ├── yellow.css │ │ │ │ │ └── zinc.css │ │ │ │ └── views/ │ │ │ │ ├── all.css │ │ │ │ └── attachments.css │ │ │ ├── dist/ │ │ │ │ └── lib/ │ │ │ │ ├── markmap/ │ │ │ │ │ └── index.js │ │ │ │ └── vendor-libs.mjs │ │ │ └── js/ │ │ │ ├── hb-animations.js │ │ │ ├── hb-citation.js │ │ │ ├── hb-clipboard.js │ │ │ ├── hb-code-copy.js │ │ │ ├── hb-head.js │ │ │ ├── hb-i18n.js │ │ │ ├── hb-init.js │ │ │ ├── hb-mermaid-config.js │ │ │ ├── hb-nav.js │ │ │ ├── hb-notifier.js │ │ │ ├── hb-search.js │ │ │ ├── hb-sidebar.js │ │ │ ├── hb-theme.js │ │ │ ├── katex-config.js │ │ │ └── vendor-libs.js │ │ ├── blox/ │ │ │ ├── collection/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── contact-info/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── cta-button-list/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── cta-card/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ ├── cta-image-paragraph/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ ├── dev-hero/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── faq/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── features/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ ├── hero/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ ├── knowledge-categories/ │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── logos/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── markdown/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── portfolio/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── research-areas/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-awards/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-biography/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-biography-3/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-experience/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-languages/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── resume-skills/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── search-hero/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── shared/ │ │ │ │ └── js/ │ │ │ │ └── components/ │ │ │ │ └── Icon.jsx │ │ │ ├── stats/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ ├── team-showcase/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── tech-stack/ │ │ │ │ ├── README.md │ │ │ │ ├── block.html │ │ │ │ └── manifest.json │ │ │ ├── testimonials/ │ │ │ │ ├── README.md │ │ │ │ ├── client.jsx │ │ │ │ ├── component.jsx │ │ │ │ └── manifest.json │ │ │ └── trending-questions/ │ │ │ ├── block.html │ │ │ └── manifest.json │ │ ├── data/ │ │ │ ├── address_formats.toml │ │ │ ├── blox_aliases.yaml │ │ │ ├── fonts/ │ │ │ │ ├── academic.yaml │ │ │ │ ├── developer.yaml │ │ │ │ ├── editorial.yaml │ │ │ │ ├── geometric.yaml │ │ │ │ ├── humanist.yaml │ │ │ │ ├── modern.yaml │ │ │ │ └── system.yaml │ │ │ ├── hugoblox.yaml │ │ │ ├── icons/ │ │ │ │ ├── academicons.json │ │ │ │ ├── brands.yaml │ │ │ │ ├── devicon.json │ │ │ │ ├── hb.yaml │ │ │ │ └── hero.json │ │ │ ├── languages.yaml │ │ │ ├── link_types.yaml │ │ │ ├── page_sharer.yaml │ │ │ └── themes/ │ │ │ ├── coffee.yaml │ │ │ ├── contrast.yaml │ │ │ ├── cupcake.yaml │ │ │ ├── default.yaml │ │ │ ├── dracula.yaml │ │ │ ├── marine.yaml │ │ │ ├── matcha.yaml │ │ │ ├── minimal.yaml │ │ │ ├── retro.yaml │ │ │ ├── solar.yaml │ │ │ └── synthwave.yaml │ │ ├── go.mod │ │ ├── hugo.yaml │ │ ├── i18n/ │ │ │ ├── ar.yaml │ │ │ ├── bn.yaml │ │ │ ├── ca.yaml │ │ │ ├── cs.yaml │ │ │ ├── da.yaml │ │ │ ├── de.yaml │ │ │ ├── el.yaml │ │ │ ├── en.yaml │ │ │ ├── es.yaml │ │ │ ├── et.yaml │ │ │ ├── eu.yaml │ │ │ ├── fa.yaml │ │ │ ├── fi.yaml │ │ │ ├── fr.yaml │ │ │ ├── he.yaml │ │ │ ├── hi.yaml │ │ │ ├── hr.yaml │ │ │ ├── ht.yaml │ │ │ ├── hu.yaml │ │ │ ├── id.yaml │ │ │ ├── it.yaml │ │ │ ├── ja.yaml │ │ │ ├── km.yaml │ │ │ ├── ko.yaml │ │ │ ├── lt.yaml │ │ │ ├── lv.yaml │ │ │ ├── mg.yaml │ │ │ ├── ms-Arab.yaml │ │ │ ├── ms.yaml │ │ │ ├── nb.yaml │ │ │ ├── nl.yaml │ │ │ ├── pl.yaml │ │ │ ├── pt.yaml │ │ │ ├── ro.yaml │ │ │ ├── ru.yaml │ │ │ ├── so.yaml │ │ │ ├── sv.yaml │ │ │ ├── tr.yaml │ │ │ ├── uk.yaml │ │ │ ├── vi.yaml │ │ │ ├── zh-Hant.yaml │ │ │ └── zh.yaml │ │ ├── layouts/ │ │ │ ├── 404.html │ │ │ ├── _markup/ │ │ │ │ ├── render-blockquote.html │ │ │ │ ├── render-codeblock-markmap.html │ │ │ │ ├── render-codeblock-mermaid.html │ │ │ │ ├── render-image.html │ │ │ │ ├── render-link.backlinks.json │ │ │ │ └── render-link.html │ │ │ ├── _partials/ │ │ │ │ ├── blox/ │ │ │ │ │ ├── contact-info/ │ │ │ │ │ │ └── config.html │ │ │ │ │ ├── dev-hero/ │ │ │ │ │ │ └── config.html │ │ │ │ │ ├── portfolio/ │ │ │ │ │ │ └── config.html │ │ │ │ │ ├── preact-wrapper.html │ │ │ │ │ └── tech-stack/ │ │ │ │ │ └── config.html │ │ │ │ ├── comments/ │ │ │ │ │ ├── disqus.html │ │ │ │ │ └── giscus.html │ │ │ │ ├── comments.html │ │ │ │ ├── components/ │ │ │ │ │ ├── backlinks.html │ │ │ │ │ ├── breadcrumb.html │ │ │ │ │ ├── cover.html │ │ │ │ │ ├── feedback.html │ │ │ │ │ ├── footers/ │ │ │ │ │ │ ├── columns.html │ │ │ │ │ │ └── minimal.html │ │ │ │ │ ├── headers/ │ │ │ │ │ │ ├── floating-theme-toggler.html │ │ │ │ │ │ ├── navbar-simple.html │ │ │ │ │ │ └── navbar.html │ │ │ │ │ ├── language-chooser.html │ │ │ │ │ ├── last-edited.html │ │ │ │ │ ├── next-in-series.html │ │ │ │ │ ├── page_sharer.html │ │ │ │ │ ├── paginator.html │ │ │ │ │ ├── search-modal.html │ │ │ │ │ ├── sidebar.html │ │ │ │ │ ├── slides-embed.html │ │ │ │ │ └── toc.html │ │ │ │ ├── css.html │ │ │ │ ├── docs_layout.html │ │ │ │ ├── functions/ │ │ │ │ │ ├── build_links.html │ │ │ │ │ ├── coerce_bool.html │ │ │ │ │ ├── coerce_int.html │ │ │ │ │ ├── deep_merge.html │ │ │ │ │ ├── demo_theme_styles.html │ │ │ │ │ ├── embed/ │ │ │ │ │ │ ├── github.html │ │ │ │ │ │ ├── hbx_content_section.html │ │ │ │ │ │ ├── hbx_platform_icon.html │ │ │ │ │ │ ├── hbx_title_section.html │ │ │ │ │ │ └── huggingface.html │ │ │ │ │ ├── generate_color_scale.html │ │ │ │ │ ├── get-block-scripts.html │ │ │ │ │ ├── get-build-id.html │ │ │ │ │ ├── get_address.html │ │ │ │ │ ├── get_author_name.html │ │ │ │ │ ├── get_author_profile.html │ │ │ │ │ ├── get_authors_data.html │ │ │ │ │ ├── get_branding.html │ │ │ │ │ ├── get_cover_image.html │ │ │ │ │ ├── get_event_dates.html │ │ │ │ │ ├── get_featured_image.html │ │ │ │ │ ├── get_hook.html │ │ │ │ │ ├── get_icon.html │ │ │ │ │ ├── get_icon_data.html │ │ │ │ │ ├── get_logo.html │ │ │ │ │ ├── get_logo_url.html │ │ │ │ │ ├── get_page_title.html │ │ │ │ │ ├── get_site_icon.html │ │ │ │ │ ├── get_sort_by_parameter.html │ │ │ │ │ ├── get_summary.html │ │ │ │ │ ├── get_theme_config.html │ │ │ │ │ ├── has_attachments.html │ │ │ │ │ ├── hbx_verify.html │ │ │ │ │ ├── layout_tokens.html │ │ │ │ │ ├── load_font_pack.html │ │ │ │ │ ├── load_theme_pack.html │ │ │ │ │ ├── logger.html │ │ │ │ │ ├── notebook/ │ │ │ │ │ │ └── render.html │ │ │ │ │ ├── parse_block_v3.html │ │ │ │ │ ├── process_responsive_image.html │ │ │ │ │ ├── render_callout.html │ │ │ │ │ ├── render_view.html │ │ │ │ │ ├── theme_generator.html │ │ │ │ │ ├── theme_variables.html │ │ │ │ │ ├── typography.html │ │ │ │ │ └── uid.html │ │ │ │ ├── hbx/ │ │ │ │ │ ├── resolve-block-param.html │ │ │ │ │ ├── resolve.html │ │ │ │ │ └── sections.html │ │ │ │ ├── hooks/ │ │ │ │ │ └── body-end/ │ │ │ │ │ ├── hbx-debug-export.html │ │ │ │ │ └── hbx-debug-hud.html │ │ │ │ ├── init.html │ │ │ │ ├── jsonld/ │ │ │ │ │ ├── article.html │ │ │ │ │ ├── breadcrumbs.html │ │ │ │ │ ├── business.html │ │ │ │ │ ├── collectionpage.html │ │ │ │ │ ├── event.html │ │ │ │ │ ├── faqpage.html │ │ │ │ │ ├── main.html │ │ │ │ │ ├── qapage.html │ │ │ │ │ ├── webpage.html │ │ │ │ │ └── website.html │ │ │ │ ├── landing_page.html │ │ │ │ ├── libraries.html │ │ │ │ ├── notification-container.html │ │ │ │ ├── page_author.html │ │ │ │ ├── page_author_card.html │ │ │ │ ├── page_edit.html │ │ │ │ ├── page_footer.html │ │ │ │ ├── page_links.html │ │ │ │ ├── page_links_div.html │ │ │ │ ├── page_metadata_authors.html │ │ │ │ ├── page_related.html │ │ │ │ ├── site_footer.html │ │ │ │ ├── site_footer_license.html │ │ │ │ ├── site_head.html │ │ │ │ ├── social_links.html │ │ │ │ ├── tags.html │ │ │ │ ├── tailwind_sources.html │ │ │ │ └── views/ │ │ │ │ ├── article-grid--end.html │ │ │ │ ├── article-grid--start.html │ │ │ │ ├── article-grid.html │ │ │ │ ├── card--end.html │ │ │ │ ├── card--start.html │ │ │ │ ├── card.html │ │ │ │ ├── citation--end.html │ │ │ │ ├── citation--start.html │ │ │ │ ├── citation.html │ │ │ │ ├── date-title-summary--end.html │ │ │ │ ├── date-title-summary--start.html │ │ │ │ ├── date-title-summary.html │ │ │ │ ├── slides-gallery--end.html │ │ │ │ ├── slides-gallery--start.html │ │ │ │ └── slides-gallery.html │ │ │ ├── _shortcodes/ │ │ │ │ ├── audio.html │ │ │ │ ├── bilibili.html │ │ │ │ ├── button.html │ │ │ │ ├── callout.html │ │ │ │ ├── card.html │ │ │ │ ├── cards.html │ │ │ │ ├── chart.html │ │ │ │ ├── cite.html │ │ │ │ ├── embed.html │ │ │ │ ├── icon.html │ │ │ │ ├── include.html │ │ │ │ ├── math.html │ │ │ │ ├── mention.html │ │ │ │ ├── notebook.html │ │ │ │ ├── spoiler.html │ │ │ │ ├── steps.html │ │ │ │ ├── table.html │ │ │ │ ├── toc.html │ │ │ │ └── video.html │ │ │ ├── authors/ │ │ │ │ └── term.html │ │ │ ├── baseof.html │ │ │ ├── docs/ │ │ │ │ ├── list.html │ │ │ │ └── single.html │ │ │ ├── events/ │ │ │ │ └── page.html │ │ │ ├── faq/ │ │ │ │ ├── list.html │ │ │ │ └── single.html │ │ │ ├── home.backlinks.json │ │ │ ├── home.html │ │ │ ├── index.llm.txt │ │ │ ├── index.webmanifest │ │ │ ├── landing/ │ │ │ │ ├── list.html │ │ │ │ └── single.html │ │ │ ├── list.html │ │ │ ├── questions/ │ │ │ │ ├── list.html │ │ │ │ └── single.html │ │ │ ├── robots.txt │ │ │ ├── rss.xml │ │ │ ├── single.html │ │ │ ├── sitemap.xml │ │ │ ├── taxonomy.html │ │ │ └── terms.html │ │ ├── package.json │ │ ├── pnpm-workspace.yaml │ │ ├── schemas/ │ │ │ └── blocks.json │ │ └── theme.toml │ ├── integrations/ │ │ └── netlify/ │ │ ├── README.md │ │ ├── config.yaml │ │ ├── go.mod │ │ └── src/ │ │ └── layouts/ │ │ ├── index.headers │ │ └── index.redirects │ └── slides/ │ ├── README.md │ ├── assets/ │ │ ├── css/ │ │ │ ├── libs/ │ │ │ │ └── chroma/ │ │ │ │ ├── dracula.css │ │ │ │ ├── github-dark.css │ │ │ │ └── github-light.css │ │ │ └── slides-branding.css │ │ └── js/ │ │ └── hugoblox-slides.js │ ├── config/ │ │ └── _default/ │ │ └── hugo.yaml │ ├── go.mod │ └── layouts/ │ ├── _partials/ │ │ ├── components/ │ │ │ └── slide-branding.html │ │ ├── functions/ │ │ │ └── slides_get_hook.html │ │ ├── hooks/ │ │ │ ├── slide-body-end/ │ │ │ │ └── _example.html │ │ │ ├── slide-footer/ │ │ │ │ └── _example.html │ │ │ ├── slide-head-end/ │ │ │ │ └── _example.html │ │ │ └── slide-header/ │ │ │ └── _example.html │ │ └── slides.html │ ├── _shortcodes/ │ │ ├── fragment.html │ │ ├── slide.html │ │ └── speaker_note.html │ └── slides/ │ ├── baseof.html │ ├── baseof.present.html │ ├── list.html │ ├── presenter.html │ ├── single.html │ └── single.present.html ├── package.json ├── pyproject.toml ├── scripts/ │ ├── list_language_packs.py │ ├── release_modules.py │ ├── rm-hugo-cache.sh │ ├── sync_i18n.py │ ├── test_release_modules.py │ ├── update_template_hugo.py │ ├── view-starter-dev.sh │ ├── view-starter-prod.sh │ └── view-test.sh ├── templates/ │ ├── academic-cv/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ ├── import-publications.yml │ │ │ ├── internal-readme-news.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ ├── authors/ │ │ │ │ └── _index.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── data-visualization/ │ │ │ │ │ ├── index.md │ │ │ │ │ ├── line-chart.json │ │ │ │ │ └── results.csv │ │ │ │ ├── get-started/ │ │ │ │ │ └── index.md │ │ │ │ ├── notebook-onboarding/ │ │ │ │ │ ├── hugoblox-onboarding.ipynb │ │ │ │ │ └── index.md │ │ │ │ ├── project-management/ │ │ │ │ │ └── index.md │ │ │ │ ├── second-brain/ │ │ │ │ │ └── index.md │ │ │ │ └── teach-courses/ │ │ │ │ └── index.md │ │ │ ├── courses/ │ │ │ │ ├── _index.md │ │ │ │ └── hugo-blox/ │ │ │ │ ├── _index.md │ │ │ │ ├── getting-started.md │ │ │ │ ├── guide/ │ │ │ │ │ ├── _index.md │ │ │ │ │ ├── configuration.md │ │ │ │ │ ├── formatting/ │ │ │ │ │ │ ├── _index.md │ │ │ │ │ │ ├── button.md │ │ │ │ │ │ ├── callout.md │ │ │ │ │ │ ├── cards.md │ │ │ │ │ │ ├── media.md │ │ │ │ │ │ ├── steps.md │ │ │ │ │ │ └── toggle.md │ │ │ │ │ └── project-structure.md │ │ │ │ └── reference/ │ │ │ │ ├── _index.md │ │ │ │ ├── customization.md │ │ │ │ └── i18n.md │ │ │ ├── events/ │ │ │ │ ├── _index.md │ │ │ │ └── example/ │ │ │ │ └── index.md │ │ │ ├── experience.md │ │ │ ├── projects/ │ │ │ │ ├── _index.md │ │ │ │ ├── pandas/ │ │ │ │ │ └── index.md │ │ │ │ ├── pytorch/ │ │ │ │ │ └── index.md │ │ │ │ └── scikit/ │ │ │ │ └── index.md │ │ │ ├── publications/ │ │ │ │ ├── _index.md │ │ │ │ ├── conference-paper/ │ │ │ │ │ ├── cite.bib │ │ │ │ │ └── index.md │ │ │ │ ├── journal-article/ │ │ │ │ │ ├── cite.bib │ │ │ │ │ └── index.md │ │ │ │ └── preprint/ │ │ │ │ └── index.md │ │ │ └── slides/ │ │ │ └── example/ │ │ │ └── index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── layouts/ │ │ │ └── _partials/ │ │ │ └── hooks/ │ │ │ └── head-end/ │ │ │ └── github-button.html │ │ ├── netlify.toml │ │ └── package.json │ ├── data-science-blog/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ ├── import-notebooks.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ ├── authors/ │ │ │ │ └── _index.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── data-visualization/ │ │ │ │ │ ├── index.md │ │ │ │ │ ├── line-chart.json │ │ │ │ │ └── results.csv │ │ │ │ ├── get-started/ │ │ │ │ │ └── index.md │ │ │ │ ├── project-management/ │ │ │ │ │ └── index.md │ │ │ │ ├── second-brain/ │ │ │ │ │ └── index.md │ │ │ │ └── teach-courses/ │ │ │ │ └── index.md │ │ │ ├── tags/ │ │ │ │ └── _index.md │ │ │ └── uses.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── netlify.toml │ │ ├── notebooks/ │ │ │ └── blog-with-jupyter.ipynb │ │ └── package.json │ ├── dev-portfolio/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ ├── authors/ │ │ │ │ └── _index.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── building-rest-api/ │ │ │ │ │ └── index.md │ │ │ │ ├── docker-deployment/ │ │ │ │ │ └── index.md │ │ │ │ └── react-performance/ │ │ │ │ └── index.md │ │ │ └── projects/ │ │ │ ├── _index.md │ │ │ ├── ecommerce-platform/ │ │ │ │ └── index.md │ │ │ ├── task-manager/ │ │ │ │ └── index.md │ │ │ └── weather-app/ │ │ │ └── index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── netlify.toml │ │ └── package.json │ ├── documentation/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .editorconfig │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ ├── authors/ │ │ │ │ └── _index.md │ │ │ ├── blog/ │ │ │ │ ├── _index.md │ │ │ │ ├── v1.0.0/ │ │ │ │ │ └── index.md │ │ │ │ └── v2.0.0/ │ │ │ │ └── index.md │ │ │ ├── community/ │ │ │ │ └── index.md │ │ │ ├── docs/ │ │ │ │ ├── _index.md │ │ │ │ ├── getting-started.md │ │ │ │ ├── guide/ │ │ │ │ │ ├── _index.md │ │ │ │ │ ├── configuration.md │ │ │ │ │ ├── project-structure.md │ │ │ │ │ └── shortcodes/ │ │ │ │ │ ├── _index.md │ │ │ │ │ ├── button.md │ │ │ │ │ ├── callout.md │ │ │ │ │ ├── cards.md │ │ │ │ │ ├── steps.md │ │ │ │ │ └── toggle.md │ │ │ │ └── reference/ │ │ │ │ ├── _index.md │ │ │ │ ├── customization.md │ │ │ │ └── i18n.md │ │ │ └── showcase/ │ │ │ ├── _index.md │ │ │ └── nvidia/ │ │ │ └── index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── netlify.toml │ │ ├── package.json │ │ ├── static/ │ │ │ └── uploads/ │ │ │ └── .gitkeep │ │ └── theme.toml │ ├── link-in-bio/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ └── authors/ │ │ │ └── _index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── layouts/ │ │ │ └── _partials/ │ │ │ └── hooks/ │ │ │ └── body-end/ │ │ │ └── change-background-color.html │ │ ├── netlify.toml │ │ └── package.json │ ├── markdown-slides/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ └── slides/ │ │ │ ├── _index.md │ │ │ ├── example/ │ │ │ │ └── index.md │ │ │ ├── hugo-static-sites/ │ │ │ │ └── index.md │ │ │ └── ml-research-overview/ │ │ │ └── index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── netlify.toml │ │ └── package.json │ ├── resume/ │ │ ├── .devcontainer/ │ │ │ └── devcontainer.json │ │ ├── .github/ │ │ │ ├── FUNDING.yml │ │ │ └── workflows/ │ │ │ ├── build.yml │ │ │ ├── deploy.yml │ │ │ └── upgrade.yml │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── assets/ │ │ │ └── media/ │ │ │ └── icons/ │ │ │ └── custom/ │ │ │ └── .gitkeep │ │ ├── config/ │ │ │ └── _default/ │ │ │ ├── hugo.yaml │ │ │ ├── languages.yaml │ │ │ ├── menus.yaml │ │ │ ├── module.yaml │ │ │ └── params.yaml │ │ ├── content/ │ │ │ ├── _index.md │ │ │ └── authors/ │ │ │ └── _index.md │ │ ├── data/ │ │ │ └── authors/ │ │ │ └── me.yaml │ │ ├── go.mod │ │ ├── hugoblox.yaml │ │ ├── netlify.toml │ │ └── package.json │ └── startup-landing-page/ │ ├── .devcontainer/ │ │ └── devcontainer.json │ ├── .github/ │ │ ├── FUNDING.yml │ │ └── workflows/ │ │ ├── build.yml │ │ ├── deploy.yml │ │ └── upgrade.yml │ ├── .gitignore │ ├── .vscode/ │ │ └── extensions.json │ ├── LICENSE.md │ ├── README.md │ ├── assets/ │ │ └── media/ │ │ └── icons/ │ │ └── custom/ │ │ └── .gitkeep │ ├── config/ │ │ └── _default/ │ │ ├── hugo.yaml │ │ ├── languages.yaml │ │ ├── menus.yaml │ │ ├── module.yaml │ │ └── params.yaml │ ├── content/ │ │ ├── _index.md │ │ ├── authors/ │ │ │ ├── _content.gotmpl │ │ │ └── _index.md │ │ ├── blog/ │ │ │ ├── _index.md │ │ │ ├── data-visualization/ │ │ │ │ ├── index.md │ │ │ │ ├── line-chart.json │ │ │ │ └── results.csv │ │ │ ├── get-started/ │ │ │ │ └── index.md │ │ │ ├── project-management/ │ │ │ │ └── index.md │ │ │ ├── second-brain/ │ │ │ │ └── index.md │ │ │ └── teach-courses/ │ │ │ └── index.md │ │ ├── changelog/ │ │ │ ├── _index.md │ │ │ ├── v1.0/ │ │ │ │ └── index.md │ │ │ └── v1.1/ │ │ │ └── index.md │ │ ├── privacy.md │ │ └── terms.md │ ├── data/ │ │ └── authors/ │ │ └── me.yaml │ ├── go.mod │ ├── hugoblox.yaml │ ├── netlify.toml │ ├── package.json │ └── theme.toml ├── test/ │ ├── config.yaml │ ├── content/ │ │ ├── _index.md │ │ └── linked/ │ │ └── index.md │ ├── data/ │ │ ├── blocks/ │ │ │ ├── features_basic.yaml │ │ │ └── hero_basic.yaml │ │ └── pages/ │ │ └── home.yaml │ ├── go.mod │ └── package.json └── vite.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cursorindexingignore ================================================ # Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references .specstory/** ================================================ FILE: .devcontainer/base.Dockerfile ================================================ # syntax=docker/dockerfile:1.5 # HugoBlox devcontainer base image FROM mcr.microsoft.com/devcontainers/go:1.22-bookworm ARG NODE_VERSION=20 ARG PNPM_VERSION=10.14.0 ARG HUGO_VERSION=0.152.2 ENV DEBIAN_FRONTEND=noninteractive ENV PNPM_HOME=/home/vscode/.local/share/pnpm ENV PATH=${PNPM_HOME}:/usr/local/go/bin:${PATH} USER root RUN set -eux; \ apt-get update; \ apt-get install -y --no-install-recommends ca-certificates curl gnupg; \ NODE_MAJOR="${NODE_VERSION%%.*}"; \ curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -; \ apt-get install -y --no-install-recommends nodejs; \ corepack enable; \ corepack prepare "pnpm@${PNPM_VERSION}" --activate; \ mkdir -p "${PNPM_HOME}"; \ chown -R vscode:vscode "${PNPM_HOME}"; \ ARCH="$(uname -m)"; \ if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then \ HUGO_ARCH="amd64"; \ elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \ HUGO_ARCH="arm64"; \ else \ echo "Unsupported architecture: ${ARCH}"; \ exit 1; \ fi; \ HUGO_PKG="hugo_extended_${HUGO_VERSION}_Linux-${HUGO_ARCH}.tar.gz"; \ curl -fsSL -o "/tmp/${HUGO_PKG}" "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/${HUGO_PKG}"; \ tar -xzf "/tmp/${HUGO_PKG}" -C /tmp hugo; \ install -m 0755 /tmp/hugo /usr/local/bin/hugo; \ rm -rf "/tmp/${HUGO_PKG}" /tmp/hugo; \ apt-get clean; \ rm -rf /var/lib/apt/lists/* USER vscode ================================================ FILE: .editorconfig ================================================ # editorconfig.org root = true [*] charset = utf-8 end_of_line = lf indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true [*.{yaml,yml}] max_line_length = 150 [*.md] trim_trailing_whitespace = false max_line_length = off [*.py] indent_size = 4 [Makefile] indent_style = tab [*.go] indent_style = tab tab_width = 8 [{**/layouts/_shortcodes/*.html, **/layouts/_markup/*.html}] insert_final_newline = false ================================================ FILE: .github/CLA.md ================================================ # HugoBlox Contributor License Agreement By contributing to this project, you agree to the following terms: 1. **Grant of License:** You grant to **George Cushen ("HugoBlox")** a perpetual, worldwide, royalty-free, and irrevocable license to use, modify, reproduce, distribute, and re-license your contributions for any purpose, including in commercial products. 2. **No Warranty:** You provide your contributions "AS IS" and WITHOUT ANY WARRANTY OR CONDITION. As far as the law allows, you will not be liable for any damages related to your contributions or this agreement. 3. **Your Representation:** You confirm that you are legally entitled to grant this license and that your contribution is your original work. ================================================ FILE: .github/CODEOWNERS ================================================ # CODEOWNERS helps route reviews automatically. # Update these owners to the correct team(s) as needed. * @gcushen # Core theme and modules modules/** @gcushen # Starters starters/** @gcushen ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Code of Conduct We want to foster a positive, inclusive, and welcoming environment 💜 We expect you to follow our [Code of Conduct](https://docs.hugoblox.com/reference/contribute/) to fulfil this goal. ================================================ FILE: .github/FUNDING.yml ================================================ github: gcushen custom: https://hugoblox.com/sponsor/ ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report.yml ================================================ name: 🐛 Bug Report description: Something isn't working as expected? Report your bugs here. labels: ['needs triage'] body: - type: markdown attributes: value: | # Welcome 👋 Thanks for taking the time to fill out this bug report. We use GitHub Issues for project management, **NOT for support**. 🚑 For **help** and **questions**, search if your question has already been asked on the community **[chat](https://discord.gg/z8wNYzb)** and **[forum](https://github.com/HugoBlox/kit/discussions)**, and if not, ask your question there instead. Bug reports also shouldn't be used for support requests about a specific problem in your site, only if the issue can be reproduced on a fresh HugoBlox Kit template. Also, you can search and browse the extensive [HugoBlox Kit](https://docs.hugoblox.com) and [Hugo](https://gohugo.io/documentation/) **documentation**. For questions on _RStudio/Blogdown_, please reach out to the [RStudio/Blogdown community](https://github.com/rstudio/blogdown). Please fill out each section below. This info allows HugoBlox Kit contributors to diagnose (and fix!) your issue as quickly as possible. Otherwise we might need to close the issue (e.g. when it's missing clear steps to reproduce). Also, please verify that your issue is present in the very latest `main` version. - type: checkboxes attributes: label: Preliminary Checks description: Please make sure that you verify each checkbox and follow the instructions for them. options: - label: "This issue is not a duplicate. Before opening a new issue, please search existing issues: https://github.com/HugoBlox/kit/issues?q=is%3Aissue" required: true - label: "This issue is not a question, feature request, or anything other than a bug report directly related to HugoBlox Kit. Please post those things on Discord: https://discord.gg/z8wNYzb" required: true - type: textarea attributes: label: Description description: Describe the issue that you're seeing. placeholder: Be as precise as you can. Feel free to share screenshots, videos, or data from the devtools of your browser. validations: required: true - type: input id: reproduction-link attributes: label: Reproduction Link placeholder: "https://github.com/username/repository-name/" description: | Link to a minimal reproduction of the issue (GitHub repository). **Ideally, create a minimal reproduction of the issue on a fresh template rather than linking to your site's repository: https://hugoblox.com/hugo-themes/ validations: required: true - type: textarea attributes: label: Steps to Reproduce description: Clear steps describing how to reproduce the issue. value: | 1. 2. 3. ... validations: required: true - type: textarea attributes: label: Expected Result description: Describe what you expected to happen. validations: required: true - type: textarea attributes: label: Actual Result description: Describe what actually happened. validations: required: true - type: textarea attributes: label: What Hugo Module versions does your site use? description: Paste your `go.mod` here. validations: required: true - type: dropdown id: os attributes: label: What operating system(s) are you seeing the problem on? multiple: true options: - Windows - macOS - Android - iOS - Linux validations: required: true - type: dropdown id: browser attributes: label: What browser(s) are you seeing the problem on? multiple: true options: - Chrome - Safari - Firefox - Microsoft Edge - Other - type: input id: hb-tpl attributes: label: Which Hugo Blox template are you using? description: 'For example, a template from https://hugoblox.com/templates/' placeholder: 'e.g., Academic CV' validations: required: true - type: input id: version-hugo attributes: label: What version of Hugo are you using? description: 'Run `hugo version` or check your `netlify.toml`' placeholder: 'Hugo Extended 0.101.0' validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: 💬 Contributing chat (Discord) url: https://discord.gg/z8wNYzb about: Ask quick questions in the Contributing channel and coordinate with Geo & contributors. - name: 🧪 Troubleshooting Guide url: https://docs.hugoblox.com/reference/troubleshooting/ about: Fix common issues fast and follow the reproducible-issue checklist before filing. - name: 🏷️ Help-wanted issues (good first tasks) url: https://github.com/HugoBlox/kit/labels/help%20wanted about: Pick a bite-sized task and open your first PR in minutes. - name: 🧭 Contributing Guide url: https://github.com/HugoBlox/kit/blob/main/CONTRIBUTING.md about: How we work, environment setup, style, and PR tips. - name: 🧵 Discussions (Q&A, ideas) url: https://github.com/HugoBlox/kit/discussions about: Ask for help, propose features, or share learnings. - name: 📚 Documentation url: https://docs.hugoblox.com/ about: Explore all Hugo Blox docs, tutorials, and references. - name: 💚 Support Hugo Blox (All Access) url: https://hugoblox.com/all-access about: Too busy to contribute? Support development and get lifetime template updates. - name: 🫶 Sponsor on GitHub url: https://github.com/sponsors/gcushen about: Prefer monthly or one-time sponsorship via GitHub. ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request.yml ================================================ name: 🚀 Feature request description: Suggest an improvement. labels: [proposal] assignees: [] body: - type: checkboxes attributes: label: Prerequisites description: Take a minute to help our open source contributors. options: - label: I have [searched](https://github.com/HugoBlox/kit/issues?q=is%3Aissue) for duplicate or closed feature requests required: true - label: I am mindful of the project [scope](https://github.com/HugoBlox/kit/blob/main/CONTRIBUTING.md#scope) required: true - type: textarea id: proposal attributes: label: Proposal description: Provide detailed information for what we should add, including relevant links to screenshots, code, or live demos whenever possible. validations: required: true - type: textarea id: motivation attributes: label: Motivation and context description: Tell us why this change is needed or helpful, and what problems it may help solve. validations: required: true ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ### 🚀 What type of change is this? - [ ] 🐛 **Bug fix** (A non-breaking change that fixes an issue) - [ ] ✨ **New feature** (A non-breaking change that adds functionality) - [ ] 💅 **Style change** (A change that only affects formatting, visuals, or styling) - [ ] 📚 **Documentation update** (Changes to documentation only) - [ ] 🧹 **Refactor or chore** (A code change that neither fixes a bug nor adds a feature) - [ ] 💥 **Breaking change** (A fix or feature that would cause existing functionality to not work as expected) --- ### 🎯 What is the purpose of this change? --- ### 📸 Screenshots or Screencast (if applicable) --- ### ℹ️ Documentation Check - [ ] No, this change does not require a documentation update. - [ ] Yes, I have updated the documentation accordingly (or will in a follow-up PR). --- ### 📜 Contributor Agreement **Thank you for your contribution!** - [ ] By checking this box, I confirm that I have read and agree to the [HugoBlox Contributor License Agreement (CLA)](/.github/CLA.md). ================================================ FILE: .github/SECURITY.md ================================================ # Security Policy We take security seriously and appreciate responsible disclosures. ## Supported Versions We generally support the latest release of Hugo Blox modules and starters. Security fixes may be backported at the maintainers' discretion. ## Reporting a Vulnerability - Do not open a public issue. - Instead, open a private GitHub Security Advisory for this repository (Security tab → Report a vulnerability). - If you cannot access advisories, email the maintainers via the repository's contact links on GitHub. Please include: - A clear description and minimal reproduction - Impact assessment and potential exploit scenario - Suggested remediation, if known We will acknowledge receipt within 72 hours and keep you updated. ## Scope - This repository and official Hugo Blox modules/starters - Third-party templates and plugins are out of scope Thank you for helping keep the community safe. ================================================ FILE: .github/SUPPORT.md ================================================ # Support Need help? Here’s how to get support efficiently: - Discord: https://discord.gg/z8wNYzb - GitHub Discussions: https://github.com/HugoBlox/kit/discussions - Docs & Guides: https://docs.hugoblox.com/ - Issues: use for confirmed bugs or well-scoped feature requests only Tips for fast responses: - Share versions (Hugo, module, OS) and a minimal reproduction - Paste relevant logs/console output - State expected vs actual behavior - Attach screenshots to visually explain the issue Pro support & templates: - Pro templates: https://hugoblox.com/pricing - Pro Discord Channel (request to be added): https://discord.gg/z8wNYzb ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: # Update GitHub Actions - package-ecosystem: 'github-actions' directory: '/' schedule: interval: 'weekly' open-pull-requests-limit: 10 labels: - 'dependencies' - 'github-actions' commit-message: prefix: 'ci' include: 'scope' # Update GitHub Actions in main starter template (academic-cv) # Other starters can be manually updated from this template - package-ecosystem: 'github-actions' directory: '/starters/academic-cv' schedule: interval: 'weekly' open-pull-requests-limit: 3 labels: - 'dependencies' - 'starters' - 'template' commit-message: prefix: 'ci' include: 'scope' ================================================ FILE: .github/labeler.yml ================================================ documentation: - changed-files: - any-glob-to-any-file: "**/*.md" ci: - changed-files: - any-glob-to-any-file: ".github/workflows/**" modules: - changed-files: - any-glob-to-any-file: "modules/**" starters: - changed-files: - any-glob-to-any-file: "starters/**" config: - changed-files: - any-glob-to-any-file: - "package.json" - "pnpm-lock.yaml" - "biome.json" - ".stylelintrc.yaml" - "vite.config.js" ================================================ FILE: .github/workflows/ci-build-starters-matrix.yml ================================================ name: CI - Build Starters Matrix run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: schedule: - cron: "0 2 * * *" workflow_dispatch: push: branches: [main] paths: - "modules/**" - "templates/**" - "test/**" - "scripts/**" - "package.json" - "pnpm-lock.yaml" - "biome.json" - "vite.config.js" pull_request: types: - opened - reopened - synchronize - ready_for_review paths: - "modules/**" - "templates/**" - "test/**" - "scripts/**" - "package.json" - "pnpm-lock.yaml" - "biome.json" - "vite.config.js" permissions: contents: read concurrency: group: templates-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: NODE_VERSION: "22" jobs: build-templates: runs-on: ubuntu-latest strategy: fail-fast: false matrix: starter: - name: academic-cv path: templates/academic-cv - name: startup-landing-page path: templates/startup-landing-page - name: dev-portfolio path: templates/dev-portfolio steps: - name: Checkout uses: actions/checkout@v6 with: submodules: true fetch-depth: 0 - name: Compute resources cache key id: reskey run: | set -euo pipefail P=${{ matrix.starter.path }} # Hash tracked files under assets/config and key files for invalidation HASH=$(git ls-files -s "$P/assets" "$P/config" "$P/hugoblox.yaml" "$P/package.json" 2>/dev/null | sha256sum | cut -d' ' -f1 || true) if [ -z "$HASH" ]; then HASH="nohash"; fi echo "key=${{ runner.os }}-hugo-resources-${{ matrix.starter.name }}-$HASH" >> $GITHUB_OUTPUT - name: Cache Hugo resources (starter) uses: actions/cache@v5 with: path: ${{ matrix.starter.path }}/resources/ key: ${{ steps.reskey.outputs.key }} restore-keys: | ${{ runner.os }}-hugo-resources-${{ matrix.starter.name }}- - name: Enable Corepack (for pnpm cache) run: corepack enable - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "${{ env.NODE_VERSION }}" cache: "pnpm" - name: Activate pnpm from root package.json run: pnpm --version - name: Install template dependencies working-directory: ${{ matrix.starter.path }} # Don't use --frozen-lockfile as starters have auto-generated package.json with simple deps (Tailwind CLI) # and may not have lock files checked into the repo run: pnpm install --no-frozen-lockfile - name: Read Hugo version from template id: hugo run: | set -euo pipefail P=${{ matrix.starter.path }} VERSION=$(grep -E "^\s*hugo_version:\s*['\"]?" "$P/hugoblox.yaml" | sed -E "s/.*hugo_version:\s*['\"]?([^'\"]+)['\"]?.*/\1/") if [ -z "$VERSION" ]; then echo "::error::Could not read hugo_version from $P/hugoblox.yaml" exit 1 fi echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Setup Hugo uses: peaceiris/actions-hugo@v3 with: hugo-version: "${{ steps.hugo.outputs.version }}" extended: true - name: Build ${{ matrix.starter.name }} working-directory: ${{ matrix.starter.path }} run: hugo --minify --panicOnWarning smoke-test-latest: name: Test site on latest Hugo (allowed to fail) runs-on: ubuntu-latest continue-on-error: true steps: - name: Checkout uses: actions/checkout@v6 with: submodules: true fetch-depth: 0 - name: Enable Corepack (for pnpm cache) run: corepack enable - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "${{ env.NODE_VERSION }}" cache: "pnpm" - name: Install root dependencies run: pnpm install --no-frozen-lockfile - name: Install test dependencies working-directory: test run: pnpm install --no-frozen-lockfile - name: Cache Hugo resources (test) uses: actions/cache@v5 with: path: test/resources/ key: ${{ runner.os }}-hugo-resources-test-${{ hashFiles('test/assets/**/*', 'test/config.yaml', 'test/package.json') }} restore-keys: | ${{ runner.os }}-hugo-resources-test- - name: Setup Hugo (latest) uses: peaceiris/actions-hugo@v3 with: hugo-version: latest extended: true - name: Build test site (latest) working-directory: test run: hugo --minify --panicOnWarning --templateMetrics --templateMetricsHints canary-academic-latest: name: academic-cv on latest Hugo (allowed to fail) runs-on: ubuntu-latest continue-on-error: true steps: - name: Checkout uses: actions/checkout@v6 with: submodules: true fetch-depth: 0 - name: Enable Corepack (for pnpm cache) run: corepack enable - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "${{ env.NODE_VERSION }}" cache: "pnpm" - name: Install template dependencies working-directory: templates/academic-cv run: pnpm install --no-frozen-lockfile - name: Cache Hugo resources (template) uses: actions/cache@v5 with: path: templates/academic-cv/resources/ key: ${{ runner.os }}-hugo-resources-academic-latest-${{ hashFiles('templates/academic-cv/assets/**/*', 'templates/academic-cv/config/**/*', 'templates/academic-cv/hugoblox.yaml', 'templates/academic-cv/package.json') }} restore-keys: | ${{ runner.os }}-hugo-resources-academic-latest- - name: Setup Hugo (latest) uses: peaceiris/actions-hugo@v3 with: hugo-version: latest extended: true - name: Build academic-cv (latest) working-directory: templates/academic-cv run: hugo --minify --panicOnWarning smoke-test-min: name: Test site on minimum supported Hugo runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 with: submodules: true fetch-depth: 0 - name: Enable Corepack (for pnpm cache) run: corepack enable - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "${{ env.NODE_VERSION }}" cache: "pnpm" - name: Install root dependencies run: pnpm install --no-frozen-lockfile - name: Install test dependencies working-directory: test run: pnpm install --no-frozen-lockfile - name: Read minimum Hugo version from framework id: min run: | set -euo pipefail VERSION=$(grep -E "^[[:space:]]*min:[[:space:]]*['\"]?" modules/blox/hugo.yaml | head -n1 | sed -E "s/.*min:[[:space:]]*['\"]?([^'\"#]+).*/\\1/") if [ -z "$VERSION" ]; then echo "::error::Could not read module.hugoVersion.min from modules/blox/hugo.yaml" exit 1 fi echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Cache Hugo resources (test - min) uses: actions/cache@v5 with: path: test/resources/ key: ${{ runner.os }}-hugo-resources-test-min-${{ steps.min.outputs.version }}-${{ hashFiles('test/assets/**/*', 'test/config.yaml', 'test/package.json') }} restore-keys: | ${{ runner.os }}-hugo-resources-test-min- - name: Setup Hugo (min) uses: peaceiris/actions-hugo@v3 with: hugo-version: "${{ steps.min.outputs.version }}" extended: true - name: Build test site (min) working-directory: test run: hugo --minify --panicOnWarning --templateMetrics --templateMetricsHints ================================================ FILE: .github/workflows/ci-lint.yml ================================================ name: CI - Lint run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: push: branches: [main] paths: - "modules/**" - "test/**" - "scripts/**" - "package.json" - "pnpm-lock.yaml" - "biome.json" - "vite.config.js" pull_request: branches: [main] paths: - "modules/**" - "test/**" - "scripts/**" - "package.json" - "pnpm-lock.yaml" - "biome.json" - "vite.config.js" permissions: contents: read concurrency: group: lint-${{ github.ref }} cancel-in-progress: true env: NODE_VERSION: "22" jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Enable Corepack (for pnpm cache) run: corepack enable - uses: actions/setup-node@v6 with: node-version: "${{ env.NODE_VERSION }}" cache: "pnpm" - name: Activate pnpm from root package.json run: pnpm --version - name: Install dependencies run: pnpm install --frozen-lockfile - name: Lint (Biome + Stylelint) run: pnpm run lint ================================================ FILE: .github/workflows/ci-pr-labeler.yml ================================================ name: CI - PR Labeler run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: pull_request_target: types: [opened, synchronize] permissions: contents: read pull-requests: write jobs: label: runs-on: ubuntu-latest steps: - uses: actions/labeler@v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} configuration-path: .github/labeler.yml ================================================ FILE: .github/workflows/codeql.yml ================================================ name: Security - CodeQL run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: schedule: - cron: "0 3 * * 0" push: branches: [main] paths: - "**/*.js" - "**/*.jsx" - "**/*.ts" - "**/*.tsx" - "**/*.py" - ".github/workflows/codeql.yml" pull_request: branches: [main] paths: - "**/*.js" - "**/*.jsx" - "**/*.ts" - "**/*.tsx" - "**/*.py" permissions: actions: read contents: read security-events: write jobs: analyze: name: Analyze (CodeQL) runs-on: ubuntu-latest strategy: fail-fast: false steps: - name: Checkout repository uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: "javascript-typescript,python" - name: Autobuild uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: category: "/language:javascript-typescript" ================================================ FILE: .github/workflows/community-welcome.yml ================================================ name: Community - Welcome New Contributor run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: pull_request_target: types: - opened issues: types: - opened permissions: contents: read issues: write pull-requests: write jobs: greeting: runs-on: ubuntu-latest steps: - uses: actions/first-interaction@v3 with: repo_token: ${{ secrets.GITHUB_TOKEN }} issue_message: > Hey, thanks for your first issue! 🚀 Your feedback is vital for improving the project for everyone. Feeling empowered? Squashing this bug yourself could be a great first open-source contribution! We're here to help you. Here's our [Contributor Guide](https://github.com/HugoBlox/kit/blob/main/CONTRIBUTING.md). Let's connect on [Discord](https://discord.gg/z8wNYzb) to chat about it. We've got a super helpful community! pr_message: > Wow, your first PR! Welcome to the community! 🎉 Thank you for this contribution to open source and open research. It makes a huge impact for the thousands of innovators building with Hugo Blox. If you're wondering about next steps, please read our [Contributor Guide](https://github.com/HugoBlox/kit/blob/main/CONTRIBUTING.md) for coding standards, how to run the project locally, and how to get help. We hope this is just the start of your journey with us. Let's build the future together! Join us on [Discord](https://discord.gg/z8wNYzb) to connect with the team and community. Awesome work, we'll take a look soon! ✨ ================================================ FILE: .github/workflows/devcontainer-image.yml ================================================ name: Build HugoBlox devcontainer image on: push: branches: [main] paths: - ".devcontainer/base.Dockerfile" - ".github/workflows/devcontainer-image.yml" workflow_dispatch: inputs: hugo_versions: description: "Comma-separated Hugo versions to build (e.g. 0.152.2,0.154.0)" required: false env: IMAGE_NAME: ghcr.io/hugoblox/hugo-blox-dev DEFAULT_HUGO_VERSION: 0.152.2 NODE_VERSION: 20 PNPM_VERSION: 10.14.0 jobs: prepare-matrix: runs-on: ubuntu-latest outputs: versions: ${{ steps.versions.outputs.matrix }} steps: - name: Select Hugo versions id: versions env: VERSIONS: ${{ github.event.inputs.hugo_versions || env.DEFAULT_HUGO_VERSION }} run: | MATRIX=$(python - <<'PY' import os, json versions = [v.strip() for v in os.environ["VERSIONS"].split(",") if v.strip()] print(json.dumps(versions)) PY ) echo "matrix=${MATRIX}" >> "$GITHUB_OUTPUT" build-and-push: needs: prepare-matrix runs-on: ubuntu-latest permissions: contents: read packages: write strategy: fail-fast: false matrix: hugo: ${{ fromJson(needs.prepare-matrix.outputs.versions) }} steps: - name: Checkout uses: actions/checkout@v6 - name: Log in to GHCR uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Compute tags id: tags env: HUGO_VERSION: ${{ matrix.hugo }} run: | TAGS="${IMAGE_NAME}:hugo${HUGO_VERSION}" if [ "${HUGO_VERSION}" = "${DEFAULT_HUGO_VERSION}" ]; then TAGS="${TAGS}\n${IMAGE_NAME}:latest" fi { echo "list<> "$GITHUB_OUTPUT" - name: Build and push image uses: docker/build-push-action@v7 with: context: . file: .devcontainer/base.Dockerfile push: true build-args: | HUGO_VERSION=${{ matrix.hugo }} NODE_VERSION=${{ env.NODE_VERSION }} PNPM_VERSION=${{ env.PNPM_VERSION }} tags: ${{ steps.tags.outputs.list }} ================================================ FILE: .github/workflows/maintenance-stale.yml ================================================ name: "Maintenance - Close Stale Issues and PRs" run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: schedule: - cron: "30 1 * * *" permissions: contents: write # only for delete-branch option issues: write pull-requests: write jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v10 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | This issue is stale because it has not had any recent activity. The resources of the project maintainers are limited, and so we are asking for your help. If this is a **bug** and you can still reproduce this error on the main branch, consider contributing a Pull Request with a fix. If this is a **feature request**, and you feel that it is still relevant and valuable, consider contributing a Pull Request for review. This issue will automatically close soon if no further activity occurs. Thank you for your contributions. stale-pr-message: | This PR is stale because it has not had any recent activity. The resources of the project maintainers are limited, and so we are asking for your help. If you feel that the PR is still relevant in the latest release, consider making the PR easier to review and finding developers to help review the PR. Please be _mindful_ that although we encourage PRs, we cannot expand the scope of the project in every possible direction. There will be requests that don't make the roadmap. This PR will automatically close soon if no further activity occurs. Thank you for your contributions. days-before-stale: 30 days-before-close: 5 stale-issue-label: stale stale-pr-label: stale exempt-issue-labels: "keep,enhancement,bug,documentation" exempt-pr-labels: "keep,enhancement,bug,documentation" ================================================ FILE: .github/workflows/release-hugoblox-modules.yml ================================================ name: Release - HugoBlox Modules run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: workflow_dispatch: inputs: dry_run: description: "Run without committing/tagging" type: boolean default: true propagate: description: "Propagate dependency bumps to dependents" type: boolean default: true update_templates_to_commits: description: "Update templates to use latest module commits instead of tagged versions" type: boolean default: false permissions: contents: write concurrency: group: release-modules cancel-in-progress: false jobs: release: runs-on: ubuntu-latest env: LOG_LEVEL: INFO steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Install Poetry uses: snok/install-poetry@v1 with: version: 1.8.3 virtualenvs-create: true virtualenvs-in-project: true - name: Install dependencies run: | poetry --version poetry install --no-interaction --no-ansi - name: Configure Git identity run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" # Skip plan display when updating templates to commits as it's not relevant for that operation - name: Show plan (dry run) if: ${{ inputs.dry_run && !inputs.update_templates_to_commits }} run: | poetry run python scripts/release_modules.py --print-plan --log-level $LOG_LEVEL # Dedicated step for updating templates to use latest commits instead of tagged versions # Only runs when specifically requested and not in dry run mode - name: Update templates to commits if: ${{ inputs.update_templates_to_commits && !inputs.dry_run }} run: | poetry run python scripts/release_modules.py --yes --update-starters-to-commits --log-level $LOG_LEVEL # Standard release process - only runs when not in dry run mode and not updating templates to commits # These operations are mutually exclusive - we either do a normal release or update starters to commits - name: Release (commit, tag, push) if: ${{ !inputs.dry_run && !inputs.update_templates_to_commits }} run: | if [ "${{ inputs.propagate }}" = "true" ]; then poetry run python scripts/release_modules.py --yes --propagate --log-level $LOG_LEVEL else poetry run python scripts/release_modules.py --yes --no-propagate --log-level $LOG_LEVEL fi ================================================ FILE: .github/workflows/release-package-splitter.yml ================================================ name: "Release - Package Splitter" run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: push: branches: - main workflow_dispatch: inputs: force_all: description: "Force split/push of all template repos, even if no changes detected" required: false type: boolean default: false # IMPORTANT: workflows below must match the upstream workflow's `name:` exactly workflow_run: workflows: - Release - HugoBlox Modules types: - completed env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} jobs: determine_changed: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} has_changes: ${{ steps.set-matrix.outputs.has_changes }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - id: changed # Only run change detection for push events if: ${{ github.event_name == 'push' }} uses: tj-actions/changed-files@v47 with: files: | templates/academic-cv/** templates/resume/** templates/blog/** templates/documentation/** templates/link-in-bio/** templates/landing-page/** templates/dev-portfolio/** templates/markdown-slides/** dir_names: true dir_names_max_depth: 2 dir_names_exclude_current_dir: true # Build dynamic matrix - name: Build dynamic matrix id: set-matrix env: CHANGED_DIRS: ${{ steps.changed.outputs.dir_names || '' }} FORCE_ALL: ${{ github.event.inputs.force_all || 'false' }} run: | # Define the full mapping declare -A STARTER_MAP=( ["templates/academic-cv"]="hugo-theme-academic-cv" ["templates/resume"]="hugo-theme-resume" ["templates/data-science-blog"]="hugo-theme-data-science-blog" ["templates/documentation"]="hugo-theme-documentation" ["templates/link-in-bio"]="hugo-theme-link-in-bio" ["templates/startup-landing-page"]="hugo-theme-startup-landing-page" ["templates/dev-portfolio"]="hugo-theme-developer-portfolio" ["templates/markdown-slides"]="hugo-theme-markdown-slides" ) build_full_matrix() { local JSON="[" FIRST=true local ROOTS=() # Sort keys to keep output stable across runs readarray -t ROOTS < <(printf "%s\n" "${!STARTER_MAP[@]}" | sort) for ROOT in "${ROOTS[@]}"; do if [ "$FIRST" = true ]; then FIRST=false else JSON+="," fi JSON+="{\"local_path\":\"$ROOT\",\"split_repository\":\"${STARTER_MAP[$ROOT]}\"}" done JSON+="]" echo "$JSON" } # Manual override to force splitting all templates if [ "$FORCE_ALL" = "true" ]; then echo "Force mode enabled; splitting all templates" FULL_MATRIX=$(build_full_matrix) echo "matrix=$FULL_MATRIX" >> "$GITHUB_OUTPUT" echo "has_changes=true" >> "$GITHUB_OUTPUT" exit 0 fi # For non-push events, always use full matrix derived from the map above if [ "${{ github.event_name }}" != "push" ]; then echo "Using full matrix for ${{ github.event_name }} event" FULL_MATRIX=$(build_full_matrix) echo "matrix=$FULL_MATRIX" >> "$GITHUB_OUTPUT" echo "has_changes=true" >> "$GITHUB_OUTPUT" exit 0 fi echo "Detected template directories: $CHANGED_DIRS" # If no changes, set empty matrix if [ -z "$CHANGED_DIRS" ]; then echo "No templates changed" echo "matrix=[]" >> "$GITHUB_OUTPUT" echo "has_changes=false" >> "$GITHUB_OUTPUT" exit 0 fi # Build JSON array for changed templates JSON="[" FIRST=true # tj-actions outputs space-separated list for DIR in $CHANGED_DIRS; do # Normalize potential trailing slash DIR="${DIR%/}" # Collapse to the template root (first two path segments), e.g. templates/landing-page IFS='/' read -r SEG1 SEG2 _ <<< "$DIR" if [[ -n "$SEG1" && -n "$SEG2" ]]; then ROOT="$SEG1/$SEG2" else ROOT="$DIR" fi # Only process if it's a known starter if [[ -n "${STARTER_MAP[$ROOT]}" ]]; then if [ "$FIRST" = true ]; then FIRST=false else JSON+="," fi JSON+="{\"local_path\":\"$ROOT\",\"split_repository\":\"${STARTER_MAP[$ROOT]}\"}" fi done JSON+="]" # Check if we actually added any starters if [ "$JSON" = "[]" ]; then echo "No valid starters found in changed directories" echo "matrix=[]" >> "$GITHUB_OUTPUT" echo "has_changes=false" >> "$GITHUB_OUTPUT" else echo "matrix=$JSON" >> "$GITHUB_OUTPUT" echo "has_changes=true" >> "$GITHUB_OUTPUT" fi packages_split: needs: determine_changed # Run when: # • Event is not workflow_run OR upstream workflow succeeded. # • Event is not push OR at least one starter changed. if: ${{ (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') && needs.determine_changed.outputs.has_changes == 'true' }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: package: ${{ fromJson(needs.determine_changed.outputs.matrix) }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 # step if no tag is pushed - if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: "symplify/monorepo-split-github-action@v2.4.4" with: package_directory: "${{ matrix.package.local_path }}" repository_organization: "HugoBlox" repository_name: "${{ matrix.package.split_repository }}" user_name: "Splitter Bot" user_email: "no.reply@hugoblox.com" ================================================ FILE: .github/workflows/security-codeql.yml ================================================ name: Security - CodeQL run-name: ${{ github.workflow }} - ${{ github.ref_name }} on: schedule: - cron: "0 3 * * 0" push: branches: [main] paths: - "**/*.js" - "**/*.jsx" - "**/*.ts" - "**/*.tsx" - "**/*.py" - ".github/workflows/codeql.yml" pull_request: branches: [main] paths: - "**/*.js" - "**/*.jsx" - "**/*.ts" - "**/*.tsx" - "**/*.py" permissions: actions: read contents: read security-events: write jobs: analyze: name: Analyze (CodeQL) runs-on: ubuntu-latest strategy: fail-fast: false steps: - name: Checkout repository uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: "javascript-typescript,python" - name: Autobuild uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: category: "/language:javascript-typescript" ================================================ FILE: .gitignore ================================================ # ============================================================================ # HugoBlox Kit - Monorepo .gitignore # ============================================================================ # ============================================================================ # Build Artifacts & Generated Files # ============================================================================ # Hugo build artifacts public/ resources/ .hugo_build.lock hugo_stats.json # Go modules go.sum # Node.js node_modules/ # Pagefind search index (generated at build time) **/pagefind/ # JSConfig files (auto-generated by Hugo) **/assets/jsconfig.json # pnpm lock files in starters (keep template clean) starters/**/pnpm-lock.yaml # ============================================================================ # Development Environment # ============================================================================ # Environment variables .env .env.local .env.*.local # IDE & Editor files .idea/ /.vscode/ .specstory/ /docs/ # ============================================================================ # Language & Framework Specific # ============================================================================ # Python (for scripts) __pycache__/ *.py[cod] *$py.class .pytest_cache/ *.egg-info/ # Jupyter Notebooks .ipynb_checkpoints/ # ============================================================================ # Operating System # ============================================================================ # macOS .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes # Windows Thumbs.db ehthumbs.db Desktop.ini # Linux *~ .nfs* # ============================================================================ # Logs & Temporary Files # ============================================================================ # Log files *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Temporary directories tmp/ temp/ .tmp/ backups/ ================================================ FILE: .prettierignore ================================================ # Vendor directories _vendor/ vendor/ # Generated directories public/ resources/ node_modules/ # We use go-template parser for HTML, but still ignore some specific files modules/blox-tailwind/assets/dist/ # JSON files with specific formats (although typically Biome now processes JSON) modules/blox-tailwind/layouts/index.json modules/blox-tailwind/layouts/index.webmanifest ================================================ FILE: .prettierrc.js ================================================ module.exports = { bracketSpacing: false, singleQuote: false, jsxBracketSameLine: true, trailingComma: "all", printWidth: 150, overrides: [ { files: ["*.html"], options: { parser: "go-template", }, }, { files: ["*.md"], options: { proseWrap: "preserve", }, }, ], }; ================================================ FILE: .stylelintignore ================================================ **/public/** **/dist/** **/libs/** modules/blox-tailwind/assets/css/color-utilities.css starters/**/static/** ================================================ FILE: CITATION.cff ================================================ cff-version: 1.2.0 message: "If you use HugoBlox in your work, please cite it as below." type: software title: "HugoBlox" abstract: > HugoBlox is an open-source ecosystem for building high-performance research portfolios, lab websites, and technical documentation. Designed for data sovereignty, it enables data scientists and researchers to publish reproducible content directly from Markdown, Jupyter Notebooks, and BibTeX, eliminating the need for complex JavaScript dependencies or proprietary AI platforms. authors: - family-names: "Cushen" given-names: "George" orcid: "https://orcid.org/0000-0003-0526-3793" license: "MIT" repository-code: "https://github.com/HugoBlox/kit" url: "https://hugoblox.com" doi: 10.5281/zenodo.17704062 # Use the latest released version here version: "0.11.0" date-released: 2026-01-02 keywords: - hugo - copilot - ai - static-site-generator - website-builder - markdown - academic-websites - documentation - blog - portfolio - research - academic - open-source - no-code ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Hugo Blox 🚀 > **Welcome, researchers and academics!** Whether you're a professor sharing your publications, a PhD student building your first portfolio, or an AI researcher showcasing your work — this guide will help you contribute to the tool that powers 100,000s of researcher and lab websites worldwide. [![All Access](https://img.shields.io/badge/Support-All%20Access-2ea44f?logo=heart)](https://hugoblox.com/all-access) [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-ea4aaa?logo=github)](https://github.com/sponsors/gcushen) [![Star us](https://img.shields.io/github/stars/HugoBlox/kit?style=social)](https://github.com/HugoBlox/kit) [![Discord](https://img.shields.io/discord/722225264733716590?logo=discord)](https://discord.gg/z8wNYzb) ## ❤️ Love Hugo Blox? Help keep it thriving. > If Hugo Blox has saved you hours, taught you something, or helped you share your work, please take 2 minutes to give back. Most people won't — but if a small part of the community pitches in today, we can ship faster, fix more bugs, and keep the project healthy for everyone. We want contributing to Hugo Blox to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including new plugins (such as new widgets, shortcodes, theme packs, and language packs), templates, features, documentation as well as updates and tweaks, blog posts, YouTube tutorials, live streaming customizations, meetups, and more. ## 🎯 Why Contribute? ### For Your Career - **📝 Add to your CV**: Open source contributions demonstrate technical skills and collaboration - **🌍 Build your reputation**: Your contributions are publicly visible and credited - **🤝 Network with peers**: Connect with researchers and developers worldwide - **📚 Learn modern web tech**: Gain experience with Hugo, Tailwind CSS, and modern web development ### For the Community - **🔬 Shape the tool you use**: Directly influence features that matter to academics - **⚡ Get fixes faster**: Contributing means your needs get addressed sooner - **🌱 Support open research**: Keep academic tools free and accessible to all - **🏆 Join 9k+ stars**: Be part of a thriving academic community ## 🚀 Quick Wins (Pick One!) ### ⏱️ 30 Seconds - **⭐ Star the repository**: [github.com/HugoBlox/kit](https://github.com/HugoBlox/kit) - **👍 Vote on issues**: Shape the roadmap by [upvoting features](https://github.com/HugoBlox/kit/issues) you need - **💡 Suggest an enhancement**: Have an idea? [Create a GitHub Issue](https://github.com/HugoBlox/kit/issues) for the community to vote on - **📢 Share your site**: Post your Hugo Blox site on X/LinkedIn/Reddit with #HugoBlox ### 🕐 5-10 Minutes - **📸 Share a screenshot**: Show your beautiful site in [Discussions](https://github.com/HugoBlox/kit/discussions) - **🐛 Report issues clearly**: Found a bug? Help us fix it with clear steps to reproduce - **💬 Help in Discord**: Answer a question in our [Discord community](https://discord.gg/z8wNYzb) - **✏️ Fix documentation typos**: Spot an error? Fix it directly on GitHub (no setup needed!) ### 🕓 ~1 Hour - **🔧 Implement a small issue**: See [help-wanted issues](https://github.com/HugoBlox/kit/labels/help%20wanted) - **📚 Write documentation**: Help keep the documentation complete and up-to-date ### 🕘 A Few Hours - **🧩 Take a larger issue**: Contribute a significant feature or improvement - **🎥 Create tutorials**: Record a YouTube video or write a detailed blog post ## Where to Start Join the **Contributing** channel on the **[community Discord](https://discord.gg/z8wNYzb)**. ## General ways to help Whether or not you're a developer, there are plenty of non-technical ways that you can help. We always need help with: - Helping the Hugo Blox community via the live [chat](https://discord.gg/z8wNYzb) and [forum](https://github.com/HugoBlox/kit/discussions) - Investigating and reviewing open [Issues](https://github.com/HugoBlox/kit/issues) and [Pull Requests](https://github.com/HugoBlox/kit/pulls) - Influence the roadmap! Give a thumbs up 👍 to upvote a feature request you would like to use - Improving the [documentation](https://docs.hugoblox.com/) and writing tutorials - Just click the _Edit_ button at the bottom of pages or open an issue with your proposed improvement - Testing and quality assurance, such as checking the latest version of the templates work as you expect and fixing any dead-links etc. - Translating the Hugo Blox templates or the Hugo Blox documentation - Hosting local Hugo Blox themed events or meetups - Promoting Hugo Blox to others by blogging, vlogging, code streaming, talking etc. ### For technical contributions ## 🛠️ Development Setup > **No Go experience needed!** Most contributions only require basic HTML/CSS knowledge. ### Prerequisites 1. **Install Node.js** (for Tailwind CSS v4) ```bash # macOS/Linux (using Homebrew) brew install node # Windows (download from nodejs.org) # Or use WSL2 for a Linux environment ``` 2. **Install pnpm** (our package manager) ```bash npm install -g pnpm ``` 3. **Install Hugo Extended** (latest version) ```bash # macOS brew install hugo # Windows (using Chocolatey) choco install hugo-extended # Linux snap install hugo --channel=extended ``` ### Getting Started 1. **Fork & Clone** ```bash # Fork on GitHub first, then: git clone https://github.com/YOUR-USERNAME/kit.git cd kit ``` 2. **Install Dependencies** ```bash pnpm install ``` 3. **View a Starter Site** ```bash # View the academic-cv starter (most popular) ./scripts/view-starter-dev.sh academic-cv # Site opens at http://localhost:8081 ``` That's it! You're ready to contribute. 🎉 ### Repository structure ``` kit/ ├── modules/ │ └── blox/ # Main theme module │ ├── layouts/ # HTML templates (easy to edit!) │ ├── assets/css/ # Tailwind CSS v4 styles │ └── i18n/ # Translations (help translate!) ├── templates/ │ ├── academic-cv/ # CV/Resume template │ ├── blog/ # Blog template │ └── documentation/ # Docs template └── scripts/ # Helper scripts ``` **Note**: To contribute an improvement to a template, make your changes to the relevant template within the `templates/` folder. **Do not submit PRs to the dedicated template repositories as they are read-only (changes are automatically propagated there from this mono-repository).** #### What are some good issues to contribute to? If you're a developer looking to contribute, but you're not sure where to begin, check out the [help wanted](https://github.com/HugoBlox/kit/labels/help%20wanted) label on Github, which contains issues which need some love. #### How can I propose an improvement? If you have a straightforward bug fix or improvement, feel free to contribute it in a [Pull Request](https://github.com/HugoBlox/kit/pulls) for the community to review. If you have an idea for a new feature, please start by [searching the issues](https://github.com/HugoBlox/kit/issues) to check that the feature has not already been suggested and then suggest it by [opening a new issue](https://github.com/HugoBlox/kit/issues/new/choose), as adding new features to Hugo Blox first requires some analysis around the design and spec. Please be mindful of the project [scope](#scope). ### Contribute Blox [Create and publish your own blox](https://github.com/HugoBlox/create-blox) ### Contribute a shortcode [Create and publish your own shortcode](https://github.com/HugoBlox/create-shortcode) ### Contribute a language pack To contribute a **new language pack** or an improvement to a language pack, refer to the [language pack guide](https://docs.hugoblox.com/reference/language/#create-or-modify-a-language-pack). Once created, [fork HugoBlox Kit](https://github.com/HugoBlox/kit), place your language pack in `modules/blox/i18n/`, add the language metadata to `modules/blox/data/languages.yaml`, and open a Pull Request on Github with these two files. ### Contribute a theme pack [View the guide](https://docs.hugoblox.com/getting-started/customize/#appearance) to contributing a color and font theme pack. ### Contribute a template Consider duplicating a bare-bones template, such as the [Link In Bio](https://github.com/HugoBlox/kit/tree/main/templates/link-in-bio) folder, and building up your own template using the Hugo Blox. Reach out on the **Contributing** channel in Discord to submit your template. ### Contribute to the Publication importer To contribute to **Hugo Academic CLI**, the automatic publication and blog post importer, refer to [its dedicated Github repository](https://github.com/GetRD/academic-file-converter) and Issue queue. ## 🤝 Getting Help ### Where to Ask Questions - **🗣️ Discord**: Real-time chat in [#contributing channel](https://discord.gg/z8wNYzb) - **💬 Discussions**: Async help in [GitHub Discussions](https://github.com/HugoBlox/kit/discussions) - **🐛 Issues**: Bug reports and feature requests ### Tips for Getting Quick Help 1. **Share your environment**: Hugo version, HugoBlox version in `go.mod`, OS, browser 2. **Provide minimal reproduction**: Smallest example showing the issue 3. **Check existing issues**: Your question might be answered 4. **Be specific**: "Publications not showing" → "BibTeX import fails with DOI links" ## 🏆 Recognition & Rewards ### How We Thank Contributors - **🎖️ Credits**: Named in release notes - **🏷️ Contributor badge**: On your GitHub profile - **📣 Social shoutouts**: Featured on our social media - **🎯 Direct impact**: Your needs prioritized - **🤝 Network access**: Connect with core team ### Hall of Fame Check our [Contributors page](https://github.com/HugoBlox/kit/graphs/contributors) to see everyone who's helped! ## 💚 Can't Contribute Code? Support the Project! ### Other Ways to Help - **💰 Sponsor**: - [All Access](https://hugoblox.com/all-access) - One-time payment for exclusive Pro templates and blocks - [GitHub Sponsors](https://github.com/sponsors/gcushen) - Monthly donation to support open source development - ☕️ [Donate a coffee](https://github.com/sponsors/gcushen?frequency=one-time) - **📢 Spread the Word**: Share your Hugo Blox site and experience - **📝 Write Tutorials**: Blog about your Hugo Blox setup - **🎥 Create Videos**: YouTube tutorials help many researchers - **🌍 Translate**: Help make Hugo Blox accessible globally ## Best practices To create a consistent experience for all contributors and help prevent bugs, we have some best practices. ### Conventional Commits Specification Please follow the [Conventional Commits Specification](https://www.conventionalcommits.org/en/v1.0.0/). For example: - new feature: `feat: add the X parameter` - bug fix: `fix: typo in implementation of X parameter` - performance: `perf: speed up init by pre-warming only pages` - refactor: `refactor: simplify citation logic` - docs: `docs: document the X parameter` - style: `style: change font color from black to blue` - build-related: `chore: rebuild JS assets` ### Linting and formatting ```sh pnpm install pnpm run lint pnpm run format ``` ## Scope Please be _mindful_ that although we encourage feature requests, we cannot expand the scope of the project in every possible direction. There will be feature requests that don't make the roadmap. Every feature requires effort not just to analyse the requirements, design it, implement it, test it, document it, merge it, write release notes for it, and release it, but also to continuously support users with it and maintain it (fixing and refactoring the feature as the project and its dependencies evolve). The more regular active volunteers (rather than one-off contributors) we have supporting users and maintaining the project, the more feasible it becomes to expand the scope of the project. The project's scope also has to be constrained so that it doesn't get too complex and unwieldy, from an architectural perspective, a testing perspective, and from a usability perspective. Plugins (widgets, shortcodes, theme packs, language packs, and third-party JavaScript integrations) as well as templates allow the community to add major features without needing to contribute to Hugo Blox itself. ## 📋 Contribution Checklist Before submitting a PR: - [ ] **Test locally**: Run `./scripts/view-starter-dev.sh academic-cv` - [ ] **Check formatting**: Run `pnpm run lint:js` (if you edited JS) - [ ] **Update docs**: If adding features, document them in the code and in the PR - [ ] **Add examples**: Show how to use new features - [ ] **Write clear commit messages**: Help future contributors understand changes ## 🙏 Thank You! Every contribution matters — whether it's fixing a typo, adding a translation, or building a new feature. You're helping thousands of researchers share their work with the world. **Welcome to the Hugo Blox community!** 🎉 --- _Questions? Join our [Discord](https://discord.gg/z8wNYzb) or start a [Discussion](https://github.com/HugoBlox/kit/discussions)._ _This project follows the [Contributor Covenant Code of Conduct](.github/CODE_OF_CONDUCT.md)._ ## ⚖️ Our Contributor License Agreement (CLA) ### Why We Have a CLA A Contributor License Agreement (CLA) is a standard best practice in professional open-source. It's a simple agreement that protects you (our contributor), our users, and the Hugo Blox project itself. - It protects you: the CLA clarifies that you are entitled to contribute the code and that your contribution is provided "as is," without any warranty. - It protects the project: it grants us the permanent legal rights needed to use your contribution as part of the project and defend the project from legal challenges. - It enables our future: having a proper CLA allows us to confidently continue to enhance and support the Hugo Blox ecosystem. This agreement doesn't change your ownership of your code; it simply grants us a clear license to use it as part of Hugo Blox. ### Your Agreement By submitting a Pull Request to this repository, you agree to our [Contributor License Agreement (CLA)](.github/CLA.md). Please ensure you have read and understood it. ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright © 2016-Present [**Lore Labs**](https://lore.tech). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ [**中文**](./README.zh.md)

Build world-class sites with HugoBlox

HugoBlox: Your Open Publishing Stack

Publish notebooks, docs, portfolios, and knowledge bases from Markdown + Jupyter.
Built for data scientists, AI engineers, researchers, labs, and tech startups who want speed without lock-in: Hugo + Tailwind with optional Researcher Plan automation (visual editing, imports, fixes, and upgrades).

Start Free in Browser  •  Get HugoBlox Studio (VS Code)

Researchers & Labs  •  Data Scientists & AI Engineers  •  Teams & Orgs  •  Automations & Plans

Discord GitHub Stars Follow on X VS Code Installs VS Code Rating

Trusted since 2016 · 150,000+ researchers and scientists (Meta, Stanford, NVIDIA) · Rated 4.9/5 by users (official survey) · Used by teams like NVIDIA Research Labs, King’s College London, and MIT · Featured by GitHub Release Radar

https://github.com/user-attachments/assets/a0be0c48-b8d5-4b40-a11b-85fedcdf89bc --- ## ⚡️ Why teams choose HugoBlox In the age of AI, **Markdown is the new source code**. HugoBlox gives you the speed of modern tooling with the durability of a static stack: **Hugo + Tailwind** (with optional Alpine/Svelte blocks for interactivity). - **Own your content**: clean Markdown, YAML, and notebooks — portable, readable, and LLM-friendly. - **Performance without the ops tax**: static output, fast builds, no runtime database. - **Beautiful by default**: high-quality templates + blocks (and Researcher Plan options when you want more). - **A hybrid workflow**: edit in code, or use a visual editor when you want velocity. --- ## For researchers & labs - **Lab sites and academic profiles** (people, publications, projects, news) - **Citable output** with BibTeX/DOI workflows - **Notebooks + LaTeX** for technical writing that actually renders ## For data scientists & AI engineers - **Project docs** and technical blogs without heavy JavaScript stacks - **Notebook-first publishing** (`.ipynb`) for reports, tutorials, and results - **Knowledge bases** and internal docs that stay searchable and maintainable ## For teams & orgs - **Consistent sites** across teams with templates + blocks - **Lower risk upgrades** with clear versioning + migration guidance - **Support options** when you need fast answers --- ## 🧠 Edit the way you like (code-first, visual when you want it) - **Code-first**: Markdown/YAML + Hugo templates for full control. - **Visual editing (Researcher Plan)**: **HugoBlox Studio** in VS Code for drag-and-drop blocks, previews, and safer config edits. - **AI automation (Researcher Plan)**: spend less time on formatting, YAML fixes, imports, and maintenance.

HugoBlox Studio in Action

HugoBlox Studio: Visual editing meets code-first control.

--- ## 🛠️ The toolkit | **Feature** | **Why it matters** | | :--- | :--- | | **HugoBlox Studio (VS Code)** | A visual CMS inside your editor. Drag-and-drop blocks without leaving VS Code. | | **Notebooks & LaTeX** | Render `.ipynb` and math-heavy pages natively. | | **BibTeX / DOI workflows** | Build publication pages and bibliographies without manual formatting. | | **Polyglot Support** | Write in Markdown, Jupyter, RMarkdown, or LaTeX Math. |

Template previews

Browse Templates →

Want to see it working fast? Pick a template and publish in ~60 seconds with the Online Copilot.
Try a template now →

--- ## 🚀 Get Started ### Option 1: The Online Copilot (Fastest) Ideal for **founders, labs, and startups**. Launch a site in minutes. 👉 [**Start Free in Browser**](https://hugoblox.com/start?utm_source=github&utm_medium=readme&utm_content=get_started_browser) ### Option 2: HugoBlox Studio (Best for Data/AI teams) The power of a visual website builder, directly inside VS Code. 1. **Install** [HugoBlox Studio from the Marketplace](https://marketplace.visualstudio.com/items?itemName=ownable.ownable). 2. **Open** any HugoBlox project folder. 3. **Click** the HugoBlox Studio icon in the menu to start visually editing. ### Option 3: The CLI (For DevOps/Eng) Scaffold a new project locally. ```bash # Requires Hugo Extended & Node.js npm install -g hugoblox hugoblox create site ``` Need guides and best practices? See the docs: [**docs.hugoblox.com**](https://docs.hugoblox.com/?utm_source=github&utm_medium=readme&utm_content=docs) --- ## ✅ Stability & upgrades (because your site should not break) - **Pin versions** to keep production stable. - **Upgrade with confidence** using migration notes and upgrade guides. - **Customize safely**: prefer configuration and blocks over fragile template overrides when possible. - **Catch config issues early (Researcher Plan)**: visual editing + validation reduces YAML/front matter mistakes. See the docs for upgrade guidance: [**docs.hugoblox.com**](https://docs.hugoblox.com/?utm_source=github&utm_medium=readme&utm_content=upgrade_guidance) ## ⚡️ Unlock Automations & Premium HugoBlox is **Open Core**. The **Free Kit** is production-grade and you will always own your data and code. The Free Kit includes: - **[HugoBlox Studio](https://marketplace.visualstudio.com/items?itemName=ownable.ownable) Core**: Visual site configuration, theming, and content editing - **Templates + blocks** for portfolios, labs, docs, and landing pages - **Markdown/YAML-first workflow** with Hugo + Tailwind performance - **Notebook + LaTeX support** for technical publishing - **Community support** via docs, GitHub issues, and Discord ### 🤖 Pro (Automation) Upgrade to **Pro** for [HugoBlox Studio](https://marketplace.visualstudio.com/items?itemName=ownable.ownable) (requires extension login) when you want automation and lower maintenance overhead: - **Less time debugging YAML** (Fix-it Bot + safer config editing) - **Less time formatting citations** (Magic Import + publication automation) - **Less time dealing with upgrades** (guided maintenance workflows) - **More velocity** (visual editing + previews in VS Code) | Feature | **Free Kit** (Open Source) | **Pro** (Automation) | | :--- | :---: | :---: | | **Site Ownership** | ✅ 100% Yours | ✅ 100% Yours | | **Visual Page Editor** | ❌ | **✅ Included** | | **AI Assistant** | ⏳ Trial | **✅ Included** | | **Auto Sync with GitHub** | ❌ | **✅ Included** | | **AI "Fix-It" Bot** (Auto-fix YAML) | ❌ | **✅ Unlimited** | | **Magic Import** (BibTeX/DOI -> Page) | ⏳ Trial | **✅ Unlimited** | | **CV Generator** (Site -> PDF Resume) | ❌ | **✅ Included** | | **Private Discord** | ❌ | ✅ | | **Support Open Research** | 💜 | **🏆 Hero Status** | 👉 [**View Full Feature Matrix**](https://hugoblox.com/pricing?utm_source=github&utm_medium=readme&utm_content=pricing_matrix)  •  [**Get Pro**](https://hugoblox.com/pricing?utm_source=github&utm_medium=readme&utm_content=cta_pro) > "HugoBlox Studio saved me **40+ hours** on my lab site. Visual edits + BibTeX auto-updates = **citations up 3×**." >
— **Dr. Sarah Yang**, AI Researcher ### 🎨 HugoBlox Premium **Get the complete kit.** Instant access to premium templates, blocks, and community support to help you launch faster. | Feature | Open Source | **HugoBlox Premium** | | :--- | :---: | :---: | | **Core Framework** | ✅ | ✅ | | **Premium Templates** (SaaS, Lab) | ❌ | **✅ Included** | | **Premium Blocks** | ❌ | **✅ Included** | | **Remove Attribution?** | ❌ | **✅ Included** | | **Private Discord** | ❌ | ✅ | | **Support Open Research** | 💜 | **🏆 Hero Status** | 👉 [**Get Premium Templates Bundle**](https://hugoblox.com/premium?utm_source=github&utm_medium=readme&utm_content=cta_premium) > "Launched my startup site with built-in docs in **10 minutes**. The premium block system is genius; onboarding time dropped 60%." >
— **Alexandre Rodrigues**, Founder --- ## 🏢 Org-ready (without the enterprise bloat) - **Deploy anywhere**: static output works with your existing infra. - **Lower ops surface area**: no runtime app to patch. - **Procurement-friendly options**: priority support and commercial features when you need them. --- ## 🗣️ Community & Support We are a community of 150,000+ researchers, engineers, and creators. - **Need Help?** Join the [Discord Server](https://discord.gg/z8wNYzb) or search the [Documentation](https://docs.hugoblox.com/). - **Found a Bug?** Open an [Issue](https://github.com/HugoBlox/kit/issues). - **Want to Contribute?** Read our [Contributing Guide](./CONTRIBUTING.md). ### Sponsors Help us keep open-source sustainable. [**❤️ Sponsor on GitHub**](https://github.com/sponsors/gcushen) | [**🏢 Become a Partner**](https://github.com/sponsors/gcushen) --- ## License Copyright © 2016-Present [**Lore Labs**](https://lore.tech/?utm_source=github&utm_medium=readme). Released under the [MIT License](./LICENSE.md).

HugoBlox™ is a trademark of Lore Labs.

================================================ FILE: README.zh.md ================================================ [**English**](./README.md)

用 HugoBlox 打造世界级站点

HugoBlox: 您的开源发布栈

基于 Markdown + Jupyter 发布笔记、文档、作品集和知识库。
专为追求速度且拒绝锁定的数据科学家、AI 工程师、研究人员、实验室和科技初创公司打造:Hugo + Tailwind 核心,可选 Researcher Plan 自动化(可视化编辑、一键导入、自动修复和升级)。

浏览器中免费试用  •  获取 HugoBlox Studio (VS Code)

研究人员与实验室  •  数据科学家与 AI 工程师  •  团队与组织  •  自动化与订阅计划

Discord GitHub Stars Follow on X VS Code Installs VS Code Rating

源自 2016 · 150,000+ 研究人员与科学家信赖 (Meta, Stanford, NVIDIA) · 用户评分 4.9/5 (官方调研) · 被 NVIDIA Research Labs, King’s College London, 以及 MIT 等团队使用 · 入选 GitHub Release Radar

--- ## ⚡️ 为什么团队选择 HugoBlox 在 AI 时代,**Markdown 就是新的源代码**。HugoBlox 赋予您现代工具的速度与静态技术栈的持久性:**Hugo + Tailwind**(支持可选的 Alpine/Svelte 模块以增强交互性)。 - **拥有您的内容**:纯净的 Markdown、YAML 和 Notebooks —— 便携、可读且对 LLM 友好。 - **无运维负担的极致性能**:静态输出,极速构建,无运行时数据库。 - **默认即美**:高质量的模板 + 积木(需要更多功能时可选 Researcher Plan)。 - **混合工作流**:代码中直接编辑,或在需要速度时使用可视化编辑器。 --- ## 面向研究人员与实验室 - **实验室站点与学术主页**(人员、出版物、项目、新闻) - **可引用的输出**,支持 BibTeX/DOI 工作流 - **Notebooks + LaTeX**,让技术写作完美渲染 ## 面向数据科学家与 AI 工程师 - **项目文档**与无需繁重 JavaScript 栈的技术博客 - **Notebook 优先发布** (`.ipynb`),用于报告、教程和结果展示 - **知识库**与内部文档,保持可搜索与可维护 ## 面向团队与组织 - **一致的站点**,通过模板 + 积木实现跨团队统一 - **低风险升级**,提供清晰的版本控制 + 迁移指南 - **支持选项**,当您需要快速解答时 --- ## 🧠 随心所欲地编辑(代码优先,亦可可视化) - **代码优先**:Markdown/YAML + Hugo 模板,掌控全局。 - **可视化编辑 (Researcher Plan)**:VS Code 中的 **HugoBlox Studio**,提供拖拽式积木、实时预览和更安全的配置编辑。 - **AI 自动化 (Researcher Plan)**:减少在格式调整、YAML 修复、导入和维护上花费的时间。

HugoBlox Studio 实战

HugoBlox Studio: 可视化编辑与代码优先掌控的完美结合。

--- ## 🛠️ 工具箱 | **功能** | **核心价值** | | :--- | :--- | | **HugoBlox Studio (VS Code)** | 编辑器内的可视化 CMS。无需离开 VS Code 即可拖拽积木。 | | **Notebooks & LaTeX** | 原生渲染 `.ipynb` 和重数学公式页面。 | | **BibTeX / DOI 工作流** | 构建出版物页面和参考文献,无需手动格式化。 | | **多语言支持** | 使用 Markdown, Jupyter, RMarkdown, 或 LaTeX Math 写作。 |

模板预览

浏览模板 →

想看它快速运行?选择一个模板,使用 Online Copilot 在约 60 秒内发布。
立即尝试模板 →

--- ## 🚀 快速开始 ### 选项 1:在线 Copilot(最快) 适合 **创始人、实验室和初创公司**。几分钟内上线站点。 👉 [**浏览器中免费试用**](https://hugoblox.com/start?utm_source=github&utm_medium=readme&utm_content=get_started_browser) ### 选项 2:HugoBlox Studio(适合数据/AI 团队) 可视化网站构建器的力量,直接集成在 VS Code 中。 1. **安装** [VS Code 市场中的 HugoBlox Studio](https://marketplace.visualstudio.com/items?itemName=ownable.ownable). 2. **打开** 任意 HugoBlox 项目文件夹。 3. **点击** 菜单中的 HugoBlox Studio 图标开始可视化编辑。 ### 选项 3:命令行 CLI(适合 DevOps/工程师) 在本地搭建新项目骨架。 ```bash # 需要 Hugo Extended & Node.js npm install -g hugoblox hugoblox create site ``` 需要指南和最佳实践?查看文档:[**docs.hugoblox.com**](https://docs.hugoblox.com/?utm_source=github&utm_medium=readme&utm_content=docs) --- ## ✅ 稳定性与升级(您的站点不应崩溃) - **锁定版本** 以保持生产环境稳定。 - **自信升级**,使用迁移说明和升级指南。 - **安全定制**:尽可能优先使用配置和积木,而非脆弱的模板覆盖。 - **尽早发现配置问题 (Researcher Plan)**:可视化编辑 + 验证减少 YAML/Front Matter 错误。 查看文档获取升级指导:[**docs.hugoblox.com**](https://docs.hugoblox.com/?utm_source=github&utm_medium=readme&utm_content=upgrade_guidance) ## ⚡️ 解锁自动化与 Premium HugoBlox 采用 **Open Core** 模式。**免费套件 (Free Kit)** 达到生产级标准,您将永远拥有您的数据和代码。 免费套件包含: - **[HugoBlox Studio](https://marketplace.visualstudio.com/items?itemName=ownable.ownable) 核心**:可视化站点配置、主题设置和内容编辑 - **模板 + 积木**,用于作品集、实验室、文档和落地页 - **Markdown/YAML 优先工作流**,具备 Hugo + Tailwind 性能 - **Notebook + LaTeX 支持**,用于技术发布 - **社区支持**,通过文档、GitHub Issues 和 Discord ### 🤖 Researcher Plan (自动化) 当您需要自动化和更低的维护开销时,升级到 [HugoBlox Studio](https://marketplace.visualstudio.com/items?itemName=ownable.ownable) 的 **Researcher Plan (研究员计划)**(需登录扩展): - **更少时间调试 YAML** (自动修复机器人 + 更安全的配置编辑) - **更少时间格式化引用** (魔法导入 + 出版物自动化) - **更少时间处理升级** (引导式维护工作流) - **更高速度** (VS Code 中的可视化编辑 + 预览) | 功能 | **免费套件** (开源) | **Researcher Plan** (自动化) | | :--- | :---: | :---: | | **站点所有权** | ✅ 100% 归您所有 | ✅ 100% 归您所有 | | **可视化页面编辑器** | ❌ | **✅ 包含** | | **AI 助手** | ⏳ 试用 | **✅ 包含** | | **GitHub 自动同步** | ❌ | **✅ 包含** | | **AI "自动修复" 机器人** (自动修复 YAML) | ❌ | **✅ 无限** | | **魔法导入** (BibTeX/DOI -> 页面) | ⏳ 试用 | **✅ 无限** | | **CV 生成器** (站点 -> PDF 简历) | ❌ | **✅ 包含** | | **私有 Discord** | ❌ | ✅ | | **支持开放科研** | 💜 | **🏆 Hero 身份** | 👉 [**查看完整功能矩阵**](https://hugoblox.com/pricing?utm_source=github&utm_medium=readme&utm_content=pricing_matrix)  •  [**升级到 Researcher Plan**](https://hugoblox.com/pricing?utm_source=github&utm_medium=readme&utm_content=cta_pro) > "HugoBlox Studio 帮我的实验室网站节省了 **40+ 小时**。可视化编辑 + BibTeX 自动更新 = **引用量提升了 3 倍**。" >
— **Dr. Sarah Yang**, AI 研究员 ### 🎨 HugoBlox Premium **获取完整套件。** 即刻访问高级模板、高级积木和社区支持,助您更快上线。 | 功能 | 开源版 | **HugoBlox Premium** | | :--- | :---: | :---: | | **核心框架** | ✅ | ✅ | | **高级模板** (SaaS, 实验室) | ❌ | **✅ 包含** | | **高级积木** | ❌ | **✅ 包含** | | **移除归属声明?** | ❌ | **✅ 包含** | | **私有 Discord** | ❌ | ✅ | | **支持开放科研** | 💜 | **🏆 Hero 身份** | 👉 [**获取 Premium 模板包**](https://hugoblox.com/premium?utm_source=github&utm_medium=readme&utm_content=cta_premium) > "用了不到 **10 分钟** 就上线了我的初创公司网站和文档。高级积木系统太天才了;新手上手时间缩短了 60%。" >
— **Alexandre Rodrigues**, 创始人 --- ## 🏢 企业级就绪(拒绝臃肿) - **随处部署**:静态输出适用于您现有的基础设施。 - **更低的运维面**:无需修补运行时应用漏洞。 - **采购友好的选项**:按需提供优先支持和商业功能。 --- ## 🗣️ 社区与支持 我们是一个由 150,000+ 研究人员、工程师和创作者组成的社区。 - **需要帮助?** 加入 [Discord 服务器](https://discord.gg/z8wNYzb) 或搜索 [文档](https://docs.hugoblox.com/)。 - **发现 Bug?** 提交 [Issue](https://github.com/HugoBlox/kit/issues)。 - **想要贡献?** 阅读我们的 [贡献指南](./CONTRIBUTING.md)。 ### 赞助商 帮助我们维持开源的可持续性。 [**❤️ 在 GitHub 上赞助**](https://github.com/sponsors/gcushen) | [**🏢 成为合作伙伴**](https://github.com/sponsors/gcushen) --- ## 许可证 Copyright © 2016-Present [**Lore Labs**](https://lore.tech/?utm_source=github&utm_medium=readme). Released under the [MIT License](./LICENSE.md).

Lore™ is a trademark of Lore Labs.

================================================ FILE: biome.json ================================================ { "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", "files": { "includes": [ "**", "!modules/**/*.html", "!**/node_modules", "!**/public", "!**/resources", "!**/_gen", "!**/assets/dist", "!**/*.min.js", "!**/*.min.css", "!**/pagefind", "!**/_vendor", "!**/vendor", "!**/*.html", "!**/layouts/**/*.html", "!**/*.webmanifest", "!**/*.backlinks.json", "!**/hugo_stats.json", "!**/*.code-workspace", "!**/modules/blox/data/icons/devicon.json", "!**/templates/**/*.html", "!**/test", "!**/modules/**/package.json", "!**/assets/jsconfig.json", "!**/docs-local", "!**/backups", "!**/modules/blox/assets/css/config/safelist.css" ] }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 150 }, "javascript": { "formatter": { "quoteStyle": "double", "trailingCommas": "all", "bracketSpacing": false }, "globals": ["PagefindUI"] }, "json": { "formatter": { "trailingCommas": "none" } }, "linter": { "enabled": true, "rules": { "recommended": true, "style": {}, "complexity": {}, "suspicious": { "noEmptyBlock": "off" }, "security": { "noDangerouslySetInnerHtml": "off" } } }, "assist": { "actions": { "source": { "organizeImports": "on" } } }, "css": { "parser": { "tailwindDirectives": true }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 150 }, "linter": { "enabled": true } } } ================================================ FILE: hugoblox.code-workspace ================================================ { "folders": [ { "path": "." } ], "settings": { "files.trimFinalNewlines": true, "editor.formatOnSaveMode": "modificationsIfAvailable", "yaml.format.enable": false, "files.exclude": { "**/node_modules/**": true, "**/public/**": true, "**/resources/**": true, "**/pagefind/**": true, "**/dist/**": true }, "search.exclude": { "**/node_modules/**": true, "**/public/**": true, "**/resources/**": true, "**/pagefind/**": true, "**/dist/**": true }, "files.watcherExclude": { "**/node_modules/**": true, "**/public/**": true, "**/resources/**": true, "**/pagefind/**": true, "**/dist/**": true }, "explorer.excludeGitIgnore": false, "workbench.editor.labelFormat": "medium", "breadcrumbs.enabled": true, "npm.packageManager": "pnpm", "editor.detectIndentation": false, "editor.formatOnSave": true, "editor.defaultFormatter": null, "editor.codeActionsOnSave": { "source.fixAll.biome": "explicit" }, "[javascript]": { "editor.defaultFormatter": "biomejs.biome" }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome" }, "[json]": { "editor.defaultFormatter": "biomejs.biome" }, "[css]": { "editor.defaultFormatter": "biomejs.biome" }, "[markdown]": { "editor.defaultFormatter": "prettier.prettier-vscode", "files.trimTrailingWhitespace": false }, "[python]": { "editor.tabSize": 4, "editor.insertSpaces": true, "editor.defaultFormatter": "charliermarsh.ruff" }, "[yaml]": { "editor.defaultFormatter": "prettier.prettier-vscode" }, "[toml]": { "editor.defaultFormatter": "prettier.prettier-vscode" }, "files.associations": { "**/layouts/**/*.html": "hugo", "**/layouts/**/*.htm": "hugo", "modules/**/*.html": "hugo", "modules/**/*.htm": "hugo", "templates/**/*.html": "hugo", "templates/**/*.htm": "hugo", "test/**/*.html": "hugo", "test/**/*.htm": "hugo" }, "[hugo]": { "editor.formatOnSave": false, "editor.defaultFormatter": null }, "emmet.excludeLanguages": [ "hugo" ], "html.format.enable": true, "biome.formatter.enabled": false, "tailwindCSS.emmetCompletions": true, "tailwindCSS.includeLanguages": { "hugo": "html" }, "tailwindCSS.experimental.classRegex": [ ":class\\s*=\\s*\"([^\"]*)\"", "x-bind:class\\s*=\\s*\"([^\"]*)\"" ], "yaml.validate": true, "[html]": { "editor.defaultFormatter": "prettier.prettier-vscode", "editor.formatOnSave": true } }, "extensions": { "recommendations": [ "redhat.vscode-yaml", "DavidAnson.vscode-markdownlint", "mikestead.dotenv", "eamodio.gitlens", "biomejs.biome", "prettier.prettier-vscode", "charliermarsh.ruff", "bradlc.vscode-tailwindcss" ] } } ================================================ FILE: modules/README.md ================================================ # HugoBlox Kit Modules Install HugoBlox features as **Hugo Modules**. ## Quick start (most sites) Add HugoBlox Kit core to `config/_default/module.yaml` (or `hugo.yaml`): ```yaml module: imports: - path: github.com/HugoBlox/kit/modules/blox ``` That’s it — **`analytics` is already included** when you use `modules/blox`. ## Module map - **Core framework**: `github.com/HugoBlox/kit/modules/blox` - Layouts, blocks (Blox), Tailwind pipeline, shortcodes, defaults - Includes: `github.com/HugoBlox/kit/modules/analytics` - **Slides (content type)**: `github.com/HugoBlox/kit/modules/slides` - Markdown slide decks (powered by Reveal.js) - **Integrations**: `github.com/HugoBlox/kit/modules/integrations/*` - Netlify: `github.com/HugoBlox/kit/modules/integrations/netlify` ## Optional installs ### Slides ```yaml module: imports: - path: github.com/HugoBlox/kit/modules/blox - path: github.com/HugoBlox/kit/modules/slides ``` ### Netlify integration (security headers + redirects outputs) ```yaml module: imports: - path: github.com/HugoBlox/kit/modules/blox - path: github.com/HugoBlox/kit/modules/integrations/netlify ``` Then enable Hugo outputs for Netlify: ```yaml outputs: home: [HTML, RSS, headers, redirects] ``` ## Updating ```bash hugo mod get -u github.com/HugoBlox/kit/modules/blox@main hugo mod tidy ``` ================================================ FILE: modules/analytics/README.md ================================================ # Analytics module **A Hugo Blox module for website analytics and search engine verification.** Are you using the `blox` module? The analytics module is already included, so you do not need to install it. For all other sites, refer to the installation guide below. ## Install Get analytics and verification for your Hugo site by following the guide below: 1. Add the module to your `config/_default/hugo.yaml`: ```yaml module: imports: - path: github.com/HugoBlox/kit/modules/analytics ``` 2. Load the module in your site's `` with: ```go {{ partial "blox-analytics/index" . }} ``` ## Usage [View the documentation](https://docs.hugoblox.com/reference/analytics/) ================================================ FILE: modules/analytics/go.mod ================================================ module github.com/HugoBlox/kit/modules/analytics go 1.19 ================================================ FILE: modules/analytics/hugo.yaml ================================================ module: mounts: - source: layouts target: layouts ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/index.html ================================================ {{/* HUGO BLOX: MARKETING MODULE */}} {{/* VERIFICATIONS */}} {{ partial "blox-analytics/verification" . }} {{/* ANALYTICS */}} {{ partial "blox-analytics/services/index" . }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/baidu_tongji.html ================================================ {{ $baidu_tongji := site.Params.hugoblox.analytics.baidu.site_id | default "" }} {{ if hugo.IsProduction | and $baidu_tongji }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/fathom.html ================================================ {{ $fathom := site.Params.hugoblox.analytics.fathom.site_id | default "" }} {{ if hugo.IsProduction | and $fathom }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/google_analytics.html ================================================ {{ $ga := site.Params.hugoblox.analytics.google.measurement_id | default "" }} {{ if hugo.IsProduction | and $ga }} {{ $gtag_config := cond (site.Params.hugoblox.privacy.anonymize_analytics | default true) "{ 'anonymize_ip': true }" "{}" }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/google_tag_manager.html ================================================ {{ $gt := site.Params.hugoblox.analytics.google_tag_manager.container_id | default "" }} {{ if hugo.IsProduction | and $gt }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/index.html ================================================ {{ partial "blox-analytics/services/google_analytics" . }} {{ partial "blox-analytics/services/google_tag_manager" . }} {{ partial "blox-analytics/services/microsoft_clarity" . }} {{ partial "blox-analytics/services/baidu_tongji" . }} {{ partial "blox-analytics/services/plausible" . }} {{ partial "blox-analytics/services/fathom" . }} {{ partial "blox-analytics/services/pirsch" . }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/microsoft_clarity.html ================================================ {{ $clarity := site.Params.hugoblox.analytics.clarity.project_id | default "" }} {{ if hugo.IsProduction | and $clarity }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/pirsch.html ================================================ {{ $pirsch := site.Params.hugoblox.analytics.pirsch.site_id | default "" }} {{ if hugo.IsProduction | and $pirsch }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/services/plausible.html ================================================ {{ $plausible := site.Params.hugoblox.analytics.plausible.domain | default "" }} {{ if hugo.IsProduction | and $plausible }} {{ end }} ================================================ FILE: modules/analytics/layouts/_partials/blox-analytics/verification.html ================================================ {{/* Site Verification with Third Party Services */}} {{- with site.Params.hugoblox.verification.google -}} {{- end -}} {{- with site.Params.hugoblox.verification.bing -}} {{- end -}} {{- with site.Params.hugoblox.verification.yandex -}} {{- end -}} {{- with site.Params.hugoblox.verification.pinterest -}} {{- end -}} {{- with site.Params.hugoblox.verification.baidu -}} {{- end -}} {{ with site.Params.hugoblox.verification.naver }} {{- end -}} ================================================ FILE: modules/blox/.npmrc ================================================ # pnpm compatibility settings auto-install-peers=true strict-peer-dependencies=false public-hoist-pattern[]=* ================================================ FILE: modules/blox/README.md ================================================ # Hugo Blox (core) The Hugo Blox web framework powered by [Tailwind CSS v4](https://tailwindcss.com/) with Hugo's native integration for styling components with Tailwind v4. ## Requirements - Hugo v0.148.2+ (Extended Edition) - Node.js v20+ - pnpm (see `packageManager` field in package.json) ## Quick Start ### 1. Install Dependencies ```bash pnpm install ``` ### 2. Run Development Server ```bash hugo server ``` Tailwind CSS is processed automatically by Hugo using the `css.TailwindCSS` function. ## Features - **Tailwind CSS v4**: Latest version with improved performance over Tailwind v3 - **Hugo Native Integration**: Uses Hugo's built-in `css.TailwindCSS` function - **Dynamic CSS Generation**: Only includes utilities actually used in your content for ultra-fast page loads - **No Pre-compilation**: CSS is generated on-demand (previously Tailwind v3 was pre-compiled in Hugo Blox as `wc.min.css`) - **Community Components**: Community components work seamlessly without manual compilation ## Configuration The Tailwind configuration is now in CSS format at `assets/css/main.css` using the `@theme` directive. The configuration includes: - Hugo Blox color schemes (primary, secondary, neutral) - Typography settings - Safelist patterns for dynamic classes - Dark mode support ## Migration from Tailwind v3 If you're upgrading from Tailwind v3: 1. Install the new dependencies: `pnpm install` 2. Remove any `assets/dist/wc.min.css` files 3. Add the `package.json` file from the latest templates 4. Update your deployment scripts to install it with `pnpm install` (refer to the latest `.github` folder in the templates) 5. The old `tailwind.config.js` and `postcss.config.js` files are no longer needed ## Development For module development: ```bash # Install dependencies pnpm install # Run development server hugo server --disableFastRender # Build for production hugo --minify ``` ## Vendor Libraries The module includes several third-party vendor libraries that are distributed with the module. These are copied from node_modules to the assets/dist/lib directory during the build process. To update the vendor libraries: ```bash # Update vendor libraries to the latest versions and rebuild pnpm vendor:update-and-build # Just rebuild vendor libraries without updating versions pnpm vendor:libs ``` The following libraries are included: - mermaid (diagrams) - plotly.js (interactive charts) - katex (math rendering) - markmap-autoloader (mind maps) - alpinejs (interactivity) - preact (interactive components) ================================================ FILE: modules/blox/archetypes/faq.md ================================================ --- title: "{{ replace .Name "-" " " | title }}" date: {{ .Date }} draft: false # Summary for SEO summary: "" # Mark this as an FAQ page to enable FAQPage structured data faq_page: true # Categories and tags categories: [] tags: [] # Pagefind search metadata (automatically indexed) # type: faq (auto-added by layout) # category: first category from categories array above # Option 1: Define FAQs inline faqs: - question: "What is your question here?" answer: "Your answer here. Can use **Markdown** formatting." - question: "Another question?" answer: "Another answer with more details." # Add more Q&As as needed # Option 2: Alternatively, create child pages under this FAQ section # and they will automatically be included # SEO settings seo: title: "" description: "" # Show breadcrumb navigation show_breadcrumb: true --- Add an introductory text here that will appear before the FAQ accordion. This is a great place to provide context about the FAQ section. ================================================ FILE: modules/blox/archetypes/questions.md ================================================ --- title: "{{ replace .Name "-" " " | title }}" date: {{ .Date }} draft: false # The question (can also use title) question: "{{ replace .Name "-" " " | title }}" # Short answer (optional - can also use content below) answer: "" # Summary for SEO and previews summary: "" # Difficulty level (optional) difficulty: "" # e.g., "Beginner", "Intermediate", "Advanced" # Categories and tags for organization categories: [] tags: [] # Pagefind search metadata (automatically indexed) # type: questions (auto-added by layout) # category: first category from categories array above # difficulty: value from difficulty field below # Vote counts (optional - for display and structured data) upvote_count: 0 downvote_count: 0 # Additional/suggested answers (optional) # suggested_answer: # - text: "Alternative answer text here..." # author: "Author Name" # date: 2024-01-15 # upvote_count: 5 # Related questions (optional - can also be auto-generated) # related: # - link-to-related-question # SEO settings seo: title: "" description: "" # Show breadcrumb navigation show_breadcrumb: true --- Write your detailed answer here using Markdown. You can include: - Code blocks - Images - Lists - Links - And more! ## Additional Details Add sections as needed to provide comprehensive information. ================================================ FILE: modules/blox/assets/css/README.md ================================================ # Hugo Blox Tailwind CSS v4 Color System ## Architecture Overview This system leverages Tailwind CSS v4's automatic utility generation to provide a comprehensive color system with minimal code. ### How It Works 1. **Theme Configuration** (`config/theme.css`) - Colors defined in `@theme` block automatically generate ALL utilities - Includes standard Tailwind colors: gray, slate, zinc, neutral, stone - Includes themeable colors: primary, secondary 2. **Theme Files** (`themes/*.css`) - Small files that override `--color-primary-*` and `--color-secondary-*` variables - Users switch themes by loading different theme CSS files - No utilities redefined - just color values changed 3. **Custom Utilities** (`color-utilities.css`) - Only 42 lines vs previous 1,228 lines! - Contains only custom colors not auto-generated (like `hb-dark`) ### Available Colors **Standard Colors (always available):** - `gray-*` - Neutral grays - `slate-*` - Cool grays - `zinc-*` - True grays - `neutral-*` - Pure grays - `stone-*` - Warm grays **Themeable Colors (vary by theme):** - `primary-*` - Main theme color - `secondary-*` - Accent theme color **Custom Colors:** - `hb-dark` - Hugo Blox brand dark color ### Auto-Generated Utilities For every color defined in `@theme`, Tailwind automatically creates: - Background: `bg-{color}-{shade}` - Text: `text-{color}-{shade}` - Border: `border-{color}-{shade}` - Hover: `hover:bg-{color}-{shade}`, `hover:text-{color}-{shade}` - Dark mode: `dark:bg-{color}-{shade}`, `dark:text-{color}-{shade}` - Gradients: `from-{color}-{shade}`, `to-{color}-{shade}` - Focus rings: `focus:ring-{color}-{shade}` - All other Tailwind color variants ### Shades Available All colors include 11 shades: `50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950` ### Usage Examples ```html
...
...
...
...
...
``` ### Benefits 1. **Dramatically Reduced File Size**: 1,228 lines → 42 lines (97% reduction!) 2. **Automatic Generation**: No manual utility definitions needed 3. **Maintainable**: Add new colors just by defining them in `@theme` 4. **Consistent**: All Tailwind variants automatically available 5. **Themeable**: Easy theme switching via CSS variable overrides ### Adding New Colors To add a new color scale: 1. Define in `config/theme.css`: ```css --color-brand-500: 59 130 246; --color-brand-600: 37 99 235; /* etc. */ ``` 2. Tailwind automatically generates all utilities: - `bg-brand-500`, `text-brand-600`, `hover:bg-brand-500`, etc. No manual utility definitions required! ================================================ FILE: modules/blox/assets/css/animations.css ================================================ /** * Hugo Blox Animations * Scroll-triggered reveals and micro-interactions */ /* Typewriter cursor */ .typewriter-cursor { display: inline-block; width: 3px; margin-left: 2px; background-color: currentColor; animation: blink 1s step-end infinite; } @keyframes blink { 50% { opacity: 0; } } /* Reveal animations base */ [x-reveal] { opacity: 0; } /* Stagger container */ [data-stagger] > [data-stagger-item] { opacity: 0; transform: translateY(20px); transition: opacity 0.5s ease-out, transform 0.5s ease-out; } [data-stagger].revealed > [data-stagger-item] { opacity: 1; transform: translateY(0); } /* Hover enhancements for cards */ .card-hover-lift { transition: transform 0.3s ease-out, box-shadow 0.3s ease-out; } .card-hover-lift:hover { transform: translateY(-4px); box-shadow: 0 12px 40px -12px rgba(0, 0, 0, 0.3); } /* Hover glow effect */ .hover-glow { position: relative; transition: all 0.3s ease-out; } .hover-glow::before { content: ""; position: absolute; inset: -2px; border-radius: inherit; background: linear-gradient(135deg, var(--color-primary-500), var(--color-secondary-500)); opacity: 0; z-index: -1; transition: opacity 0.3s ease-out; filter: blur(8px); } .hover-glow:hover::before { opacity: 0.5; } /* Icon bounce on hover */ .icon-bounce:hover { animation: iconBounce 0.5s ease-out; } @keyframes iconBounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } } /* Scale up on hover */ .scale-hover { transition: transform 0.2s ease-out; } .scale-hover:hover { transform: scale(1.05); } /* Button pulse */ .btn-pulse { position: relative; } .btn-pulse::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 0 0 0 currentColor; opacity: 0.4; animation: pulse-ring 2s infinite; } @keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 currentColor; opacity: 0.4; } 100% { box-shadow: 0 0 0 12px currentColor; opacity: 0; } } /* Float animation for background orbs */ @keyframes float { 0%, 100% { transform: translateY(0) translateX(0); } 25% { transform: translateY(-20px) translateX(10px); } 50% { transform: translateY(-10px) translateX(-10px); } 75% { transform: translateY(-30px) translateX(5px); } } .animate-float { animation: float 8s ease-in-out infinite; } /* Slow rotate for decorative elements */ @keyframes rotate-slow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .animate-rotate-slow { animation: rotate-slow 30s linear infinite; } /* Fade in up - for scroll reveals */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } .animate-fade-in-up { animation: fadeInUp 0.6s ease-out forwards; } /* Scale in - for icons/badges */ @keyframes scaleIn { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } } .animate-scale-in { animation: scaleIn 0.4s ease-out forwards; } /* Slide in from left */ @keyframes slideInLeft { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } } .animate-slide-in-left { animation: slideInLeft 0.5s ease-out forwards; } /* Respect reduced motion */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms; animation-iteration-count: 1; transition-duration: 0.01ms; } .typewriter-cursor { animation: none; opacity: 1; } [x-reveal], [data-stagger] > [data-stagger-item] { opacity: 1; transform: none; } } /* Dark mode adjustments */ .dark .hover-glow::before { opacity: 0; } .dark .hover-glow:hover::before { opacity: 0.3; } /* Dark mode icon visibility fix */ /* For icons that are dark/black and invisible on dark backgrounds */ .dark .dark-mode-icon svg, .dark .dark-mode-icon img { filter: invert(1) brightness(2); } /* Alternative: Add subtle background to icon containers */ .dark .dark-mode-icon { background: rgba(255, 255, 255, 0.08); border-radius: 0.5rem; padding: 0.25rem; } /* Hover state restores some contrast */ .dark .group:hover .dark-mode-icon svg, .dark .group:hover .dark-mode-icon img { filter: invert(1) brightness(1.5); } ================================================ FILE: modules/blox/assets/css/blox/all.css ================================================ @import "biography.css"; @import "skills.css"; @import "navbar.css"; ================================================ FILE: modules/blox/assets/css/blox/biography.css ================================================ .resume-biography { #profile { text-align: center; padding: 30px 10px; position: relative; } /* Custom avatar size on homepage - size controlled by template params */ .avatar { width: auto; height: auto; object-fit: cover; } .network-icon { display: inline-flex; flex-direction: row; flex-wrap: wrap; justify-content: center; list-style: none; padding: 0; margin: 0; } #profile .network-icon { margin-top: 0.5rem; } .network-icon li { margin-right: 10px; @media (max-width: 640px) { /* Min 48px Lighthouse tap targets on mobile */ margin-right: 12px; } } .network-icon li:last-of-type { margin-right: 0; } .network-icon li:hover { transform: scale(1.2); } .big-icon { font-size: 2rem; } .ul-interests li { font-size: 0.9rem; } .ul-edu li .description p.course { font-size: 0.9rem; } .ul-edu li .description p.institution { font-size: 0.75rem; } .network-icon .big-icon { font-size: 1.5rem; } .bio-text { max-width: 680px; } } /* Modern Biography Block Enhancements */ .resume-biography-modern { /* Ensure proper stacking context for gradients and effects */ position: relative; z-index: 1; } /* Ruby pronunciation styling - 2026+ modern design */ .hb-ruby-name { ruby-position: over; display: ruby; text-align: center; } .hb-ruby-name rt { /* Elegant, subdued annotation text */ font-size: 0.45em; font-weight: var(--hb-font-weight-body-bold, 600); letter-spacing: 0.08em; line-height: 1.2; /* Subtle gradient text for premium feel */ background: linear-gradient(135deg, var(--color-gray-500) 0%, var(--color-gray-400) 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; /* Smooth reveal animation */ opacity: 0.85; transition: opacity 0.3s ease, transform 0.3s ease; } .dark .hb-ruby-name rt { background: linear-gradient(135deg, var(--color-gray-400) 0%, var(--color-gray-300) 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } /* Hover enhancement - subtle lift */ .hb-ruby-name:hover rt { opacity: 1; transform: translateY(-1px); } /* CJK-optimized variant - larger annotation for CJK characters over Latin */ .hb-ruby-name--cjk rt { font-size: 0.5em; font-weight: 400; letter-spacing: 0.12em; } /* Latin-optimized variant - smaller annotation for romanization over CJK */ .hb-ruby-name--latin rt { font-size: 0.4em; font-weight: var(--hb-font-weight-body-bold, 600); text-transform: none; } /* Accessibility: respect reduced motion */ @media (prefers-reduced-motion: reduce) { .hb-ruby-name rt { transition: none; } .hb-ruby-name:hover rt { transform: none; } } /* Fallback styling for browsers without ruby support */ @supports not (display: ruby) { .hb-ruby-name { display: inline-block; } .hb-ruby-name rt { display: block; font-size: 0.6em; margin-bottom: 0.25em; } } /* Legacy class support */ .ruby-modern { ruby-position: over; } .ruby-modern rt { font-size: 0.7em; opacity: 0.8; letter-spacing: 0.05em; } /* Enhanced backdrop blur support */ @supports (backdrop-filter: blur(10px)) { .resume-biography-modern [class*="backdrop-blur"] { backdrop-filter: blur(10px); } } /* Smooth animations for all interactive elements */ .resume-biography-modern * { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } /* Enhanced focus states for accessibility */ .resume-biography-modern a:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: 2px; border-radius: 0.5rem; } /* Improved text selection styling */ .resume-biography-modern ::selection { background-color: color-mix(in oklch, var(--color-primary-200) 30%, transparent); color: var(--color-primary-900); } .dark .resume-biography-modern ::selection { background-color: color-mix(in oklch, var(--color-primary-800) 30%, transparent); color: var(--color-primary-100); } /* Enhanced gradient text support */ .resume-biography-modern .bg-clip-text { -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } /* Ensure text remains readable on fallback */ @supports not (background-clip: text) { .resume-biography-modern .bg-clip-text { color: var(--color-neutral-900); } .dark .resume-biography-modern .bg-clip-text { color: var(--color-neutral-100); } } .avatar-wrapper { position: relative; /* width and height controlled by template params */ margin-left: auto; margin-right: auto; } .avatar-emoji { position: absolute; width: 40px; height: 40px; line-height: 40px; border-radius: 100%; bottom: 0; right: 0; text-align: center; font-size: 20px; background-color: #fff; color: #000; /* override parent alpha */ box-shadow: 0 10px 20px rgb(0 0 0 / 4%), 0 2px 6px rgb(0 0 0 / 4%), 0 0 1px rgb(0 0 0 / 4%); } .dark .avatar-emoji { background-color: #000; box-shadow: 0 10px 20px rgb(0 0 0 / 4%), 0 2px 6px rgb(0 0 0 / 4%), 0 0 1px rgb(255 255 255 / 96%); } /* Biography Block */ .hbx-bg-gradient { position: relative; isolation: isolate; } .hbx-bg-gradient::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; background-attachment: fixed; transition: opacity 0.5s ease-in-out; opacity: 1; } /* Light Mode Gradient */ .hbx-bg-gradient::before { background-image: radial-gradient(at 20% 25%, hsla(212, 80%, 95%, 1) 0px, transparent 50%), radial-gradient(at 75% 30%, hsla(160, 80%, 95%, 1) 0px, transparent 50%), radial-gradient(at 25% 80%, hsla(280, 80%, 95%, 1) 0px, transparent 50%), radial-gradient(at 75% 85%, hsla(30, 80%, 95%, 1) 0px, transparent 50%); } /* Dark Mode Gradient */ .dark .hbx-bg-gradient::before { background-image: radial-gradient(at 20% 25%, hsla(212, 35%, 15%, 1) 0px, transparent 50%), radial-gradient(at 75% 30%, hsla(160, 35%, 15%, 1) 0px, transparent 50%), radial-gradient(at 25% 80%, hsla(280, 35%, 15%, 1) 0px, transparent 50%), radial-gradient(at 75% 85%, hsla(30, 35%, 15%, 1) 0px, transparent 50%); } ================================================ FILE: modules/blox/assets/css/blox/navbar.css ================================================ /* Navigation Styles */ .navbar { @apply relative flex flex-wrap items-center justify-between; } .navbar-brand { /* @apply text-black dark:text-white text-xl font-semibold; */ color: var(--hb-color-header-fg); @apply text-xl font-semibold; } .navbar-brand svg { @apply max-h-full max-w-full h-[1em] w-auto inline-block; } .navbar-brand img { /* To shrink to line height, add: h-[1em] */ @apply max-h-full w-auto inline-block; } /* Ensure interactive controls show hand cursor */ .theme-toggle, [data-search-toggle], #search-toggle, [data-te-collapse-init], .nav-dropdown > .nav-link[role="button"] { @apply cursor-pointer; } /* navbar toggler */ input#nav-toggle:checked + label #show-button { @apply hidden; } input#nav-toggle:checked + label #hide-button { @apply block; } input#nav-toggle:checked ~ #nav-menu { @apply block; } #site-header.header { background-color: var(--hb-color-header-bg); color: var(--hb-color-header-fg); @apply py-3 shadow; } /* navbar items */ .navbar-nav { @apply text-center lg:text-left; } .nav-link { /* @apply dark:text-white block p-3 font-semibold transition lg:px-2 lg:py-3; */ color: var(--hb-color-header-fg); @apply block p-3 font-semibold transition lg:px-2 lg:py-3; } .nav-link:hover { color: var(--color-primary-700); } .dark .nav-link:hover { color: var(--color-primary-300); } .nav-dropdown { @apply mr-0; } .nav-dropdown > svg { @apply pointer-events-none; } .nav-dropdown-list { @apply bg-white dark:bg-slate-900 z-10 min-w-[180px] rounded py-4 shadow hidden lg:invisible lg:absolute lg:block lg:opacity-0; /* Ensure dropdown appears above content and under header */ top: 100%; left: 0; } .nav-dropdown.active .nav-dropdown-list { @apply block lg:visible lg:opacity-100; } /* Ensure hover opens dropdown in desktop (CSS-driven) */ @media (min-width: 1024px) { .nav-dropdown:hover > .nav-dropdown-list { @apply visible opacity-100; } } .nav-dropdown-item { @apply px-4 [&:not(:last-child)]:mb-2; } .dark .nav-dropdown-item:hover { background-color: var(--color-primary-500); } .nav-dropdown-link { @apply dark:text-white dark:hover:text-white block py-1 font-semibold transition; } .nav-dropdown-link:hover { color: var(--color-primary-700); } ================================================ FILE: modules/blox/assets/css/blox/skills.css ================================================ /************************************************* * Hugo Blox: Skills **************************************************/ /* MOVED TO HTML */ /* .skill-group-title { */ /* display: inline-block; */ /* margin-bottom: 15px; */ /* padding-bottom: 5px; */ /* border-bottom: 2px solid #c7c7c7; */ /* font-size: 1rem; */ /* line-height: 30px; */ /* font-weight: 600; */ /* text-transform: uppercase; */ /* letter-spacing: 1px; */ /* } */ .skills-content { margin-bottom: 15px; } .skills-name { margin-bottom: 6px; /* color: #888; */ /* Inaccessible */ font-size: 1rem; letter-spacing: 1px; text-transform: uppercase; } /* .dark .skills-name { */ /* color: #eee; */ /* } */ .skills-description { margin-bottom: 6px; font-size: 0.7rem; text-transform: none; } .skills-icon { margin-right: 0.5em; } .skills-wrapper { position: relative; overflow: hidden; width: 100%; height: 10px; border: 1px solid var(--color-primary-200, #cbd5f5); border-radius: 10px; } .skills-percent { position: absolute; width: 60%; height: 10px; background-color: var(--color-primary-600, #2563eb); } ================================================ FILE: modules/blox/assets/css/chroma.css ================================================ @import "./libs/chroma/light.css"; @import "./libs/chroma/dark.css"; /* Code Blocks: Apply theme background */ /* Requires relative position for Code Copy button */ .prose .chroma, .prose pre { @apply relative rounded-md; color: var(--color-neutral-700); background-color: var(--color-neutral-50); } .dark .prose .chroma, .dark .prose pre { color: white; background-color: rgb(71 85 105); /* slate-700 equivalent */ } /* Fix LaTeX/TeX math rendering in code blocks - prevent inheriting italic from Chroma in dark mode */ .chroma .language-latex, .chroma .language-latex *, .chroma .language-tex, .chroma .language-tex * { /* biome-ignore lint/complexity/noImportantStyles: Required to override Chroma's default italic for LaTeX/TeX */ font-style: normal !important; } ================================================ FILE: modules/blox/assets/css/color-utilities.css ================================================ /* Hugo Blox Custom Color Utilities for Tailwind v4 */ /* * Standard color utilities (bg-*, text-*, border-*, hover:*, dark:*, from-*, to-*, etc.) * are automatically generated by Tailwind v4 from colors defined in @theme block. * * This file only contains custom utilities not auto-generated by Tailwind. */ @layer utilities { /* Custom Hugo Blox Dark Color */ .bg-hb-dark { background-color: var(--color-hb-dark, rgb(23 24 28)); } .text-hb-dark { color: var(--color-hb-dark, rgb(23 24 28)); } .border-hb-dark { border-color: var(--color-hb-dark, rgb(23 24 28)); } /* Dark mode variants */ .dark\:bg-hb-dark:where(.dark, .dark *) { background-color: var(--color-hb-dark, rgb(23 24 28)); } .dark\:text-hb-dark:where(.dark, .dark *) { color: var(--color-hb-dark, rgb(23 24 28)); } } /* * Available Auto-Generated Utilities (from @theme colors): * * Standard Colors: gray, slate, zinc, neutral, stone * Theme Colors: primary, secondary (overridden by theme files) * * Auto-generated utilities include: * - Background: .bg-{color}-{shade} * - Text: .text-{color}-{shade} * - Border: .border-{color}-{shade} * - Hover: .hover:bg-{color}-{shade}, .hover:text-{color}-{shade} * - Dark: .dark:bg-{color}-{shade}, .dark:text-{color}-{shade} * - Gradients: .from-{color}-{shade}, .to-{color}-{shade} * - Focus: .focus:ring-{color}-{shade} * - And all other Tailwind color variants * * Shades: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 */ ================================================ FILE: modules/blox/assets/css/components/all.css ================================================ @import "page.css"; @import "task-list.css"; @import "copy.css"; @import "sidebar-left.css"; @import "charts.css"; @import "steps.css"; @import "cards.css"; @import "math.css"; @import "notebook.css"; @import "author-notes.css"; @import "glassmorphism.css"; @import "cover.css"; ================================================ FILE: modules/blox/assets/css/components/author-notes.css ================================================ /* Author Notes Tooltip Styles */ /* Hide elements with x-cloak until Alpine.js initializes */ [x-cloak] { /* biome-ignore lint/complexity/noImportantStyles: Required to reliably hide until Alpine initializes */ display: none !important; } /* Ensure tooltip appears above other content */ .author-notes-tooltip { z-index: 9999; } /* Smooth hover effect for the info icon */ .author-notes { @apply inline-flex items-center justify-center; @apply transition-all duration-200 ease-in-out; } /* Focus styles for accessibility */ .author-notes:focus { @apply outline-none ring-2 ring-primary-500 ring-offset-2 rounded-full; } /* Additional responsive styles for mobile */ @media (max-width: 640px) { /* On mobile, tooltips should be wider if needed */ .author-notes-tooltip { white-space: normal; max-width: 200px; } } /* Print styles - show author notes inline when printing */ @media print { .author-notes { display: none; } /* Show author notes as superscript numbers in print */ .author-notes::after { display: inline; content: attr(data-tooltip); vertical-align: super; font-size: 0.75em; margin-left: 0.25em; } } ================================================ FILE: modules/blox/assets/css/components/cards.css ================================================ :root { --hb-cols: 2; } .hb-cards { grid-template-columns: repeat(auto-fill, minmax(max(250px, calc((100% - 1rem * 2) / var(--hb-cols))), 1fr)); } .hb-card { @apply flex flex-col justify-start overflow-hidden rounded-lg border border-gray-200 text-current no-underline dark:shadow-transparent hover:shadow-gray-100 dark:hover:shadow-transparent shadow-gray-100 active:shadow-sm active:shadow-gray-200 transition-all duration-200; @apply hover:border-gray-300 bg-transparent shadow-sm hover:bg-slate-50 hover:shadow-md; border-color: var(--color-neutral-700); } .dark .hb-card { border-color: var(--color-neutral-700); } .dark .hb-card:hover { border-color: var(--color-neutral-600); background-color: var(--color-neutral-800); } .hb-card-title { @apply flex font-semibold gap-2 text-gray-700 hover:text-gray-900 items-center; color: var(--color-neutral-700); } .hb-card-title:hover { color: var(--color-neutral-900); } .dark .hb-card-title { color: var(--color-neutral-200); } .dark .hb-card-title:hover { color: var(--color-neutral-50); } .hb-card-subtitle { @apply line-clamp-3 text-sm font-normal text-gray-500 dark:text-gray-400 px-4 mb-4 mt-2; } .hb-card svg { color: var(--color-neutral-700); width: 1.5rem; transition: color 0.3s ease; } .hb-card:hover svg { color: currentcolor; } .hb-card p { margin-top: 0.5rem; } .dark .hb-card svg { color: var(--color-neutral-300); } .dark .hb-card:hover svg { color: currentcolor; } ================================================ FILE: modules/blox/assets/css/components/charts.css ================================================ /* Mermaid.js diagram div */ div.mermaid { width: 100%; margin-bottom: 1rem; svg { margin-left: auto; margin-right: auto; } } /* Plotly chart */ div.chart { max-width: 100%; margin-left: auto; margin-right: auto; margin-bottom: 1rem; /* Add horizontal scroll on mobile since Plotly */ overflow-x: auto; } ================================================ FILE: modules/blox/assets/css/components/copy.css ================================================ /* Code Copy */ /* Hugo's Code Block Wrapper Class */ .highlight { @apply relative z-0; } .copy-button { @apply invisible absolute right-0 top-0 z-10 w-20 py-1 cursor-pointer font-mono text-sm whitespace-nowrap rounded-bl-md rounded-tr-md bg-neutral-200 text-neutral-700 opacity-90 dark:bg-neutral-600 dark:text-neutral-200; } /* Copy Button */ .highlight:hover > .copy-button { @apply visible; } .copy-button:hover, .copy-button:focus, .copy-button:active, .copy-button:active:hover { background-color: var(--color-primary-100); } .dark .copy-button:hover, .dark .copy-button:focus, .dark .copy-button:active, .dark .copy-button:active:hover { background-color: var(--color-primary-600); } ================================================ FILE: modules/blox/assets/css/components/cover.css ================================================ /** * Article Cover Component Styles * Notion-inspired page cover with icon overlay */ .article-cover { @apply relative w-full; /* Height is set inline via style attribute, but ensure it displays */ min-height: 200px; /* Allow icon to overflow bottom */ overflow: visible; /* Add margin for overlapping icon */ margin-bottom: 2.5rem; /* Responsive height adjustments for mobile */ @media (max-width: 768px) { height: 240px; min-height: 240px; } } /* Cover image container */ .article-cover img { @apply w-full h-full object-cover; } /* Cover icon container base styles */ .article-cover-icon { @apply flex items-center justify-center w-full h-full; transition: transform 0.2s ease-in-out; } .article-cover-icon:hover { @apply scale-105; } /* Glass morphism effect for icons */ .article-cover-icon.glass { background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(12px) saturate(180%); border: 1px solid rgba(255, 255, 255, 0.3); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } .dark .article-cover-icon.glass { background: rgba(0, 0, 0, 0.7); border-color: rgba(255, 255, 255, 0.1); } /* Fade effect styles */ .article-cover-fade { @apply absolute left-0 right-0 pointer-events-none; bottom: -1px; background: linear-gradient(to bottom, transparent, white); } .dark .article-cover-fade { background: linear-gradient(to bottom, transparent, rgb(15, 23, 42)); } /* Style variants */ .article-cover[data-cover-style="minimal"] { @apply shadow-sm; } .article-cover[data-cover-style="glass"] { @apply overflow-visible; } .article-cover[data-cover-style="gradient"] { /* Applied via inline overlay divs */ } /* Ensure cover works well with dark mode */ .dark .article-cover { @apply border-b border-gray-800; } /* Caption styles */ .article-cover .cover-caption { @apply absolute bottom-4 left-4 right-4 text-sm text-white/90; @apply bg-black/50 backdrop-blur-sm px-3 py-2 rounded-lg; } /* Responsive adjustments */ @media (max-width: 640px) { .article-cover-icon { @apply scale-90; } } /* Parallax effect support (optional feature) */ .article-cover.parallax { transform-style: preserve-3d; } .article-cover.parallax img { transform: translateZ(-1px) scale(1.5); } /* Link hover effect if cover is clickable */ .article-cover a { @apply block w-full h-full; } .article-cover a:hover img { @apply scale-105 transition-transform duration-500; } /* Print styles - show cover but optimize */ @media print { .article-cover { max-height: 200px; page-break-after: avoid; } .article-cover-fade, .article-cover-icon { @apply hidden; } } /* Accessibility: Reduced motion */ @media (prefers-reduced-motion: reduce) { .article-cover, .article-cover *, .article-cover-icon { animation: none; transition: none; } .article-cover.parallax img { transform: none; } } /* High contrast mode support */ @media (prefers-contrast: high) { .article-cover-icon { @apply border-2 border-current; } .article-cover .cover-caption { @apply bg-black text-white; } } ================================================ FILE: modules/blox/assets/css/components/glassmorphism.css ================================================ /** * 2025 Hugo Blox Glassmorphism Utility Classes * * Modern glassmorphism effects for Hugo Blox CTA cards and other components */ /* ========================================================================== Glassmorphism Base Classes ========================================================================== */ .glassmorphism-primary { @apply relative overflow-hidden; background: linear-gradient( 135deg, color-mix(in oklch, var(--color-primary-500) 90%, transparent), color-mix(in oklch, var(--color-primary-600) 95%, transparent), color-mix(in oklch, var(--color-primary-700) 90%, transparent) ); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); } .glassmorphism-primary::before { content: ""; @apply absolute inset-0 pointer-events-none; background: linear-gradient(45deg, rgb(0 0 0 / 0.1), transparent, rgb(255 255 255 / 0.1)); mix-blend-mode: overlay; } .glassmorphism-secondary { @apply relative overflow-hidden; background: linear-gradient( 135deg, color-mix(in oklch, var(--color-secondary-500) 90%, transparent), color-mix(in oklch, var(--color-secondary-600) 95%, transparent), color-mix(in oklch, var(--color-secondary-700) 90%, transparent) ); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); } .glassmorphism-secondary::before { content: ""; @apply absolute inset-0 pointer-events-none; background: linear-gradient(45deg, rgb(0 0 0 / 0.1), transparent, rgb(255 255 255 / 0.1)); mix-blend-mode: overlay; } .glassmorphism-dark { @apply relative overflow-hidden; background: linear-gradient(135deg, rgb(0 0 0 / 0.7), rgb(31 41 55 / 0.8), rgb(0 0 0 / 0.9)); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); } .glassmorphism-dark::before { content: ""; @apply absolute inset-0 pointer-events-none; background: linear-gradient(45deg, rgb(255 255 255 / 0.05), transparent, rgb(255 255 255 / 0.1)); mix-blend-mode: overlay; } .glassmorphism-light { @apply relative overflow-hidden; background: linear-gradient(135deg, rgb(255 255 255 / 0.9), rgb(248 250 252 / 0.95), rgb(241 245 249 / 0.9)); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); } .glassmorphism-light::before { content: ""; @apply absolute inset-0 pointer-events-none; background: linear-gradient(45deg, rgb(0 0 0 / 0.02), transparent, rgb(255 255 255 / 0.05)); mix-blend-mode: overlay; } /* ========================================================================== Noise Texture Classes (when used as background image) ========================================================================== */ .noise-texture { position: relative; } .noise-texture::after { content: ""; @apply absolute inset-0 pointer-events-none; background-image: url("/media/textures/noise-pattern.svg"); background-size: 100px 100px; background-repeat: repeat; opacity: 0.03; mix-blend-mode: multiply; } .dark .noise-texture::after { mix-blend-mode: screen; opacity: 0.02; } /* ========================================================================== Enhanced Ring Classes for 2025 Design ========================================================================== */ .glass-ring { @apply ring-1 ring-white/20 hover:ring-white/40 dark:ring-gray-700/50 dark:hover:ring-gray-600/70; } .glass-shadow { box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25), 0 0 0 1px rgb(255 255 255 / 0.1), inset 0 1px 0 rgb(255 255 255 / 0.1); } .dark .glass-shadow { box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5), 0 0 0 1px rgb(255 255 255 / 0.05), inset 0 1px 0 rgb(255 255 255 / 0.05); } /* ========================================================================== CTA Card Glassmorphism Overlay (works with section backgrounds) ========================================================================== */ .cta-glassmorphism { @apply relative; /* Dynamic overlay opacity control */ --glassmorphism-opacity: 0.15; /* Subtle overlay tint that works with any background */ background: linear-gradient( 135deg, rgb(255 255 255 / var(--glassmorphism-opacity)) 0%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.5)) 50%, rgb(255 255 255 / var(--glassmorphism-opacity)) 100% ); /* Enhanced glassmorphism effects */ backdrop-filter: blur(20px) saturate(1.2); -webkit-backdrop-filter: blur(20px) saturate(1.2); /* Modern border and shadow for light mode */ border: 1px solid rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.1)); box-shadow: 0 32px 64px -12px rgb(0 0 0 / 0.25), inset 0 1px 0 rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.05)); } .cta-glassmorphism:hover { /* Enhanced hover state */ background: linear-gradient( 135deg, rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.05)) 0%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.7)) 50%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.05)) 100% ); border: 1px solid rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.2)); box-shadow: 0 40px 80px -16px rgb(0 0 0 / 0.3), inset 0 1px 0 rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.1)); } /* Dark mode adjustments for CTA glassmorphism */ .dark .cta-glassmorphism { background: linear-gradient( 135deg, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.5)) 0%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.25)) 50%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.5)) 100% ); border: 1px solid rgb(255 255 255 / var(--glassmorphism-opacity)); box-shadow: 0 32px 64px -12px rgb(0 0 0 / 0.4), inset 0 1px 0 rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.5)); } .dark .cta-glassmorphism:hover { background: linear-gradient( 135deg, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.75)) 0%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.4)) 50%, rgb(255 255 255 / calc(var(--glassmorphism-opacity) * 0.75)) 100% ); border: 1px solid rgb(255 255 255 / calc(var(--glassmorphism-opacity) + 0.05)); } /* ========================================================================== CTA Button Glassmorphism (nested within CTA cards) ========================================================================== */ .cta-glassmorphism .group { /* Ensure proper text contrast in light mode */ color: var(--color-gray-900); } .dark .cta-glassmorphism .group { /* Maintain white text in dark mode */ color: var(--color-gray-100); } /* Enhanced button glassmorphism for light mode visibility */ .cta-glassmorphism .group > div:first-child { /* Light mode button background */ background: rgb(255 255 255 / 0.9); border: 1px solid rgb(0 0 0 / 0.1); box-shadow: 0 10px 25px -5px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.1), inset 0 1px 0 rgb(255 255 255 / 0.3); } .dark .cta-glassmorphism .group > div:first-child { /* Dark mode button background */ background: rgb(0 0 0 / 0.4); border: 1px solid rgb(255 255 255 / 0.2); box-shadow: 0 10px 25px -5px rgb(0 0 0 / 0.3), 0 4px 6px -2px rgb(0 0 0 / 0.2), inset 0 1px 0 rgb(255 255 255 / 0.1); } .cta-glassmorphism .group:hover > div:first-child { background: rgb(255 255 255); border: 1px solid rgb(0 0 0 / 0.15); box-shadow: 0 20px 40px -8px rgb(0 0 0 / 0.15), 0 8px 12px -4px rgb(0 0 0 / 0.1), inset 0 1px 0 rgb(255 255 255 / 0.4); } .dark .cta-glassmorphism .group:hover > div:first-child { background: rgb(0 0 0 / 0.6); border: 1px solid rgb(255 255 255 / 0.3); } ================================================ FILE: modules/blox/assets/css/components/math.css ================================================ /* Prevent long equations overflowing on small screens by scrolling horizontally instead. */ .katex-display { overflow: auto hidden; } ================================================ FILE: modules/blox/assets/css/components/notebook.css ================================================ .hb-notebook { --hb-notebook-output-max-height: 26rem; @apply relative isolate my-10 rounded-3xl border border-zinc-200/70 bg-white/90 p-6 shadow-xl shadow-primary-500/5 transition-shadow duration-300; @apply dark:border-zinc-800/70 dark:bg-zinc-900/70 dark:shadow-black/30 text-zinc-800 dark:text-zinc-50; } .hb-notebook::after { content: ""; @apply pointer-events-none absolute inset-0 rounded-3xl bg-gradient-to-r from-primary-500/5 via-transparent to-secondary-500/5 opacity-0 transition-opacity duration-300; } .hb-notebook:hover::after { @apply opacity-100; } .hb-notebook--dense { @apply p-4; } .hb-notebook-header { @apply flex flex-wrap items-start justify-between gap-4 border-b border-zinc-200/70 pb-4 dark:border-zinc-800/70; } .hb-notebook-heading { @apply space-y-1; } .hb-notebook-title { @apply text-lg font-semibold text-zinc-900 dark:text-white tracking-tight; } .hb-notebook-subtitle { @apply text-sm font-medium text-zinc-500 dark:text-zinc-400; } .hb-notebook-download { @apply inline-flex items-center gap-2 rounded-full border border-primary-500/70 px-4 py-2 text-sm font-medium text-primary-600 no-underline transition-all duration-200; @apply hover:-translate-y-0.5 hover:bg-primary-50/60 hover:text-primary-700 dark:text-primary-300 dark:border-primary-400/60 dark:hover:bg-primary-500/10; } .hb-notebook-download svg { @apply h-4 w-4; } .hb-notebook-metadata { @apply mt-4 grid gap-3 rounded-2xl border border-dashed border-zinc-200/70 px-4 py-3 text-sm; @apply dark:border-zinc-800/70; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } .hb-notebook-metadata dt { @apply text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400; } .hb-notebook-metadata dd { @apply font-medium text-zinc-800 dark:text-zinc-100; } .hb-notebook-body { @apply mt-6 flex flex-col gap-5; } .hb-notebook-cell { @apply rounded-2xl border border-zinc-200/70 bg-white p-4 shadow-sm shadow-zinc-200/60 transition-all duration-200; @apply dark:border-zinc-800/60 dark:bg-zinc-900/70 dark:shadow-none; } .hb-notebook-cell--markdown { @apply bg-gradient-to-br from-white via-white to-primary-50/40 dark:from-zinc-900 dark:via-zinc-900 dark:to-primary-900/10; } .hb-notebook-cell-header { @apply mb-3 flex flex-wrap items-center gap-3; } .hb-notebook-pill { @apply inline-flex items-center rounded-full bg-zinc-100 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-zinc-600; @apply dark:bg-zinc-800 dark:text-zinc-300; } .hb-notebook-tags { @apply flex flex-wrap gap-1; } .hb-notebook-tags span { @apply inline-flex items-center rounded-full bg-primary-100/80 px-2 py-0.5 text-[11px] font-medium text-primary-700; @apply dark:bg-primary-400/20 dark:text-primary-200; } .hb-notebook-code { @apply overflow-hidden rounded-2xl border border-zinc-900/10 bg-zinc-950/95 shadow-inner shadow-black/30; } .hb-notebook-code pre { @apply m-0 overflow-auto rounded-2xl p-5 text-sm leading-relaxed; } .hb-notebook-markdown { @apply prose-h1:text-2xl prose-h2:text-xl prose-p:leading-relaxed prose-a:text-primary-600 max-w-none; } .hb-notebook-raw { @apply rounded-xl border border-dashed border-zinc-300/80 bg-zinc-50 p-4 font-mono text-sm text-zinc-700; @apply dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200 overflow-auto; } .hb-notebook-outputs { @apply mt-4 space-y-3 rounded-2xl border border-zinc-100/80 bg-zinc-50/80 p-4; @apply dark:border-zinc-800/60 dark:bg-zinc-900/50; } .hb-notebook-output { @apply overflow-auto rounded-xl border border-transparent bg-white/90 p-3 text-sm leading-relaxed text-zinc-700; @apply dark:bg-zinc-950/50 dark:text-zinc-100; max-height: var(--hb-notebook-output-max-height, 26rem); } .hb-notebook-output--stream { @apply font-mono bg-zinc-900 text-zinc-100; } .hb-notebook-output--error { @apply border-red-200 bg-red-50/90 text-red-700 dark:border-red-500/30 dark:bg-red-500/10 dark:text-red-200; } .hb-notebook-output--image { @apply bg-transparent p-0 border-none; } .hb-notebook-output--image img, .hb-notebook-output--image svg { @apply h-auto w-full rounded-xl border border-zinc-100/80 bg-white object-contain dark:border-zinc-800/60 dark:bg-zinc-900; } .hb-notebook-output--markdown { @apply bg-transparent p-0 border-none; } .hb-notebook-output pre { @apply m-0; } .hb-notebook-output code { @apply font-mono text-sm; } .hb-notebook-empty { @apply mt-4 rounded-2xl border border-dashed border-zinc-300/70 bg-zinc-50/80 px-4 py-3 text-center text-sm text-zinc-500; @apply dark:border-zinc-700 dark:bg-zinc-900/40 dark:text-zinc-300; } ================================================ FILE: modules/blox/assets/css/components/page.css ================================================ /* Page layout to push footer to bottom of page */ .page-wrapper { /* Min height = viewport height - navbar height */ min-height: 100vh; display: grid; grid-template-rows: auto 1fr auto; grid-template-columns: 100%; } .page-header, .page-footer { flex-shrink: 0; } .page-body { flex-grow: 1; } .article-header { position: relative; /* Required for caption positioning */ clear: both; } .article-banner { width: 100%; height: 260px; object-fit: cover; /* @include media-breakpoint-up(lg) { */ /* height: 310px; !* Increased height on desktop *! */ /* } */ } .featured-image-wrapper { position: relative; padding-left: 0; /* Override container padding. */ padding-right: 0; /* Override container padding. */ } .featured-image { position: relative; width: 100%; display: block; margin: 0 auto; } .article-header-caption { position: absolute; bottom: 0; right: 0; margin: 0 auto; padding: 2px 5px; color: #fff; font-size: 0.7em; background: #000; text-align: right; z-index: 5; opacity: 0.65; border-radius: 5px 0 0; } @media (min-width: 64em) { .article-header-caption { padding: 5px 10px; } } .article-header-caption a { color: #fff; text-decoration: none; } #page-bg { position: fixed; left: 0; right: 0; height: 100%; width: 100%; z-index: -1; display: block; } .backlink { @apply text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50; } /* For ToC shortcode, Spoiler shortcode, and direct HTML Details snippets. */ details > summary { @apply cursor-pointer font-semibold; color: var(--color-primary-700); } .dark details > summary { color: var(--color-primary-300); } ================================================ FILE: modules/blox/assets/css/components/sidebar-left.css ================================================ /* Match Tailwind lg (default 1024px): https://tailwindcss.com/docs/screens */ @media (max-width: 1024px) { .hb-sidebar-container { @apply fixed top-0 w-full bottom-0 z-[15] pt-[calc(var(--navbar-height))] overscroll-contain; contain: layout style; transition: transform 0.8s cubic-bezier(0.52, 0.16, 0.04, 1); will-change: transform, opacity; backface-visibility: hidden; } } .hb-sidebar-container { @apply flex flex-col print:hidden lg:top-16 lg:shrink-0 lg:w-64 lg:self-start; li > div { @apply h-0; } li.open > div { @apply h-auto pt-1; } li.open > a > span > svg > path { @apply rotate-90; } } .hb-sidebar-list { @apply relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0; } .hb-sidebar-list::before { background-color: var(--color-neutral-200); } .dark .hb-sidebar-list::before { background-color: var(--color-neutral-700); } .hb-scrollbar { @apply overflow-y-auto overflow-x-hidden p-4 grow; scrollbar-width: thin; scrollbar-color: oklch(55.55% 0 0 / 40%) transparent; scrollbar-gutter: stable; &::-webkit-scrollbar { @apply w-3 h-3; } &::-webkit-scrollbar-track { @apply bg-transparent; } &::-webkit-scrollbar-thumb { @apply rounded-[10px]; } &:hover::-webkit-scrollbar-thumb { border: 3px solid transparent; background-color: var(--tw-shadow-color); background-clip: content-box; @apply shadow-neutral-500/20 hover:shadow-neutral-500/40; } } .hb-docs-link { @apply flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-50; } .dark .hb-docs-link:hover { background-color: color-mix(in oklch, var(--color-primary-100) 5%, transparent); } .hb-sidebar-mobile-menu { @apply [transition:background-color_0.5s_ease]; } .hb-sidebar-mobile-toc { @apply flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3; } .hb-sidebar-mobile-toc::before { background-color: var(--color-neutral-200); } .dark .hb-sidebar-mobile-toc::before { background-color: var(--color-neutral-800); } .hb-sidebar-custom-link { @apply flex items-center justify-between gap-2 cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]; } ================================================ FILE: modules/blox/assets/css/components/steps.css ================================================ .hb-steps { @apply ml-4 mb-12 pl-6 border-l border-gray-200 [counter-reset:hb_step]; border-left-color: var(--color-neutral-200); } .dark .hb-steps { border-left-color: var(--color-neutral-600); } .hb-steps h3 { counter-increment: hb-step; &::before { @apply absolute w-[33px] h-[33px]; @apply rounded-full border-4 border-white dark:border-slate-300; @apply bg-gray-100 dark:bg-hb-dark; @apply text-base font-normal text-center -indent-px; @apply mt-[3px] ml-[-41px]; color: var(--color-neutral-700); content: counter(hb-step); } } .dark .hb-steps h3::before { color: var(--color-neutral-200); } ================================================ FILE: modules/blox/assets/css/components/task-list.css ================================================ /* HugoBlox Kit - https://hugoblox.com * Task List Component * License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */ ul.task-list { list-style: none; } ul.task-list li input[type="checkbox"] { margin-right: 0.5rem; } ul.task-list input[type="checkbox"]:checked { appearance: none; width: 1em; height: 1em; border: none; background: initial; position: relative; } ul.task-list input[type="checkbox"]:not(:checked) { width: 0.9em; height: 0.9em; } ul.task-list input[type="checkbox"]:checked::after { content: "✅"; } ================================================ FILE: modules/blox/assets/css/config/safelist.css ================================================ /* Safelist patterns for dynamic classes */ /* Note: In v4, we use @source inline to ensure these are included */ /* This ensures Tailwind generates these classes even if not found in templates */ /* Inline safelist for classes used in dynamic content and YAML configuration */ /* Includes search modal Quick Actions dynamic color classes */ @source inline("
"); /* Force generation of all CSS custom properties for dynamic usage in YAML front matter */ /* Hidden utility class that forces all color variables to be generated */ .force-all-color-vars { /* Primary Colors */ color: var(--color-primary-50); color: var(--color-primary-100); color: var(--color-primary-200); color: var(--color-primary-300); color: var(--color-primary-400); color: var(--color-primary-500); color: var(--color-primary-600); color: var(--color-primary-700); color: var(--color-primary-800); color: var(--color-primary-900); color: var(--color-primary-950); /* Secondary Colors */ color: var(--color-secondary-50); color: var(--color-secondary-100); color: var(--color-secondary-200); color: var(--color-secondary-300); color: var(--color-secondary-400); color: var(--color-secondary-500); color: var(--color-secondary-600); color: var(--color-secondary-700); color: var(--color-secondary-800); color: var(--color-secondary-900); color: var(--color-secondary-950); /* Extended Color Palette for Dynamic Gradients */ color: var(--color-indigo-50); color: var(--color-indigo-100); color: var(--color-indigo-200); color: var(--color-indigo-300); color: var(--color-indigo-400); color: var(--color-indigo-500); color: var(--color-indigo-600); color: var(--color-indigo-700); color: var(--color-indigo-800); color: var(--color-indigo-900); color: var(--color-indigo-950); color: var(--color-purple-50); color: var(--color-purple-100); color: var(--color-purple-200); color: var(--color-purple-300); color: var(--color-purple-400); color: var(--color-purple-500); color: var(--color-purple-600); color: var(--color-purple-700); color: var(--color-purple-800); color: var(--color-purple-900); color: var(--color-purple-950); color: var(--color-pink-50); color: var(--color-pink-100); color: var(--color-pink-200); color: var(--color-pink-300); color: var(--color-pink-400); color: var(--color-pink-500); color: var(--color-pink-600); color: var(--color-pink-700); color: var(--color-pink-800); color: var(--color-pink-900); color: var(--color-pink-950); color: var(--color-red-50); color: var(--color-red-100); color: var(--color-red-200); color: var(--color-red-300); color: var(--color-red-400); color: var(--color-red-500); color: var(--color-red-600); color: var(--color-red-700); color: var(--color-red-800); color: var(--color-red-900); color: var(--color-red-950); color: var(--color-orange-50); color: var(--color-orange-100); color: var(--color-orange-200); color: var(--color-orange-300); color: var(--color-orange-400); color: var(--color-orange-500); color: var(--color-orange-600); color: var(--color-orange-700); color: var(--color-orange-800); color: var(--color-orange-900); color: var(--color-orange-950); color: var(--color-amber-50); color: var(--color-amber-100); color: var(--color-amber-200); color: var(--color-amber-300); color: var(--color-amber-400); color: var(--color-amber-500); color: var(--color-amber-600); color: var(--color-amber-700); color: var(--color-amber-800); color: var(--color-amber-900); color: var(--color-amber-950); color: var(--color-yellow-50); color: var(--color-yellow-100); color: var(--color-yellow-200); color: var(--color-yellow-300); color: var(--color-yellow-400); color: var(--color-yellow-500); color: var(--color-yellow-600); color: var(--color-yellow-700); color: var(--color-yellow-800); color: var(--color-yellow-900); color: var(--color-yellow-950); color: var(--color-lime-50); color: var(--color-lime-100); color: var(--color-lime-200); color: var(--color-lime-300); color: var(--color-lime-400); color: var(--color-lime-500); color: var(--color-lime-600); color: var(--color-lime-700); color: var(--color-lime-800); color: var(--color-lime-900); color: var(--color-lime-950); color: var(--color-green-50); color: var(--color-green-100); color: var(--color-green-200); color: var(--color-green-300); color: var(--color-green-400); color: var(--color-green-500); color: var(--color-green-600); color: var(--color-green-700); color: var(--color-green-800); color: var(--color-green-900); color: var(--color-green-950); color: var(--color-emerald-50); color: var(--color-emerald-100); color: var(--color-emerald-200); color: var(--color-emerald-300); color: var(--color-emerald-400); color: var(--color-emerald-500); color: var(--color-emerald-600); color: var(--color-emerald-700); color: var(--color-emerald-800); color: var(--color-emerald-900); color: var(--color-emerald-950); color: var(--color-teal-50); color: var(--color-teal-100); color: var(--color-teal-200); color: var(--color-teal-300); color: var(--color-teal-400); color: var(--color-teal-500); color: var(--color-teal-600); color: var(--color-teal-700); color: var(--color-teal-800); color: var(--color-teal-900); color: var(--color-teal-950); color: var(--color-cyan-50); color: var(--color-cyan-100); color: var(--color-cyan-200); color: var(--color-cyan-300); color: var(--color-cyan-400); color: var(--color-cyan-500); color: var(--color-cyan-600); color: var(--color-cyan-700); color: var(--color-cyan-800); color: var(--color-cyan-900); color: var(--color-cyan-950); color: var(--color-sky-50); color: var(--color-sky-100); color: var(--color-sky-200); color: var(--color-sky-300); color: var(--color-sky-400); color: var(--color-sky-500); color: var(--color-sky-600); color: var(--color-sky-700); color: var(--color-sky-800); color: var(--color-sky-900); color: var(--color-sky-950); color: var(--color-blue-50); color: var(--color-blue-100); color: var(--color-blue-200); color: var(--color-blue-300); color: var(--color-blue-400); color: var(--color-blue-500); color: var(--color-blue-600); color: var(--color-blue-700); color: var(--color-blue-800); color: var(--color-blue-900); color: var(--color-blue-950); color: var(--color-violet-50); color: var(--color-violet-100); color: var(--color-violet-200); color: var(--color-violet-300); color: var(--color-violet-400); color: var(--color-violet-500); color: var(--color-violet-600); color: var(--color-violet-700); color: var(--color-violet-800); color: var(--color-violet-900); color: var(--color-violet-950); /* Never display this class */ display: none !important; } /* Support for dual light/dark background colors in parse_block_v2.html */ @media (prefers-color-scheme: dark) { .home-section-bg[style*="--dark-bg-color"] { background-color: var(--dark-bg-color) !important; } } .dark .home-section-bg[style*="--dark-bg-color"] { background-color: var(--dark-bg-color) !important; } ================================================ FILE: modules/blox/assets/css/config/tailwind.css ================================================ /* Tailwind CSS v4 Configuration */ /* Content detection and plugin configuration */ /* Typography plugin for prose styles */ @plugin "@tailwindcss/typography"; /* Content detection sources */ /* Note: @source is a Tailwind v4 directive - linters may show warnings that can be ignored */ /* Hugo stats file contains all detected classes from templates */ @source "hugo_stats.json"; /* Custom Variants Configuration */ /* Configure dark mode to use class strategy */ @custom-variant dark (&:where(.dark, .dark *)); /* Configure hover to work on all devices (like v3 behavior) */ @custom-variant hover (&:hover); /* Dark mode configuration */ @media (prefers-color-scheme: dark) { :root { color-scheme: dark; } } ================================================ FILE: modules/blox/assets/css/config/theme.css ================================================ /* Tailwind CSS v4 Hugo BloxTheme Configuration */ /* Theme Configuration */ @theme { /* Custom Colors */ --color-hb-dark: rgb(23 24 28); /* Standard Tailwind Color Scales - Provide variables as valid CSS colors */ /* Gray */ --color-gray-50: rgb(249 250 251); --color-gray-100: rgb(243 244 246); --color-gray-200: rgb(229 231 235); --color-gray-300: rgb(209 213 219); --color-gray-400: rgb(156 163 175); --color-gray-500: rgb(107 114 128); --color-gray-600: rgb(75 85 99); --color-gray-700: rgb(55 65 81); --color-gray-800: rgb(31 41 55); --color-gray-900: rgb(17 24 39); --color-gray-950: rgb(3 7 18); /* Slate */ --color-slate-50: rgb(248 250 252); --color-slate-100: rgb(241 245 249); --color-slate-200: rgb(226 232 240); --color-slate-300: rgb(203 213 225); --color-slate-400: rgb(148 163 184); --color-slate-500: rgb(100 116 139); --color-slate-600: rgb(71 85 105); --color-slate-700: rgb(51 65 85); --color-slate-800: rgb(30 41 59); --color-slate-900: rgb(15 23 42); --color-slate-950: rgb(2 6 23); /* Zinc */ --color-zinc-50: rgb(250 250 250); --color-zinc-100: rgb(244 244 245); --color-zinc-200: rgb(228 228 231); --color-zinc-300: rgb(212 212 216); --color-zinc-400: rgb(161 161 170); --color-zinc-500: rgb(113 113 122); --color-zinc-600: rgb(82 82 91); --color-zinc-700: rgb(63 63 70); --color-zinc-800: rgb(39 39 42); --color-zinc-900: rgb(24 24 27); --color-zinc-950: rgb(9 9 11); /* Neutral */ --color-neutral-50: rgb(250 250 250); --color-neutral-100: rgb(245 245 245); --color-neutral-200: rgb(229 229 229); --color-neutral-300: rgb(212 212 212); --color-neutral-400: rgb(163 163 163); --color-neutral-500: rgb(115 115 115); --color-neutral-600: rgb(82 82 82); --color-neutral-700: rgb(64 64 64); --color-neutral-800: rgb(38 38 38); --color-neutral-900: rgb(23 23 23); --color-neutral-950: rgb(10 10 10); /* Stone */ --color-stone-50: rgb(250 250 249); --color-stone-100: rgb(245 245 244); --color-stone-200: rgb(231 229 228); --color-stone-300: rgb(214 211 209); --color-stone-400: rgb(168 162 158); --color-stone-500: rgb(120 113 108); --color-stone-600: rgb(87 83 78); --color-stone-700: rgb(68 64 60); --color-stone-800: rgb(41 37 36); --color-stone-900: rgb(28 25 23); --color-stone-950: rgb(12 10 9); /* Red */ --color-red-50: rgb(254 242 242); --color-red-100: rgb(254 226 226); --color-red-200: rgb(254 202 202); --color-red-300: rgb(252 165 165); --color-red-400: rgb(248 113 113); --color-red-500: rgb(239 68 68); --color-red-600: rgb(220 38 38); --color-red-700: rgb(185 28 28); --color-red-800: rgb(153 27 27); --color-red-900: rgb(127 29 29); --color-red-950: rgb(69 10 10); /* Orange */ --color-orange-50: rgb(255 247 237); --color-orange-100: rgb(255 237 213); --color-orange-200: rgb(254 215 170); --color-orange-300: rgb(253 186 116); --color-orange-400: rgb(251 146 60); --color-orange-500: rgb(249 115 22); --color-orange-600: rgb(234 88 12); --color-orange-700: rgb(194 65 12); --color-orange-800: rgb(154 52 18); --color-orange-900: rgb(124 45 18); --color-orange-950: rgb(67 20 7); /* Amber */ --color-amber-50: rgb(255 251 235); --color-amber-100: rgb(254 243 199); --color-amber-200: rgb(253 230 138); --color-amber-300: rgb(252 211 77); --color-amber-400: rgb(251 191 36); --color-amber-500: rgb(245 158 11); --color-amber-600: rgb(217 119 6); --color-amber-700: rgb(180 83 9); --color-amber-800: rgb(146 64 14); --color-amber-900: rgb(120 53 15); --color-amber-950: rgb(69 26 3); /* Yellow */ --color-yellow-50: rgb(254 252 232); --color-yellow-100: rgb(254 249 195); --color-yellow-200: rgb(254 240 138); --color-yellow-300: rgb(253 224 71); --color-yellow-400: rgb(250 204 21); --color-yellow-500: rgb(234 179 8); --color-yellow-600: rgb(202 138 4); --color-yellow-700: rgb(161 98 7); --color-yellow-800: rgb(133 77 14); --color-yellow-900: rgb(113 63 18); --color-yellow-950: rgb(66 32 6); /* Lime */ --color-lime-50: rgb(247 254 231); --color-lime-100: rgb(236 252 203); --color-lime-200: rgb(217 249 157); --color-lime-300: rgb(190 242 100); --color-lime-400: rgb(163 230 53); --color-lime-500: rgb(132 204 22); --color-lime-600: rgb(101 163 13); --color-lime-700: rgb(77 124 15); --color-lime-800: rgb(63 98 18); --color-lime-900: rgb(54 83 20); --color-lime-950: rgb(26 46 5); /* Green */ --color-green-50: rgb(240 253 244); --color-green-100: rgb(220 252 231); --color-green-200: rgb(187 247 208); --color-green-300: rgb(134 239 172); --color-green-400: rgb(74 222 128); --color-green-500: rgb(34 197 94); --color-green-600: rgb(22 163 74); --color-green-700: rgb(21 128 61); --color-green-800: rgb(22 101 52); --color-green-900: rgb(20 83 45); --color-green-950: rgb(5 46 22); /* Emerald */ --color-emerald-50: rgb(236 253 245); --color-emerald-100: rgb(209 250 229); --color-emerald-200: rgb(167 243 208); --color-emerald-300: rgb(110 231 183); --color-emerald-400: rgb(52 211 153); --color-emerald-500: rgb(16 185 129); --color-emerald-600: rgb(5 150 105); --color-emerald-700: rgb(4 120 87); --color-emerald-800: rgb(6 95 70); --color-emerald-900: rgb(6 78 59); --color-emerald-950: rgb(2 44 34); /* Teal */ --color-teal-50: rgb(240 253 250); --color-teal-100: rgb(204 251 241); --color-teal-200: rgb(153 246 228); --color-teal-300: rgb(94 234 212); --color-teal-400: rgb(45 212 191); --color-teal-500: rgb(20 184 166); --color-teal-600: rgb(13 148 136); --color-teal-700: rgb(15 118 110); --color-teal-800: rgb(17 94 89); --color-teal-900: rgb(19 78 74); --color-teal-950: rgb(4 47 46); /* Cyan */ --color-cyan-50: rgb(236 254 255); --color-cyan-100: rgb(207 250 254); --color-cyan-200: rgb(165 243 252); --color-cyan-300: rgb(103 232 249); --color-cyan-400: rgb(34 211 238); --color-cyan-500: rgb(6 182 212); --color-cyan-600: rgb(8 145 178); --color-cyan-700: rgb(14 116 144); --color-cyan-800: rgb(21 94 117); --color-cyan-900: rgb(22 78 99); --color-cyan-950: rgb(8 51 68); /* Sky */ --color-sky-50: rgb(240 249 255); --color-sky-100: rgb(224 242 254); --color-sky-200: rgb(186 230 253); --color-sky-300: rgb(125 211 252); --color-sky-400: rgb(56 189 248); --color-sky-500: rgb(14 165 233); --color-sky-600: rgb(2 132 199); --color-sky-700: rgb(3 105 161); --color-sky-800: rgb(7 89 133); --color-sky-900: rgb(12 74 110); --color-sky-950: rgb(8 47 73); /* Blue */ --color-blue-50: rgb(239 246 255); --color-blue-100: rgb(219 234 254); --color-blue-200: rgb(191 219 254); --color-blue-300: rgb(147 197 253); --color-blue-400: rgb(96 165 250); --color-blue-500: rgb(59 130 246); --color-blue-600: rgb(37 99 235); --color-blue-700: rgb(29 78 216); --color-blue-800: rgb(30 64 175); --color-blue-900: rgb(30 58 138); --color-blue-950: rgb(23 37 84); /* Indigo */ --color-indigo-50: rgb(238 242 255); --color-indigo-100: rgb(224 231 255); --color-indigo-200: rgb(199 210 254); --color-indigo-300: rgb(165 180 252); --color-indigo-400: rgb(129 140 248); --color-indigo-500: rgb(99 102 241); --color-indigo-600: rgb(79 70 229); --color-indigo-700: rgb(67 56 202); --color-indigo-800: rgb(55 48 163); --color-indigo-900: rgb(49 46 129); --color-indigo-950: rgb(30 27 75); /* Violet */ --color-violet-50: rgb(245 243 255); --color-violet-100: rgb(237 233 254); --color-violet-200: rgb(221 214 254); --color-violet-300: rgb(196 181 253); --color-violet-400: rgb(167 139 250); --color-violet-500: rgb(139 92 246); --color-violet-600: rgb(124 58 237); --color-violet-700: rgb(109 40 217); --color-violet-800: rgb(91 33 182); --color-violet-900: rgb(76 29 149); --color-violet-950: rgb(46 16 101); /* Purple */ --color-purple-50: rgb(250 245 255); --color-purple-100: rgb(243 232 255); --color-purple-200: rgb(233 213 255); --color-purple-300: rgb(216 180 254); --color-purple-400: rgb(192 132 252); --color-purple-500: rgb(168 85 247); --color-purple-600: rgb(147 51 234); --color-purple-700: rgb(126 34 206); --color-purple-800: rgb(107 33 168); --color-purple-900: rgb(88 28 135); --color-purple-950: rgb(59 7 100); /* Fuchsia */ --color-fuchsia-50: rgb(253 244 255); --color-fuchsia-100: rgb(250 232 255); --color-fuchsia-200: rgb(245 208 254); --color-fuchsia-300: rgb(240 171 252); --color-fuchsia-400: rgb(232 121 249); --color-fuchsia-500: rgb(217 70 239); --color-fuchsia-600: rgb(192 38 211); --color-fuchsia-700: rgb(162 28 175); --color-fuchsia-800: rgb(134 25 143); --color-fuchsia-900: rgb(112 26 117); --color-fuchsia-950: rgb(74 4 78); /* Pink */ --color-pink-50: rgb(253 242 248); --color-pink-100: rgb(252 231 243); --color-pink-200: rgb(251 207 232); --color-pink-300: rgb(249 168 212); --color-pink-400: rgb(244 114 182); --color-pink-500: rgb(236 72 153); --color-pink-600: rgb(219 39 119); --color-pink-700: rgb(190 24 93); --color-pink-800: rgb(157 23 77); --color-pink-900: rgb(131 24 67); --color-pink-950: rgb(80 7 36); /* Rose */ --color-rose-50: rgb(255 241 242); --color-rose-100: rgb(255 228 230); --color-rose-200: rgb(254 205 211); --color-rose-300: rgb(253 164 175); --color-rose-400: rgb(251 113 133); --color-rose-500: rgb(244 63 94); --color-rose-600: rgb(225 29 72); --color-rose-700: rgb(190 18 60); --color-rose-800: rgb(159 18 57); --color-rose-900: rgb(136 19 55); --color-rose-950: rgb(76 5 25); /* Themeable Colors */ --color-primary-50: rgb(var(--hb-primary-50-rgb, 239 246 255)); --color-primary-100: rgb(var(--hb-primary-100-rgb, 219 234 254)); --color-primary-200: rgb(var(--hb-primary-200-rgb, 191 219 254)); --color-primary-300: rgb(var(--hb-primary-300-rgb, 147 197 253)); --color-primary-400: rgb(var(--hb-primary-400-rgb, 96 165 250)); --color-primary-500: rgb(var(--hb-primary-500-rgb, 59 130 246)); --color-primary-600: rgb(var(--hb-primary-600-rgb, 37 99 235)); --color-primary-700: rgb(var(--hb-primary-700-rgb, 29 78 216)); --color-primary-800: rgb(var(--hb-primary-800-rgb, 30 64 175)); --color-primary-900: rgb(var(--hb-primary-900-rgb, 30 58 138)); --color-primary-950: rgb(var(--hb-primary-950-rgb, 23 37 84)); /* Semantic UI Colors - Defined in theme_generator.html */ /* Do not redeclare them here to avoid circular references */ --color-secondary-50: rgb(var(--hb-secondary-50-rgb, 236 254 255)); --color-secondary-100: rgb(var(--hb-secondary-100-rgb, 207 250 254)); --color-secondary-200: rgb(var(--hb-secondary-200-rgb, 165 243 252)); --color-secondary-300: rgb(var(--hb-secondary-300-rgb, 103 232 249)); --color-secondary-400: rgb(var(--hb-secondary-400-rgb, 34 211 238)); --color-secondary-500: rgb(var(--hb-secondary-500-rgb, 6 182 212)); --color-secondary-600: rgb(var(--hb-secondary-600-rgb, 8 145 178)); --color-secondary-700: rgb(var(--hb-secondary-700-rgb, 14 116 144)); --color-secondary-800: rgb(var(--hb-secondary-800-rgb, 21 94 117)); --color-secondary-900: rgb(var(--hb-secondary-900-rgb, 22 78 99)); --color-secondary-950: rgb(var(--hb-secondary-950-rgb, 8 51 68)); /* Note: Providing these palettes in @theme ensures theme-pack mappings like var(--color-rose-600) always resolve */ /* Font families */ --hb-font-family-sans: inter var, ui-sans-serif, system-ui, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; --hb-font-heading: var(--hb-font-family-sans); --hb-font-body: var(--hb-font-family-sans); --hb-font-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --hb-font-nav: var(--hb-font-heading); /* Font weights */ --hb-font-weight-heading: 700; --hb-font-weight-body: 400; --hb-font-weight-body-bold: 600; /* Line heights */ --hb-font-leading-heading: 1.2; --hb-font-leading-body: 1.6; --hb-font-leading-code: 1.5; /* Letter spacing */ --hb-font-tracking-heading: -0.02em; --hb-font-tracking-body: 0; --hb-font-tracking-caps: 0.05em; /* Font sizes */ --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --font-size-xl: 1.25rem; --font-size-2xl: 1.5rem; --font-size-3xl: 1.875rem; --font-size-4xl: 2.25rem; --font-size-5xl: 3rem; --font-size-6xl: 4rem; } ================================================ FILE: modules/blox/assets/css/framework/base.css ================================================ /* Base styles for better text rendering */ @layer base { html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizelegibility; /* Apply the runtime font vars injected by Hugo's typography partial */ font-family: var(--hb-font-body); } body { font-family: var(--hb-font-body); font-weight: var(--hb-font-weight-body, 400); line-height: var(--hb-font-leading-body, 1.6); letter-spacing: var(--hb-font-tracking-body, 0); } h1, h2, h3, h4, h5, h6 { font-family: var(--hb-font-heading); font-weight: var(--hb-font-weight-heading, 700); line-height: var(--hb-font-leading-heading, 1.2); letter-spacing: var(--hb-font-tracking-heading, -0.02em); } code, pre, kbd, samp { font-family: var(--hb-font-code); } } /* Gradient Mesh Animations */ @keyframes float { 0%, 100% { transform: translateY(0) translateX(0); } 25% { transform: translateY(-20px) translateX(10px); } 50% { transform: translateY(-10px) translateX(-10px); } 75% { transform: translateY(-30px) translateX(5px); } } @keyframes rotate-slow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .animate-float { animation: float 8s ease-in-out infinite; } .animate-rotate-slow { animation: rotate-slow 20s linear infinite; } /* Custom utilities and components */ @utility task-list { list-style: none; padding-left: 1.5rem; } /* Custom typography styles - the plugin handles the base styles */ /* Additional customization for prose elements */ @layer components { .prose a { text-decoration: underline; text-decoration-color: var(--color-primary-300); font-weight: var(--hb-font-weight-body-bold, 600); } .prose a:hover { color: var(--color-primary-600); text-decoration: none; border-radius: 0.09rem; } .prose mark { color: var(--color-neutral-900); background-color: var(--color-primary-200); padding: 0.1rem 0.2rem; border-radius: 0.25rem; } .dark .prose-invert a { text-decoration-color: var(--color-neutral-500); } .dark .prose-invert a:hover { color: var(--color-primary-300); } .dark .prose-invert mark { background-color: var(--color-primary-400); color: black; } /* Inline Code Styling */ .prose code:not(:where(pre *)) { @apply rounded-md bg-neutral-100 px-1.5 py-0.5 text-[0.875em] font-normal text-primary-700; @apply dark:bg-neutral-700/50 dark:text-primary-300; } .prose code:not(:where(pre *))::before, .prose code:not(:where(pre *))::after { content: none; } } ================================================ FILE: modules/blox/assets/css/framework/components.css ================================================ /* Hugo Blox Framework Custom Classes */ @layer components { /* Section styles for Hugo Blox blocks */ .hbb-section { padding-top: 6rem; padding-bottom: 6rem; } .section-subheading { font-size: 1.25rem; font-weight: var(--hb-font-weight-heading, 700); } /* Home section background styles */ .home-section-bg { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: -1; } .home-section-bg.bg-image { background-position: center; background-repeat: no-repeat; background-size: cover; } /* 2025 Glassmorphism texture support - disable conflicting defaults */ .home-section-bg.bg-image[style*="background-size"][style*="background-repeat"] { /* biome-ignore lint/complexity/noImportantStyles: Required to override inline background-size for glass textures */ background-size: revert !important; /* biome-ignore lint/complexity/noImportantStyles: Required to override inline background-repeat for glass textures */ background-repeat: revert !important; /* biome-ignore lint/complexity/noImportantStyles: Required to override inline background-position for glass textures */ background-position: revert !important; } /* Specific glassmorphism texture class override */ .blox-cta-card .home-section-bg.bg-image { background-size: revert; background-repeat: revert; background-position: revert; } /* Video background */ .bg-video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 1; } /* Flip video horizontally */ .bg-video.flip { transform: scaleX(-1); } /* Container styles */ .universal-wrapper { margin: 0 auto; padding-right: 1rem; padding-left: 1rem; width: 100%; } @media (min-width: 1200px) { .universal-wrapper { max-width: 1200px; } } .article-container { max-width: 760px; margin: 0 auto; } /* Button toolbar */ .btn-toolbar { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; } /* Documentation specific */ .docs-article-container { max-width: 760px; } /* Powered-by footer styles */ .powered-by { font-size: 0.75rem; } .powered-by a { color: inherit; text-decoration: none; } .powered-by a:hover { text-decoration: underline; } /* Parallax effect */ .parallax { background-attachment: fixed; background-position: center; background-repeat: no-repeat; background-size: cover; position: relative; } /* When parallax is used with home-section-bg, preserve absolute positioning */ .home-section-bg.parallax { position: absolute; } /* Section color schemes - for backward compatibility */ section.light { background-color: transparent; } section.dark { background-color: transparent; } } ================================================ FILE: modules/blox/assets/css/hb-search.css ================================================ /* Hugo Blox Search - Custom Pagefind Implementation */ /* Animations */ @keyframes spin { to { transform: rotate(360deg); } } .animate-spin { animation: spin 1s linear infinite; } /* Search result highlights */ .search-result mark { background-color: rgb(254 240 138); color: rgb(17 24 39); font-weight: var(--hb-font-weight-body-bold, 600); padding: 0.05rem 0.2rem; border-radius: 0.125rem; } .dark .search-result mark { background-color: rgb(133 77 14); color: rgb(254 240 138); } /* Result hover state */ .search-result:hover mark { background-color: rgb(253 224 71); } .dark .search-result:hover mark { background-color: rgb(161 98 7); } /* Smooth transitions */ .search-modal-enter { animation: slide-in-up 0.2s ease-out; } @keyframes slide-in-up { from { opacity: 0; transform: translateY(1rem) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } } /* Loading skeleton */ .search-skeleton { background: linear-gradient(90deg, rgb(229 231 235) 25%, rgb(243 244 246) 50%, rgb(229 231 235) 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; } .dark .search-skeleton { background: linear-gradient(90deg, rgb(55 65 81) 25%, rgb(75 85 99) 50%, rgb(55 65 81) 75%); background-size: 200% 100%; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } /* Keyboard navigation highlight - handled by Alpine :class binding */ /* Smooth transition for selection state */ .search-result { transition: all 0.15s ease; } /* Additional hover effects for keyboard-selected items */ .search-result:focus-visible { outline: 2px solid rgb(59 130 246); outline-offset: -2px; } ================================================ FILE: modules/blox/assets/css/layout-utilities.css ================================================ /* Hugo Blox Layout Utilities Provides CSS utilities that use the configurable layout tokens: - --hb-radius: Border radius token - --hb-spacing-base: Base spacing unit - --hb-spacing-section: Section padding - --hb-font-size-base: Base font size */ /* Border radius utility - use instead of hardcoded rounded-* classes */ .hb-rounded { border-radius: var(--hb-radius, 0.5rem); } .hb-rounded-sm { border-radius: calc(var(--hb-radius, 0.5rem) * 0.5); } .hb-rounded-lg { border-radius: calc(var(--hb-radius, 0.5rem) * 1.5); } .hb-rounded-xl { border-radius: calc(var(--hb-radius, 0.5rem) * 2); } /* Section spacing */ .hb-section { padding-top: var(--hb-spacing-section, 4rem); padding-bottom: var(--hb-spacing-section, 4rem); } .hb-section-sm { padding-top: calc(var(--hb-spacing-section, 4rem) * 0.5); padding-bottom: calc(var(--hb-spacing-section, 4rem) * 0.5); } /* Component spacing */ .hb-gap { gap: var(--hb-spacing-base, 1rem); } .hb-gap-sm { gap: calc(var(--hb-spacing-base, 1rem) * 0.5); } .hb-gap-lg { gap: calc(var(--hb-spacing-base, 1rem) * 1.5); } /* Padding utilities */ .hb-p { padding: var(--hb-spacing-base, 1rem); } .hb-px { padding-left: var(--hb-spacing-base, 1rem); padding-right: var(--hb-spacing-base, 1rem); } .hb-py { padding-top: var(--hb-spacing-base, 1rem); padding-bottom: var(--hb-spacing-base, 1rem); } /* Margin utilities */ .hb-m { margin: var(--hb-spacing-base, 1rem); } .hb-mx { margin-left: var(--hb-spacing-base, 1rem); margin-right: var(--hb-spacing-base, 1rem); } .hb-my { margin-top: var(--hb-spacing-base, 1rem); margin-bottom: var(--hb-spacing-base, 1rem); } ================================================ FILE: modules/blox/assets/css/libs/chroma/dark.css ================================================ /* Dracula dark theme */ .dark .highlight { /* Background */ /*.bg { color: #f8f8f2; background-color: #282a36 }*/ /* PreWrapper */ /*.chroma { color: #f8f8f2; background-color: #282a36; }*/ /* Other */ .chroma .x { } /* Error */ .chroma .err { } /* CodeLine */ .chroma .cl { } /* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } /* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } /* LineHighlight */ .chroma .hl { background-color: #ffc; } /* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em; color: #7f7f7f; } /* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em; color: #7f7f7f; } /* Line */ .chroma .line { display: flex; } /* Keyword */ .chroma .k { color: #ff79c6; } /* KeywordConstant */ .chroma .kc { color: #ff79c6; } /* KeywordDeclaration */ .chroma .kd { color: #8be9fd; font-style: italic; } /* KeywordNamespace */ .chroma .kn { color: #ff79c6; } /* KeywordPseudo */ .chroma .kp { color: #ff79c6; } /* KeywordReserved */ .chroma .kr { color: #ff79c6; } /* KeywordType */ .chroma .kt { color: #8be9fd; } /* Name */ .chroma .n { } /* NameAttribute */ .chroma .na { color: #50fa7b; } /* NameBuiltin */ .chroma .nb { color: #8be9fd; font-style: italic; } /* NameBuiltinPseudo */ .chroma .bp { } /* NameClass */ .chroma .nc { color: #50fa7b; } /* NameConstant */ .chroma .no { } /* NameDecorator */ .chroma .nd { } /* NameEntity */ .chroma .ni { } /* NameException */ .chroma .ne { } /* NameFunction */ .chroma .nf { color: #50fa7b; } /* NameFunctionMagic */ .chroma .fm { } /* NameLabel */ .chroma .nl { color: #8be9fd; font-style: italic; } /* NameNamespace */ .chroma .nn { } /* NameOther */ .chroma .nx { } /* NameProperty */ .chroma .py { } /* NameTag */ .chroma .nt { color: #ff79c6; } /* NameVariable */ .chroma .nv { color: #8be9fd; font-style: italic; } /* NameVariableClass */ .chroma .vc { color: #8be9fd; font-style: italic; } /* NameVariableGlobal */ .chroma .vg { color: #8be9fd; font-style: italic; } /* NameVariableInstance */ .chroma .vi { color: #8be9fd; font-style: italic; } /* NameVariableMagic */ .chroma .vm { } /* Literal */ .chroma .l { } /* LiteralDate */ .chroma .ld { } /* LiteralString */ .chroma .s { color: #f1fa8c; } /* LiteralStringAffix */ .chroma .sa { color: #f1fa8c; } /* LiteralStringBacktick */ .chroma .sb { color: #f1fa8c; } /* LiteralStringChar */ .chroma .sc { color: #f1fa8c; } /* LiteralStringDelimiter */ .chroma .dl { color: #f1fa8c; } /* LiteralStringDoc */ .chroma .sd { color: #f1fa8c; } /* LiteralStringDouble */ .chroma .s2 { color: #f1fa8c; } /* LiteralStringEscape */ .chroma .se { color: #f1fa8c; } /* LiteralStringHeredoc */ .chroma .sh { color: #f1fa8c; } /* LiteralStringInterpol */ .chroma .si { color: #f1fa8c; } /* LiteralStringOther */ .chroma .sx { color: #f1fa8c; } /* LiteralStringRegex */ .chroma .sr { color: #f1fa8c; } /* LiteralStringSingle */ .chroma .s1 { color: #f1fa8c; } /* LiteralStringSymbol */ .chroma .ss { color: #f1fa8c; } /* LiteralNumber */ .chroma .m { color: #bd93f9; } /* LiteralNumberBin */ .chroma .mb { color: #bd93f9; } /* LiteralNumberFloat */ .chroma .mf { color: #bd93f9; } /* LiteralNumberHex */ .chroma .mh { color: #bd93f9; } /* LiteralNumberInteger */ .chroma .mi { color: #bd93f9; } /* LiteralNumberIntegerLong */ .chroma .il { color: #bd93f9; } /* LiteralNumberOct */ .chroma .mo { color: #bd93f9; } /* Operator */ .chroma .o { color: #ff79c6; } /* OperatorWord */ .chroma .ow { color: #ff79c6; } /* Punctuation */ .chroma .p { } /* Comment */ .chroma .c { color: #6272a4; } /* CommentHashbang */ .chroma .ch { color: #6272a4; } /* CommentMultiline */ .chroma .cm { color: #6272a4; } /* CommentSingle */ .chroma .c1 { color: #6272a4; } /* CommentSpecial */ .chroma .cs { color: #6272a4; } /* CommentPreproc */ .chroma .cp { color: #ff79c6; } /* CommentPreprocFile */ .chroma .cpf { color: #ff79c6; } /* Generic */ .chroma .g { } /* GenericDeleted */ .chroma .gd { color: #f55; } /* GenericEmph */ .chroma .ge { text-decoration: underline; } /* GenericError */ .chroma .gr { } /* GenericHeading */ .chroma .gh { font-weight: bold; } /* GenericInserted */ .chroma .gi { color: #50fa7b; font-weight: bold; } /* GenericOutput */ .chroma .go { color: #44475a; } /* GenericPrompt */ .chroma .gp { } /* GenericStrong */ .chroma .gs { } /* GenericSubheading */ .chroma .gu { font-weight: bold; } /* GenericTraceback */ .chroma .gt { } /* GenericUnderline */ .chroma .gl { text-decoration: underline; } /* TextWhitespace */ .chroma .w { } } ================================================ FILE: modules/blox/assets/css/libs/chroma/light.css ================================================ /* Github light theme */ html:not(.dark) .highlight { /* Background */ /*.bg { background-color: #fff }*/ /* PreWrapper */ /*.chroma { background-color: #fff; }*/ /* Other */ .chroma .x { } /* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2; } /* CodeLine */ .chroma .cl { } /* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } /* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } /* LineHighlight */ .chroma .hl { background-color: #ffc; } /* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em; color: #7f7f7f; } /* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em; color: #7f7f7f; } /* Line */ .chroma .line { display: flex; } /* Keyword */ .chroma .k { color: #000; font-weight: bold; } /* KeywordConstant */ .chroma .kc { color: #000; font-weight: bold; } /* KeywordDeclaration */ .chroma .kd { color: #000; font-weight: bold; } /* KeywordNamespace */ .chroma .kn { color: #000; font-weight: bold; } /* KeywordPseudo */ .chroma .kp { color: #000; font-weight: bold; } /* KeywordReserved */ .chroma .kr { color: #000; font-weight: bold; } /* KeywordType */ .chroma .kt { color: #458; font-weight: bold; } /* Name */ .chroma .n { } /* NameAttribute */ .chroma .na { color: #008080; } /* NameBuiltin */ .chroma .nb { color: #0086b3; } /* NameBuiltinPseudo */ .chroma .bp { color: #999; } /* NameClass */ .chroma .nc { color: #458; font-weight: bold; } /* NameConstant */ .chroma .no { color: #008080; } /* NameDecorator */ .chroma .nd { color: #3c5d5d; font-weight: bold; } /* NameEntity */ .chroma .ni { color: #800080; } /* NameException */ .chroma .ne { color: #900; font-weight: bold; } /* NameFunction */ .chroma .nf { color: #900; font-weight: bold; } /* NameFunctionMagic */ .chroma .fm { } /* NameLabel */ .chroma .nl { color: #900; font-weight: bold; } /* NameNamespace */ .chroma .nn { color: #555; } /* NameOther */ .chroma .nx { } /* NameProperty */ .chroma .py { } /* NameTag */ .chroma .nt { color: #000080; } /* NameVariable */ .chroma .nv { color: #008080; } /* NameVariableClass */ .chroma .vc { color: #008080; } /* NameVariableGlobal */ .chroma .vg { color: #008080; } /* NameVariableInstance */ .chroma .vi { color: #008080; } /* NameVariableMagic */ .chroma .vm { } /* Literal */ .chroma .l { } /* LiteralDate */ .chroma .ld { } /* LiteralString */ .chroma .s { color: #d14; } /* LiteralStringAffix */ .chroma .sa { color: #d14; } /* LiteralStringBacktick */ .chroma .sb { color: #d14; } /* LiteralStringChar */ .chroma .sc { color: #d14; } /* LiteralStringDelimiter */ .chroma .dl { color: #d14; } /* LiteralStringDoc */ .chroma .sd { color: #d14; } /* LiteralStringDouble */ .chroma .s2 { color: #d14; } /* LiteralStringEscape */ .chroma .se { color: #d14; } /* LiteralStringHeredoc */ .chroma .sh { color: #d14; } /* LiteralStringInterpol */ .chroma .si { color: #d14; } /* LiteralStringOther */ .chroma .sx { color: #d14; } /* LiteralStringRegex */ .chroma .sr { color: #009926; } /* LiteralStringSingle */ .chroma .s1 { color: #d14; } /* LiteralStringSymbol */ .chroma .ss { color: #990073; } /* LiteralNumber */ .chroma .m { color: #099; } /* LiteralNumberBin */ .chroma .mb { color: #099; } /* LiteralNumberFloat */ .chroma .mf { color: #099; } /* LiteralNumberHex */ .chroma .mh { color: #099; } /* LiteralNumberInteger */ .chroma .mi { color: #099; } /* LiteralNumberIntegerLong */ .chroma .il { color: #099; } /* LiteralNumberOct */ .chroma .mo { color: #099; } /* Operator */ .chroma .o { color: #000; font-weight: bold; } /* OperatorWord */ .chroma .ow { color: #000; font-weight: bold; } /* Punctuation */ .chroma .p { } /* Comment */ .chroma .c { color: #998; font-style: italic; } /* CommentHashbang */ .chroma .ch { color: #998; font-style: italic; } /* CommentMultiline */ .chroma .cm { color: #998; font-style: italic; } /* CommentSingle */ .chroma .c1 { color: #998; font-style: italic; } /* CommentSpecial */ .chroma .cs { color: #999; font-weight: bold; font-style: italic; } /* CommentPreproc */ .chroma .cp { color: #999; font-weight: bold; font-style: italic; } /* CommentPreprocFile */ .chroma .cpf { color: #999; font-weight: bold; font-style: italic; } /* Generic */ .chroma .g { } /* GenericDeleted */ .chroma .gd { color: #000; background-color: #fdd; } /* GenericEmph */ .chroma .ge { color: #000; font-style: italic; } /* GenericError */ .chroma .gr { color: #a00; } /* GenericHeading */ .chroma .gh { color: #999; } /* GenericInserted */ .chroma .gi { color: #000; background-color: #dfd; } /* GenericOutput */ .chroma .go { color: #888; } /* GenericPrompt */ .chroma .gp { color: #555; } /* GenericStrong */ .chroma .gs { font-weight: bold; } /* GenericSubheading */ .chroma .gu { color: #aaa; } /* GenericTraceback */ .chroma .gt { color: #a00; } /* GenericUnderline */ .chroma .gl { text-decoration: underline; } /* TextWhitespace */ .chroma .w { color: #bbb; } } ================================================ FILE: modules/blox/assets/css/main.css ================================================ /* Hugo Blox Tailwind CSS v4 - Main Entry Point This file orchestrates all CSS imports in the correct order: 1. Tailwind base with configuration 2. Theme and color definitions 3. Base styles and utilities 4. Hugo Blox framework components 5. Hugo Blox module components 6. Safelist for dynamic classes */ /* Tailwind CSS v4 Base */ @import "tailwindcss"; /* Dynamic sources are injected by the css.html partial */ /* This handles both monorepo dev and end-user environments */ /* Configuration */ @import "config/tailwind.css"; @import "config/theme.css"; /* Base styles and utilities */ @import "framework/base.css"; /* Hugo Blox theme system (color utilities) */ @import "color-utilities.css"; /* Hugo Blox layout utilities (radius, spacing tokens) */ @import "layout-utilities.css"; /* Hugo Blox framework components */ @import "framework/components.css"; /* Hugo Blox module components */ @import "components/all.css"; @import "blox/all.css"; @import "views/all.css"; @import "chroma.css"; /* Hugo Blox Search */ @import "hb-search.css"; /* Hugo Blox Animations (typewriter, scroll reveals) */ @import "animations.css"; /* Safelist for dynamic classes */ @import "config/safelist.css"; ================================================ FILE: modules/blox/assets/css/themes/amber.css ================================================ /* Hugo Blox color theme: AMBER */ :root { /* Amber Primary Palette */ --hb-primary-50-rgb: 255 251 235; --hb-primary-100-rgb: 254 243 199; --hb-primary-200-rgb: 253 230 138; --hb-primary-300-rgb: 252 211 77; --hb-primary-400-rgb: 251 191 36; --hb-primary-500-rgb: 245 158 11; --hb-primary-600-rgb: 217 119 6; --hb-primary-700-rgb: 180 83 9; --hb-primary-800-rgb: 146 64 14; --hb-primary-900-rgb: 120 53 15; --hb-primary-950-rgb: 69 26 3; /* Yellow Secondary Palette */ --hb-secondary-50-rgb: 254 252 232; --hb-secondary-100-rgb: 254 249 195; --hb-secondary-200-rgb: 254 240 138; --hb-secondary-300-rgb: 253 224 71; --hb-secondary-400-rgb: 250 204 21; --hb-secondary-500-rgb: 234 179 8; --hb-secondary-600-rgb: 202 138 4; --hb-secondary-700-rgb: 161 98 7; --hb-secondary-800-rgb: 133 77 14; --hb-secondary-900-rgb: 113 63 18; --hb-secondary-950-rgb: 66 32 6; } ================================================ FILE: modules/blox/assets/css/themes/blue.css ================================================ /* Hugo Blox color theme: BLUE */ :root { /* TW Blue Palette */ --hb-primary-50-rgb: 239 246 255; --hb-primary-100-rgb: 219 234 254; --hb-primary-200-rgb: 191 219 254; --hb-primary-300-rgb: 147 197 253; --hb-primary-400-rgb: 96 165 250; --hb-primary-500-rgb: 59 130 246; --hb-primary-600-rgb: 37 99 235; --hb-primary-700-rgb: 29 78 216; --hb-primary-800-rgb: 30 64 175; --hb-primary-900-rgb: 30 58 138; --hb-primary-950-rgb: 23 37 84; /* TW Cyan Palette */ --hb-secondary-50-rgb: 236 254 255; --hb-secondary-100-rgb: 207 250 254; --hb-secondary-200-rgb: 165 243 252; --hb-secondary-300-rgb: 103 232 249; --hb-secondary-400-rgb: 34 211 238; --hb-secondary-500-rgb: 6 182 212; --hb-secondary-600-rgb: 8 145 178; --hb-secondary-700-rgb: 14 116 144; --hb-secondary-800-rgb: 21 94 117; --hb-secondary-900-rgb: 22 78 99; --hb-secondary-950-rgb: 8 51 68; } ================================================ FILE: modules/blox/assets/css/themes/cyan.css ================================================ /* Hugo Blox color theme: CYAN */ :root { /* Cyan Primary Palette */ --hb-primary-50-rgb: 236 254 255; --hb-primary-100-rgb: 207 250 254; --hb-primary-200-rgb: 165 243 252; --hb-primary-300-rgb: 103 232 249; --hb-primary-400-rgb: 34 211 238; --hb-primary-500-rgb: 6 182 212; --hb-primary-600-rgb: 8 145 178; --hb-primary-700-rgb: 14 116 144; --hb-primary-800-rgb: 21 94 117; --hb-primary-900-rgb: 22 78 99; --hb-primary-950-rgb: 8 51 68; /* Sky Secondary Palette */ --hb-secondary-50-rgb: 240 249 255; --hb-secondary-100-rgb: 224 242 254; --hb-secondary-200-rgb: 186 230 253; --hb-secondary-300-rgb: 125 211 252; --hb-secondary-400-rgb: 56 189 248; --hb-secondary-500-rgb: 14 165 233; --hb-secondary-600-rgb: 2 132 199; --hb-secondary-700-rgb: 3 105 161; --hb-secondary-800-rgb: 7 89 133; --hb-secondary-900-rgb: 12 74 110; --hb-secondary-950-rgb: 8 47 73; } ================================================ FILE: modules/blox/assets/css/themes/emerald.css ================================================ /* Hugo Blox color theme: EMERALD */ :root { /* Emerald Primary Palette */ --hb-primary-50-rgb: 236 253 245; --hb-primary-100-rgb: 209 250 229; --hb-primary-200-rgb: 167 243 208; --hb-primary-300-rgb: 110 231 183; --hb-primary-400-rgb: 52 211 153; --hb-primary-500-rgb: 16 185 129; --hb-primary-600-rgb: 5 150 105; --hb-primary-700-rgb: 4 120 87; --hb-primary-800-rgb: 6 95 70; --hb-primary-900-rgb: 6 78 59; --hb-primary-950-rgb: 2 44 34; /* Green Secondary Palette */ --hb-secondary-50-rgb: 240 253 244; --hb-secondary-100-rgb: 220 252 231; --hb-secondary-200-rgb: 187 247 208; --hb-secondary-300-rgb: 134 239 172; --hb-secondary-400-rgb: 74 222 128; --hb-secondary-500-rgb: 34 197 94; --hb-secondary-600-rgb: 22 163 74; --hb-secondary-700-rgb: 21 128 61; --hb-secondary-800-rgb: 22 101 52; --hb-secondary-900-rgb: 20 83 45; --hb-secondary-950-rgb: 5 46 22; } ================================================ FILE: modules/blox/assets/css/themes/fuchsia.css ================================================ /* Hugo Blox color theme: FUCHSIA */ :root { /* Fuchsia Primary Palette */ --hb-primary-50-rgb: 253 244 255; --hb-primary-100-rgb: 250 232 255; --hb-primary-200-rgb: 245 208 254; --hb-primary-300-rgb: 240 171 252; --hb-primary-400-rgb: 232 121 249; --hb-primary-500-rgb: 217 70 239; --hb-primary-600-rgb: 192 38 211; --hb-primary-700-rgb: 162 28 175; --hb-primary-800-rgb: 134 25 143; --hb-primary-900-rgb: 112 26 117; --hb-primary-950-rgb: 74 4 78; /* Violet Secondary Palette */ --hb-secondary-50-rgb: 245 243 255; --hb-secondary-100-rgb: 237 233 254; --hb-secondary-200-rgb: 221 214 254; --hb-secondary-300-rgb: 196 181 253; --hb-secondary-400-rgb: 167 139 250; --hb-secondary-500-rgb: 139 92 246; --hb-secondary-600-rgb: 124 58 237; --hb-secondary-700-rgb: 109 40 217; --hb-secondary-800-rgb: 91 33 182; --hb-secondary-900-rgb: 76 29 149; --hb-secondary-950-rgb: 46 16 101; } ================================================ FILE: modules/blox/assets/css/themes/green.css ================================================ /* Hugo Blox color theme: GREEN */ :root { /* Green Primary Palette */ --hb-primary-50-rgb: 240 253 244; --hb-primary-100-rgb: 220 252 231; --hb-primary-200-rgb: 187 247 208; --hb-primary-300-rgb: 134 239 172; --hb-primary-400-rgb: 74 222 128; --hb-primary-500-rgb: 34 197 94; --hb-primary-600-rgb: 22 163 74; --hb-primary-700-rgb: 21 128 61; --hb-primary-800-rgb: 22 101 52; --hb-primary-900-rgb: 20 83 45; --hb-primary-950-rgb: 5 46 22; /* Teal Secondary Palette */ --hb-secondary-50-rgb: 240 253 250; --hb-secondary-100-rgb: 204 251 241; --hb-secondary-200-rgb: 153 246 228; --hb-secondary-300-rgb: 94 234 212; --hb-secondary-400-rgb: 45 212 191; --hb-secondary-500-rgb: 20 184 166; --hb-secondary-600-rgb: 13 148 136; --hb-secondary-700-rgb: 15 118 110; --hb-secondary-800-rgb: 17 94 89; --hb-secondary-900-rgb: 19 78 74; --hb-secondary-950-rgb: 4 47 46; } ================================================ FILE: modules/blox/assets/css/themes/indigo.css ================================================ /* Hugo Blox color theme: INDIGO */ :root { /* Indigo Primary Palette */ --hb-primary-50-rgb: 238 242 255; --hb-primary-100-rgb: 224 231 255; --hb-primary-200-rgb: 199 210 254; --hb-primary-300-rgb: 165 180 252; --hb-primary-400-rgb: 129 140 248; --hb-primary-500-rgb: 99 102 241; --hb-primary-600-rgb: 79 70 229; --hb-primary-700-rgb: 67 56 202; --hb-primary-800-rgb: 55 48 163; --hb-primary-900-rgb: 49 46 129; --hb-primary-950-rgb: 30 27 75; /* Blue Secondary Palette */ --hb-secondary-50-rgb: 239 246 255; --hb-secondary-100-rgb: 219 234 254; --hb-secondary-200-rgb: 191 219 254; --hb-secondary-300-rgb: 147 197 253; --hb-secondary-400-rgb: 96 165 250; --hb-secondary-500-rgb: 59 130 246; --hb-secondary-600-rgb: 37 99 235; --hb-secondary-700-rgb: 29 78 216; --hb-secondary-800-rgb: 30 64 175; --hb-secondary-900-rgb: 30 58 138; --hb-secondary-950-rgb: 23 37 84; } ================================================ FILE: modules/blox/assets/css/themes/lime.css ================================================ /* Hugo Blox color theme: LIME */ :root { /* Lime Primary Palette */ --hb-primary-50-rgb: 247 254 231; --hb-primary-100-rgb: 236 252 203; --hb-primary-200-rgb: 217 249 157; --hb-primary-300-rgb: 190 242 100; --hb-primary-400-rgb: 163 230 53; --hb-primary-500-rgb: 132 204 22; --hb-primary-600-rgb: 101 163 13; --hb-primary-700-rgb: 77 124 15; --hb-primary-800-rgb: 63 98 18; --hb-primary-900-rgb: 54 83 20; --hb-primary-950-rgb: 26 46 5; /* Yellow Secondary Palette */ --hb-secondary-50-rgb: 254 252 232; --hb-secondary-100-rgb: 254 249 195; --hb-secondary-200-rgb: 254 240 138; --hb-secondary-300-rgb: 253 224 71; --hb-secondary-400-rgb: 250 204 21; --hb-secondary-500-rgb: 234 179 8; --hb-secondary-600-rgb: 202 138 4; --hb-secondary-700-rgb: 161 98 7; --hb-secondary-800-rgb: 133 77 14; --hb-secondary-900-rgb: 113 63 18; --hb-secondary-950-rgb: 66 32 6; } ================================================ FILE: modules/blox/assets/css/themes/orange.css ================================================ /* Hugo Blox color theme: ORANGE */ :root { /* Orange Primary Palette */ --hb-primary-50-rgb: 255 247 237; --hb-primary-100-rgb: 255 237 213; --hb-primary-200-rgb: 254 215 170; --hb-primary-300-rgb: 253 186 116; --hb-primary-400-rgb: 251 146 60; --hb-primary-500-rgb: 249 115 22; --hb-primary-600-rgb: 234 88 12; --hb-primary-700-rgb: 194 65 12; --hb-primary-800-rgb: 154 52 18; --hb-primary-900-rgb: 124 45 18; --hb-primary-950-rgb: 67 20 7; /* Red Secondary Palette */ --hb-secondary-50-rgb: 254 242 242; --hb-secondary-100-rgb: 254 226 226; --hb-secondary-200-rgb: 254 202 202; --hb-secondary-300-rgb: 252 165 165; --hb-secondary-400-rgb: 248 113 113; --hb-secondary-500-rgb: 239 68 68; --hb-secondary-600-rgb: 220 38 38; --hb-secondary-700-rgb: 185 28 28; --hb-secondary-800-rgb: 153 27 27; --hb-secondary-900-rgb: 127 29 29; --hb-secondary-950-rgb: 69 10 10; } ================================================ FILE: modules/blox/assets/css/themes/pink.css ================================================ /* Hugo Blox color theme: PINK */ :root { /* Pink Primary Palette */ --hb-primary-50-rgb: 253 242 248; --hb-primary-100-rgb: 252 231 243; --hb-primary-200-rgb: 251 207 232; --hb-primary-300-rgb: 249 168 212; --hb-primary-400-rgb: 244 114 182; --hb-primary-500-rgb: 236 72 153; --hb-primary-600-rgb: 219 39 119; --hb-primary-700-rgb: 190 24 93; --hb-primary-800-rgb: 157 23 77; --hb-primary-900-rgb: 131 24 67; --hb-primary-950-rgb: 80 7 36; /* Rose Secondary Palette */ --hb-secondary-50-rgb: 255 241 242; --hb-secondary-100-rgb: 255 228 230; --hb-secondary-200-rgb: 254 205 211; --hb-secondary-300-rgb: 253 164 175; --hb-secondary-400-rgb: 251 113 133; --hb-secondary-500-rgb: 244 63 94; --hb-secondary-600-rgb: 225 29 72; --hb-secondary-700-rgb: 190 18 60; --hb-secondary-800-rgb: 159 18 57; --hb-secondary-900-rgb: 136 19 55; --hb-secondary-950-rgb: 76 5 25; } ================================================ FILE: modules/blox/assets/css/themes/purple.css ================================================ /* Hugo Blox color theme: PURPLE */ :root { /* Purple Primary Palette */ --hb-primary-50-rgb: 250 245 255; --hb-primary-100-rgb: 243 232 255; --hb-primary-200-rgb: 233 213 255; --hb-primary-300-rgb: 216 180 254; --hb-primary-400-rgb: 192 132 252; --hb-primary-500-rgb: 168 85 247; --hb-primary-600-rgb: 147 51 234; --hb-primary-700-rgb: 126 34 206; --hb-primary-800-rgb: 107 33 168; --hb-primary-900-rgb: 88 28 135; --hb-primary-950-rgb: 59 7 100; /* Violet Secondary Palette */ --hb-secondary-50-rgb: 245 243 255; --hb-secondary-100-rgb: 237 233 254; --hb-secondary-200-rgb: 221 214 254; --hb-secondary-300-rgb: 196 181 253; --hb-secondary-400-rgb: 167 139 250; --hb-secondary-500-rgb: 139 92 246; --hb-secondary-600-rgb: 124 58 237; --hb-secondary-700-rgb: 109 40 217; --hb-secondary-800-rgb: 91 33 182; --hb-secondary-900-rgb: 76 29 149; --hb-secondary-950-rgb: 46 16 101; } ================================================ FILE: modules/blox/assets/css/themes/red.css ================================================ /* Hugo Blox color theme: RED */ :root { /* Red Primary Palette */ --hb-primary-50-rgb: 254 242 242; --hb-primary-100-rgb: 254 226 226; --hb-primary-200-rgb: 254 202 202; --hb-primary-300-rgb: 252 165 165; --hb-primary-400-rgb: 248 113 113; --hb-primary-500-rgb: 239 68 68; --hb-primary-600-rgb: 220 38 38; --hb-primary-700-rgb: 185 28 28; --hb-primary-800-rgb: 153 27 27; --hb-primary-900-rgb: 127 29 29; --hb-primary-950-rgb: 69 10 10; /* Orange Secondary Palette */ --hb-secondary-50-rgb: 255 247 237; --hb-secondary-100-rgb: 255 237 213; --hb-secondary-200-rgb: 254 215 170; --hb-secondary-300-rgb: 253 186 116; --hb-secondary-400-rgb: 251 146 60; --hb-secondary-500-rgb: 249 115 22; --hb-secondary-600-rgb: 234 88 12; --hb-secondary-700-rgb: 194 65 12; --hb-secondary-800-rgb: 154 52 18; --hb-secondary-900-rgb: 124 45 18; --hb-secondary-950-rgb: 67 20 7; } ================================================ FILE: modules/blox/assets/css/themes/rose.css ================================================ /* Hugo Blox color theme: ROSE */ :root { /* Rose Primary Palette */ --hb-primary-50-rgb: 255 241 242; --hb-primary-100-rgb: 255 228 230; --hb-primary-200-rgb: 254 205 211; --hb-primary-300-rgb: 253 164 175; --hb-primary-400-rgb: 251 113 133; --hb-primary-500-rgb: 244 63 94; --hb-primary-600-rgb: 225 29 72; --hb-primary-700-rgb: 190 18 60; --hb-primary-800-rgb: 159 18 57; --hb-primary-900-rgb: 136 19 55; --hb-primary-950-rgb: 76 5 25; /* Pink Secondary Palette */ --hb-secondary-50-rgb: 253 242 248; --hb-secondary-100-rgb: 252 231 243; --hb-secondary-200-rgb: 251 207 232; --hb-secondary-300-rgb: 249 168 212; --hb-secondary-400-rgb: 244 114 182; --hb-secondary-500-rgb: 236 72 153; --hb-secondary-600-rgb: 219 39 119; --hb-secondary-700-rgb: 190 24 93; --hb-secondary-800-rgb: 157 23 77; --hb-secondary-900-rgb: 131 24 67; --hb-secondary-950-rgb: 80 7 36; } ================================================ FILE: modules/blox/assets/css/themes/sky.css ================================================ /* Hugo Blox color theme: SKY */ :root { /* Sky Primary Palette */ --hb-primary-50-rgb: 240 249 255; --hb-primary-100-rgb: 224 242 254; --hb-primary-200-rgb: 186 230 253; --hb-primary-300-rgb: 125 211 252; --hb-primary-400-rgb: 56 189 248; --hb-primary-500-rgb: 14 165 233; --hb-primary-600-rgb: 2 132 199; --hb-primary-700-rgb: 3 105 161; --hb-primary-800-rgb: 7 89 133; --hb-primary-900-rgb: 12 74 110; --hb-primary-950-rgb: 8 47 73; /* Cyan Secondary Palette */ --hb-secondary-50-rgb: 236 254 255; --hb-secondary-100-rgb: 207 250 254; --hb-secondary-200-rgb: 165 243 252; --hb-secondary-300-rgb: 103 232 249; --hb-secondary-400-rgb: 34 211 238; --hb-secondary-500-rgb: 6 182 212; --hb-secondary-600-rgb: 8 145 178; --hb-secondary-700-rgb: 14 116 144; --hb-secondary-800-rgb: 21 94 117; --hb-secondary-900-rgb: 22 78 99; --hb-secondary-950-rgb: 8 51 68; } ================================================ FILE: modules/blox/assets/css/themes/slate.css ================================================ /* Hugo Blox color theme: SLATE */ :root { /* Slate Primary Palette */ --hb-primary-50-rgb: 248 250 252; --hb-primary-100-rgb: 241 245 249; --hb-primary-200-rgb: 226 232 240; --hb-primary-300-rgb: 203 213 225; --hb-primary-400-rgb: 148 163 184; --hb-primary-500-rgb: 100 116 139; --hb-primary-600-rgb: 71 85 105; --hb-primary-700-rgb: 51 65 85; --hb-primary-800-rgb: 30 41 59; --hb-primary-900-rgb: 15 23 42; --hb-primary-950-rgb: 2 6 23; /* Stone Secondary Palette */ --hb-secondary-50-rgb: 250 250 249; --hb-secondary-100-rgb: 245 245 244; --hb-secondary-200-rgb: 231 229 228; --hb-secondary-300-rgb: 214 211 209; --hb-secondary-400-rgb: 168 162 158; --hb-secondary-500-rgb: 120 113 108; --hb-secondary-600-rgb: 87 83 78; --hb-secondary-700-rgb: 68 64 60; --hb-secondary-800-rgb: 41 37 36; --hb-secondary-900-rgb: 28 25 23; --hb-secondary-950-rgb: 12 10 9; } ================================================ FILE: modules/blox/assets/css/themes/stone.css ================================================ /* Hugo Blox color theme: STONE */ :root { /* Stone Primary Palette */ --hb-primary-50-rgb: 250 250 249; --hb-primary-100-rgb: 245 245 244; --hb-primary-200-rgb: 231 229 228; --hb-primary-300-rgb: 214 211 209; --hb-primary-400-rgb: 168 162 158; --hb-primary-500-rgb: 120 113 108; --hb-primary-600-rgb: 87 83 78; --hb-primary-700-rgb: 68 64 60; --hb-primary-800-rgb: 41 37 36; --hb-primary-900-rgb: 28 25 23; --hb-primary-950-rgb: 12 10 9; /* Slate Secondary Palette */ --hb-secondary-50-rgb: 248 250 252; --hb-secondary-100-rgb: 241 245 249; --hb-secondary-200-rgb: 226 232 240; --hb-secondary-300-rgb: 203 213 225; --hb-secondary-400-rgb: 148 163 184; --hb-secondary-500-rgb: 100 116 139; --hb-secondary-600-rgb: 71 85 105; --hb-secondary-700-rgb: 51 65 85; --hb-secondary-800-rgb: 30 41 59; --hb-secondary-900-rgb: 15 23 42; --hb-secondary-950-rgb: 2 6 23; } ================================================ FILE: modules/blox/assets/css/themes/teal.css ================================================ /* Hugo Blox color theme: TEAL */ :root { /* Teal Primary Palette */ --hb-primary-50-rgb: 240 253 250; --hb-primary-100-rgb: 204 251 241; --hb-primary-200-rgb: 153 246 228; --hb-primary-300-rgb: 94 234 212; --hb-primary-400-rgb: 45 212 191; --hb-primary-500-rgb: 20 184 166; --hb-primary-600-rgb: 13 148 136; --hb-primary-700-rgb: 15 118 110; --hb-primary-800-rgb: 17 94 89; --hb-primary-900-rgb: 19 78 74; --hb-primary-950-rgb: 4 47 46; /* Emerald Secondary Palette */ --hb-secondary-50-rgb: 236 253 245; --hb-secondary-100-rgb: 209 250 229; --hb-secondary-200-rgb: 167 243 208; --hb-secondary-300-rgb: 110 231 183; --hb-secondary-400-rgb: 52 211 153; --hb-secondary-500-rgb: 16 185 129; --hb-secondary-600-rgb: 5 150 105; --hb-secondary-700-rgb: 4 120 87; --hb-secondary-800-rgb: 6 95 70; --hb-secondary-900-rgb: 6 78 59; --hb-secondary-950-rgb: 2 44 34; } ================================================ FILE: modules/blox/assets/css/themes/violet.css ================================================ /* Hugo Blox color theme: VIOLET */ :root { /* Violet Primary Palette */ --hb-primary-50-rgb: 245 243 255; --hb-primary-100-rgb: 237 233 254; --hb-primary-200-rgb: 221 214 254; --hb-primary-300-rgb: 196 181 253; --hb-primary-400-rgb: 167 139 250; --hb-primary-500-rgb: 139 92 246; --hb-primary-600-rgb: 124 58 237; --hb-primary-700-rgb: 109 40 217; --hb-primary-800-rgb: 91 33 182; --hb-primary-900-rgb: 76 29 149; --hb-primary-950-rgb: 46 16 101; /* Fuchsia Secondary Palette */ --hb-secondary-50-rgb: 253 244 255; --hb-secondary-100-rgb: 250 232 255; --hb-secondary-200-rgb: 245 208 254; --hb-secondary-300-rgb: 240 171 252; --hb-secondary-400-rgb: 232 121 249; --hb-secondary-500-rgb: 217 70 239; --hb-secondary-600-rgb: 192 38 211; --hb-secondary-700-rgb: 162 28 175; --hb-secondary-800-rgb: 134 25 143; --hb-secondary-900-rgb: 112 26 117; --hb-secondary-950-rgb: 74 4 78; } ================================================ FILE: modules/blox/assets/css/themes/yellow.css ================================================ /* Hugo Blox color theme: YELLOW */ :root { /* Yellow Primary Palette */ --hb-primary-50-rgb: 254 252 232; --hb-primary-100-rgb: 254 249 195; --hb-primary-200-rgb: 254 240 138; --hb-primary-300-rgb: 253 224 71; --hb-primary-400-rgb: 250 204 21; --hb-primary-500-rgb: 234 179 8; --hb-primary-600-rgb: 202 138 4; --hb-primary-700-rgb: 161 98 7; --hb-primary-800-rgb: 133 77 14; --hb-primary-900-rgb: 113 63 18; --hb-primary-950-rgb: 66 32 6; /* Amber Secondary Palette */ --hb-secondary-50-rgb: 255 251 235; --hb-secondary-100-rgb: 254 243 199; --hb-secondary-200-rgb: 253 230 138; --hb-secondary-300-rgb: 252 211 77; --hb-secondary-400-rgb: 251 191 36; --hb-secondary-500-rgb: 245 158 11; --hb-secondary-600-rgb: 217 119 6; --hb-secondary-700-rgb: 180 83 9; --hb-secondary-800-rgb: 146 64 14; --hb-secondary-900-rgb: 120 53 15; --hb-secondary-950-rgb: 69 26 3; } ================================================ FILE: modules/blox/assets/css/themes/zinc.css ================================================ /* Hugo Blox color theme: ZINC */ :root { /* Zinc Primary Palette */ --hb-primary-50-rgb: 250 250 250; --hb-primary-100-rgb: 244 244 245; --hb-primary-200-rgb: 228 228 231; --hb-primary-300-rgb: 212 212 216; --hb-primary-400-rgb: 161 161 170; --hb-primary-500-rgb: 113 113 122; --hb-primary-600-rgb: 82 82 91; --hb-primary-700-rgb: 63 63 70; --hb-primary-800-rgb: 39 39 42; --hb-primary-900-rgb: 24 24 27; --hb-primary-950-rgb: 9 9 11; /* Slate Secondary Palette */ --hb-secondary-50-rgb: 248 250 252; --hb-secondary-100-rgb: 241 245 249; --hb-secondary-200-rgb: 226 232 240; --hb-secondary-300-rgb: 203 213 225; --hb-secondary-400-rgb: 148 163 184; --hb-secondary-500-rgb: 100 116 139; --hb-secondary-600-rgb: 71 85 105; --hb-secondary-700-rgb: 51 65 85; --hb-secondary-800-rgb: 30 41 59; --hb-secondary-900-rgb: 15 23 42; --hb-secondary-950-rgb: 2 6 23; } ================================================ FILE: modules/blox/assets/css/views/all.css ================================================ @import "attachments.css"; ================================================ FILE: modules/blox/assets/css/views/attachments.css ================================================ .hb-attachment-link { @apply inline-block font-semibold uppercase outline-none mr-4 mb-1.5 transition-all text-sm tracking-wide focus:outline-none; color: var(--color-primary-600); } .hb-attachment-link:hover { color: var(--color-primary-700); text-decoration: underline; } .dark .hb-attachment-link { color: var(--color-primary-400); } .dark .hb-attachment-link:hover { color: var(--color-primary-300); } /* Small links - used in list views */ .hb-attachment-link-small { @apply p-0 text-xs; } /* Large links - used on single pages */ .hb-attachment-link-large { @apply p-0 text-sm; } ================================================ FILE: modules/blox/assets/dist/lib/markmap/index.js ================================================ this.markmap = this.markmap || {}; (function(exports) { "use strict"; var _a; const testPath = "npm2url/dist/index.cjs"; const defaultProviders = { jsdelivr: (path) => `https://cdn.jsdelivr.net/npm/${path}`, unpkg: (path) => `https://unpkg.com/${path}` }; async function checkUrl(url, signal) { const res = await fetch(url, { signal }); if (!res.ok) { throw res; } await res.text(); } class UrlBuilder { constructor() { this.providers = { ...defaultProviders }; this.provider = "jsdelivr"; } /** * Get the fastest provider name. * If none of the providers returns a valid response within `timeout`, an error will be thrown. */ async getFastestProvider(timeout = 5e3, path = testPath) { const controller = new AbortController(); let timer = 0; try { return await new Promise((resolve, reject) => { Promise.all( Object.entries(this.providers).map(async ([name, factory]) => { try { await checkUrl(factory(path), controller.signal); resolve(name); } catch { } }) ).then(() => reject(new Error("All providers failed"))); timer = setTimeout(reject, timeout, new Error("Timed out")); }); } finally { controller.abort(); clearTimeout(timer); } } /** * Set the current provider to the fastest provider found by `getFastestProvider`. */ async findFastestProvider(timeout, path) { this.provider = await this.getFastestProvider(timeout, path); return this.provider; } setProvider(name, factory) { if (factory) { this.providers[name] = factory; } else { delete this.providers[name]; } } getFullUrl(path, provider = this.provider) { if (path.includes("://")) { return path; } const factory = this.providers[provider]; if (!factory) { throw new Error(`Provider ${provider} not found`); } return factory(path); } } const urlBuilder = new UrlBuilder(); Math.random().toString(36).slice(2, 8); function defer() { const obj = {}; obj.promise = new Promise((resolve, reject) => { obj.resolve = resolve; obj.reject = reject; }); return obj; } function memoize(fn) { const cache = {}; return function memoized(...args) { const key = `${args[0]}`; let data = cache[key]; if (!data) { data = { value: fn(...args) }; cache[key] = data; } return data.value; }; } /*! @gera2ld/jsx-dom v2.2.2 | ISC License */ const VTYPE_ELEMENT = 1; const VTYPE_FUNCTION = 2; const SVG_NS = "http://www.w3.org/2000/svg"; const XLINK_NS = "http://www.w3.org/1999/xlink"; const NS_ATTRS = { show: XLINK_NS, actuate: XLINK_NS, href: XLINK_NS }; const isLeaf = (c) => typeof c === "string" || typeof c === "number"; const isElement = (c) => (c == null ? void 0 : c.vtype) === VTYPE_ELEMENT; const isRenderFunction = (c) => (c == null ? void 0 : c.vtype) === VTYPE_FUNCTION; function h(type, props, ...children) { props = Object.assign({}, props, { children: children.length === 1 ? children[0] : children }); return jsx(type, props); } function jsx(type, props) { let vtype; if (typeof type === "string") vtype = VTYPE_ELEMENT; else if (typeof type === "function") vtype = VTYPE_FUNCTION; else throw new Error("Invalid VNode type"); return { vtype, type, props }; } function Fragment(props) { return props.children; } const DEFAULT_ENV = { isSvg: false }; function insertDom(parent, nodes) { if (!Array.isArray(nodes)) nodes = [nodes]; nodes = nodes.filter(Boolean); if (nodes.length) parent.append(...nodes); } function mountAttributes(domElement, props, env) { for (const key in props) { if (key === "key" || key === "children" || key === "ref") continue; if (key === "dangerouslySetInnerHTML") { domElement.innerHTML = props[key].__html; } else if (key === "innerHTML" || key === "textContent" || key === "innerText" || key === "value" && ["textarea", "select"].includes(domElement.tagName)) { const value = props[key]; if (value != null) domElement[key] = value; } else if (key.startsWith("on")) { domElement[key.toLowerCase()] = props[key]; } else { setDOMAttribute(domElement, key, props[key], env.isSvg); } } } const attrMap = { className: "class", labelFor: "for" }; function setDOMAttribute(el, attr, value, isSVG) { attr = attrMap[attr] || attr; if (value === true) { el.setAttribute(attr, ""); } else if (value === false) { el.removeAttribute(attr); } else { const namespace = isSVG ? NS_ATTRS[attr] : void 0; if (namespace !== void 0) { el.setAttributeNS(namespace, attr, value); } else { el.setAttribute(attr, value); } } } function flatten(arr) { return arr.reduce((prev, item) => prev.concat(item), []); } function mountChildren(children, env) { return Array.isArray(children) ? flatten(children.map((child) => mountChildren(child, env))) : mount(children, env); } function mount(vnode, env = DEFAULT_ENV) { if (vnode == null || typeof vnode === "boolean") { return null; } if (vnode instanceof Node) { return vnode; } if (isRenderFunction(vnode)) { const { type, props } = vnode; if (type === Fragment) { const node = document.createDocumentFragment(); if (props.children) { const children = mountChildren(props.children, env); insertDom(node, children); } return node; } const childVNode = type(props); return mount(childVNode, env); } if (isLeaf(vnode)) { return document.createTextNode(`${vnode}`); } if (isElement(vnode)) { let node; const { type, props } = vnode; if (!env.isSvg && type === "svg") { env = Object.assign({}, env, { isSvg: true }); } if (!env.isSvg) { node = document.createElement(type); } else { node = document.createElementNS(SVG_NS, type); } mountAttributes(node, props, env); if (props.children) { let childEnv = env; if (env.isSvg && type === "foreignObject") { childEnv = Object.assign({}, childEnv, { isSvg: false }); } const children = mountChildren(props.children, childEnv); if (children != null) insertDom(node, children); } const { ref } = props; if (typeof ref === "function") ref(node); return node; } throw new Error("mount: Invalid Vnode!"); } function mountDom(vnode) { return mount(vnode); } function hm(...args) { return mountDom(h(...args)); } const memoizedPreloadJS = memoize((url) => { document.head.append( hm("link", { rel: "preload", as: "script", href: url }) ); }); const jsCache = {}; const cssCache = {}; async function loadJSItem(item, context) { var _a2; const src = item.type === "script" && ((_a2 = item.data) == null ? void 0 : _a2.src) || ""; item.loaded || (item.loaded = jsCache[src]); if (!item.loaded) { const deferred = defer(); item.loaded = deferred.promise; if (item.type === "script") { document.head.append( hm("script", { ...item.data, onLoad: () => deferred.resolve(), onError: deferred.reject }) ); if (!src) { deferred.resolve(); } else { jsCache[src] = item.loaded; } } if (item.type === "iife") { const { fn, getParams } = item.data; fn(...(getParams == null ? void 0 : getParams(context)) || []); deferred.resolve(); } } await item.loaded; } async function loadCSSItem(item) { const url = item.type === "stylesheet" && item.data.href || ""; item.loaded || (item.loaded = cssCache[url]); if (!item.loaded) { const deferred = defer(); item.loaded = deferred.promise; if (url) cssCache[url] = item.loaded; if (item.type === "style") { document.head.append( hm("style", { textContent: item.data }) ); deferred.resolve(); } else if (url) { document.head.append( hm("link", { rel: "stylesheet", ...item.data }) ); fetch(url).then((res) => { if (res.ok) return res.text(); throw res; }).then(() => deferred.resolve(), deferred.reject); } } await item.loaded; } async function loadJS(items, context) { items.forEach((item) => { var _a2; if (item.type === "script" && ((_a2 = item.data) == null ? void 0 : _a2.src)) { memoizedPreloadJS(item.data.src); } }); context = { getMarkmap: () => window.markmap, ...context }; for (const item of items) { await loadJSItem(item, context); } } async function loadCSS(items) { await Promise.all(items.map((item) => loadCSSItem(item))); } function buildJSItem(path) { return { type: "script", data: { src: path } }; } function buildCSSItem(path) { return { type: "stylesheet", data: { href: path } }; } const enabled = {}; const autoLoaderOptions = { baseJs: [ `d3@${"7.9.0"}`, `markmap-lib@${"0.18.12"}`, `markmap-view@${"0.18.12"}`, `markmap-toolbar@${"0.18.12"}` ], baseCss: [`markmap-toolbar@${"0.18.12"}/dist/style.css`], manual: false, toolbar: false, ...(_a = window.markmap) == null ? void 0 : _a.autoLoader }; async function initialize() { var _a2; if (typeof autoLoaderOptions.provider === "function") { urlBuilder.setProvider( urlBuilder.provider = "autoLoader", autoLoaderOptions.provider ); } else if (typeof autoLoaderOptions.provider === "string") { urlBuilder.provider = autoLoaderOptions.provider; } else { try { await urlBuilder.findFastestProvider(); } catch { } } await Promise.all([ loadJS( autoLoaderOptions.baseJs.map( (item) => typeof item === "string" ? buildJSItem(urlBuilder.getFullUrl(item)) : item ) ), loadCSS( autoLoaderOptions.baseCss.map( (item) => typeof item === "string" ? buildCSSItem(urlBuilder.getFullUrl(item)) : item ) ) ]); const { markmap } = window; const style = document.createElement("style"); style.textContent = markmap.globalCSS; document.body.prepend(style); (_a2 = autoLoaderOptions.onReady) == null ? void 0 : _a2.call(autoLoaderOptions); } const ready = initialize(); function transform(transformer, content) { const result = transformer.transform(content); const keys = Object.keys(result.features).filter((key) => !enabled[key]); keys.forEach((key) => { enabled[key] = true; }); const { styles, scripts } = transformer.getAssets(keys); const { markmap } = window; if (styles) markmap.loadCSS(styles); if (scripts) markmap.loadJS(scripts); return result; } function render(el) { var _a2; const { Transformer, Markmap, deriveOptions, Toolbar } = window.markmap; const lines = ((_a2 = el.textContent) == null ? void 0 : _a2.split("\n")) || []; let indent = Infinity; lines.forEach((line) => { var _a3; const spaces = ((_a3 = line.match(/^\s*/)) == null ? void 0 : _a3[0].length) || 0; if (spaces < line.length) indent = Math.min(indent, spaces); }); const content = lines.map((line) => line.slice(indent)).join("\n").trim(); const transformer = new Transformer(autoLoaderOptions.transformPlugins); transformer.urlBuilder = urlBuilder; el.innerHTML = ""; const svg = el.firstChild; const mm = Markmap.create(svg, { embedGlobalCSS: false }); if (autoLoaderOptions.toolbar) { const { el: toolbar } = Toolbar.create(mm); Object.assign(toolbar.style, { position: "absolute", right: "20px", bottom: "20px" }); el.append(toolbar); } const doRender = async () => { const { root, frontmatter } = transform(transformer, content); const markmapOptions = frontmatter == null ? void 0 : frontmatter.markmap; const frontmatterOptions = deriveOptions(markmapOptions); await mm.setData(root, frontmatterOptions); mm.fit(); }; transformer.hooks.retransform.tap(doRender); doRender(); } async function renderAllUnder(container) { await ready; container.querySelectorAll(".markmap").forEach(render); } function renderAll() { return renderAllUnder(document); } if (!autoLoaderOptions.manual) { if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", () => { renderAll(); }); else renderAll(); } exports.ready = ready; exports.render = render; exports.renderAll = renderAll; exports.renderAllUnder = renderAllUnder; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); })(this.markmap.autoLoader = this.markmap.autoLoader || {}); ================================================ FILE: modules/blox/assets/dist/lib/vendor-libs.mjs ================================================ const e = {}; export { e as default }; ================================================ FILE: modules/blox/assets/js/hb-animations.js ================================================ /** * Hugo Blox Animations * Typewriter effect and scroll-triggered animations using Alpine.js */ document.addEventListener("alpine:init", () => { // Typewriter effect component Alpine.data("typewriter", (strings = [], options = {}) => ({ strings: strings, currentIndex: 0, currentText: "", isDeleting: false, typeSpeed: options.typeSpeed || 80, deleteSpeed: options.deleteSpeed || 50, pauseTime: options.pauseTime || 2000, loop: options.loop !== false, showCursor: options.cursor !== false, init() { if (this.strings.length === 0) return; this.type(); }, type() { const current = this.strings[this.currentIndex]; if (this.isDeleting) { this.currentText = current.substring(0, this.currentText.length - 1); } else { this.currentText = current.substring(0, this.currentText.length + 1); } let delay = this.isDeleting ? this.deleteSpeed : this.typeSpeed; if (!this.isDeleting && this.currentText === current) { // Finished typing, pause then delete delay = this.pauseTime; this.isDeleting = true; } else if (this.isDeleting && this.currentText === "") { // Finished deleting, move to next string this.isDeleting = false; this.currentIndex = (this.currentIndex + 1) % this.strings.length; if (!this.loop && this.currentIndex === 0) { // Don't loop, show first string permanently this.currentText = this.strings[0]; return; } delay = 500; // Pause before typing next } setTimeout(() => this.type(), delay); }, })); // Scroll reveal directive Alpine.directive("reveal", (el, {expression, modifiers}, {evaluate}) => { const options = expression ? evaluate(expression) : {}; const delay = options.delay || 0; const duration = options.duration || 600; const distance = options.distance || "20px"; const direction = modifiers.includes("left") ? "left" : modifiers.includes("right") ? "right" : modifiers.includes("down") ? "down" : "up"; // Set initial state el.style.opacity = "0"; el.style.transition = `opacity ${duration}ms ease-out, transform ${duration}ms ease-out`; el.style.transitionDelay = `${delay}ms`; const transforms = { up: `translateY(${distance})`, down: `translateY(-${distance})`, left: `translateX(${distance})`, right: `translateX(-${distance})`, }; el.style.transform = transforms[direction]; // Observe intersection const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { el.style.opacity = "1"; el.style.transform = "translate(0, 0)"; observer.unobserve(el); } }); }, {threshold: 0.1, rootMargin: "0px 0px -50px 0px"}, ); observer.observe(el); }); }); // Staggered reveal for groups of elements document.addEventListener("DOMContentLoaded", () => { // Add stagger delays to elements with data-stagger attribute document.querySelectorAll("[data-stagger]").forEach((container) => { const children = container.querySelectorAll("[data-stagger-item]"); const baseDelay = parseInt(container.dataset.stagger, 10) || 100; children.forEach((child, index) => { child.style.transitionDelay = `${index * baseDelay}ms`; }); }); }); // Respect reduced motion preference if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { document.documentElement.classList.add("reduce-motion"); } ================================================ FILE: modules/blox/assets/js/hb-citation.js ================================================ /** * Citation clipboard handler for Hugo Blox Kit * Copies BibTeX citation to clipboard when cite button is clicked */ import {hugoEnvironment, i18n} from "@params"; import {ClipboardCache, copyToClipboardSync} from "./hb-clipboard.js"; import {showNotification} from "./hb-notifier.js"; // Debug mode based on environment const isDebugMode = hugoEnvironment === "development"; // Cache for citation content const citationCache = new ClipboardCache(); // Initialize citation handlers when DOM is ready if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initializeCitation); } else { initializeCitation(); } function initializeCitation() { // Handle citation button clicks using event delegation document.addEventListener("click", handleCiteClick); // Prefetch citations on hover/focus for better UX and Safari compatibility document.addEventListener("mouseover", prefetchOnHover); document.addEventListener("focusin", prefetchOnHover); // Prefetch all citations on page load prefetchAllCitations(); } /** * Prefetch all citations on page load */ function prefetchAllCitations() { const citeButtons = document.querySelectorAll(".js-cite-clipboard[data-filename]"); citeButtons.forEach((button) => { const filename = button.getAttribute("data-filename"); if (filename && !citationCache.has(filename)) { // Fetch in background, don't await fetchAndCacheCitation(filename); } }); } /** * Prefetch citation on hover/focus * @param {Event} e - Hover or focus event */ function prefetchOnHover(e) { const citeButton = e.target.closest(".js-cite-clipboard"); if (!citeButton) return; const filename = citeButton.getAttribute("data-filename"); if (filename && !citationCache.has(filename)) { // Fetch in background, don't await fetchAndCacheCitation(filename); } } /** * Fetch and cache citation content * @param {string} filename - Citation file URL * @returns {Promise} - Citation content or null if failed */ async function fetchAndCacheCitation(filename) { try { const response = await fetch(filename); if (!response.ok) { throw new Error(`Failed to fetch citation: ${response.statusText}`); } const citation = await response.text(); citationCache.set(filename, citation); return citation; } catch (error) { if (isDebugMode) { console.error(`Failed to fetch citation ${filename}:`, error); } return null; } } /** * Handle cite button clicks - synchronous clipboard write for Safari compatibility * @param {Event} e - Click event */ function handleCiteClick(e) { // Check if clicked element or its parent is a cite button const citeButton = e.target.closest(".js-cite-clipboard"); if (!citeButton) return; e.preventDefault(); e.stopPropagation(); const filename = citeButton.getAttribute("data-filename"); if (!filename) { if (isDebugMode) { console.error("No filename specified for citation"); } showNotification("Citation file not found", "error"); return; } // Check if citation is cached const cachedCitation = citationCache.get(filename); if (cachedCitation) { // Citation is cached, copy immediately (synchronous for Safari) copyToClipboardSync(cachedCitation).then((success) => { if (success) { showNotification(i18n?.copied || "Citation copied!", "success"); updateButtonText(citeButton); } else { showNotification("Failed to copy citation", "error"); } }); } else { // Not cached, need to fetch first (will fail in Safari with strict mode) fetchAndCopyWithFallback(filename, citeButton); } } /** * Fetch and copy with fallback (for browsers that allow async clipboard) * @param {string} filename - Citation file URL * @param {HTMLElement} button - Cite button element */ async function fetchAndCopyWithFallback(filename, button) { try { const citation = await fetchAndCacheCitation(filename); if (citation) { // Try to copy (might fail in Safari due to lost user activation) const success = await copyToClipboardSync(citation); if (success) { showNotification(i18n?.copied || "Citation copied!", "success"); updateButtonText(button); } else { showNotification("Failed to copy citation", "error"); } } else { showNotification("Failed to load citation", "error"); } } catch (error) { if (isDebugMode) { console.error("Failed to copy citation:", error); } // If it's a NotAllowedError, suggest hovering first if (error.name === "NotAllowedError") { showNotification("Please hover over the button first, then click", "info"); } else { showNotification("Failed to copy citation", "error"); } } } /** * Update button text to show copied state * @param {HTMLElement} button - The cite button element */ function updateButtonText(button) { const copiedText = i18n?.copied || "Copied!"; // Find text element to update (skip icon) const textElement = button.querySelector("span"); if (!textElement) { if (isDebugMode) { console.warn("Could not find text element in cite button"); } return; } const originalText = textElement.textContent; textElement.textContent = copiedText; // Add visual feedback button.classList.add("opacity-70"); // Revert after 2 seconds setTimeout(() => { textElement.textContent = originalText; button.classList.remove("opacity-70"); }, 2000); } // Export functions for potential reuse export {handleCiteClick, prefetchAllCitations}; ================================================ FILE: modules/blox/assets/js/hb-clipboard.js ================================================ /** * Clipboard Utilities for Hugo Blox Kit * Provides cross-browser clipboard functionality */ import {hugoEnvironment} from "@params"; // Debug mode based on environment const isDebugMode = hugoEnvironment === "development"; /** * Copy text to clipboard with multiple fallback methods * @param {string} text - Text to copy * @returns {Promise} - Whether the copy was successful */ export async function copyToClipboard(text) { // Method 1: Modern Clipboard API if (navigator.clipboard && window.isSecureContext) { try { await navigator.clipboard.writeText(text); if (isDebugMode) { console.log("Copied using Clipboard API"); } return true; } catch (err) { if (isDebugMode) { console.warn("Clipboard API failed:", err); } } } // Method 2: execCommand fallback return copyUsingExecCommand(text); } /** * Copy text to clipboard synchronously (Safari-compatible) * @param {string} text - Text to copy * @returns {Promise} - Whether the copy was successful */ export function copyToClipboardSync(text) { return new Promise((resolve) => { // Try modern clipboard API first if (navigator.clipboard && window.isSecureContext) { navigator.clipboard .writeText(text) .then(() => { if (isDebugMode) { console.log("Copied using Clipboard API (sync)"); } resolve(true); }) .catch((err) => { if (isDebugMode) { console.warn("Clipboard API failed:", err); } // Fallback to execCommand resolve(copyUsingExecCommand(text)); }); } else { // Use execCommand directly resolve(copyUsingExecCommand(text)); } }); } /** * Legacy copy method using execCommand * @param {string} text - Text to copy * @returns {boolean} - Success status */ export function copyUsingExecCommand(text) { const textarea = document.createElement("textarea"); textarea.value = text; // Make it invisible but copyable Object.assign(textarea.style, { position: "fixed", top: "0", left: "0", width: "2em", height: "2em", padding: "0", border: "none", outline: "none", boxShadow: "none", background: "transparent", fontSize: "16px", // Prevent zoom on iOS }); document.body.appendChild(textarea); // Select the text textarea.focus(); textarea.select(); // For iOS if (navigator.userAgent.match(/ipad|iphone/i)) { const range = document.createRange(); range.selectNodeContents(textarea); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); textarea.setSelectionRange(0, 999999); } let success = false; try { success = document.execCommand("copy"); if (isDebugMode) { console.log(`execCommand copy ${success ? "succeeded" : "failed"}`); } } catch (err) { if (isDebugMode) { console.error("execCommand failed:", err); } } document.body.removeChild(textarea); return success; } /** * Test if clipboard API is available and working * @returns {boolean} - Whether clipboard API is available */ export function isClipboardAPIAvailable() { return !!(navigator.clipboard && window.isSecureContext); } /** * Create a prefetch cache for clipboard content * Useful for Safari compatibility where content must be copied synchronously */ export class ClipboardCache { constructor() { this.cache = new Map(); } /** * Add content to cache * @param {string} key - Cache key * @param {string} content - Content to cache */ set(key, content) { this.cache.set(key, content); if (isDebugMode) { console.log(`Cached clipboard content for: ${key}`); } } /** * Get content from cache * @param {string} key - Cache key * @returns {string|null} - Cached content or null */ get(key) { return this.cache.get(key) || null; } /** * Check if content is cached * @param {string} key - Cache key * @returns {boolean} - Whether content is cached */ has(key) { return this.cache.has(key); } /** * Clear the cache */ clear() { this.cache.clear(); } /** * Get cache size * @returns {number} - Number of cached items */ get size() { return this.cache.size; } } // Export default clipboard copy function export default copyToClipboard; ================================================ FILE: modules/blox/assets/js/hb-code-copy.js ================================================ import {hugoEnvironment, i18n} from "@params"; // Constants const NOTIFICATION_DURATION = 2000; // milliseconds const DEBOUNCE_DELAY = 300; // milliseconds // Debug mode based on environment const isDebugMode = hugoEnvironment === "development"; /** * Debounce function to prevent rapid clicking * @param {Function} func - Function to debounce * @param {number} wait - Wait time in milliseconds * @returns {Function} Debounced function */ const debounce = (func, wait) => { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }; /** * Copies code to clipboard, excluding the copy button text * @param {HTMLElement} button - The copy button element * @param {HTMLElement} codeWrapper - The wrapper containing the code * @throws {Error} When clipboard operations fail */ async function copyCodeToClipboard(button, codeWrapper) { if (!button || !(button instanceof HTMLElement)) { throw new Error("Invalid button element"); } if (!codeWrapper || !(codeWrapper instanceof HTMLElement)) { throw new Error("Invalid code wrapper element"); } // Clone the wrapper to avoid modifying the displayed content const tempWrapper = codeWrapper.cloneNode(true); // Remove the copy button from the cloned wrapper const copyButton = tempWrapper.querySelector(".copy-button"); if (copyButton) { copyButton.remove(); } const codeToCopy = tempWrapper.textContent?.trim() ?? ""; if (!codeToCopy) { throw new Error("No code content found to copy"); } try { await navigator.clipboard.writeText(codeToCopy); copiedNotification(button); isDebugMode && console.debug("Code copied successfully"); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Unknown error"; console.error("Failed to copy:", errorMessage); button.innerHTML = i18n.copyFailed || "Failed"; setTimeout(() => { button.innerHTML = i18n.copy; }, NOTIFICATION_DURATION); throw err; // Re-throw for potential error boundary handling } } /** * Updates button text to show copied notification * @param {HTMLElement} copyBtn - The copy button element */ function copiedNotification(copyBtn) { copyBtn.innerHTML = i18n.copied; copyBtn.disabled = true; copyBtn.classList.add("copied"); setTimeout(() => { copyBtn.innerHTML = i18n.copy; copyBtn.disabled = false; copyBtn.classList.remove("copied"); }, NOTIFICATION_DURATION); } /** * Creates a copy button element * @returns {HTMLButtonElement} The created button */ function createCopyButton() { const copyBtn = document.createElement("button"); copyBtn.classList.add("copy-button"); copyBtn.innerHTML = i18n.copy; copyBtn.setAttribute("aria-label", i18n.copyLabel || "Copy code to clipboard"); copyBtn.setAttribute("type", "button"); // Explicit button type return copyBtn; } /** * Gets the appropriate wrapper for a code block * @param {HTMLElement} codeblock - The code block element * @returns {HTMLElement} The wrapper element */ function getCodeWrapper(codeblock) { const container = codeblock.parentNode?.parentNode; if (!container) { throw new Error("Invalid code block structure"); } if (container.classList.contains("highlight")) { return container; } const tableWrapper = container.closest("table"); if (tableWrapper) { return tableWrapper; } const preElement = codeblock.parentElement; if (preElement) { preElement.classList.add("highlight"); return preElement; } throw new Error("Could not determine code wrapper"); } /** * Initializes copy buttons for all code blocks */ function initializeCodeCopyButtons() { try { const codeBlocks = document.querySelectorAll("pre > code"); isDebugMode && console.debug(`Found ${codeBlocks.length} code blocks`); codeBlocks.forEach((codeblock, index) => { try { const wrapper = getCodeWrapper(codeblock); const copyBtn = createCopyButton(); // Use debounced version of copy function const debouncedCopy = debounce(() => copyCodeToClipboard(copyBtn, wrapper), DEBOUNCE_DELAY); copyBtn.addEventListener("click", debouncedCopy); wrapper.appendChild(copyBtn); } catch (err) { console.error(`Failed to initialize copy button for code block ${index}:`, err); } }); } catch (err) { console.error("Failed to initialize code copy buttons:", err); } } // Initialize when DOM is ready if (document.readyState === "loading") { window.addEventListener("DOMContentLoaded", initializeCodeCopyButtons); } else { initializeCodeCopyButtons(); } ================================================ FILE: modules/blox/assets/js/hb-head.js ================================================ import {applyHugoStyleFixes, initTheme} from "./hb-init.js"; // Initialize Hugo Blox Kit global object const root = document.documentElement; const defaultTheme = root.dataset.wcThemeDefault || "system"; const relBase = root.dataset.hbbRelurl || "/"; const normalizedRelBase = relBase.endsWith("/") ? relBase : `${relBase}/`; const buildAssetPath = (relativePath) => { const sanitizedRelative = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath; return `${normalizedRelBase}${sanitizedRelative}`; }; // Create global HBB object with theme functions window.hbb = { defaultTheme: defaultTheme, relBase: normalizedRelBase, assetPaths: { pagefind: buildAssetPath("pagefind/pagefind.js"), }, setDarkTheme: () => { root.classList.add("dark"); root.style.colorScheme = "dark"; }, setLightTheme: () => { root.classList.remove("dark"); root.style.colorScheme = "light"; }, }; initTheme(); applyHugoStyleFixes(); ================================================ FILE: modules/blox/assets/js/hb-i18n.js ================================================ window.addEventListener("DOMContentLoaded", () => { // Toggle language chooser sub-menu const languageChoosers = document.querySelectorAll("[data-hb-language-chooser]"); languageChoosers.forEach((languageChooser) => { languageChooser.addEventListener("click", (e) => { e.preventDefault(); languageChooser.dataset.state = languageChooser.dataset.state === "open" ? "closed" : "open"; const languageOptions = languageChooser.nextElementSibling; languageOptions.classList.toggle("hidden"); const languageChooserRect = languageChooser.getBoundingClientRect(); const translateY = languageChooserRect.bottom - window.innerHeight + 40; languageOptions.style.transform = `translate3d(${languageChooserRect.left}px, ${translateY}px, 0)`; languageOptions.style.minWidth = `${Math.max(languageChooserRect.width, 50)}px`; }); }); // Handle clicks outside chooser document.addEventListener("click", (e) => { if (e.target.closest("[data-hb-language-chooser]") === null) { languageChoosers.forEach((languageChooser) => { languageChooser.dataset.state = "closed"; const languageOptions = languageChooser.nextElementSibling; languageOptions.classList.add("hidden"); }); } }); }); ================================================ FILE: modules/blox/assets/js/hb-init.js ================================================ // Hugo Blox JS Global Init (CSP-friendly) export function initTheme() { const root = document.documentElement; const defaultTheme = root.dataset.wcThemeDefault; const setDark = () => { root.classList.add("dark"); root.style.colorScheme = "dark"; }; const setLight = () => { root.classList.remove("dark"); root.style.colorScheme = "light"; }; if ("wc-color-theme" in localStorage) { localStorage.getItem("wc-color-theme") === "dark" ? setDark() : setLight(); } else { if (defaultTheme === "dark") setDark(); else if (defaultTheme === "light") setLight(); else if (defaultTheme === "system") { window.matchMedia("(prefers-color-scheme: dark)").matches ? setDark() : setLight(); } } } export function applyHugoStyleFixes() { document.addEventListener("DOMContentLoaded", () => { const checkboxes = document.querySelectorAll("li input[type='checkbox'][disabled]"); checkboxes.forEach((e) => { const parent = e.parentElement?.parentElement; if (parent) parent.classList.add("task-list"); }); const liNodes = document.querySelectorAll(".task-list li"); liNodes.forEach((nodes) => { const textNodes = Array.from(nodes.childNodes).filter((node) => node.nodeType === 3 && node.textContent && node.textContent.trim().length > 1); if (textNodes.length > 0) { const span = document.createElement("label"); textNodes[0].after(span); const input = nodes.querySelector("input[type='checkbox']"); if (input) span.appendChild(input); span.appendChild(textNodes[0]); } }); }); } ================================================ FILE: modules/blox/assets/js/hb-mermaid-config.js ================================================ function getCssVar(name) { const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim(); return value ? `rgb(${value})` : null; } window.mermaid.initialize({ theme: "base", themeVariables: { background: getCssVar("--color-neutral-50") || "#fafafa", primaryColor: getCssVar("--color-primary-200") || "#bfdbfe", secondaryColor: getCssVar("--color-secondary-200") || "#a5f3fc", tertiaryColor: getCssVar("--color-neutral-100") || "#f5f5f5", primaryBorderColor: getCssVar("--color-primary-400") || "#60a5fa", secondaryBorderColor: getCssVar("--color-secondary-400") || "#22d3ee", tertiaryBorderColor: getCssVar("--color-neutral-400") || "#a3a3a3", lineColor: getCssVar("--color-neutral-600") || "#525252", fontFamily: getComputedStyle(document.documentElement).getPropertyValue("font-family"), fontSize: "16px", }, }); ================================================ FILE: modules/blox/assets/js/hb-nav.js ================================================ // Navigation const applyScrollPadding = () => { const header = document.querySelector(".page-header"); const position = header.getBoundingClientRect(); document.documentElement.style.scrollPaddingTop = `${position.height.toString()}px`; const r = document.querySelector(":root"); r.style.setProperty("--navbar-height", `${position.height.toString()}px`); }; window.addEventListener("DOMContentLoaded", () => { const dropdownMenus = document.querySelectorAll(".nav-dropdown > .nav-link[role='button']"); dropdownMenus.forEach((toggler) => { const toggle = (el) => { const parent = el.closest(".nav-dropdown"); const willActivate = !parent.classList.contains("active"); parent.classList.toggle("active", willActivate); el.setAttribute("aria-expanded", willActivate ? "true" : "false"); }; toggler?.addEventListener("click", (e) => { e.preventDefault(); toggle(e.currentTarget); }); // Keyboard support toggler?.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggle(e.currentTarget); } if (e.key === "Escape") { const parent = e.currentTarget.closest(".nav-dropdown"); parent?.classList.remove("active"); e.currentTarget.setAttribute("aria-expanded", "false"); } }); }); applyScrollPadding(); }); ================================================ FILE: modules/blox/assets/js/hb-notifier.js ================================================ /** * Notification/Toast System for Hugo Blox Kit * Provides reusable notification functionality */ import {hugoEnvironment} from "@params"; // Debug mode based on environment const isDebugMode = hugoEnvironment === "development"; /** * Show a notification message using Tailwind styles * @param {string} message - The message to display * @param {string} type - The type of notification ('success', 'error', 'info', 'warning') * @param {number} duration - Duration in milliseconds (default 3000) * @returns {HTMLElement} - The notification element */ export function showNotification(message, type = "success", duration = 3000) { // Get or create the notification container const container = getOrCreateContainer(); // Remove any existing notifications with same message const existingNotification = container.querySelector(".hb-notification"); if (existingNotification?.textContent?.includes(message)) { existingNotification.remove(); } // Create notification element const notification = createNotificationElement(message, type); // Add to container container.appendChild(notification); // Handle close button const closeBtn = notification.querySelector(".hb-notification-close"); if (closeBtn) { closeBtn.addEventListener("click", () => { removeNotification(notification); }); } // Auto-remove after duration if (duration > 0) { setTimeout(() => { removeNotification(notification); }, duration); } return notification; } /** * Get or create the notification container * @returns {HTMLElement} - The container element */ function getOrCreateContainer() { let container = document.getElementById("hb-notification-container"); if (!container) { if (isDebugMode) { console.warn("Notification container not found, creating fallback"); } container = document.createElement("div"); container.id = "hb-notification-container"; container.className = "fixed top-20 right-4 z-[9999] pointer-events-none"; container.setAttribute("aria-live", "polite"); container.setAttribute("aria-atomic", "true"); document.body.appendChild(container); } return container; } /** * Create a notification element * @param {string} message - The message to display * @param {string} type - The type of notification * @returns {HTMLElement} - The notification element */ function createNotificationElement(message, type) { const notification = document.createElement("div"); notification.setAttribute("role", "alert"); // Define colors for different types const colors = { success: {bg: "#10b981", bgClass: "bg-green-500"}, error: {bg: "#ef4444", bgClass: "bg-red-500"}, info: {bg: "#3b82f6", bgClass: "bg-blue-500"}, warning: {bg: "#f59e0b", bgClass: "bg-amber-500"}, }; const color = colors[type] || colors.info; // Set classes notification.className = `hb-notification pointer-events-auto flex items-center gap-2 px-4 py-3 text-white rounded-lg shadow-lg ${color.bgClass} animate-slide-in`; // Add inline styles as fallback notification.style.cssText = ` background-color: ${color.bg}; color: white; display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; border-radius: 0.5rem; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); margin-bottom: 0.5rem; pointer-events: auto; `; // Add icon based on type const icons = { success: '', error: '', info: '', warning: '', }; const icon = icons[type] || icons.info; notification.innerHTML = ` ${icon} ${message} `; // Ensure animation styles exist ensureAnimationStyles(); return notification; } /** * Remove notification with animation * @param {HTMLElement} notification - The notification element to remove */ export function removeNotification(notification) { if (!notification || !notification.parentNode) return; notification.classList.remove("animate-slide-in"); notification.classList.add("animate-slide-out"); setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); } /** * Ensure animation styles are in the document */ function ensureAnimationStyles() { if (!document.querySelector("#hb-notification-styles")) { const style = document.createElement("style"); style.id = "hb-notification-styles"; style.textContent = ` @keyframes slide-in { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slide-out { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } } .animate-slide-in { animation: slide-in 0.3s ease-out; } .animate-slide-out { animation: slide-out 0.3s ease-out; } `; document.head.appendChild(style); } } // Export default for convenience export default showNotification; ================================================ FILE: modules/blox/assets/js/hb-search.js ================================================ // Hugo Blox Search - Custom Pagefind API Implementation // Search is handled by Alpine.js component in search-modal.html // Additional keyboard shortcuts and utilities document.addEventListener("DOMContentLoaded", () => { console.log("✓ Hugo Blox Search initialized (Pagefind Headless API)"); // Handle search toggle buttons const searchButtons = document.querySelectorAll("[data-search-toggle]"); searchButtons.forEach((button) => { button.addEventListener("click", () => { const prefilledQuery = button.dataset.searchQuery; if (window.Alpine && Alpine.store("search")) { Alpine.store("search").open = true; // Pre-fill query if specified if (prefilledQuery) { setTimeout(() => { const searchInput = document.querySelector('[x-ref="searchInput"]'); if (searchInput) { searchInput.value = prefilledQuery; searchInput.dispatchEvent(new Event("input")); } }, 100); } } }); }); // Note: Keyboard navigation (arrow keys, Enter) is handled by Alpine.js in search-modal.html }); ================================================ FILE: modules/blox/assets/js/hb-sidebar.js ================================================ document.addEventListener("DOMContentLoaded", () => { const buttons = document.querySelectorAll("[data-hb-sidebar-toggle]"); buttons.forEach((button) => { button.addEventListener("click", (e) => { e.preventDefault(); const parent = button.parentElement.parentElement; if (parent) { parent.classList.toggle("open"); } }); }); }); // Hamburger menu for mobile navigation document.addEventListener("DOMContentLoaded", () => { const menu = document.querySelector("#nav-toggle"); const overlay = document.querySelector(".hb-sidebar-mobile-menu"); const sidebarContainer = document.querySelector(".hb-sidebar-container"); if (!overlay) { return; } // Initialize the overlay const overlayClasses = ["fixed", "z-10", "inset-0", "bg-white", "dark:bg-black/80"]; overlay.classList.add("bg-transparent"); overlay.classList.remove("hidden", ...overlayClasses); function toggleMenu() { // Toggle the hamburger menu // See `hb-nav.js` - it handles the default behavior (irrespective of if sidebar is shown). // When menu is open, show the navigation sidebar sidebarContainer.classList.toggle("max-lg:[transform:translate3d(0,-100%,0)]"); sidebarContainer.classList.toggle("max-lg:[transform:translate3d(0,0,0)]"); // When menu is open, prevent body from scrolling document.body.classList.toggle("overflow-hidden"); document.body.classList.toggle("lg:overflow-auto"); } menu.addEventListener("click", (e) => { console.debug("Hamburger clicked."); e.preventDefault(); toggleMenu(); if (overlay.classList.contains("bg-transparent")) { // Show overlay overlay.classList.add(...overlayClasses); overlay.classList.remove("bg-transparent"); } else { // Hide overlay overlay.classList.remove(...overlayClasses); overlay.classList.add("bg-transparent"); } }); overlay.addEventListener("click", (e) => { e.preventDefault(); toggleMenu(); // Hide overlay overlay.classList.remove(...overlayClasses); overlay.classList.add("bg-transparent"); }); }); ================================================ FILE: modules/blox/assets/js/hb-theme.js ================================================ // Hugo Blox Kit Light / Dark theme toggle document.addEventListener("DOMContentLoaded", () => { addThemeToggleListener(); }); function addThemeToggleListener() { const defaultTheme = window.hbb.defaultTheme; const themeToggleButtons = document.querySelectorAll(".theme-toggle"); // Change the icons of the buttons based on previous settings or system theme if ( localStorage.getItem("wc-color-theme") === "dark" || (!("wc-color-theme" in localStorage) && ((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultTheme === "system") || defaultTheme === "dark")) ) { themeToggleButtons.forEach((el) => { el.dataset.theme = "dark"; }); } else { themeToggleButtons.forEach((el) => { el.dataset.theme = "light"; }); } // Add click event handler to the light/dark buttons themeToggleButtons.forEach((el) => { el.addEventListener("click", () => { console.debug("Theme toggled"); if (localStorage.getItem("wc-color-theme")) { if (localStorage.getItem("wc-color-theme") === "light") { window.hbb.setDarkTheme(); localStorage.setItem("wc-color-theme", "dark"); } else { window.hbb.setLightTheme(); localStorage.setItem("wc-color-theme", "light"); } } else { if (document.documentElement.classList.contains("dark")) { window.hbb.setLightTheme(); localStorage.setItem("wc-color-theme", "light"); } else { window.hbb.setDarkTheme(); localStorage.setItem("wc-color-theme", "dark"); } } el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"; // Dispatch `hbThemeChange` event to support themeable user plugins. const themeChangeEvent = new CustomEvent("hbThemeChange", { detail: { isDarkTheme: () => document.documentElement.classList.contains("dark"), }, }); document.dispatchEvent(themeChangeEvent); }); }); // Listen for dark mode toggling in OS window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => { if (defaultTheme === "system" && !("wc-color-theme" in localStorage)) { event.matches ? window.hbb.setDarkTheme() : window.hbb.setLightTheme(); themeToggleButtons.forEach((el) => { const isDark = document.documentElement.classList.contains("dark"); el.dataset.theme = isDark ? "dark" : "light"; }); } }); } ================================================ FILE: modules/blox/assets/js/katex-config.js ================================================ document.addEventListener("DOMContentLoaded", () => { window.renderMathInElement(document.body, { delimiters: [ {left: "$$", right: "$$", display: true}, {left: "$", right: "$", display: false}, {left: "\\(", right: "\\)", display: false}, {left: "\\[", right: "\\]", display: true}, ], throwOnError: false, }); }); ================================================ FILE: modules/blox/assets/js/vendor-libs.js ================================================ /** * Dummy entry file for Vite lib mode. * * This file exists as an entry point for the Vite build process. * The actual vendor libraries are copied to their respective directories * using vite-plugin-static-copy, while this file generates the empty * vendor-libs.mjs module in the dist directory. * * See vite.config.js for the build configuration. */ export default {}; ================================================ FILE: modules/blox/blox/collection/README.md ================================================ # Collection Block **Transform your content into stunning, organized displays** The Collection block is your ultimate content curation tool, designed to showcase your blog posts, publications, projects, or any content type in beautifully organized, filterable displays. ## ✨ Key Features - **Smart Filtering**: Filter by folders, tags, categories, authors, publication types, and more - **Flexible Sorting**: Sort by date, title, or any custom field in ascending or descending order - **Multiple Views**: Choose from card, compact, showcase, citation, list, or masonry layouts - **Pagination Ready**: Built-in support for limiting items and pagination - **Archive Integration**: Automatic "See All" links to full archive pages - **Responsive Design**: Perfectly optimized for all screen sizes ## 🎯 Perfect For - **Blog Showcases**: Display your latest blog posts with beautiful card layouts - **Publication Lists**: Showcase academic papers and research with citation views - **Project Galleries**: Present your portfolio work in stunning visual grids - **News & Updates**: Keep visitors informed with filtered content streams - **Content Archives**: Create organized content hubs by topic or category ## 🚀 Why Choose Collection Block? **Effortless Content Management**: No manual updates needed - your content automatically appears as you publish **Advanced Filtering**: Powerful filtering system that works with Hugo's built-in taxonomies and custom parameters **SEO Optimized**: Clean markup and semantic HTML structure for better search engine visibility **Performance First**: Lightweight and fast, with optimized queries and lazy loading support ## 📊 Use Cases - Academic portfolios showcasing publications by research area - Corporate blogs with category-based content organization - Creative portfolios with project filtering by type or client - News sites with topic-based content streams - Personal blogs with tag-based content discovery Start building engaging content displays that keep your visitors exploring and discovering more of what you have to offer. ================================================ FILE: modules/blox/blox/collection/block.html ================================================ {{/* Hugo Blox: Collection */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $view := "card" }} {{ $view_raw := index $design "view" }} {{ if eq (printf "%T" $view_raw) "string" }} {{ $view = lower (strings.TrimSpace $view_raw) }} {{ end }} {{ $items_offset := partial "functions/coerce_int" (dict "value" (index $content "offset") "default" 0 "min" 0) }} {{ $items_count := partial "functions/coerce_int" (dict "value" (index $content "count") "default" 5 "min" 0) }} {{ if eq $items_count 0 }} {{ $items_count = 65535 }} {{ end }} {{/* Query */}} {{ $query := site.Pages }} {{ $archive_page := "" }} {{/* Filters */}} {{ $filters := index $content "filters" }} {{ if not (reflect.IsMap $filters) }}{{ $filters = dict }}{{ end }} {{ $kinds := slice }} {{ $kinds_raw := index $filters "kinds" }} {{ if reflect.IsSlice $kinds_raw }} {{ range $kinds_raw }} {{ $kind := strings.TrimSpace (printf "%v" .) }} {{ if $kind }} {{ $kinds = $kinds | append $kind }} {{ end }} {{ end }} {{ else if eq (printf "%T" $kinds_raw) "string" }} {{ $kind := strings.TrimSpace $kinds_raw }} {{ if $kind }} {{ $kinds = slice $kind }} {{ end }} {{ end }} {{ if eq (len $kinds) 0 }} {{ $kinds = slice "page" }} {{ end }} {{ $query = where $query "Kind" "in" $kinds }} {{ $page_type := "" }} {{ $page_type_raw := index $content "page_type" }} {{ if eq (printf "%T" $page_type_raw) "string" }} {{ $page_type = strings.TrimSpace $page_type_raw }} {{ end }} {{ if $page_type }} {{ $query = where $query "Type" $page_type }} {{ $archive_page = site.GetPage "Section" $page_type }} {{ end }} {{ $folders_raw := index $filters "folders" }} {{ $folders := slice }} {{ if reflect.IsSlice $folders_raw }} {{ range $folders_raw }} {{ $folder := strings.TrimSpace (printf "%v" .) }} {{ if $folder }} {{ $folders = $folders | append $folder }} {{ end }} {{ end }} {{ else if eq (printf "%T" $folders_raw) "string" }} {{ $folder := strings.TrimSpace $folders_raw }} {{ if $folder }} {{ $folders = slice $folder }} {{ end }} {{ end }} {{ if gt (len $folders) 0 }} {{ $query = where $query "Section" "in" $folders }} {{ $main_folder := strings.TrimSpace (printf "%v" (index $folders 0)) }} {{ if $main_folder }} {{ $archive_page = site.GetPage "Section" $main_folder }} {{ end }} {{ end }} {{ $tags_raw := index $filters "tags" }} {{ $tags := slice }} {{ if reflect.IsSlice $tags_raw }} {{ range $tags_raw }} {{ $tag := strings.TrimSpace (printf "%v" .) }} {{ if $tag }} {{ $tags = $tags | append $tag }} {{ end }} {{ end }} {{ else if eq (printf "%T" $tags_raw) "string" }} {{ $tag := strings.TrimSpace $tags_raw }} {{ if $tag }} {{ $tags = slice $tag }} {{ end }} {{ end }} {{ if gt (len $tags) 0 }} {{ $selected := slice }} {{ range $tags }} {{ $tag_page := site.GetPage (printf "tags/%s" (urlize .)) }} {{ if $tag_page }} {{ $selected = $selected | union $tag_page.Pages }} {{ end }} {{ end }} {{ if gt (len $selected) 0 }} {{ $query = $query | intersect $selected }} {{ $first_tag := index $tags 0 }} {{ $archive_page = site.GetPage (printf "tags/%s" (urlize $first_tag)) }} {{ end }} {{ end }} {{ $tag := "" }} {{ $tag_raw := index $filters "tag" }} {{ if eq (printf "%T" $tag_raw) "string" }} {{ $tag = strings.TrimSpace $tag_raw }} {{ end }} {{ if $tag }} {{ with site.GetPage (printf "tags/%s" (urlize $tag)) }} {{ $archive_page = . }} {{ $query = $query | intersect .Pages }} {{ end }} {{ end }} {{ $category := "" }} {{ $category_raw := index $filters "category" }} {{ if eq (printf "%T" $category_raw) "string" }} {{ $category = strings.TrimSpace $category_raw }} {{ end }} {{ if $category }} {{ with site.GetPage (printf "categories/%s" (urlize $category)) }} {{ $archive_page = . }} {{ $query = $query | intersect .Pages }} {{ end }} {{ end }} {{ $publication_type := "" }} {{ $publication_type_raw := index $filters "publication_type" }} {{ if eq (printf "%T" $publication_type_raw) "string" }} {{ $publication_type = strings.TrimSpace $publication_type_raw }} {{ end }} {{ if $publication_type }} {{ with site.GetPage (printf "publication_types/%s" $publication_type) }} {{ $archive_page = . }} {{ $query = $query | intersect .Pages }} {{ end }} {{ end }} {{ $exclude_publication_type := "" }} {{ $exclude_publication_type_raw := index $filters "exclude_publication_type" }} {{ if eq (printf "%T" $exclude_publication_type_raw) "string" }} {{ $exclude_publication_type = strings.TrimSpace $exclude_publication_type_raw }} {{ end }} {{ if $exclude_publication_type }} {{ with site.GetPage (printf "publication_types/%s" $exclude_publication_type) }} {{ $query = $query | complement .Pages }} {{ end }} {{ end }} {{ $author_filter := "" }} {{ $author_filter_raw := index $filters "author" }} {{ if eq (printf "%T" $author_filter_raw) "string" }} {{ $author_filter = strings.TrimSpace $author_filter_raw }} {{ end }} {{ if $author_filter }} {{ with site.GetPage (printf "authors/%s" (urlize $author_filter)) }} {{ $archive_page = . }} {{ $query = $query | intersect .Pages }} {{ end }} {{ end }} {{ $featured_only := partial "functions/coerce_bool" (dict "value" (index $filters "featured_only") "default" false) }} {{ if $featured_only }} {{ $query = where $query "Params.featured" "==" true }} {{ end }} {{ $exclude_featured := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_featured") "default" false) }} {{ if $exclude_featured }} {{ $query = where $query "Params.featured" "!=" true }} {{ end }} {{ $exclude_past := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_past") "default" false) }} {{ if $exclude_past }} {{/* Use event_end -> event_start -> Date to decide if an item is past */}} {{ $filtered := slice }} {{ range $query }} {{ $start := .Date }} {{ with .Params.event_start }}{{ $start = . }}{{ end }} {{ $end := $start }} {{ with .Params.event_end }}{{ $end = . }}{{ end }} {{ if ge $end now }} {{ $filtered = $filtered | append . }} {{ end }} {{ end }} {{ $query = $filtered }} {{ end }} {{ $exclude_future := partial "functions/coerce_bool" (dict "value" (index $filters "exclude_future") "default" false) }} {{ if $exclude_future }} {{/* Use event_start -> Date to drop future/unscheduled items */}} {{ $filtered := slice }} {{ range $query }} {{ $start := .Date }} {{ with .Params.event_start }}{{ $start = . }}{{ end }} {{ if lt $start now }} {{ $filtered = $filtered | append . }} {{ end }} {{ end }} {{ $query = $filtered }} {{ end }} {{ $count := len $query }} {{/* Sort */}} {{ $sort_by := "Date" }} {{ $sort_by_raw := index $content "sort_by" }} {{ if eq (printf "%T" $sort_by_raw) "string" }} {{ $sort_by_raw = strings.TrimSpace $sort_by_raw }} {{ if ne $sort_by_raw "" }} {{ $sort_by = $sort_by_raw }} {{ end }} {{ end }} {{ $sort_by = partial "functions/get_sort_by_parameter" $sort_by }} {{ $sort_ascending := false }} {{ if isset $content "sort_ascending" }} {{ $sort_ascending = partial "functions/coerce_bool" (dict "value" (index $content "sort_ascending") "default" false) }} {{ else }} {{ $order_raw := index $content "order" }} {{ if eq (printf "%T" $order_raw) "string" }} {{ if eq (lower (strings.TrimSpace $order_raw)) "asc" }} {{ $sort_ascending = true }} {{ end }} {{ end }} {{ end }} {{ $sort_order := cond $sort_ascending "asc" "desc" }} {{ $query = sort $query $sort_by $sort_order }} {{/* Offset and Limit */}} {{ if gt $items_offset 0 }} {{ $query = first $items_count (after $items_offset $query) }} {{ else }} {{ $query = first $items_count $query }} {{ end }} {{/* Check if any items have author_notes to enable Alpine.js */}} {{ range $query }} {{ if isset .Params "author_notes" }} {{ $page.Store.Set "has_alpine" true }} {{ break }} {{ end }} {{ end }} {{ $columns := partial "functions/coerce_int" (dict "value" (index $design "columns") "default" 2 "min" 1 "max" 4) }} {{ $title := "" }} {{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $text := "" }} {{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ if $title }}
{{ $title }}
{{ with $text }}

{{ . }}

{{ end }}
{{ end }}
{{ $config := dict "columns" $columns "len" (len $query) "fill_image" (partial "functions/coerce_bool" (dict "value" (index $design "fill_image") "default" true)) "show_date" (partial "functions/coerce_bool" (dict "value" (index $design "show_date") "default" true)) "show_read_time" (partial "functions/coerce_bool" (dict "value" (index $design "show_read_time") "default" true)) "show_read_more" (partial "functions/coerce_bool" (dict "value" (index $design "show_read_more") "default" true)) }} {{ partial "functions/render_view" (dict "fragment" "start" "page" $block "item" . "view" $view "config" $config) }} {{ range $index, $item := $query }} {{ partial "functions/render_view" (dict "page" $block "item" . "view" $view "index" $index "config" $config) }} {{end}} {{ partial "functions/render_view" (dict "fragment" "end" "page" $block "item" . "view" $view) }}
{{/* Archive link */}} {{ $archive := index $content "archive" }} {{ if not (reflect.IsMap $archive) }}{{ $archive = dict }}{{ end }} {{ $show_archive_link := gt $count $items_count }} {{ if isset $archive "enable" }} {{ $show_archive_link = partial "functions/coerce_bool" (dict "value" (index $archive "enable") "default" false) }} {{ end }} {{ if $show_archive_link | and $archive_page }} {{ $archive_link := "" }} {{ $archive_link_raw := index $archive "link" }} {{ if eq (printf "%T" $archive_link_raw) "string" }} {{ $archive_link = strings.TrimSpace $archive_link_raw }} {{ end }} {{ if not $archive_link }} {{ $archive_link = $archive_page.RelPermalink }} {{ end }} {{ if $archive_link }} {{ $scheme := (urls.Parse $archive_link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $archive_link "#") }} {{ $archive_link = $archive_link | relLangURL }} {{ end }} {{ end }} {{ end }} {{/* Localisation */}} {{ $items_type := $archive_page.Type }} {{ $i18n := "" }} {{ if eq $items_type "blog" }} {{ $i18n = "more_posts" }} {{ else if eq $items_type "event" }} {{ $i18n = "more_talks" }} {{ else if eq $items_type "publication" }} {{ $i18n = "more_publications" }} {{ else }} {{ $i18n = "more_pages" }} {{ end }} {{ $archive_text := "" }} {{ $archive_text_raw := index $archive "text" }} {{ if eq (printf "%T" $archive_text_raw) "string" }} {{ $archive_text = strings.TrimSpace $archive_text_raw }} {{ end }} {{ if not $archive_text }} {{ $archive_text = i18n $i18n | default "See all" }} {{ end }} {{ end }} ================================================ FILE: modules/blox/blox/collection/manifest.json ================================================ { "id": "collection", "name": "Collection", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["collection", "blog", "publications", "filter", "sort", "content-display", "archive"], "description": "Display filtered and sorted collections of pages with customizable views and pagination", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "static-site", "content", "blog", "publications", "filtering"] } ================================================ FILE: modules/blox/blox/contact-info/README.md ================================================ # Contact Info Block Display comprehensive contact information for your lab or organization with a modern, responsive card layout. ## Features - **Dual Card Layout**: Separate cards for location and contact methods - **Rich Information Display**: Address, office hours, phone, email, social media - **Interactive Elements**: Click-to-call, email links, map integration - **Optional Contact Form**: Built-in contact form support - **Map Integration**: External map links or embedded maps - **Social Media Links**: Connect your social profiles - **Prospective Members Section**: Dedicated area for recruitment - **Fully Responsive**: Beautiful on all devices - **Dark Mode Support**: Seamless light/dark theme switching ## Usage ```yaml sections: - block: contact-info content: title: Contact Us subtitle: Get in touch with our research team visit_title: Visit Our Lab connect_title: Connect With Us address: lines: - Smith Laboratory - Department of Computer Science - University of Excellence - 123 Science Drive - Excellence City, EC 12345 - United States office_hours: - "Monday - Friday: 9:00 AM - 5:00 PM" - "Lab Meetings: Fridays 2:00 PM" email: lab@example.edu phone: "+1 (555) 123-4567" social: - icon: brands/x url: https://x.com/SmithLabResearch - icon: brands/linkedin url: https://linkedin.com/company/smith-lab - icon: brands/github url: https://github.com/smith-lab prospective: title: Prospective Members text: Interested in joining our lab? We're looking for motivated researchers. button: text: View Open Positions url: /opportunities map_url: https://maps.google.com/?q=University+of+Excellence show_form: false design: css_class: "bg-gray-50 dark:bg-gray-900" spacing: padding: ["3rem", 0, "3rem", 0] ``` ## Options ### Content Options - **title**: Main heading for the contact section - **subtitle**: Optional subtitle text - **visit_title**: Heading for the location card (default: "Visit Us") - **connect_title**: Heading for the contact card (default: "Connect") - **address**: Physical address with multiple lines - `lines`: Array of address line strings - **office_hours**: Array of office hour strings - **email**: Contact email address - **phone**: Contact phone number - **social**: Array of social media links - `icon`: Icon identifier (e.g., "brands/x", "brands/linkedin") - `url`: Social media profile URL - **prospective**: Information for prospective members - `title`: Section heading - `text`: Description text - `button`: CTA button with `text` and `url` - **map_url**: External map service link - **map_embed**: HTML embed code for inline map - **show_form**: Display contact form (default: false) - **form_action**: Form submission endpoint ### Design Options Standard design options apply including: - `css_class`: Background and styling classes - `spacing`: Padding configuration ## Map Integration ### External Map Link Provide a `map_url` to link to Google Maps, Apple Maps, or other services: ```yaml map_url: "https://maps.google.com/?q=Your+Location" ``` ### Embedded Map For inline maps, provide the iframe HTML in `map_embed`: ```yaml map_embed: | ``` ## Contact Form Enable the built-in contact form: ```yaml show_form: true form_action: "https://formspree.io/f/YOUR_FORM_ID" ``` Note: You'll need to set up a form handler service like Formspree, Netlify Forms, or custom endpoint. ## Styling The block uses modern card-based design with: - Subtle shadows and hover effects - Icon accents for visual hierarchy - Consistent spacing and typography - Fully responsive grid layout - Dark mode optimized colors ## Best Practices 1. **Complete Information**: Provide all relevant contact methods 2. **Office Hours**: Clearly state availability 3. **Social Proof**: Link active social media profiles 4. **Map Integration**: Help visitors find your location 5. **Recruitment CTA**: Include prospective member information 6. **Form Handler**: Set up proper form submission handling 7. **Mobile Testing**: Verify all links work on mobile devices ================================================ FILE: modules/blox/blox/contact-info/block.html ================================================ {{/* Hugo Blox: Contact Info Block */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{/* Enable Alpine.js for copy-to-clipboard functionality */}} {{ $page.Store.Set "has_alpine" true }} {{ $default_title := i18n "block_contact_title" | default "Contact Us" }} {{ $title := $default_title }} {{ $title_raw := index $content "title" }} {{ if eq (printf "%T" $title_raw) "string" }} {{ $title_raw = strings.TrimSpace $title_raw }} {{ if ne $title_raw "" }} {{ $title = $title_raw }} {{ end }} {{ end }} {{ $title = $title | emojify | $page.RenderString }} {{ $subtitle := "" }} {{ $subtitle_raw := index $content "subtitle" }} {{ if eq (printf "%T" $subtitle_raw) "string" }} {{ $subtitle = $subtitle_raw | emojify | $page.RenderString }} {{ end }} {{ $visit_title := i18n "block_contact_visit_title" | default "Visit Us" }} {{ $visit_title_raw := index $content "visit_title" }} {{ if eq (printf "%T" $visit_title_raw) "string" }} {{ $visit_title_raw = strings.TrimSpace $visit_title_raw }} {{ if ne $visit_title_raw "" }} {{ $visit_title = $visit_title_raw }} {{ end }} {{ end }} {{ $connect_title_raw := "" }} {{ $connect_title_value := index $content "connect_title" }} {{ if eq (printf "%T" $connect_title_value) "string" }} {{ $connect_title_raw = strings.TrimSpace $connect_title_value }} {{ end }} {{ $connect_title_standard := $connect_title_raw | default (i18n "block_contact_connect_title" | default "Connect") }} {{ $connect_title_single := $connect_title_raw | default (i18n "block_contact_connect_title" | default "Let's Connect") }} {{ $connect_text := "" }} {{ $connect_text_raw := index $content "text" }} {{ if eq (printf "%T" $connect_text_raw) "string" }} {{ $connect_text = strings.TrimSpace $connect_text_raw }} {{ end }} {{ if not $connect_text }} {{ $connect_text = "I'm always open to discussing new projects, opportunities, or just having a chat." }} {{ end }} {{ $address_lines := slice }} {{ $address_raw := index $content "address" }} {{ if and $address_raw (reflect.IsMap $address_raw) }} {{ $lines_raw := index $address_raw "lines" }} {{ if reflect.IsSlice $lines_raw }} {{ range $lines_raw }} {{ $line := strings.TrimSpace (printf "%v" .) }} {{ if $line }}{{ $address_lines = $address_lines | append $line }}{{ end }} {{ end }} {{ else if eq (printf "%T" $lines_raw) "string" }} {{ $line := strings.TrimSpace $lines_raw }} {{ if $line }}{{ $address_lines = slice $line }}{{ end }} {{ end }} {{ else if eq (printf "%T" $address_raw) "string" }} {{ $line := strings.TrimSpace $address_raw }} {{ if $line }}{{ $address_lines = slice $line }}{{ end }} {{ end }} {{ $office_hours := slice }} {{ $office_raw := index $content "office_hours" }} {{ if reflect.IsSlice $office_raw }} {{ range $office_raw }} {{ $line := strings.TrimSpace (printf "%v" .) }} {{ if $line }}{{ $office_hours = $office_hours | append $line }}{{ end }} {{ end }} {{ else if eq (printf "%T" $office_raw) "string" }} {{ $line := strings.TrimSpace $office_raw }} {{ if $line }}{{ $office_hours = slice $line }}{{ end }} {{ end }} {{ $map_url := "" }} {{ $map_url_raw := index $content "map_url" }} {{ if eq (printf "%T" $map_url_raw) "string" }} {{ $map_url = strings.TrimSpace $map_url_raw }} {{ end }} {{ $map_embed := "" }} {{ $map_embed_raw := index $content "map_embed" }} {{ if eq (printf "%T" $map_embed_raw) "string" }} {{ $map_embed = $map_embed_raw }} {{ end }} {{ $show_form := partial "functions/coerce_bool" (dict "value" (index $content "show_form") "default" false) }} {{ $form_action := "" }} {{ $form_action_raw := index $content "form_action" }} {{ if eq (printf "%T" $form_action_raw) "string" }} {{ $form_action = strings.TrimSpace $form_action_raw }} {{ end }} {{ if not $form_action }}{{ $form_action = "#" }}{{ end }} {{/* Check if Visit Us card has content */}} {{ $has_visit_content := or (gt (len $address_lines) 0) (gt (len $office_hours) 0) $map_url }} {{/* Check if Connect card has content - fallback to author profile if no email/social */}} {{ $author := "me" }} {{ $author_raw := index $content "username" }} {{ if eq (printf "%T" $author_raw) "string" }} {{ $author = strings.TrimSpace $author_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $author }} {{ $authors := partialCached "functions/get_authors_data" $page site.Language.Lang }} {{ $author_data := index $authors (urlize $author) }} {{ $email := "" }} {{ $email_raw := index $content "email" }} {{ if eq (printf "%T" $email_raw) "string" }} {{ $email = strings.TrimSpace $email_raw }} {{ end }} {{ if and (not $email) $author_data (reflect.IsMap $author_data) }} {{ $author_email_raw := index $author_data "email" }} {{ if eq (printf "%T" $author_email_raw) "string" }} {{ $email = strings.TrimSpace $author_email_raw }} {{ end }} {{ end }} {{ $phone := "" }} {{ $phone_raw := index $content "phone" }} {{ if eq (printf "%T" $phone_raw) "string" }} {{ $phone = strings.TrimSpace $phone_raw }} {{ end }} {{ if and (not $phone) $author_data (reflect.IsMap $author_data) }} {{ $author_phone_raw := index $author_data "phone" }} {{ if eq (printf "%T" $author_phone_raw) "string" }} {{ $phone = strings.TrimSpace $author_phone_raw }} {{ end }} {{ end }} {{ $social_raw := index $content "social" }} {{ if eq $social_raw nil }}{{ $social_raw = $profile.links }}{{ end }} {{ $social := slice }} {{ if reflect.IsSlice $social_raw }} {{ range $social_raw }} {{ $url := "" }} {{ $icon := "hero/link" }} {{ $label := "" }} {{ if reflect.IsMap . }} {{ $url_raw := index . "url" | default (index . "link") }} {{ if eq (printf "%T" $url_raw) "string" }} {{ $url = strings.TrimSpace $url_raw }} {{ end }} {{ $icon_raw := index . "icon" }} {{ if eq (printf "%T" $icon_raw) "string" }} {{ $icon = $icon_raw }} {{ end }} {{ $label_raw := index . "label" | default (index . "name") }} {{ if eq (printf "%T" $label_raw) "string" }} {{ $label = $label_raw }} {{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $url = strings.TrimSpace . }} {{ end }} {{ if $url }} {{ $social = $social | append (dict "url" $url "icon" $icon "label" $label) }} {{ end }} {{ end }} {{ else if eq (printf "%T" $social_raw) "string" }} {{ $url := strings.TrimSpace $social_raw }} {{ if $url }} {{ $social = slice (dict "url" $url "icon" "hero/link" "label" "") }} {{ end }} {{ end }} {{ $prospective_raw := index $content "prospective" }} {{ $prospective := dict }} {{ if and $prospective_raw (reflect.IsMap $prospective_raw) }} {{ $prospective = $prospective_raw }} {{ end }} {{ $prospective_title := "" }} {{ $prospective_title_raw := index $prospective "title" }} {{ if eq (printf "%T" $prospective_title_raw) "string" }} {{ $prospective_title = strings.TrimSpace $prospective_title_raw }} {{ end }} {{ $prospective_text := "" }} {{ $prospective_text_raw := index $prospective "text" }} {{ if eq (printf "%T" $prospective_text_raw) "string" }} {{ $prospective_text = strings.TrimSpace $prospective_text_raw }} {{ end }} {{ $prospective_button := index $prospective "button" }} {{ if not (reflect.IsMap $prospective_button) }}{{ $prospective_button = dict }}{{ end }} {{ $prospective_button_text := "" }} {{ with index $prospective_button "text" }}{{ $prospective_button_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $prospective_button_url := "" }} {{ with index $prospective_button "url" }}{{ $prospective_button_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $has_connect_content := or $email $phone (gt (len $social) 0) $prospective_title $prospective_text $prospective_button_text $prospective_button_url }} {{/* Determine grid layout - single column centered if only one card */}} {{ $grid_class := "grid-cols-1 lg:grid-cols-2" }} {{ $card_max_width := "" }} {{ $is_single_card := false }} {{ if and $has_visit_content (not $has_connect_content) }} {{ $grid_class = "grid-cols-1" }} {{ $card_max_width = "max-w-3xl mx-auto" }} {{ $is_single_card = true }} {{ else if and $has_connect_content (not $has_visit_content) }} {{ $grid_class = "grid-cols-1" }} {{ $card_max_width = "max-w-3xl mx-auto" }} {{ $is_single_card = true }} {{ end }}
{{/* Section Header */}}
{{ with $title }}

{{ . }}

{{ end }} {{ with $subtitle }}

{{ . }}

{{ end }}
{{/* Contact Cards Grid */}}
{{/* Visit Us Card - Only show if has content */}} {{ if $has_visit_content }}
{{ partial "functions/get_icon" (dict "name" "hero/map-pin" "attributes" "class=\"w-6 h-6 text-primary-600 dark:text-primary-400\"") }}

{{ $visit_title }}

{{ if gt (len $address_lines) 0 }}
{{ range $address_lines }}

{{ . }}

{{ end }}
{{ end }} {{ if gt (len $office_hours) 0 }}

{{ i18n "block_contact_office_hours" | default "Office Hours" }}

{{ range $office_hours }}

{{ . }}

{{ end }}
{{ end }} {{ if $map_url }} {{ $map_link := $map_url }} {{ $map_target := "" }} {{ $map_scheme := (urls.Parse $map_link).Scheme }} {{ if not $map_scheme }} {{ if not (hasPrefix $map_link "#") }} {{ $map_link = $map_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $map_scheme }} {{ $map_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" "hero/map" "attributes" "class=\"w-5 h-5 mr-2\"") }} {{ i18n "block_contact_view_on_map" | default "View on Map" }} {{ end }}
{{ end }} {{/* Connect Card - Only show if has content */}} {{ if $has_connect_content }}
{{/* Filter social links - remove mailto if email is shown separately */}} {{ $filtered_social := slice }} {{ range $social }} {{ $url := index . "url" }} {{ if and $url (not (and $email (hasPrefix $url "mailto:"))) }} {{ $filtered_social = $filtered_social | append . }} {{ end }} {{ end }} {{ if $is_single_card }} {{/* Single card layout - horizontal on desktop */}}
{{/* Left: Email & CTA */}}

{{ $connect_title_single }}

{{ $connect_text }}

{{ with $email }} {{/* Email with click-to-copy */}}
{{/* Toast notification */}}
✓ Copied to clipboard!
{{/* Primary CTA Button */}} {{ partial "functions/get_icon" (dict "name" "hero/paper-airplane" "attributes" "class=\"w-5 h-5 mr-2\"") }} Send a message {{ end }} {{ with $phone }}
{{ partial "functions/get_icon" (dict "name" "hero/phone" "attributes" "class=\"w-6 h-6 text-primary-600 dark:text-primary-400\"") }}

Call me

{{ . }}

{{ end }}
{{/* Right: Social Links */}} {{ if gt (len $filtered_social) 0 }}

{{ i18n "block_contact_follow_me" | default "Find me on" }}

{{ range $filtered_social }} {{ $social_url := index . "url" }} {{ $social_label := index . "label" }} {{ $social_icon := index . "icon" }} {{ $link := $social_url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }}
{{ partial "functions/get_icon" (dict "name" $social_icon "attributes" "class=\"w-7 h-7\"") }}
{{ end }}
{{ end }}
{{ else }} {{/* Standard card layout (when shown alongside Visit Us) */}}
{{ partial "functions/get_icon" (dict "name" "hero/chat-bubble-left-right" "attributes" "class=\"w-6 h-6 text-primary-600 dark:text-primary-400\"") }}

{{ $connect_title_standard }}

{{/* Contact Methods */}}
{{ with $email }}
{{ partial "functions/get_icon" (dict "name" "hero/envelope" "attributes" "class=\"w-5 h-5 text-primary-600 dark:text-primary-400\"") }}

Email

{{ . }}

{{ end }} {{ with $phone }}
{{ partial "functions/get_icon" (dict "name" "hero/phone" "attributes" "class=\"w-5 h-5 text-primary-600 dark:text-primary-400\"") }}

Phone

{{ . }}

{{ end }} {{/* Social Media */}} {{ if gt (len $filtered_social) 0 }}

{{ i18n "block_contact_follow_me" | default "Find me on" }}

{{ range $filtered_social }} {{ $social_url := index . "url" }} {{ $social_label := index . "label" }} {{ $social_icon := index . "icon" }} {{ $link := $social_url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $social_icon "attributes" "class=\"w-5 h-5\"") }} {{ end }}
{{ end }}
{{ end }} {{/* Prospective Members - shown in both layouts */}} {{ if or $prospective_title $prospective_text $prospective_button_text $prospective_button_url }} {{ $prospective_heading := $prospective_title | default (i18n "block_contact_prospective_title" | default "Prospective Members") }}

{{ $prospective_heading }}

{{ with $prospective_text }}

{{ . }}

{{ end }} {{ if and $prospective_button_text $prospective_button_url }} {{ $cta_link := $prospective_button_url }} {{ $cta_target := "" }} {{ $cta_scheme := (urls.Parse $cta_link).Scheme }} {{ if not $cta_scheme }} {{ if not (hasPrefix $cta_link "#") }} {{ $cta_link = $cta_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $cta_scheme }} {{ $cta_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" "hero/user-plus" "attributes" "class=\"w-5 h-5 mr-2\"") }} {{ $prospective_button_text }} {{ end }}
{{ end }}
{{ end }}
{{/* Optional Map Embed */}} {{ with $map_embed }}
{{ . | safeHTML }}
{{ end }} {{/* Contact Form (optional) */}} {{ if $show_form }}

{{ i18n "block_contact_form_title" | default "Send us a Message" }}

{{ end }}
================================================ FILE: modules/blox/blox/contact-info/manifest.json ================================================ { "id": "contact-info", "name": "Contact Info", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["contact", "information", "address", "location", "lab", "research", "organization"], "description": "Display contact information with modern card layout, including address, phone, email, social media, and optional contact form", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "static-site", "contact", "information", "address", "research-lab"] } ================================================ FILE: modules/blox/blox/cta-button-list/README.md ================================================ # CTA Button List Block **Drive action with beautiful, conversion-focused button lists** Transform your visitors into engaged users with the CTA Button List block - a sleek, modern way to present multiple call-to-action options in an organized, visually appealing format. ## ✨ Key Features - **Icon Integration**: Add engaging icons to every button for visual impact - **Hover Animations**: Smooth scale and transition effects that invite interaction - **Responsive Design**: Perfect button sizing and spacing across all devices - **External Link Support**: Built-in support for external links with proper security attributes - **Markdown Support**: Rich text formatting for button labels - **Clean Styling**: Modern card-based design with subtle shadows and borders ## 🎯 Perfect For - **Social Media Links**: Create an elegant "link in bio" style page - **Resource Collections**: Direct visitors to your key resources and tools - **Service Offerings**: Showcase different services or products you offer - **Contact Options**: Multiple ways for visitors to reach you - **Download Centers**: Organize files, guides, and resources for easy access - **Partner Links**: Highlight collaborations and partnerships ## 🚀 Why Choose CTA Button List? **High Conversion Design**: Proven button styling that encourages clicks and engagement **Flexible & Scalable**: Add as many buttons as needed without compromising design **Professional Appeal**: Clean, modern aesthetic that works for any industry or use case **Easy Maintenance**: Simple configuration that keeps your links organized and up-to-date ## 📊 Conversion Benefits - Increased click-through rates with prominent, well-designed buttons - Better user experience with clear visual hierarchy - Reduced bounce rates by providing multiple engagement paths - Improved accessibility with proper labeling and focus states ## 💡 Pro Tips - Use contrasting icons to make each button distinct - Keep button text concise but descriptive - Order buttons by priority or user journey importance - Test different icon styles to match your brand aesthetic Perfect for entrepreneurs, creators, businesses, and anyone who wants to turn their website visitors into active participants in their ecosystem. ================================================ FILE: modules/blox/blox/cta-button-list/block.html ================================================ {{/* Hugo Blox: Buttons */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }}
{{ $buttons_raw := index $content "buttons" }} {{ $buttons := slice }} {{ if reflect.IsSlice $buttons_raw }} {{ $buttons = $buttons_raw }} {{ else if and $buttons_raw (reflect.IsMap $buttons_raw) }} {{ $buttons = slice $buttons_raw }} {{ else if eq (printf "%T" $buttons_raw) "string" }} {{ $buttons = slice (dict "url" $buttons_raw) }} {{ end }} {{ range $index, $item := $buttons }} {{ $text := "" }} {{ $url := "" }} {{ $icon := "" }} {{ $new_tab := false }} {{ if reflect.IsMap $item }} {{ $text_raw := index $item "text" | default (index $item "label") | default (index $item "name") }} {{ if ne $text_raw nil }}{{ $text = strings.TrimSpace (printf "%v" $text_raw) }}{{ end }} {{ $url_raw := index $item "url" | default (index $item "link") }} {{ if eq (printf "%T" $url_raw) "string" }}{{ $url = strings.TrimSpace $url_raw }}{{ end }} {{ $icon_raw := index $item "icon" }} {{ if eq (printf "%T" $icon_raw) "string" }}{{ $icon = $icon_raw }}{{ end }} {{ $new_tab = partial "functions/coerce_bool" (dict "value" (index $item "new_tab") "default" false) }} {{ else if eq (printf "%T" $item) "string" }} {{ $url = strings.TrimSpace $item }} {{ end }} {{ if and (not $text) $url }} {{ $text = $url }} {{ end }} {{ if $url }} {{ $link := $url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }} {{ $new_tab = true }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $new_tab = true }} {{ end }} {{ if $new_tab }} {{ $target = "target=\"_blank\" rel=\"noopener noreferrer\"" }} {{ end }}
{{ with $icon }} {{ partial "functions/get_icon" (dict "name" . "attributes" "height=\"40\" width=\"40\" class=\"rounded-sm\"") }} {{ end }}
{{ $text | markdownify | emojify }}
{{ end }} {{ end }}
================================================ FILE: modules/blox/blox/cta-button-list/manifest.json ================================================ { "id": "cta-button-list", "name": "CTA Button List", "version": "1.0.0", "license": "MIT", "category": "marketing", "tags": ["cta", "buttons", "links", "social", "marketing", "conversion", "list"], "description": "Create compelling vertical lists of call-to-action buttons with icons and hover effects", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "cta", "buttons", "conversion", "marketing", "social-links"] } ================================================ FILE: modules/blox/blox/cta-card/README.md ================================================ # CTA Card Block **Create irresistible calls-to-action that convert** Make a bold statement and drive immediate action with the CTA Card block - a high-impact, conversion-optimized component designed to capture attention and compel your visitors to take the next step. ## ✨ Key Features - **🪟 2025 Glassmorphism**: Modern translucent backgrounds with backdrop blur effects - **🎨 Gradient Typography**: Beautiful gradient text effects for maximum visual appeal - **🔗 Smart Icon Support**: Add icons to buttons with automatic sizing and hover animations - **📱 Enhanced Responsiveness**: Fluid typography scaling from mobile to desktop - **✨ Micro-Interactions**: Smooth hover animations with glow effects and transforms - **🎯 Customizable Styling**: Multiple glassmorphism presets or custom CSS classes - **♿ Accessibility Enhanced**: Improved focus states and semantic markup ## 🎯 Perfect For - **Newsletter Signups**: Encourage email subscriptions with compelling copy - **Product Launches**: Announce new products or services with impact - **Event Promotions**: Drive registrations and attendance - **Lead Generation**: Capture leads with irresistible offers - **Content Downloads**: Promote whitepapers, guides, and resources - **Service Inquiries**: Convert visitors into prospects and clients ## 🚀 Why Choose CTA Card? **Maximum Visual Impact**: Bold design that stands out on any page and captures immediate attention **Conversion Focused**: Every element is optimized for driving action, from typography to button placement **Brand Flexible**: Fully customizable styling to match your brand colors and aesthetic **Proven Results**: Based on high-converting design patterns used by top marketing teams ## 📊 Conversion Psychology - **Contrast Principle**: Dark background creates visual separation and focus - **Size Hierarchy**: Large headlines establish clear information priority - **Action Clarity**: Single, prominent button reduces decision paralysis - **Emotional Appeal**: Space for compelling copy that connects with your audience ## 💡 Best Practices - Keep headlines short and benefit-focused - Use action-oriented button text ("Get Started", "Download Now", "Join Today") - Ensure your copy addresses a specific pain point or desire - Test different background colors to maximize contrast with your site Transform casual visitors into engaged users with a CTA Card that's impossible to ignore. ## 🎨 2025 Glassmorphism Styling Options ### **Glassmorphism Primary** (Recommended) ```yaml - block: cta-card content: title: 'Ready to Get Started?' text: 'Join thousands of users creating amazing websites' button: text: 'Get Started Free' url: '/signup/' icon: 'hero/rocket-launch' design: card: css_class: 'cta-glassmorphism' text_color: 'auto' # auto|light|dark overlay_opacity: 0.15 # 0.0-1.0 for contrast control background: gradient: start: 'primary-500' end: 'primary-700' direction: 135 image: filename: 'textures/noise-pattern.svg' size: '32px' position: 'repeat' ``` ### **Glassmorphism Dark** ```yaml design: card: css_class: 'glassmorphism-dark glass-ring glass-shadow text-white' ``` ### **Glassmorphism Light** ```yaml design: card: css_class: 'glassmorphism-light glass-ring glass-shadow text-gray-900' ``` ### **Custom Background + Glassmorphism** ```yaml design: card: css_class: 'glassmorphism-secondary noise-texture text-white' background: color: 'primary-600' image: filename: 'your-background.jpg' size: 'cover' position: 'center' opacity: 0.8 gradient: start: 'primary-500' end: 'secondary-600' direction: 135 ``` ## 🔗 Icon Support Add icons to your CTA buttons: ```yaml button: text: 'Download Now' url: '/download/' icon: 'hero/download' # Download icon button: text: 'Contact Us' url: 'mailto:hello@example.com' icon: 'hero/paper-airplane' # Email icon button: text: 'Learn More' url: '#features' icon: 'hero/arrow-right' # Arrow icon ``` ## 🎨 Contrast Control Options ### **Text Color Modes** ```yaml card: text_color: 'auto' # Auto-detects based on background brightness text_color: 'light' # Force white text (for dark backgrounds) text_color: 'dark' # Force dark text (for light backgrounds) ``` ### **Overlay Opacity Control** ```yaml card: overlay_opacity: 0.1 # Subtle glassmorphism (better for text contrast) overlay_opacity: 0.15 # Default glassmorphism overlay_opacity: 0.25 # Strong glassmorphism (may reduce contrast) overlay_opacity: 0.05 # Minimal glassmorphism (maximum contrast) ``` ### **Perfect Contrast Examples** **Dark Background (Light Text):** ```yaml design: card: css_class: 'cta-glassmorphism' text_color: 'light' overlay_opacity: 0.1 background: gradient: start: 'gray-800' end: 'gray-900' ``` **Light Background (Dark Text):** ```yaml design: card: css_class: 'cta-glassmorphism' text_color: 'dark' overlay_opacity: 0.2 background: gradient: start: 'gray-100' end: 'gray-300' ``` **Vibrant Background (Auto Detection):** ```yaml design: card: css_class: 'cta-glassmorphism' text_color: 'auto' # Will detect primary-500 as medium and use adaptive colors overlay_opacity: 0.15 background: gradient: start: 'primary-500' end: 'primary-700' ``` ## ✨ Available Glassmorphism Classes - **`cta-glassmorphism`**: Smart adaptive glassmorphism with contrast controls - **`glassmorphism-primary`**: Primary color glassmorphism (legacy) - **`glassmorphism-secondary`**: Secondary color glassmorphism (legacy) - **`glassmorphism-dark`**: Dark glassmorphism (legacy) - **`glassmorphism-light`**: Light glassmorphism (legacy) - **`glass-ring`**: Enhanced ring borders - **`glass-shadow`**: Multi-layer glass shadows - **`noise-texture`**: Subtle noise texture overlay ================================================ FILE: modules/blox/blox/cta-card/client.jsx ================================================ import {render} from "preact"; import {CtaCardBlock} from "./component.jsx"; function renderCtaCardBlock() { const blocks = document.querySelectorAll('.cta-card-block-container[data-preact-render="true"]'); blocks.forEach((block) => { try { if (block.dataset.rendered === "true") return; const props = JSON.parse(block.dataset.props); render(, block); block.dataset.rendered = "true"; } catch (e) { console.error("Error rendering CTA Card Block:", e, block); } }); } // Initial render if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", renderCtaCardBlock); } else { renderCtaCardBlock(); } ================================================ FILE: modules/blox/blox/cta-card/component.jsx ================================================ /** * CTA Card Block Component * A centered card with title, text, and primary action button. * Supports glassmorphism, custom backgrounds, and automatic text color adjustment. */ import {Icon} from "../../shared/components/Icon.jsx"; // Simple markdown renderer function renderText(text) { if (!text) return ""; return String(text) .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1") .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); } export const CtaCardBlock = ({content, design, _id, button_icon_svg}) => { const card = design?.card || {}; const cardClass = card.css_class || ""; const cardStyle = card.css_style || ""; // Overlay Opacity Logic let overlayOpacity = 0.15; if (card.overlay_opacity !== undefined) { const val = parseFloat(card.overlay_opacity); if (!Number.isNaN(val)) overlayOpacity = Math.max(0, Math.min(1, val)); } // Text Color Logic let textColorMode = "auto"; if (["light", "dark", "auto"].includes(card.text_color?.toLowerCase())) { textColorMode = card.text_color.toLowerCase(); } let textClasses = "text-gray-900 dark:text-white"; let buttonClasses = "text-gray-900 dark:text-gray-100"; // Auto-detect based on background gradient const bg = design?.background || {}; const gradientStart = bg.gradient?.start || ""; const isDarkBg = ["primary-7", "primary-8", "primary-9", "secondary-7", "secondary-8", "secondary-9"].some((p) => gradientStart.startsWith(p)); if (textColorMode === "light") { textClasses = "text-white"; buttonClasses = "text-gray-900 dark:text-white"; } else if (textColorMode === "dark") { textClasses = "text-gray-900 dark:text-white"; buttonClasses = "text-gray-900 dark:text-white"; } else if (isDarkBg) { textClasses = "text-white"; buttonClasses = "text-gray-900"; } // Button Logic const button = content?.button || {}; const buttonText = button.text?.trim(); const buttonUrl = button.url?.trim(); const showButton = !!(buttonText && buttonUrl); let isExternal = false; let isNewTab = button.new_tab === true; if (buttonUrl) { try { const url = new URL(buttonUrl, window.location.origin); isExternal = url.origin !== window.location.origin; } catch { isExternal = /^https?:\/\//.test(buttonUrl); } if (buttonUrl.endsWith(".pdf")) isNewTab = true; if (isExternal) isNewTab = true; } const defaultBgClass = "bg-gradient-to-br from-primary-500/90 via-primary-600/95 to-primary-700/90"; const finalCardClass = cardClass || defaultBgClass; const style = `--glassmorphism-opacity: ${overlayOpacity}; ${cardStyle}`; return (
{/* Title */} {content.title && (

)} {/* Text */} {content.text && ( ); }; ================================================ FILE: modules/blox/blox/cta-card/manifest.json ================================================ { "id": "cta-card", "name": "CTA Card", "version": "1.0.0", "license": "MIT", "category": "marketing", "tags": ["cta", "card", "conversion", "marketing", "hero", "call-to-action", "banner"], "description": "Create high-impact call-to-action cards with bold typography and compelling buttons", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "cta", "marketing", "conversion", "banner", "card"] } ================================================ FILE: modules/blox/blox/cta-image-paragraph/README.md ================================================ # CTA Image Paragraph Block **Tell your story with stunning visuals and compelling copy** Engage your audience with the CTA Image Paragraph block - a powerful storytelling component that combines beautiful imagery, descriptive content, feature highlights, and strategic calls-to-action in an alternating layout that keeps visitors scrolling. ## ✨ Key Features - **Alternating Layout**: Images automatically alternate left/right for visual rhythm - **Responsive Images**: Smart image processing with multiple sizes and WebP support - **Feature Lists**: Highlight key benefits with customizable icons - **GIF Support**: Full support for animated GIFs alongside static images - **CTA Integration**: Strategic button placement for maximum conversion - **Markdown Rich**: Full Markdown support for titles and descriptions - **Mobile Optimized**: Stacks beautifully on mobile devices ## 🎯 Perfect For - **Product Showcases**: Highlight different product features with supporting visuals - **Service Explanations**: Break down complex services into digestible sections - **Company Story**: Tell your brand story with compelling narratives and imagery - **Feature Announcements**: Introduce new features with visual demonstrations - **Process Explanations**: Guide users through multi-step processes - **Benefits Highlighting**: Showcase the value proposition of your offerings ## 🚀 Why Choose CTA Image Paragraph? **Visual Storytelling**: Combine the power of images and words for maximum engagement **Conversion Optimized**: Strategic placement of features and CTAs guides users toward action **Professional Polish**: Alternating layout creates visual interest and professional appearance **Content Flexibility**: Support any number of sections with unique images, copy, and features ## 📊 Engagement Benefits - **Higher Time on Page**: Alternating content keeps visitors engaged longer - **Better Comprehension**: Visual-text combinations improve understanding and retention - **Increased Conversions**: Strategic CTA placement at optimal engagement points - **Mobile Excellence**: Responsive design ensures great experience on all devices ## 💡 Design Psychology - **Visual Rhythm**: Alternating layout creates pleasing visual flow - **Information Chunking**: Breaking content into sections improves readability - **Social Proof**: Feature lists build credibility and trust - **Action Momentum**: Multiple CTAs capture interest at different engagement levels Perfect for SaaS companies, service providers, product teams, and anyone who needs to explain complex offerings through engaging visual storytelling. ================================================ FILE: modules/blox/blox/cta-image-paragraph/client.jsx ================================================ /** * CTA Image Paragraph Block - Client-side Hydration */ import {render} from "preact"; import {CtaImageParagraphBlock} from "./component.jsx"; function renderCtaImageParagraphBlocks() { const blocks = document.querySelectorAll('[data-block-type="cta-image-paragraph"]'); blocks.forEach((block) => { const propsData = block.dataset.props; if (propsData) { try { const props = JSON.parse(propsData); render(, block); console.debug(`✓ CTA Image Paragraph block "${block.id}" rendered with Preact`); } catch (error) { console.error(`Failed to render CTA Image Paragraph block "${block.id}":`, error); } } }); } renderCtaImageParagraphBlocks(); ================================================ FILE: modules/blox/blox/cta-image-paragraph/component.jsx ================================================ /** * CTA Image Paragraph Block Component - Single source of truth * Alternating image + text sections with feature lists and CTA buttons * Images are pre-processed by Hugo's responsive image pipeline (srcset) */ import {Icon} from "../../shared/components/Icon.jsx"; // Simple markdown renderer function renderText(text) { if (!text) return ""; return String(text) .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1") .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); } // Arrow icon for CTA buttons const ArrowIcon = () => ( ); function CtaItem({item, idx, imageData, featureIconSvg}) { const isReversed = idx % 2 === 1; const hasImage = !!imageData; const _featureIcon = item.feature_icon || "check"; // Resolve button link const buttonUrl = item.button?.url || ""; let isExternal = false; if (buttonUrl) { try { const url = new URL(buttonUrl, window.location.origin); isExternal = url.origin !== window.location.origin; } catch { isExternal = /^https?:\/\//.test(buttonUrl); } } const features = Array.isArray(item.features) ? item.features : typeof item.features === "string" ? [item.features] : []; return (
{/* Image */} {hasImage && (imageData.srcset ? ( {item.title ) : ( {item.title ))} {/* Text Content */}
{item.title && (

)} {item.text && (

)} {/* Feature List */} {features.length > 0 && (

    {features.map((feature, fIdx) => (
  • {featureIconSvg ? : null}
  • ))}
)} {/* CTA Button */} {item.button?.text && item.button?.url && ( {item.button.text} )}

); } export const CtaImageParagraphBlock = ({content, _design, _id, item_images, icon_svgs}) => { const items = Array.isArray(content?.items) ? content.items : []; const imageMap = item_images || {}; const iconMap = icon_svgs || {}; return (
{items.map((item, idx) => ( ))}
); }; ================================================ FILE: modules/blox/blox/cta-image-paragraph/manifest.json ================================================ { "id": "cta-image-paragraph", "name": "CTA Image Paragraph", "version": "1.0.0", "license": "MIT", "category": "marketing", "tags": ["cta", "image", "features", "alternating", "marketing", "storytelling", "visual"], "description": "Engaging alternating image and text sections with feature lists and call-to-action buttons", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "marketing", "images", "features", "storytelling", "conversion"] } ================================================ FILE: modules/blox/blox/dev-hero/README.md ================================================ # Dev Hero Block A modern, developer-focused hero section optimized for dark mode with gradient effects, animated backgrounds, and flexible layouts. ## Features - **Gradient Text**: Name displayed with beautiful gradient styling - **Animated Background**: Floating orbs with subtle grid pattern - **Social Links**: Automatic icon detection for common platforms - **CTA Buttons**: Primary and secondary button styling - **Two Layouts**: Centered or split (avatar on side) layouts - **Author Integration**: Pulls data from author profiles - **Emoji Status Badge**: Optional personalized emoji on avatar (💻 developer, 🎨 designer, 🚀 startup, etc.) - **Scroll Indicator**: Optional animated scroll prompt ## Usage ### Centered Layout (Default) ```yaml - block: dev-hero id: hero content: username: me greeting: "Hi, I'm" show_status: true show_scroll_indicator: true cta_buttons: - text: View My Work url: "#projects" icon: arrow-down - text: Get In Touch url: "#contact" icon: envelope design: style: centered avatar_shape: circle background: color: dark: "#0a0a0f" ``` ### Split Layout ```yaml - block: dev-hero id: hero content: username: me greeting: "Hello, I'm" cta_buttons: - text: View Projects url: "#projects" - text: Download Resume url: "/resume.pdf" icon: document-arrow-down design: style: split avatar_shape: rounded ``` ## Parameters ### Content | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `username` | string | `me` | Author folder to pull data from | | `title` | string | - | Override author title | | `tagline` | string | - | Override author role | | `bio` | string | - | Override author bio | | `greeting` | string | - | Text above the name | | `name_prefix` | string | - | Prefix before name (styled differently) | | `show_status` | boolean | `false` | Show emoji status badge (uses author's `status.icon`) | | `show_scroll_indicator` | boolean | `false` | Show scroll prompt | | `social` | array | - | Override author social links | | `cta_buttons` | array | - | Call-to-action buttons | ### Design | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `style` | string | `centered` | Layout style (`centered` or `split`) | | `avatar_shape` | string | `circle` | Avatar shape (`circle` or `rounded`) | ## Social Networks The block automatically detects icons for these networks: - `github` → GitHub logo - `linkedin` → LinkedIn logo - `twitter` → X (Twitter) logo - `email` → Envelope icon Other networks will use a generic link icon unless you specify a custom `icon`. ## CTA Buttons The first button is styled as primary (filled), subsequent buttons are secondary (outlined). ```yaml cta_buttons: - text: Primary Button url: "#action" icon: arrow-right # optional - text: Secondary Button url: "#other" ``` ## Author Data The block automatically pulls from `/data/authors/{username}.yaml`: - `name.display` → Name - `role` → Tagline/role - `bio` → Short biography - `links` → Social links - `avatar` → Profile image - `status.icon` → Emoji badge (shown when `show_status: true`) **Status Emoji Examples:** ```yaml # In data/authors/me.yaml status: icon: "💻" # Developer # Or: 🎨 Designer, 🚀 Entrepreneur, 🔬 Researcher, 🎓 Student ``` ## Styling The block includes: - Animated gradient orbs in the background - Subtle grid pattern overlay - Gradient text effect on the name - Glass morphism social buttons - Primary/secondary CTA button styles ================================================ FILE: modules/blox/blox/dev-hero/block.html ================================================ {{/* Hugo Blox: Dev Hero */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{/* Enable animations if typewriter or scroll animations are configured */}} {{ $typewriter := index $content "typewriter" }} {{ if not (reflect.IsMap $typewriter) }}{{ $typewriter = dict }}{{ end }} {{ $typewriter_enabled := partial "functions/coerce_bool" (dict "value" (index $typewriter "enable") "default" false) }} {{ $animations_enabled := partial "functions/coerce_bool" (dict "value" (index $design "animations") "default" false) }} {{ $has_animations := or $typewriter_enabled $animations_enabled }} {{ if $has_animations }} {{ $page.Store.Set "has_animations" true }} {{ $page.Store.Set "has_alpine" true }} {{ end }} {{/* Get author data from YAML */}} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $author := partial "functions/get_author_profile" $username }} {{/* Get avatar */}} {{ $avatar := "" }} {{ $avatar_shape := "circle" }} {{ $avatar_shape_raw := index $design "avatar_shape" }} {{ if eq (printf "%T" $avatar_shape_raw) "string" }} {{ $avatar_shape = lower (strings.TrimSpace $avatar_shape_raw) }} {{ end }} {{ with $author.avatar }} {{ $avatar = .Fill "300x300 webp Center" }} {{ end }} {{/* Layout style */}} {{ $style := "centered" }} {{ $style_raw := index $design "style" }} {{ if eq (printf "%T" $style_raw) "string" }} {{ $style_candidate := lower (strings.TrimSpace $style_raw) }} {{ if in (slice "centered" "split") $style_candidate }} {{ $style = $style_candidate }} {{ end }} {{ end }} {{ $show_status := partial "functions/coerce_bool" (dict "value" (index $content "show_status") "default" false) }} {{ $show_scroll := partial "functions/coerce_bool" (dict "value" (index $content "show_scroll_indicator") "default" false) }} {{ $scroll_target := "#projects" }} {{ $scroll_target_raw := index $content "scroll_target" }} {{ if eq (printf "%T" $scroll_target_raw) "string" }} {{ $scroll_target = strings.TrimSpace $scroll_target_raw }} {{ end }} {{ if not $scroll_target }}{{ $scroll_target = "#projects" }}{{ end }} {{ $greeting := "" }} {{ $greeting_raw := index $content "greeting" }} {{ if eq (printf "%T" $greeting_raw) "string" }}{{ $greeting = $greeting_raw }}{{ end }} {{ $name_prefix := "" }} {{ $name_prefix_raw := index $content "name_prefix" }} {{ if eq (printf "%T" $name_prefix_raw) "string" }}{{ $name_prefix = $name_prefix_raw }}{{ end }} {{ $title_override := "" }} {{ $title_raw := index $content "title" }} {{ if eq (printf "%T" $title_raw) "string" }}{{ $title_override = strings.TrimSpace $title_raw }}{{ end }} {{ $tagline := "" }} {{ $tagline_raw := index $content "tagline" }} {{ if eq (printf "%T" $tagline_raw) "string" }}{{ $tagline = $tagline_raw }}{{ end }} {{ $bio_override := "" }} {{ $bio_raw := index $content "bio" }} {{ if eq (printf "%T" $bio_raw) "string" }}{{ $bio_override = $bio_raw }}{{ end }} {{ $role := $author.role | default $tagline }} {{ $bio := $author.bio | default $bio_override }} {{ $typewriter_strings := slice }} {{ $strings_raw := index $typewriter "strings" }} {{ if reflect.IsSlice $strings_raw }} {{ range $strings_raw }} {{ $val := strings.TrimSpace (printf "%v" .) }} {{ if $val }}{{ $typewriter_strings = $typewriter_strings | append $val }}{{ end }} {{ end }} {{ else if eq (printf "%T" $strings_raw) "string" }} {{ $val := strings.TrimSpace $strings_raw }} {{ if $val }}{{ $typewriter_strings = slice $val }}{{ end }} {{ end }} {{ $typewriter_prefix := "" }} {{ $typewriter_prefix_raw := index $typewriter "prefix" }} {{ if eq (printf "%T" $typewriter_prefix_raw) "string" }}{{ $typewriter_prefix = $typewriter_prefix_raw }}{{ end }} {{ $type_speed := partial "functions/coerce_int" (dict "value" (index $typewriter "type_speed") "default" 80 "min" 10 "max" 500) }} {{ $delete_speed := partial "functions/coerce_int" (dict "value" (index $typewriter "delete_speed") "default" 50 "min" 10 "max" 500) }} {{ $pause_time := partial "functions/coerce_int" (dict "value" (index $typewriter "pause_time") "default" 2000 "min" 200 "max" 10000) }} {{ $links_raw := $author.links | default (index $content "links") }} {{ $links := slice }} {{ if reflect.IsSlice $links_raw }} {{ range $links_raw }} {{ $url := "" }} {{ $icon := "hero/link" }} {{ $label := "" }} {{ if reflect.IsMap . }} {{ $url_raw := index . "url" | default (index . "link") }} {{ if eq (printf "%T" $url_raw) "string" }}{{ $url = strings.TrimSpace $url_raw }}{{ end }} {{ $icon_raw := index . "icon" }} {{ if eq (printf "%T" $icon_raw) "string" }}{{ $icon = $icon_raw }}{{ end }} {{ $label_raw := index . "label" | default (index . "name") }} {{ if eq (printf "%T" $label_raw) "string" }}{{ $label = $label_raw }}{{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $url = strings.TrimSpace . }} {{ end }} {{ if $url }} {{ $links = $links | append (dict "url" $url "icon" $icon "label" $label) }} {{ end }} {{ end }} {{ else if eq (printf "%T" $links_raw) "string" }} {{ $url := strings.TrimSpace $links_raw }} {{ if $url }} {{ $links = slice (dict "url" $url "icon" "hero/link" "label" "") }} {{ end }} {{ end }} {{ $cta_buttons_raw := index $content "cta_buttons" }} {{ $cta_buttons := slice }} {{ if reflect.IsSlice $cta_buttons_raw }} {{ $cta_buttons = $cta_buttons_raw }} {{ else if and $cta_buttons_raw (reflect.IsMap $cta_buttons_raw) }} {{ $cta_buttons = slice $cta_buttons_raw }} {{ end }} {{ $status_icon := "" }} {{ $status := $author.status }} {{ if and $status (reflect.IsMap $status) }} {{ $status_icon_raw := index $status "icon" }} {{ if eq (printf "%T" $status_icon_raw) "string" }} {{ $status_icon = $status_icon_raw }} {{ end }} {{ end }}
{{/* Background Effects - only visible in dark mode */}} {{/* Light mode subtle background */}}
{{ if eq $style "split" }} {{/* Split layout with avatar on side */}}
{{/* Avatar */}} {{ with $avatar }}
{{ $author.title }}
{{/* Status emoji badge */}} {{ if $show_status }} {{ with $status_icon }} {{ . | emojify }} {{ end }} {{ end }} {{/* Decorative ring */}}
{{ end }} {{/* Content */}}
{{/* Greeting */}} {{ with $greeting }}

{{ . }}

{{ end }} {{/* Name */}}

{{ with $name_prefix }}{{ . }} {{ end }} {{ $author.title | default $title_override | default (i18n "developer" | default "Developer") }}

{{/* Role/Tagline with optional typewriter */}} {{ if and $typewriter_enabled (gt (len $typewriter_strings) 0) }}

{{ with $typewriter_prefix }}{{ . }} {{ end }}

{{ else if $role }}

{{ $role | $page.RenderString }}

{{ end }} {{/* Bio */}} {{ with $bio }}

{{ . | $page.RenderString }}

{{ end }} {{/* Social Links */}} {{ if gt (len $links) 0 }}
{{ range $links }} {{ $icon := index . "icon" | default "hero/link" }} {{ $url := index . "url" }} {{ $link := $url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener noreferrer\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-5 h-5\"") }} {{ end }}
{{ end }} {{/* CTA Buttons */}} {{ if gt (len $cta_buttons) 0 }}
{{ range $idx, $btn := $cta_buttons }} {{ if reflect.IsMap $btn }} {{ $is_primary := eq $idx 0 }} {{ $btn_text := "" }} {{ $btn_url := "" }} {{ $btn_icon := "" }} {{ $btn_new_tab := partial "functions/coerce_bool" (dict "value" (index $btn "new_tab") "default" false) }} {{ with index $btn "text" }}{{ $btn_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $btn "url" }}{{ $btn_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $btn "icon" }}{{ $btn_icon = printf "%v" . }}{{ end }} {{ if and $btn_text $btn_url }} {{ $link := $btn_url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }}{{ $btn_new_tab = true }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $btn_new_tab = true }} {{ end }} {{ if $btn_new_tab }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ if $btn_icon }} {{ partial "functions/get_icon" (dict "name" $btn_icon "attributes" "class=\"w-5 h-5\"") }} {{ end }} {{ $btn_text }} {{ end }} {{ end }} {{ end }}
{{ end }}
{{ else }} {{/* Centered layout */}} {{/* Avatar */}} {{ with $avatar }}
{{ $author.title }}
{{/* Status emoji badge */}} {{ if $show_status }} {{ with $status_icon }} {{ . | emojify }} {{ end }} {{ end }}
{{ end }} {{/* Greeting */}} {{ with $greeting }}

{{ . }}

{{ end }} {{/* Name */}}

{{ with $name_prefix }}{{ . }} {{ end }} {{ $author.title | default $title_override | default (i18n "developer" | default "Developer") }}

{{/* Role/Tagline with optional typewriter */}} {{ if and $typewriter_enabled (gt (len $typewriter_strings) 0) }}

{{ with $typewriter_prefix }}{{ . }} {{ end }}

{{ else if $role }}

{{ $role | $page.RenderString }}

{{ end }} {{/* Bio */}} {{ with $bio }}

{{ . | $page.RenderString }}

{{ end }} {{/* Social Links */}} {{ if gt (len $links) 0 }}
{{ range $links }} {{ $icon := index . "icon" | default "hero/link" }} {{ $url := index . "url" }} {{ $link := $url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener noreferrer\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-5 h-5\"") }} {{ end }}
{{ end }} {{/* CTA Buttons */}} {{ if gt (len $cta_buttons) 0 }}
{{ range $idx, $btn := $cta_buttons }} {{ if reflect.IsMap $btn }} {{ $is_primary := eq $idx 0 }} {{ $btn_text := "" }} {{ $btn_url := "" }} {{ $btn_icon := "" }} {{ $btn_new_tab := partial "functions/coerce_bool" (dict "value" (index $btn "new_tab") "default" false) }} {{ with index $btn "text" }}{{ $btn_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $btn "url" }}{{ $btn_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $btn "icon" }}{{ $btn_icon = printf "%v" . }}{{ end }} {{ if and $btn_text $btn_url }} {{ $link := $btn_url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }}{{ $btn_new_tab = true }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $btn_new_tab = true }} {{ end }} {{ if $btn_new_tab }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ if $btn_icon }} {{ partial "functions/get_icon" (dict "name" $btn_icon "attributes" "class=\"w-5 h-5\"") }} {{ end }} {{ $btn_text }} {{ end }} {{ end }} {{ end }}
{{ end }} {{ end }} {{/* Scroll indicator - clicks to scroll to next section */}} {{ if $show_scroll }} {{ $scroll_link := $scroll_target }} {{ $scroll_target_attr := "" }} {{ $scroll_scheme := (urls.Parse $scroll_link).Scheme }} {{ if not $scroll_scheme }} {{ if not (hasPrefix $scroll_link "#") }} {{ $scroll_link = $scroll_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scroll_scheme }} {{ $scroll_target_attr = "target=\"_blank\" rel=\"noopener\"" }} {{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/dev-hero/manifest.json ================================================ { "id": "dev-hero", "name": "Dev Hero", "version": "1.0.0", "license": "MIT", "category": "hero", "tags": ["hero", "developer", "portfolio", "introduction", "landing"], "description": "A developer-focused hero section with gradient effects, social links, and CTA buttons - optimized for dark mode", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "hero", "developer", "portfolio", "landing-page"] } ================================================ FILE: modules/blox/blox/faq/README.md ================================================ # FAQ Block Display frequently asked questions in an interactive accordion format with automatic FAQPage structured data for SEO. ## Features - ✅ Interactive accordion with Alpine.js - ✅ FAQPage Schema.org structured data for Google rich results - ✅ Responsive design with Tailwind CSS - ✅ Dark mode support - ✅ Markdown support in answers ## Usage Add to your page's front matter: ```yaml sections: - block: faq content: title: Frequently Asked Questions subtitle: Find answers to common questions text: Can't find what you're looking for? [Contact us](/contact) items: - question: What is HugoBlox Kit? answer: HugoBlox Kit is a no-code website builder framework powered by Hugo and Tailwind CSS. - question: Is it free to use? answer: Yes! HugoBlox Kit is open source and free to use under the MIT license. - question: How do I get started? answer: | Getting started is easy: 1. Choose a template 2. Click "Use Template" 3. Customize your content 4. Deploy to GitHub Pages or Netlify button: text: View All FAQs url: /faq/ icon: arrow-right design: spacing: padding: ["6rem", "0", "6rem", "0"] ``` ## Structured Data This block automatically generates FAQPage structured data for better SEO and eligibility for Google's FAQ rich results. ## Customization - **Accordion behavior**: One item open at a time (default) - **Colors**: Automatically adapts to your theme - **Spacing**: Customizable via `design.spacing` - **Background**: Customizable via `design.background.color` ================================================ FILE: modules/blox/blox/faq/block.html ================================================ {{- $wcPage := .wcPage -}} {{- $wcBlock := .wcBlock -}} {{- $wcIdentifier := .wcIdentifier -}} {{- $content := $wcBlock.content -}} {{- if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end -}} {{- $design := $wcBlock.design -}} {{- if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end -}} {{/* Enable Alpine.js for interactive accordion */}} {{ $wcPage.Page.Store.Set "has_alpine" true }} {{- $st := index $design "spacing" -}} {{- if not (reflect.IsMap $st) }}{{ $st = dict }}{{ end -}} {{- $pad := slice "20px" "0" "20px" "0" -}} {{- $pad_raw := index $st "padding" -}} {{- if and (reflect.IsSlice $pad_raw) (ge (len $pad_raw) 4) }}{{ $pad = $pad_raw }}{{ end -}} {{- $pad_sm := slice "3rem" "0" -}} {{- $pad_sm_raw := index $st "padding_sm" -}} {{- if and (reflect.IsSlice $pad_sm_raw) (ge (len $pad_sm_raw) 2) }}{{ $pad_sm = $pad_sm_raw }}{{ end -}} {{- $mar := slice "0" "0" "0" "0" -}} {{- $mar_raw := index $st "margin" -}} {{- if and (reflect.IsSlice $mar_raw) (ge (len $mar_raw) 4) }}{{ $mar = $mar_raw }}{{ end -}} {{- $bg := index $design "background" -}} {{- if not (reflect.IsMap $bg) }}{{ $bg = dict }}{{ end -}} {{- $bg_color_val := "" -}} {{- $bg_color_raw := index $bg "color" -}} {{- if eq (printf "%T" $bg_color_raw) "string" }}{{ $bg_color_val = $bg_color_raw }}{{ end -}} {{- $title := "" -}} {{- $title_raw := index $content "title" -}} {{- if eq (printf "%T" $title_raw) "string" }}{{ $title = $title_raw }}{{ end -}} {{- $subtitle := "" -}} {{- $subtitle_raw := index $content "subtitle" -}} {{- if eq (printf "%T" $subtitle_raw) "string" }}{{ $subtitle = $subtitle_raw }}{{ end -}} {{- $text := "" -}} {{- $text_raw := index $content "text" -}} {{- if eq (printf "%T" $text_raw) "string" }}{{ $text = $text_raw }}{{ end -}} {{- $items_raw := index $content "items" -}} {{- $items := slice -}} {{- if reflect.IsSlice $items_raw }}{{ $items = $items_raw }}{{ end -}} {{- $button := index $content "button" -}} {{- if not (reflect.IsMap $button) }}{{ $button = dict }}{{ end -}} {{- $button_text := "" -}} {{- with index $button "text" }}{{ $button_text = strings.TrimSpace (printf "%v" .) }}{{ end -}} {{- $button_url := "" -}} {{- with index $button "url" }}{{ $button_url = strings.TrimSpace (printf "%v" .) }}{{ end -}} {{- $button_icon := "" -}} {{- with index $button "icon" }}{{ $button_icon = printf "%v" . }}{{ end -}}
{{- with $title -}}

{{ . | markdownify | emojify }}

{{- with $subtitle -}}

{{ . | markdownify | emojify }}

{{- end -}}
{{- end -}} {{- with $text -}}
{{ . | markdownify | emojify }}
{{- end -}} {{- if gt (len $items) 0 -}}
{{- range $index, $item := $items -}} {{- if reflect.IsMap $item -}} {{- $question := "" -}} {{- $question_raw := index $item "question" | default (index $item "title") -}} {{- if ne $question_raw nil }}{{ $question = printf "%v" $question_raw }}{{ end -}} {{- $answer := "" -}} {{- $answer_raw := index $item "answer" | default (index $item "text") -}} {{- if ne $answer_raw nil }}{{ $answer = printf "%v" $answer_raw }}{{ end -}} {{- if or $question $answer -}}
{{ $answer | markdownify | emojify }}
{{- end -}} {{- end -}} {{- end -}}
{{- end -}} {{- if and $button_text $button_url -}} {{- $link := $button_url -}} {{- $target := "" -}} {{- $scheme := (urls.Parse $link).Scheme -}} {{- if not $scheme -}} {{- if not (hasPrefix $link "#") -}} {{- $link = $link | relLangURL -}} {{- end -}} {{- if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end -}} {{- else if in (slice "http" "https") $scheme -}} {{- $target = "target=\"_blank\" rel=\"noopener\"" -}} {{- end -}} {{- end -}}
================================================ FILE: modules/blox/blox/faq/manifest.json ================================================ { "name": "faq", "version": "1", "title": "FAQ", "description": "Display frequently asked questions in an accordion format with SEO-optimized structured data", "categories": ["content", "interactive"], "preview": "preview.svg" } ================================================ FILE: modules/blox/blox/features/README.md ================================================ # Features Block **Showcase what makes you special with stunning feature grids** Present your key features, services, or benefits in a clean, organized grid that helps visitors quickly understand your value proposition. The Features block combines beautiful icons with compelling descriptions to create trust and drive engagement. ## ✨ Key Features - **Responsive Grid**: Automatically adapts from 1 column (mobile) to 3 columns (desktop) - **Icon Integration**: Beautiful icons that reinforce each feature's purpose - **Flexible Layout**: 2-3 column layouts that work perfectly with any number of features - **Brand Consistency**: Cohesive color scheme with your primary brand colors - **Markdown Support**: Rich text formatting for feature names and descriptions - **Center-Aligned**: Professional center-aligned layout for maximum impact ## 🎯 Perfect For - **SaaS Features**: Highlight the key capabilities of your software platform - **Service Offerings**: Present your professional services in an organized manner - **Product Benefits**: Showcase why customers should choose your product - **Company Values**: Display your core principles and what sets you apart - **Process Steps**: Break down your workflow or methodology - **Technology Stack**: Present your technical capabilities and tools ## 🚀 Why Choose Features Block? **Visual Clarity**: Icons and organized layout help visitors quickly scan and understand your offerings **Professional Credibility**: Clean, modern design builds trust and demonstrates attention to detail **Conversion Ready**: Well-organized features help visitors make informed decisions faster **Brand Reinforcement**: Consistent use of your brand colors creates cohesive visual identity ## 📊 Business Impact - **Faster Decision Making**: Clear feature presentation reduces visitor confusion - **Higher Engagement**: Visual icons and organized content keep visitors interested - **Better Communication**: Structured format ensures key benefits are clearly communicated - **Mobile Excellence**: Responsive design captures mobile traffic effectively ## 💡 Best Practices - Limit features to 3-6 items for optimal impact and readability - Use consistent icon styles that align with your brand aesthetic - Keep feature descriptions concise but compelling (1-2 sentences) - Order features by importance or user journey priority - Choose icons that instantly communicate each feature's value Ideal for startups, SaaS companies, service providers, and any business that needs to clearly communicate their value proposition to potential customers. ================================================ FILE: modules/blox/blox/features/client.jsx ================================================ /** * Features Block - Client-side Hydration */ import {render} from "preact"; import {FeaturesBlock} from "./component.jsx"; function renderFeaturesBlocks() { const blocks = document.querySelectorAll('[data-block-type="features"]'); blocks.forEach((block) => { const propsData = block.dataset.props; if (propsData) { try { const props = JSON.parse(propsData); render(, block); console.debug(`✓ Features block "${block.id}" rendered with Preact`); } catch (error) { console.error(`Failed to render Features block "${block.id}":`, error); } } }); } renderFeaturesBlocks(); ================================================ FILE: modules/blox/blox/features/component.jsx ================================================ /** * Features Block Component - Single source of truth * Responsive grid of feature items with icon, name, and description */ import {Icon} from "../../shared/components/Icon.jsx"; // Simple markdown renderer function renderText(text) { if (!text) return ""; return String(text) .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1"); } function FeatureItem({item, iconSvg}) { return (
{iconSvg && (
)} {item.name &&

} {item.description &&

}

); } export const FeaturesBlock = ({content, _design, _id, icon_svgs}) => { const title = content?.title; const text = content?.text; const items = Array.isArray(content?.items) ? content.items : []; const iconMap = icon_svgs || {}; return (
{/* Section Header */} {(title || text) && (
{title && (

)} {text &&

}

)} {/* Feature Grid */}
{items.map((item, idx) => ( ))}
); }; ================================================ FILE: modules/blox/blox/features/manifest.json ================================================ { "id": "features", "name": "Features", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["features", "grid", "icons", "benefits", "product", "services", "highlights"], "description": "Showcase features, benefits, or services in an organized grid with icons and descriptions", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "features", "grid", "services", "benefits", "product"] } ================================================ FILE: modules/blox/blox/hero/README.md ================================================ # Hero Block **Make an unforgettable first impression** Capture attention and drive action from the moment visitors land on your site with the Hero block - a conversion-optimized centerpiece designed to communicate your value proposition and guide users toward meaningful engagement. ## ✨ Key Features - **Dual CTA Strategy**: Primary and secondary action buttons to capture different user intents - **Announcement Banner**: Highlight special offers, news, or important updates - **Typography Hierarchy**: Large, attention-grabbing headlines with supporting descriptive text - **Icon Support**: Add visual elements to your primary action button - **Smart Link Handling**: Automatic external link detection with proper security attributes - **Responsive Typography**: Headlines scale from 4xl to 6xl based on screen size - **Center-Aligned**: Professional center-aligned layout for maximum impact ## 🎯 Perfect For - **Landing Pages**: Convert visitors into leads with compelling headlines and clear CTAs - **Product Launches**: Announce new products with maximum visual impact - **Service Introduction**: Present your core offering with confidence - **Event Promotion**: Drive registrations and attendance with compelling copy - **Brand Positioning**: Establish your unique value proposition front and center - **Lead Generation**: Capture emails, demos, or consultation requests ## 🚀 Why Choose Hero Block? **Conversion Psychology**: Designed using proven principles that drive user action **Flexible CTA Options**: Primary button for main action, secondary link for alternative paths **Announcement Integration**: Built-in banner for promotions without cluttering the main message **Professional Polish**: Clean, modern design that builds trust and credibility instantly ## 📊 Conversion Elements - **Headline Optimization**: Large, scannable headlines that communicate value instantly - **Announcement Strategy**: Special offers and news that create urgency and relevance - **Dual Path Design**: Primary and secondary CTAs capture users at different decision stages - **Visual Hierarchy**: Clear information flow that guides users toward action ## 💡 Marketing Best Practices - Lead with benefits, not features in your headline - Use announcement banner for limited-time offers or important news - Make primary CTA action-oriented ("Get Started", "Try Free", "Book Demo") - Use secondary CTA for lower-commitment actions ("Learn More", "View Demo") - Test different headline variations to optimize for your audience The Hero block is your digital storefront - make it count with compelling copy, strategic CTAs, and professional design that converts visitors into customers. ================================================ FILE: modules/blox/blox/hero/client.jsx ================================================ /** * Hero Block - Client-side Hydration * Uses the shared component for consistency */ import {render} from "preact"; import {HeroBlock} from "./component.jsx"; // Render function - immediately renders Hero components function renderHeroBlocks() { // Find all hero block containers (using both old and new selectors for compatibility) const heroBlocks = document.querySelectorAll('[data-block-type="hero"], [data-hero-render="immediate"]'); heroBlocks.forEach((block) => { const propsData = block.dataset.props; if (propsData) { try { const props = JSON.parse(propsData); // Render the Preact component into the container render(, block); console.debug(`✓ Hero block "${block.id}" rendered with Preact`); } catch (error) { console.error(`Failed to render Hero block "${block.id}":`, error); } } }); if (heroBlocks.length > 0) { console.debug(`✓ ${heroBlocks.length} Hero blocks initialized with Preact`); } } // Initialize immediately when script loads // The script is already deferred, so DOM is ready renderHeroBlocks(); ================================================ FILE: modules/blox/blox/hero/component.jsx ================================================ /** * Hero Block Component - Single source of truth * Used for both SSR and client-side hydration */ import {Icon} from "../../shared/components/Icon.jsx"; // Simple markdown renderer export function renderText(text) { if (!text) return ""; return text .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1"); } // Process URLs export function processUrl(url) { if (!url) return {href: "#"}; if (url.startsWith("http://") || url.startsWith("https://")) { return { href: url, target: "_blank", rel: "noopener", }; } if (url.startsWith("#")) { return {href: url}; } return {href: url}; } // Hero Block Component - Single implementation export const HeroBlock = ({content, design, _id, icon_svg}) => { const paddingClasses = design?.no_padding ? "" : "py-32 sm:py-48 lg:py-56"; return (
{/* Announcement Banner */} {content.announcement?.text && ( )} {/* Main Content */}
{/* Title */} {content.title && (

)} {/* Subtitle/Text */} {content.text && (

)} {/* Action Buttons */} {(content.primary_action?.url || content.secondary_action?.url) && (

{/* Primary CTA */} {content.primary_action?.url && ( {content.primary_action.icon && ( )} )} {/* Secondary CTA */} {content.secondary_action?.url && ( )}
)}

); }; ================================================ FILE: modules/blox/blox/hero/manifest.json ================================================ { "id": "hero", "name": "Hero", "version": "1.0.0", "license": "MIT", "category": "marketing", "tags": ["hero", "landing", "cta", "announcement", "headline", "conversion", "primary"], "description": "Create compelling hero sections with headlines, announcements, and dual call-to-action buttons", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "hero", "landing-page", "cta", "marketing", "headlines"] } ================================================ FILE: modules/blox/blox/knowledge-categories/block.html ================================================ {{- $wcPage := .wcPage -}} {{- $wcBlock := .wcBlock -}} {{- $wcIdentifier := .wcIdentifier -}} {{- $content := $wcBlock.content -}} {{- if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end -}} {{- $design := $wcBlock.design -}} {{- if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end -}} {{- $st := index $design "spacing" -}} {{- if not (reflect.IsMap $st) }}{{ $st = dict }}{{ end -}} {{- $pad := slice "4rem" "0" "4rem" "0" -}} {{- $pad_raw := index $st "padding" -}} {{- if and (reflect.IsSlice $pad_raw) (ge (len $pad_raw) 4) }}{{ $pad = $pad_raw }}{{ end -}} {{- $title := "" -}} {{- $title_raw := index $content "title" -}} {{- if eq (printf "%T" $title_raw) "string" }}{{ $title = $title_raw }}{{ end -}} {{- $subtitle := "" -}} {{- $subtitle_raw := index $content "subtitle" -}} {{- if eq (printf "%T" $subtitle_raw) "string" }}{{ $subtitle = $subtitle_raw }}{{ end -}} {{- $categories_raw := index $content "categories" -}} {{- $categories := slice -}} {{- if reflect.IsSlice $categories_raw }}{{ $categories = $categories_raw }}{{ end -}} {{- $view_all := index $content "view_all" -}} {{- if not (reflect.IsMap $view_all) }}{{ $view_all = dict }}{{ end -}} {{- $view_all_text := "" -}} {{- with index $view_all "text" }}{{ $view_all_text = strings.TrimSpace (printf "%v" .) }}{{ end -}} {{- $view_all_link := "" -}} {{- with index $view_all "link" }}{{ $view_all_link = strings.TrimSpace (printf "%v" .) }}{{ end -}}
{{/* Section header */}} {{ if or $title $subtitle }}
{{ with $title }}

{{ . | markdownify }}

{{ end }} {{ with $subtitle }}

{{ . | markdownify }}

{{ end }}
{{ end }} {{/* Categories grid - with dynamic counts from Hugo taxonomy */}}
{{ range $categories }} {{ if reflect.IsMap . }} {{ $category_name := "" }} {{ $category_raw := index . "category" | default (index . "title") }} {{ if ne $category_raw nil }}{{ $category_name = strings.TrimSpace (printf "%v" $category_raw) }}{{ end }} {{/* Get actual count from Hugo taxonomy - proper Hugo syntax */}} {{ $category_url := "" }} {{ $actual_count := 0 }} {{ if $category_name }} {{ with site.Taxonomies.categories.Get $category_name }} {{ $actual_count = .Count }} {{ $category_url = .Page.RelPermalink }} {{ end }} {{ end }} {{ $manual_count := partial "functions/coerce_int" (dict "value" (index . "count") "default" 0 "min" 0) }} {{ $item_link := "" }} {{ $link_raw := index . "link" }} {{ if eq (printf "%T" $link_raw) "string" }}{{ $item_link = strings.TrimSpace $link_raw }}{{ end }} {{ if not $item_link }}{{ $item_link = $category_url }}{{ end }} {{/* Only show category if it has content OR if count is explicitly set */}} {{ if or (gt $actual_count 0) (gt $manual_count 0) }} {{ if $item_link }} {{ $link := $item_link }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ end }} {{ else }} {{ end }} {{ end }} {{ end }} {{ end }}
{{/* View all link */}} {{ if and $view_all_text $view_all_link }} {{ $link := $view_all_link }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ end }} {{ end }}
================================================ FILE: modules/blox/blox/knowledge-categories/manifest.json ================================================ { "name": "knowledge-categories", "version": "1", "title": "Knowledge Categories", "description": "Grid of knowledge base category cards", "categories": ["content", "navigation"], "preview": "preview.svg" } ================================================ FILE: modules/blox/blox/logos/README.md ================================================ # Logos Block Display partner, sponsor, or collaborator logos with modern interactive effects and multiple display modes. Perfect for showcasing affiliations, building trust, and highlighting collaborations. ## Features - **Multiple Display Modes**: Grid, carousel, or marquee layouts - **Interactive Effects**: Grayscale to color on hover, smooth scaling - **Clickable Logos**: Link to partner websites - **Hover Tooltips**: Show partner descriptions on hover - **Responsive Design**: Adapts perfectly to all screen sizes - **Smooth Animations**: Professional transitions and effects - **Flexible Configuration**: Use structured data or folder-based logos - **Performance Optimized**: Lazy loading and WebP format support - **Dark Mode Support**: Seamless theme switching ## Display Modes ### Grid Mode (Default) Classic responsive grid layout with hover effects: - 2 columns on mobile - 3-6 columns on larger screens - Grayscale to color transition on hover - Scale animation on hover ### Carousel Mode Auto-scrolling horizontal carousel: - Continuous smooth scrolling - Pauses on hover - Duplicate items for seamless loop - Ideal for many logos ### Marquee Mode Traditional marquee scroll effect: - Continuous horizontal movement - Lightweight and performant - Good for header/footer placement ## Usage ### Basic Grid Layout ```yaml sections: - block: logos content: title: Our Partners & Collaborators subtitle: Working with leading institutions worldwide text: We collaborate with top universities and research centers logos: - name: MIT image: partners/mit.png url: https://mit.edu description: Massachusetts Institute of Technology - name: Stanford University image: partners/stanford.svg url: https://stanford.edu description: Leading research university - name: Google Research image: partners/google.png url: https://research.google description: AI and ML research - name: Microsoft Research image: partners/microsoft.svg url: https://www.microsoft.com/research description: Computing research lab design: display_mode: grid css_class: "bg-gray-50 dark:bg-gray-900" ``` ### Carousel Display ```yaml sections: - block: logos content: title: Trusted By Industry Leaders logos: # Add 8-12 logos for best carousel effect - name: Company 1 image: sponsors/company1.png url: https://example.com # ... more logos design: display_mode: carousel ``` ### Legacy Folder Mode For backward compatibility or quick setup: ```yaml sections: - block: logos content: title: Our Sponsors logo_folder: sponsors # Loads all images from assets/media/sponsors/ design: display_mode: grid ``` ## Options ### Content Options - **title**: Main heading for the section - **subtitle**: Optional subtitle (shown in accent color) - **text**: Description text below title - **logos**: Array of logo configurations - `name`: Partner/sponsor name (shown in tooltip) - `image`: Path relative to `assets/media/` - `url`: Website URL - `external`: Open in new tab (default: true) - `description`: Hover tooltip text - **logo_folder**: Legacy option to load all images from a folder - **cta**: Optional call-to-action button - `text`: Button text - `url`: Button link - `icon`: Optional icon ### Design Options - **display_mode**: Choose layout style - `grid`: Responsive grid (default) - `carousel`: Auto-scrolling carousel - `marquee`: Classic marquee effect - **show_pattern**: Add decorative background pattern (default: false) ## Image Guidelines ### Recommended Formats - **SVG**: Best for logos (scalable, small file size) - **PNG**: For logos with transparency - **WebP**: Modern format with best compression ### Size Recommendations - **Grid Mode**: 280x140px (will be auto-fitted) - **Carousel Mode**: 280x140px minimum - **Aspect Ratio**: 2:1 or square works best ### Optimization Tips 1. Use SVG when possible for crisp rendering 2. Optimize PNGs with tools like TinyPNG 3. Keep file sizes under 50KB per logo 4. Use consistent dimensions for visual harmony ## Styling ### Hover Effects - Grayscale filter removed on hover - Opacity increases from 60% to 100% - Smooth scale transformation (110%) - Background highlight on hover ### Custom CSS Add custom styles to enhance the block: ```css /* Example: Custom logo sizing */ .logos-block img { max-height: 80px; } /* Example: Remove grayscale on specific logo */ .partner-featured img { filter: none !important; opacity: 1 !important; } ``` ## Best Practices 1. **Logo Quality**: Use high-resolution logos (2x display size) 2. **Consistency**: Keep logos similar in visual weight 3. **Accessibility**: Always provide alt text via `name` field 4. **Performance**: Optimize images before adding 5. **Responsive**: Test on mobile devices 6. **Links**: Verify all external links work 7. **Copyright**: Ensure you have permission to display logos ## Examples ### Research Lab Partners ```yaml logos: - name: National Science Foundation image: partners/nsf.svg url: https://nsf.gov description: Federal funding agency - name: NIH image: partners/nih.png url: https://nih.gov description: National Institutes of Health ``` ### Conference Sponsors ```yaml logos: - name: Gold Sponsor - Microsoft image: sponsors/microsoft-gold.png url: https://microsoft.com description: Gold level sponsor ``` ### Industry Collaborations ```yaml logos: - name: OpenAI image: collaborators/openai.svg url: https://openai.com description: AI research partnership ``` ## Animation Speed To adjust animation speeds, modify the CSS: ```yaml design: css_style: | .animate-marquee { animation-duration: 20s; } .animate-scroll { animation-duration: 30s; } ``` ================================================ FILE: modules/blox/blox/logos/block.html ================================================ {{/* Hugo Blox: Logos Block */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $display_mode := "grid" }} {{ $display_raw := index $design "display_mode" }} {{ if eq (printf "%T" $display_raw) "string" }} {{ $display_mode = lower (strings.TrimSpace $display_raw) }} {{ end }} {{ if not (in (slice "grid" "carousel" "marquee") $display_mode) }} {{ $display_mode = "grid" }} {{ end }} {{ $show_pattern := partial "functions/coerce_bool" (dict "value" (index $design "show_pattern") "default" false) }} {{ $title := "" }} {{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $subtitle := "" }} {{ with index $content "subtitle" }}{{ $subtitle = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $text := "" }} {{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $logos_raw := index $content "logos" }} {{ $logos := slice }} {{ if reflect.IsSlice $logos_raw }}{{ $logos = $logos_raw }}{{ end }} {{ $logo_folder := "" }} {{ $logo_folder_raw := index $content "logo_folder" }} {{ if eq (printf "%T" $logo_folder_raw) "string" }}{{ $logo_folder = strings.TrimSpace $logo_folder_raw }}{{ end }} {{ $cta := index $content "cta" }} {{ if not (reflect.IsMap $cta) }}{{ $cta = dict }}{{ end }} {{ $cta_text := "" }} {{ with index $cta "text" }}{{ $cta_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $cta_url := "" }} {{ with index $cta "url" }}{{ $cta_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $cta_icon := "" }} {{ with index $cta "icon" }}{{ $cta_icon = printf "%v" . }}{{ end }}
{{/* Background Pattern */}} {{ if $show_pattern }}
{{ end }}
{{/* Section Header */}}
{{ with $title }}

{{ . }}

{{ end }} {{ with $subtitle }}

{{ . }}

{{ end }} {{ with $text }}

{{ . }}

{{ end }}
{{/* Grid Display Mode */}} {{ if eq $display_mode "grid" }}
{{/* Logo Items from Data */}} {{ if gt (len $logos) 0 }} {{ range $logos }} {{ if reflect.IsMap . }} {{ $name := "" }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $description := "" }} {{ with index . "description" }}{{ $description = printf "%v" . }}{{ end }} {{ $image_name := "" }} {{ with index . "image" }}{{ $image_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $link := "" }} {{ with index . "url" }}{{ $link = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $external := partial "functions/coerce_bool" (dict "value" (index . "external") "default" false) }} {{ if $link }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $external = true }} {{ end }} {{ end }}
{{ if $link }} {{ else }}
{{ end }}
{{/* Logo Image */}} {{/* Logo Image */}} {{ if $image_name }} {{/* Resolve image from page bundle, site assets, remote, or static URLs */}} {{ $image_resource := false }} {{ $image_url := "" }} {{ $image_path := strings.TrimSpace (printf "%v" $image_name) }} {{ $is_remote := or (strings.HasPrefix $image_path "http://") (strings.HasPrefix $image_path "https://") }} {{ if $is_remote }} {{ $remote := try (resources.GetRemote $image_path) }} {{ if and $remote (not $remote.Err) }} {{ $image_resource = $remote.Value }} {{ else }} {{ $image_url = $image_path }} {{ end }} {{ else }} {{ $image_path = strings.TrimPrefix "/" $image_path }} {{ $image_path = strings.TrimPrefix "./" $image_path }} {{ $image_path = strings.TrimPrefix "assets/" $image_path }} {{ $image_path = strings.TrimPrefix "media/" $image_path }} {{ $normalized := path.Clean $image_path }} {{ if and $normalized (ne $normalized ".") }} {{ with $page }} {{ $image_resource = (.Resources.ByType "image").GetMatch $normalized }} {{ end }} {{ if not $image_resource }} {{ $image_resource = resources.Get (path.Join "media" $normalized) }} {{ end }} {{ if not $image_resource }} {{ $image_url = printf "/media/%s" $normalized }} {{ end }} {{ end }} {{ end }} {{ $img := $image_resource }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ if not $isSVG }} {{ $img = $img.Fit "280x140 webp" }} {{ end }} {{ $name | default {{ else if $image_url }} {{ $is_external := or (strings.HasPrefix $image_url "http://") (strings.HasPrefix $image_url "https://") }} {{ $name | default {{ end }} {{ end }} {{/* Tooltip on Hover */}} {{ with $description }}
{{ . }}
{{ end }}
{{ if $link }}
{{ else }}
{{ end }}
{{ end }} {{ end }} {{/* Logo Images from Folder (Legacy Support) */}} {{ else if $logo_folder }} {{ $images := resources.Match (printf "media/%s/*.{svg,png,jpg,webp}" $logo_folder) }} {{ range $images }}
{{ $image := . }} {{ $isSVG := eq $image.MediaType.SubType "svg" }} {{ if not $isSVG }} {{ $image = $image.Fit "280x140 webp" }} {{ end }} Partner logo
{{ end }} {{ end }}
{{/* Carousel Display Mode */}} {{ else if eq $display_mode "carousel" }}
{{/* Duplicate items for continuous scroll */}} {{ $items := slice }} {{ if gt (len $logos) 0 }} {{ range $logos }} {{ if reflect.IsMap . }} {{ $img_name := index . "image" }} {{ if eq (printf "%T" $img_name) "string" }} {{ $items = $items | append (dict "image" (strings.TrimSpace $img_name) "name" (index . "name")) }} {{ end }} {{ end }} {{ end }} {{ else if $logo_folder }} {{ $images := resources.Match (printf "media/%s/*.{svg,png,jpg,webp}" $logo_folder) }} {{ range $images }} {{ $items = $items | append (dict "image" .Name) }} {{ end }} {{ end }} {{/* First set of logos */}} {{ range $items }}
{{ if .image }} {{ $img := resources.Get (printf "media/%s" .image) }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ if not $isSVG }} {{ $img = $img.Fit "280x140 webp" }} {{ end }} {{ .name | default {{ end }} {{ end }}
{{ end }} {{/* Duplicate for seamless loop */}} {{ range $items }}
{{ if .image }} {{ $img := resources.Get (printf "media/%s" .image) }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ if not $isSVG }} {{ $img = $img.Fit "280x140 webp" }} {{ end }} {{ .name | default {{ end }} {{ end }}
{{ end }}
{{/* Marquee Display Mode */}} {{ else if eq $display_mode "marquee" }}
{{ if gt (len $logos) 0 }} {{ range $logos }} {{ if reflect.IsMap . }} {{ $image_name := "" }} {{ with index . "image" }}{{ $image_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $name := "" }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }}
{{ if $image_name }} {{ $img := resources.Get (printf "media/%s" $image_name) }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ if not $isSVG }} {{ $img = $img.Fit "280x140 webp" }} {{ end }} {{ $name | default {{ end }} {{ end }}
{{ end }} {{ end }} {{ end }}
{{ end }} {{/* Call to Action */}} {{ if and $cta_text $cta_url }} {{ $link := $cta_url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }}
{{/* Custom CSS for Animations */}} ================================================ FILE: modules/blox/blox/logos/manifest.json ================================================ { "id": "logos", "name": "Logos", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["logos", "partners", "sponsors", "collaborators", "brands", "clients", "affiliations"], "description": "Display partner, sponsor, or collaborator logos with interactive effects and multiple display modes", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "static-site", "logos", "partners", "sponsors", "carousel", "marquee"] } ================================================ FILE: modules/blox/blox/markdown/README.md ================================================ # Markdown Block **Beautiful typography for your content** Transform your written content into beautifully formatted, readable sections with the Markdown block - a clean, minimalist component that puts your words front and center with professional typography and perfect readability. ## ✨ Key Features - **Prose Optimization**: Beautiful typography with the prose class for optimal readability - **Dark Mode Support**: Automatic dark mode styling with prose-invert - **Responsive Typography**: Scales from base to large (lg:prose-xl) on bigger screens - **Markdown Rich**: Full Markdown support including links, formatting, lists, and more - **Optional Titles**: Add section headers with consistent styling - **Center-Aligned**: Content centered with optimal line length for reading - **Emoji Support**: Built-in emoji rendering for expressive content ## 🎯 Perfect For - **About Pages**: Tell your story with beautifully formatted text - **Blog Content**: Create rich, readable blog post sections - **Documentation**: Present technical content with professional formatting - **Company Information**: Share detailed company background and mission - **Policy Pages**: Format terms, privacy policies, and legal content - **Long-Form Content**: Any substantial text content that deserves beautiful presentation ## 🚀 Why Choose Markdown Block? **Reading Experience**: Optimized typography that makes long-form content a pleasure to read **Flexible Content**: Support for all Markdown features including links, emphasis, lists, and code **Consistent Styling**: Professional typography that matches your site's design system **Accessibility First**: Semantic HTML structure with proper heading hierarchy and contrast ## 📊 Content Benefits - **Improved Readability**: Optimal line length and spacing reduce eye strain - **Better Engagement**: Beautiful typography encourages visitors to read more - **SEO Friendly**: Clean, semantic HTML structure helps search engines understand content - **Mobile Optimized**: Responsive text sizing ensures readability on all devices ## 💡 Typography Science - **Optimal Line Length**: Content width designed for comfortable reading speed - **Proper Contrast**: Light and dark mode support ensures accessibility - **Hierarchical Structure**: Clear visual hierarchy guides readers through content - **Breathing Room**: Generous spacing prevents information overload ## 🎨 Use Cases - **Storytelling**: Share your journey, mission, or company history - **Educational Content**: Present tutorials, guides, or learning materials - **Announcements**: Communicate important updates or changes - **Content Marketing**: Create engaging blog posts and articles - **Documentation**: Technical guides, API docs, or user manuals Perfect for bloggers, businesses, educators, and anyone who values beautiful, readable content presentation. Make your words shine with typography that respects both your message and your readers. ================================================ FILE: modules/blox/blox/markdown/block.html ================================================ {{/* Hugo Blox: Markdown */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $title := "" }} {{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $text := "" }} {{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString | safeHTML }}{{ end }}
{{ with $title }}
{{ . }}
{{ end }} {{/* We use DIV rather than P to support `prose` class and multiple paragraphs */}} {{ with $text }}
{{ . }}
{{ end }}
================================================ FILE: modules/blox/blox/markdown/manifest.json ================================================ { "id": "markdown", "name": "Markdown", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["markdown", "content", "text", "prose", "writing", "simple", "flexible"], "description": "Display rich markdown content with beautiful typography and optional section titles", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "markdown", "content", "typography", "prose", "text"] } ================================================ FILE: modules/blox/blox/portfolio/README.md ================================================ # Portfolio Block A flexible, filterable portfolio block for showcasing work with Alpine.js-powered filtering and modern glass morphism styling. **Versatile Use Cases:** Software projects, research papers, design work, photography, teaching portfolios, case studies, publications, and more. ## Features - **Tag Filtering**: Filter items by tags with smooth Alpine.js transitions - **Glass Morphism**: Modern card design with backdrop blur and gradient borders - **Status Badges**: Display status (Live, In Progress, Completed, Published, etc.) - **Flexible Keywords**: Show skills, technologies, tools, materials, or methods - **Custom Links**: GitHub, live sites, PDFs, videos, or any custom link type - **Responsive Grid**: Configurable 2, 3, or 4 column layout - **Smooth Animations**: Fade and scale transitions on filter - **Customizable Icons**: Configure fallback icon for items without images ## Basic Usage ```yaml - block: portfolio id: portfolio content: title: "My Work" subtitle: "A selection of recent projects" count: 6 filters: folders: - projects # Or: research, portfolio, work, teaching, etc. buttons: - name: All tag: '*' - name: Category A tag: CategoryA - name: Category B tag: CategoryB default_button_index: 0 archive: # Auto-shown if more items exist than displayed # Optionally customize: # enable: false # Explicitly hide # link: "/work/" # Custom URL # text: "Browse All" # Custom text design: columns: 3 fallback_icon: code-bracket # Or: academic-cap, paint-brush, camera, etc. ``` ## Item Frontmatter Each portfolio item should include the following frontmatter: ```yaml --- title: "Item Title" date: 2024-01-15 summary: "Brief description of the work" tags: - Category - Subcategory - Tag tech_stack: # Or think of as: tools, methods, skills, materials - Tool 1 - Tool 2 - Tool 3 links: - type: custom # Or: github, live, pdf, video, etc. url: https://example.com label: View Project icon: globe-alt # Optional status: "Completed" # Or: Live, Published, In Progress, etc. featured: true --- ``` ## Parameters ### Content | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `title` | string | - | Section title | | `subtitle` | string | - | Section subtitle | | `count` | integer | 0 (all) | Number of projects to display (set to `0` or omit to show all) | | `filters.folders` | array | `["projects"]` | Content folders to query | | `buttons` | array | `[{name: "All", tag: "*"}]` | Filter buttons | | `default_button_index` | integer | 0 | Default active filter | | `archive.enable` | boolean | auto | Show "View All" link (auto-shown if more projects exist, set to `false` to hide) | | `archive.link` | string | auto | Archive URL (defaults to first folder in `filters.folders`) | | `archive.text` | string | i18n | Archive link text (uses i18n `portfolio_view_all`) | | `status.text` | string | - | Override status badge text (falls back to each item's `status`) | ### Design | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `columns` | integer | 3 | Grid columns (2, 3, or 4) | | `fallback_icon` | string | `code-bracket` | Icon shown when item has no image. Supports all Hugo Blox icon packs (hero, brands, devicon, emoji, custom). Format: `icon-name` or `pack/icon-name` | | `status_badge.enable` | boolean | true | Show or hide the status badge | ## Link Types Each link supports the following properties: - `type`: Link type (github, live, demo, or custom) - `url`: Link URL - `label`: Custom label text (optional, overrides default) - `icon`: Custom icon (optional, overrides default - supports all icon packs) | Type | Icon | Default Label | |------|------|---------------| | `github` | `brands/github` | "Code" | | `live` | `globe-alt` | "Live" | | `demo` | `play` | "Demo" | | Other | `link` | "Link" | **Note:** Labels are shared with the project page header, so setting them in frontmatter ensures consistency across card and page views. **Icon Examples:** ```yaml links: - type: custom url: "..." label: "Watch Video" icon: play-circle # Hero icon (default pack) - type: custom url: "..." label: "View on GitHub" icon: brands/github # Brand icon - type: pdf url: "paper.pdf" label: "Read Paper" icon: document-text # Hero icon - type: custom url: "..." label: "Python Code" icon: devicon/python # Devicon ``` ## Status Badges | Status | Color | |--------|-------| | `Live` | Emerald/Green | | `WIP` | Amber/Yellow | | `Archived` | Gray | **Note:** You can use any custom status text. Color coding: emerald for active/live/published, amber for in-progress, gray for archived/completed. ## Use Case Examples ### Software Developer Portfolio ```yaml - block: portfolio content: title: "Featured Projects" filters: folders: [projects] buttons: - {name: All, tag: '*'} - {name: Full-Stack, tag: Full-Stack} - {name: Frontend, tag: Frontend} design: fallback_icon: code-bracket ``` **Project frontmatter:** ```yaml title: "E-Commerce Platform" tags: [Full-Stack, React, Node.js] tech_stack: [React, TypeScript, PostgreSQL] links: - {type: github, url: "...", label: Code} - {type: live, url: "...", label: Demo} status: "Live" ``` ### Academic Research Portfolio ```yaml - block: portfolio content: title: "Research Projects" filters: folders: [research] buttons: - {name: All, tag: '*'} - {name: Machine Learning, tag: ML} - {name: Computational Biology, tag: CompBio} design: fallback_icon: academic-cap # Or: beaker, emoji/microscope, devicon/python columns: 2 ``` **Research project frontmatter:** ```yaml title: "Neural Network Optimization Study" tags: [ML, Optimization, Deep Learning] tech_stack: [Python, PyTorch, CUDA, NumPy] # Or rename to "methods", "tools" links: - {type: pdf, url: "paper.pdf", label: Read Paper} - {type: code, url: "github.com/...", label: Code} - {type: dataset, url: "...", label: Dataset} status: "Published" ``` ### Design/Creative Portfolio ```yaml - block: portfolio content: title: "Design Work" filters: folders: [portfolio] buttons: - {name: All, tag: '*'} - {name: Brand Design, tag: Branding} - {name: UI/UX, tag: UI/UX} - {name: Illustration, tag: Illustration} design: fallback_icon: paint-brush # Or: camera, emoji/art, brands/dribbble columns: 3 ``` **Design project frontmatter:** ```yaml title: "Acme Corp Brand Identity" tags: [Branding, Logo Design, Print] tech_stack: [Adobe Illustrator, Photoshop, Figma] # Tools used links: - {type: custom, url: "behance.net/...", label: View on Behance, icon: globe-alt} - {type: pdf, url: "case-study.pdf", label: Case Study} status: "Completed" ``` ### Teaching Portfolio ```yaml - block: portfolio content: title: "Courses & Materials" filters: folders: [teaching] buttons: - {name: All, tag: '*'} - {name: Undergraduate, tag: Undergrad} - {name: Graduate, tag: Grad} design: fallback_icon: document-text ``` **Course frontmatter:** ```yaml title: "Introduction to Data Science" tags: [Undergrad, Statistics, Programming] tech_stack: [Python, R, Jupyter, Pandas] # Tools taught links: - {type: custom, url: "syllabus.pdf", label: Syllabus, icon: document-text} - {type: custom, url: "github.com/...", label: Course Materials, icon: brands/github} status: "Spring 2024" ``` ## Customization Tips 1. **Rename fields conceptually** - While `tech_stack` is the parameter name, you can use it for: - Software: Technologies, frameworks, tools - Research: Methods, techniques, software - Design: Tools, software, materials - Writing: Genres, themes, topics 2. **Custom link types** - Beyond `github`, `live`, `demo`: - `pdf` for papers, reports, case studies - `dataset` for research data - `video` for presentations, demos - `slides` for slide decks - Custom types with your own labels and icons 3. **Flexible status badges** - Use any text: - Software: "Live", "Beta", "Archived" - Research: "Published", "Under Review", "In Progress" - Design: "Completed", "Ongoing", "Client Work" - Academic: "Spring 2024", "Fall 2023", "Ongoing" 4. **Icon selection** - Choose an appropriate `fallback_icon`: - **Hero icons** (default pack, no prefix needed): - `code-bracket` - Software/development - `academic-cap` - Academic/education - `beaker` - Research/science - `paint-brush` - Art/design - `camera` - Photography - `document-text` - Writing/documentation - `star` - Featured/highlights - **Brand icons** (use `brands/` prefix): - `brands/github` - GitHub projects - `brands/linkedin` - Professional work - `brands/dribbble` - Design work - **Devicon** (use `devicon/` prefix): - `devicon/python` - Python projects - `devicon/react` - React projects - `devicon/docker` - DevOps work - **Emoji** (use `emoji/` prefix or direct unicode): - `emoji/rocket` or 🚀 - `emoji/art` or 🎨 - `emoji/microscope` or 🔬 - **Custom icons**: Place in `assets/media/icons//` and use `/` ================================================ FILE: modules/blox/blox/portfolio/block.html ================================================ {{/* Hugo Blox: Portfolio */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{/* Enable Alpine.js and animations for this block */}} {{ $page.Store.Set "has_alpine" true }} {{ $animations_enabled := true }} {{ if isset $design "animations" }} {{ $animations_enabled = partial "functions/coerce_bool" (dict "value" (index $design "animations") "default" true) }} {{ end }} {{ if $animations_enabled }} {{ $page.Store.Set "has_animations" true }} {{ end }} {{/* Query projects */}} {{ $query := site.Pages }} {{ $filters := index $content "filters" }} {{ if not (reflect.IsMap $filters) }}{{ $filters = dict }}{{ end }} {{ $folders_raw := index $filters "folders" }} {{ $folders := slice }} {{ if reflect.IsSlice $folders_raw }} {{ range $folders_raw }} {{ $folder := strings.TrimSpace (printf "%v" .) }} {{ if $folder }}{{ $folders = $folders | append $folder }}{{ end }} {{ end }} {{ else if eq (printf "%T" $folders_raw) "string" }} {{ $folder := strings.TrimSpace $folders_raw }} {{ if $folder }}{{ $folders = slice $folder }}{{ end }} {{ end }} {{ if eq (len $folders) 0 }}{{ $folders = slice "projects" }}{{ end }} {{ $query = where $query "Section" "in" $folders }} {{ $query = where $query "Kind" "eq" "page" }} {{/* Get archive page for "View All" link */}} {{ $archive_page := "" }} {{ $main_folder := index $folders 0 }} {{ $archive_page = site.GetPage "Section" $main_folder }} {{/* Sort */}} {{ $sort_by := "Date" }} {{ $sort_by_raw := index $content "sort_by" }} {{ if eq (printf "%T" $sort_by_raw) "string" }} {{ $sort_by_raw = strings.TrimSpace $sort_by_raw }} {{ if ne $sort_by_raw "" }}{{ $sort_by = $sort_by_raw }}{{ end }} {{ end }} {{ $sort_by = partial "functions/get_sort_by_parameter" $sort_by }} {{ $sort_ascending := partial "functions/coerce_bool" (dict "value" (index $content "sort_ascending") "default" false) }} {{ $sort_order := cond $sort_ascending "asc" "desc" }} {{ $query = sort $query $sort_by $sort_order }} {{ $all_items := $query }} {{/* Get filter buttons */}} {{ $buttons_raw := index $content "buttons" }} {{ $buttons := slice }} {{ if reflect.IsSlice $buttons_raw }} {{ $buttons = $buttons_raw }} {{ else if and $buttons_raw (reflect.IsMap $buttons_raw) }} {{ $buttons = slice $buttons_raw }} {{ end }} {{ if eq (len $buttons) 0 }} {{ $buttons = slice (dict "name" "All" "tag" "*") }} {{ end }} {{ $default_idx := partial "functions/coerce_int" (dict "value" (index $content "default_button_index") "default" 0 "min" 0) }} {{ $default_tag := "*" }} {{ if lt $default_idx (len $buttons) }} {{ with index $buttons $default_idx }} {{ if reflect.IsMap . }} {{ with index . "tag" }}{{ $default_tag = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ end }} {{ end }} {{ if eq $default_tag "" }}{{ $default_tag = "*" }}{{ end }} {{/* Status configuration */}} {{ $status_content := index $content "status" }} {{ if not (reflect.IsMap $status_content) }}{{ $status_content = dict }}{{ end }} {{ $status_text_override := "" }} {{ with index $status_content "text" }} {{ if eq (printf "%T" .) "string" }}{{ $status_text_override = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ $status_design := index $design "status_badge" }} {{ if not (reflect.IsMap $status_design) }}{{ $status_design = dict }}{{ end }} {{ $show_status_badge := partial "functions/coerce_bool" (dict "value" (index $status_design "enable") "default" true) }} {{/* Store total count before limiting */}} {{ $total_count := len $all_items }} {{/* Limit per filter while keeping per-button visibility accurate */}} {{ $count := partial "functions/coerce_int" (dict "value" (index $content "count") "default" 0 "min" 0) }} {{ $button_items := dict }} {{ $allowed_map := dict }} {{ range $buttons }} {{ if reflect.IsMap . }} {{ $tag := "*" }} {{ with index . "tag" }}{{ $tag = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if eq $tag "" }}{{ $tag = "*" }}{{ end }} {{ $tag_key := lower $tag }} {{ $items := slice }} {{ if le $count 0 }} {{ if eq $tag_key "*" }} {{ $items = $all_items }} {{ else }} {{ $items = where $all_items "Params.tags" "intersect" (slice $tag_key) }} {{ if eq (len $items) 0 }} {{ $items = where $all_items "Params.tags" "intersect" (slice $tag) }} {{ end }} {{ end }} {{ else }} {{ if eq $tag_key "*" }} {{ $items = first $count $all_items }} {{ else }} {{ $items = first $count (where $all_items "Params.tags" "intersect" (slice $tag_key)) }} {{ if eq (len $items) 0 }} {{ $items = first $count (where $all_items "Params.tags" "intersect" (slice $tag)) }} {{ end }} {{ end }} {{ end }} {{ $button_items = merge $button_items (dict $tag_key $items) }} {{ range $items }} {{ $key := .RelPermalink }} {{ $allowed := slice }} {{ with index $allowed_map $key }}{{ $allowed = . }}{{ end }} {{ if not (in $allowed $tag) }} {{ $allowed = $allowed | append $tag }} {{ end }} {{ $allowed_map = merge $allowed_map (dict $key $allowed) }} {{ end }} {{ end }} {{ end }} {{/* Build render list in sorted order, only keeping items that belong to a filter */}} {{ $render_items := slice }} {{ range $all_items }} {{ if isset $allowed_map .RelPermalink }} {{ $render_items = $render_items | append . }} {{ end }} {{ end }} {{/* Fallback to all items if something went wrong */}} {{ if eq (len $render_items) 0 }} {{ $render_items = $all_items }} {{ range $render_items }} {{ $allowed_map = merge $allowed_map (dict .RelPermalink (slice "*")) }} {{ end }} {{ end }} {{ $query = $render_items }} {{ $default_items := index $button_items (lower $default_tag) | default (slice) }} {{ $displayed_count := len $default_items }} {{/* Columns */}} {{ $columns := partial "functions/coerce_int" (dict "value" (index $design "columns") "default" 3 "min" 1 "max" 4) }} {{ $grid_class := "md:grid-cols-2 lg:grid-cols-3" }} {{ if eq $columns 2 }} {{ $grid_class = "md:grid-cols-2" }} {{ else if eq $columns 4 }} {{ $grid_class = "md:grid-cols-2 lg:grid-cols-4" }} {{ end }} {{ $fallback_icon := "code-bracket" }} {{ $fallback_raw := index $design "fallback_icon" }} {{ if eq (printf "%T" $fallback_raw) "string" }} {{ $fallback_icon = $fallback_raw }} {{ end }}
{{/* Header */}}
{{ with index $content "title" }}

{{ printf "%v" . | emojify | $page.RenderString }}

{{ end }} {{ with index $content "subtitle" }}

{{ printf "%v" . | emojify | $page.RenderString }}

{{ end }}
{{/* Filter Buttons */}} {{ if gt (len $buttons) 1 }}
{{ range $idx, $button := $buttons }} {{ if reflect.IsMap $button }} {{ $button_name := "" }} {{ with index $button "name" }}{{ $button_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $button_tag := "*" }} {{ with index $button "tag" }}{{ $button_tag = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ end }}
{{ end }} {{/* Project Grid with staggered reveal animation */}}
{{ range $index, $item := $query }} {{ $item_key := $item.RelPermalink }} {{ $card_allowed_filters := index $allowed_map $item_key }} {{ if not $card_allowed_filters }}{{ $card_allowed_filters = slice "*" }}{{ end }} {{ $card_allowed_filters_json := $card_allowed_filters | jsonify }} {{/* Get tags as comma-separated string */}} {{ $tags := slice }} {{ $tags_raw := $item.Params.tags }} {{ if reflect.IsSlice $tags_raw }} {{ range $tags_raw }} {{ $tag := strings.TrimSpace (printf "%v" .) }} {{ if $tag }}{{ $tags = $tags | append $tag }}{{ end }} {{ end }} {{ else if eq (printf "%T" $tags_raw) "string" }} {{ $tag_string := strings.TrimSpace $tags_raw }} {{ if $tag_string }} {{ if strings.Contains $tag_string "," }} {{ range (split $tag_string ",") }} {{ $tag := strings.TrimSpace . }} {{ if $tag }}{{ $tags = $tags | append $tag }}{{ end }} {{ end }} {{ else }} {{ $tags = slice $tag_string }} {{ end }} {{ end }} {{ end }} {{/* Get status */}} {{ $status := "" }} {{ $status_raw := $item.Params.status }} {{ if eq (printf "%T" $status_raw) "string" }} {{ $status = strings.TrimSpace $status_raw }} {{ end }} {{ $status_display := $status }} {{ if ne $status_text_override "" }} {{ $status_display = $status_text_override }} {{ end }} {{ $status_color_source := cond (ne $status "" ) $status $status_display }} {{ $status_norm := upper $status_color_source }} {{ $status_class := "bg-emerald-600 text-white border-emerald-500 shadow-md shadow-emerald-500/30 dark:bg-emerald-500 dark:border-emerald-400" }} {{ if eq $status_norm "WIP" }} {{ $status_class = "bg-amber-500 text-white border-amber-400 shadow-md shadow-amber-400/30 dark:bg-amber-500" }} {{ else if eq $status_norm "ARCHIVED" }} {{ $status_class = "bg-gray-600 text-white border-gray-500 shadow-md shadow-gray-500/30 dark:bg-gray-500" }} {{ end }} {{ $render_status_badge := and $show_status_badge (ne $status_display "") }}
{{/* Card Header / Image */}}
{{ $image := $item.Resources.GetMatch "{featured,cover,thumbnail}*" }} {{ if $image }} {{ if strings.Contains $image.MediaType.SubType "svg" }} {{ $item.Title }} {{ else }} {{ $img := $image.Fill "600x400 webp" }} {{ $item.Title }} {{ end }} {{ else }} {{/* Gradient placeholder with configurable icon */}}
{{ partial "functions/get_icon" (dict "name" $fallback_icon "attributes" "class=\"w-16 h-16 text-white/30\"") }}
{{ end }} {{/* Status Badge */}} {{ if $render_status_badge }}
{{ $status_display }}
{{ end }} {{/* Gradient Overlay */}}
{{/* Card Content - use flex-col to push links to bottom */}}
{{/* Title */}}

{{ $item.Title }}

{{/* Summary */}} {{ $summary := "" }} {{ $summary_raw := $item.Params.summary }} {{ if $summary_raw }} {{ $summary = strings.TrimSpace (printf "%v" $summary_raw) }} {{ end }} {{ if $summary }}

{{ $summary | $page.RenderString }}

{{ else }}

{{ $item.Summary | truncate 100 }}

{{ end }} {{/* Tech Stack Tags - fixed 2-line height for consistency */}} {{ $tech_stack := slice }} {{ $tech_raw := $item.Params.tech_stack }} {{ if reflect.IsSlice $tech_raw }} {{ range $tech_raw }} {{ $tech := strings.TrimSpace (printf "%v" .) }} {{ if $tech }}{{ $tech_stack = $tech_stack | append $tech }}{{ end }} {{ end }} {{ else if eq (printf "%T" $tech_raw) "string" }} {{ $tech_string := strings.TrimSpace $tech_raw }} {{ if $tech_string }} {{ if strings.Contains $tech_string "," }} {{ range (split $tech_string ",") }} {{ $tech := strings.TrimSpace . }} {{ if $tech }}{{ $tech_stack = $tech_stack | append $tech }}{{ end }} {{ end }} {{ else }} {{ $tech_stack = slice $tech_string }} {{ end }} {{ end }} {{ end }} {{ if gt (len $tech_stack) 0 }}
{{ range first 4 $tech_stack }} {{ . }} {{ end }} {{ if gt (len $tech_stack) 4 }} +{{ sub (len $tech_stack) 4 }} {{ end }}
{{ end }} {{/* Action Links - pushed to bottom with mt-auto */}} {{ $links := slice }} {{ $links_raw := $item.Params.links }} {{ $links_iter := slice }} {{ if reflect.IsSlice $links_raw }} {{ $links_iter = $links_raw }} {{ else if and $links_raw (reflect.IsMap $links_raw) }} {{ $links_iter = slice $links_raw }} {{ end }} {{ if gt (len $links_iter) 0 }} {{ range $links_iter }} {{ $url := "" }} {{ $label := "" }} {{ $icon := "" }} {{ $type := "" }} {{ $new_tab := false }} {{ if reflect.IsMap . }} {{ with index . "url" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $url }} {{ with index . "link" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ with index . "label" }}{{ $label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $label }} {{ with index . "name" }}{{ $label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ with index . "type" }}{{ $type = lower (strings.TrimSpace (printf "%v" .)) }}{{ end }} {{ with index . "icon" }}{{ $icon = printf "%v" . }}{{ end }} {{ $new_tab = partial "functions/coerce_bool" (dict "value" (index . "new_tab") "default" false) }} {{ else if eq (printf "%T" .) "string" }} {{ $url = strings.TrimSpace . }} {{ end }} {{ if $url }} {{ if not $label }} {{ if eq $type "github" }} {{ $label = i18n "portfolio_link_code" | default "Code" }} {{ else if eq $type "live" }} {{ $label = i18n "portfolio_link_live" | default "Live" }} {{ else if eq $type "demo" }} {{ $label = i18n "portfolio_link_demo" | default "Demo" }} {{ else }} {{ $label = i18n "portfolio_link_default" | default "Link" }} {{ end }} {{ end }} {{ if not $icon }} {{ if eq $type "github" }} {{ $icon = "brands/github" }} {{ else if eq $type "live" }} {{ $icon = "globe-alt" }} {{ else if eq $type "demo" }} {{ $icon = "play" }} {{ else }} {{ $icon = "link" }} {{ end }} {{ end }} {{ $links = $links | append (dict "url" $url "label" $label "icon" $icon "new_tab" $new_tab) }} {{ end }} {{ end }} {{ end }} {{ if gt (len $links) 0 }}
{{ range $links }} {{ $icon := index . "icon" | default "link" }} {{ $label := index . "label" | default (i18n "portfolio_link_default" | default "Link") }} {{ $link_url := index . "url" }} {{ $new_tab := partial "functions/coerce_bool" (dict "value" (index . "new_tab") "default" false) }} {{ $target := "" }} {{ $scheme := (urls.Parse $link_url).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link_url "#") }} {{ $link_url = $link_url | relLangURL }} {{ end }} {{ if eq (path.Ext $link_url) ".pdf" }}{{ $new_tab = true }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $new_tab = true }} {{ end }} {{ if $new_tab }} {{ $target = "target=\"_blank\" rel=\"noopener noreferrer\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-4 h-4\"") }} {{ $label }} {{ end }}
{{ end }}
{{ end }}
{{/* View All Link */}} {{/* Smart default: show link if there are more items than displayed, unless explicitly disabled */}} {{ $archive := index $content "archive" }} {{ if not (reflect.IsMap $archive) }}{{ $archive = dict }}{{ end }} {{ $default_show_archive := false }} {{ $default_show_archive = gt $total_count $displayed_count }} {{ $show_archive_link := partial "functions/coerce_bool" (dict "value" (index $archive "enable") "default" $default_show_archive) }} {{ if and $show_archive_link $archive_page }} {{ $archive_link := "" }} {{ $archive_link_raw := index $archive "link" }} {{ if eq (printf "%T" $archive_link_raw) "string" }} {{ $archive_link = strings.TrimSpace $archive_link_raw }} {{ end }} {{ if not $archive_link }} {{ $archive_link = $archive_page.RelPermalink }} {{ end }} {{ $archive_target := "" }} {{ $archive_scheme := (urls.Parse $archive_link).Scheme }} {{ if not $archive_scheme }} {{ if not (hasPrefix $archive_link "#") }} {{ $archive_link = $archive_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $archive_scheme }} {{ $archive_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $archive_text := "" }} {{ $archive_text_raw := index $archive "text" }} {{ if eq (printf "%T" $archive_text_raw) "string" }} {{ $archive_text = strings.TrimSpace $archive_text_raw }} {{ end }} {{ if not $archive_text }}{{ $archive_text = i18n "portfolio_view_all" | default "View All Projects" }}{{ end }} {{ end }}
================================================ FILE: modules/blox/blox/portfolio/manifest.json ================================================ { "id": "portfolio", "name": "Portfolio", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["portfolio", "projects", "filter", "alpine", "developer", "showcase"], "description": "Display filterable project cards with Alpine.js powered tag filtering, glass morphism styling, and smooth animations", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "portfolio", "projects", "filtering", "alpine.js", "developer"] } ================================================ FILE: modules/blox/blox/research-areas/README.md ================================================ # Research Areas Block Display your research focus areas with stunning visuals, metrics, and interactive layouts. Perfect for research labs, academic groups, and R&D departments to showcase their areas of expertise. ## Features - **Multiple Layout Options**: Cards, hexagon, or timeline layouts - **Rich Visual Options**: Icons, emojis, images, or gradient backgrounds - **Metrics Display**: Team size, publications, funding - **Interactive Elements**: Hover effects, status badges, CTAs - **Topic Keywords**: Highlight key research topics - **Responsive Design**: Beautiful on all devices - **Dark Mode Support**: Seamless theme switching - **Performance Optimized**: Lazy loading and WebP support ## Layout Options ### Cards Layout (Default) Modern card-based design with: - Large visual header (image/icon/emoji) - Rich content area - Hover animations - Status badges - Metrics display ### Hexagon Layout Unique hexagonal grid for visual impact: - Geometric design - Gradient backgrounds - Compact information display - Great for 3-6 areas ### Timeline Layout Chronological or priority-based display: - Vertical timeline - Alternating left/right cards - Visual progression - Good for research evolution ## Usage Examples ### Basic Research Areas with Cards ```yaml sections: - block: research-areas content: title: Research Focus Areas subtitle: Advancing Science Through Innovation text: Our lab conducts cutting-edge research across multiple domains items: - name: Computational Biology description: Developing algorithms for genomic analysis and protein structure prediction emoji: 🧬 gradient: from-green-400 to-blue-500 status: active topics: - Genomics - Proteomics - Bioinformatics - Systems Biology team_size: 12 researchers publications: 45 papers funding: $2.5M cta: text: Learn More url: /research/computational-biology - name: Machine Learning description: Advancing deep learning methods for scientific discovery emoji: 🤖 gradient: from-purple-400 to-pink-500 status: active topics: - Deep Learning - Neural Networks - Computer Vision - NLP team_size: 8 researchers publications: 32 papers funding: $1.8M - name: Materials Science description: Designing novel materials through computational modeling emoji: 🔬 gradient: from-orange-400 to-red-500 status: emerging topics: - Nanomaterials - Quantum Materials - Polymers team_size: 6 researchers publications: 28 papers funding: $1.2M design: layout: cards ``` ### Using Icons Instead of Emojis ```yaml items: - name: Artificial Intelligence description: Building next-generation AI systems icon: hero/cpu-chip gradient: from-blue-500 to-indigo-600 # ... rest of configuration ``` ### Using Images ```yaml items: - name: Climate Science description: Understanding and mitigating climate change image: research/climate-hero.jpg status: active # ... rest of configuration ``` ### Hexagon Layout for Visual Impact ```yaml sections: - block: research-areas content: title: Core Research Pillars items: - name: AI & ML description: Artificial intelligence research icon: hero/cpu-chip gradient: from-blue-400 to-purple-600 - name: Quantum description: Quantum computing systems icon: hero/sparkles gradient: from-green-400 to-teal-600 # ... more items design: layout: hexagon ``` ### Timeline Layout for Evolution ```yaml sections: - block: research-areas content: title: Research Evolution subtitle: Our Journey of Discovery items: - name: Foundation (2015-2018) description: Established core ML research icon: hero/academic-cap - name: Expansion (2018-2021) description: Added biomedical applications icon: hero/beaker - name: Current Focus (2021-Present) description: AI for scientific discovery icon: hero/sparkles design: layout: timeline ``` ## Configuration Options ### Content Options - **title**: Main section heading - **subtitle**: Section subtitle (accent color) - **text**: Description paragraph - **items**: Array of research areas - `name`: Area name (required) - `description`: Area description (required) - `icon`: Icon identifier (e.g., 'hero/beaker') - `emoji`: Emoji alternative to icon - `image`: Image path relative to assets/media/ - `gradient`: Tailwind gradient classes - `url`: Link to detailed page - `status`: 'active', 'emerging', or 'planning' - `topics`: Array of keywords/topics - `team_size`: Team member count - `publications`: Publication count - `funding`: Funding amount - `cta`: Individual area CTA with text and url - **cta**: Global call-to-action button ### Design Options - **layout**: Visual layout style - `cards`: Modern card grid (default) - `hexagon`: Hexagonal grid - `timeline`: Vertical timeline ## Visual Guidelines ### Gradients Use Tailwind gradient classes for visual appeal: ```yaml gradient: from-blue-400 to-purple-600 gradient: from-green-500 to-teal-400 gradient: from-orange-400 to-red-500 ``` ### Icons vs Emojis vs Images - **Icons**: Professional, consistent style - **Emojis**: Friendly, universal, no loading - **Images**: Rich visuals, specific imagery ### Status Badges - `active`: Green - Currently active research - `emerging`: Yellow - Growing area - `planning`: Blue - Future direction ## Best Practices 1. **Consistency**: Use the same visual type (icons OR emojis OR images) across all areas 2. **Metrics**: Include quantifiable achievements 3. **Keywords**: 3-5 relevant topics per area 4. **Descriptions**: Keep concise (50-100 words) 5. **CTAs**: Link to detailed pages for each area 6. **Gradients**: Choose complementary colors 7. **Status**: Be transparent about research maturity ## Responsive Behavior ### Cards Layout - Mobile: Single column - Tablet: 2 columns - Desktop: 3 columns ### Hexagon Layout - Mobile: Stacked hexagons - Desktop: Honeycomb grid ### Timeline Layout - Mobile: Single column timeline - Desktop: Alternating left/right ## Performance Tips 1. **Images**: Optimize to <100KB 2. **WebP Format**: Use for better compression 3. **Lazy Loading**: Automatic for images 4. **Icon Usage**: Prefer icons/emojis over images for speed ## Accessibility - Semantic HTML structure - Proper heading hierarchy - Alt text for images - Keyboard navigable - Screen reader friendly - High contrast for text ## Examples by Field ### AI/ML Lab ```yaml items: - name: Deep Learning emoji: 🧠 gradient: from-purple-500 to-pink-500 - name: Computer Vision emoji: 👁️ gradient: from-blue-500 to-cyan-500 - name: NLP emoji: 💬 gradient: from-green-500 to-teal-500 ``` ### Biology Lab ```yaml items: - name: Genomics emoji: 🧬 gradient: from-green-400 to-emerald-600 - name: Cell Biology emoji: 🦠 gradient: from-purple-400 to-indigo-600 - name: Neuroscience emoji: 🧠 gradient: from-pink-400 to-rose-600 ``` ### Physics Lab ```yaml items: - name: Quantum Computing emoji: ⚛️ gradient: from-indigo-500 to-purple-600 - name: Particle Physics emoji: 🌌 gradient: from-blue-500 to-indigo-600 - name: Condensed Matter emoji: 💎 gradient: from-cyan-500 to-blue-600 ``` ================================================ FILE: modules/blox/blox/research-areas/block.html ================================================ {{/* Hugo Blox: Research Areas Block */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $layout := "cards" }} {{ $layout_raw := index $design "layout" }} {{ if eq (printf "%T" $layout_raw) "string" }} {{ $layout_candidate := lower (strings.TrimSpace $layout_raw) }} {{ if in (slice "cards" "hexagon" "timeline") $layout_candidate }} {{ $layout = $layout_candidate }} {{ end }} {{ end }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }} {{ $title = strings.TrimSpace (printf "%v" $title_raw) }} {{ end }} {{ if $title }}{{ $title = $title | emojify | $page.RenderString }}{{ end }} {{ $subtitle := "" }} {{ $subtitle_raw := index $content "subtitle" }} {{ if $subtitle_raw }} {{ $subtitle = strings.TrimSpace (printf "%v" $subtitle_raw) }} {{ end }} {{ if $subtitle }}{{ $subtitle = $subtitle | emojify | $page.RenderString }}{{ end }} {{ $text := "" }} {{ $text_raw := index $content "text" }} {{ if $text_raw }} {{ $text = strings.TrimSpace (printf "%v" $text_raw) }} {{ end }} {{ if $text }}{{ $text = $text | emojify | $page.RenderString }}{{ end }} {{ $items_raw := index $content "items" }} {{ $items_iter := slice }} {{ if reflect.IsSlice $items_raw }} {{ $items_iter = $items_raw }} {{ else if and $items_raw (reflect.IsMap $items_raw) }} {{ $items_iter = slice $items_raw }} {{ end }} {{ $items := slice }} {{ if gt (len $items_iter) 0 }} {{ range $items_iter }} {{ if reflect.IsMap . }} {{ $name := "" }} {{ $description := "" }} {{ $icon := "" }} {{ $image := "" }} {{ $gradient := "" }} {{ $url := "" }} {{ $status := "" }} {{ $topics := slice }} {{ $team_size := "" }} {{ $publications := "" }} {{ $funding := "" }} {{ $cta_url := "" }} {{ $cta_text := "" }} {{ $cta_icon := "" }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "description" }}{{ $description = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $icon = printf "%v" . }}{{ end }} {{ with index . "image" }}{{ $image = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "gradient" }}{{ $gradient = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "url" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "status" }}{{ $status = lower (strings.TrimSpace (printf "%v" .)) }}{{ end }} {{ $topics_raw := index . "topics" }} {{ if reflect.IsSlice $topics_raw }} {{ range $topics_raw }} {{ $topic := strings.TrimSpace (printf "%v" .) }} {{ if $topic }}{{ $topics = $topics | append $topic }}{{ end }} {{ end }} {{ else if eq (printf "%T" $topics_raw) "string" }} {{ $topic_string := strings.TrimSpace $topics_raw }} {{ if $topic_string }} {{ if strings.Contains $topic_string "," }} {{ range (split $topic_string ",") }} {{ $topic := strings.TrimSpace . }} {{ if $topic }}{{ $topics = $topics | append $topic }}{{ end }} {{ end }} {{ else }} {{ $topics = slice $topic_string }} {{ end }} {{ end }} {{ end }} {{ with index . "team_size" }}{{ $team_size = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "publications" }}{{ $publications = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "funding" }}{{ $funding = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $cta_raw := index . "cta" }} {{ if reflect.IsMap $cta_raw }} {{ with index $cta_raw "url" }}{{ $cta_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $cta_raw "text" }}{{ $cta_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $cta_raw "icon" }}{{ $cta_icon = printf "%v" . }}{{ end }} {{ end }} {{ if or $name $description }} {{ $items = $items | append (dict "name" $name "description" $description "icon" $icon "image" $image "gradient" $gradient "url" $url "status" $status "topics" $topics "team_size" $team_size "publications" $publications "funding" $funding "cta" (dict "url" $cta_url "text" $cta_text "icon" $cta_icon)) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $cta := index $content "cta" }} {{ if not (reflect.IsMap $cta) }}{{ $cta = dict }}{{ end }} {{ $cta_text := "" }} {{ $cta_link := "" }} {{ $cta_icon := "" }} {{ with index $cta "text" }}{{ $cta_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $cta "url" }}{{ $cta_link = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $cta "icon" }}{{ $cta_icon = printf "%v" . }}{{ end }}
{{/* Section Header */}}
{{ with $title }}

{{ . }}

{{ end }} {{ with $subtitle }}

{{ . }}

{{ end }} {{ with $text }}

{{ . }}

{{ end }}
{{/* Cards Layout */}} {{ if eq $layout "cards" }}
{{ range $idx, $item := $items }} {{ $name := index $item "name" }} {{ $description := index $item "description" }} {{ $icon := index $item "icon" }} {{ $image := index $item "image" }} {{ $gradient := index $item "gradient" | default "from-primary-400 to-secondary-400" }} {{ $item_url := index $item "url" }} {{ $status := index $item "status" }} {{ $topics := index $item "topics" }} {{ $team_size := index $item "team_size" }} {{ $publications := index $item "publications" }} {{ $funding := index $item "funding" }} {{ $item_cta := index $item "cta" }} {{ $item_cta_url := "" }} {{ $item_cta_text := "" }} {{ $item_cta_icon := "" }} {{ if reflect.IsMap $item_cta }} {{ with index $item_cta "url" }}{{ $item_cta_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $item_cta "text" }}{{ $item_cta_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $item_cta "icon" }}{{ $item_cta_icon = printf "%v" . }}{{ end }} {{ end }}
{{/* Card Image/Icon Header */}} {{ $header_content := "" }} {{ if $image }} {{/* Resolve image from page bundle, site assets, remote, or static URLs */}} {{ $image_resource := false }} {{ $image_url := "" }} {{ $image_path := strings.TrimSpace (printf "%v" $image) }} {{ $is_remote := or (strings.HasPrefix $image_path "http://") (strings.HasPrefix $image_path "https://") }} {{ if $is_remote }} {{ $remote := try (resources.GetRemote $image_path) }} {{ if and $remote (not $remote.Err) }} {{ $image_resource = $remote.Value }} {{ else }} {{ $image_url = $image_path }} {{ end }} {{ else }} {{ $image_path = strings.TrimPrefix "/" $image_path }} {{ $image_path = strings.TrimPrefix "./" $image_path }} {{ $image_path = strings.TrimPrefix "assets/" $image_path }} {{ $image_path = strings.TrimPrefix "media/" $image_path }} {{ $normalized := path.Clean $image_path }} {{ if and $normalized (ne $normalized ".") }} {{ with $page }} {{ $image_resource = (.Resources.ByType "image").GetMatch $normalized }} {{ end }} {{ if not $image_resource }} {{ $image_resource = resources.Get (path.Join "media" $normalized) }} {{ end }} {{ if not $image_resource }} {{ $image_url = printf "/media/%s" $normalized }} {{ end }} {{ end }} {{ end }} {{ $img := $image_resource }} {{ if $img }} {{ $img = $img.Fill "600x400 Center webp" }} {{ $alt := $name | plainify }} {{ $header_content = printf "\"%s\"" $img.RelPermalink $alt }} {{ else if $image_url }} {{ $alt := $name | plainify }} {{ $is_external := or (strings.HasPrefix $image_url "http://") (strings.HasPrefix $image_url "https://") }} {{ $src := cond $is_external $image_url ($image_url | relURL) }} {{ $header_content = printf "\"%s\"" $src $alt }} {{ end }} {{ else if $icon }} {{ $icon_html := partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-24 h-24 text-white/80 group-hover:scale-110 transition-transform duration-300\"") }} {{ $header_content = printf "
%s
" $icon_html }} {{ end }} {{ $item_cta_link := "" }} {{ $item_cta_target := "" }} {{ if $item_cta_url }} {{ $item_cta_link = $item_cta_url }} {{ $item_cta_scheme := (urls.Parse $item_cta_link).Scheme }} {{ if not $item_cta_scheme }} {{ if not (hasPrefix $item_cta_link "#") }} {{ $item_cta_link = $item_cta_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $item_cta_scheme }} {{ $item_cta_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ if and $item_cta_link $header_content }} {{ $header_content | safeHTML }} {{ else }}
{{ $header_content | safeHTML }}
{{ end }} {{/* Status Badge */}} {{ with $status }}
{{ . | title }}
{{ end }} {{/* Card Content - Flexible layout */}}
{{/* Main Content */}}

{{ if $item_url }} {{ $item_link := $item_url }} {{ $item_target := "" }} {{ $item_scheme := (urls.Parse $item_link).Scheme }} {{ if not $item_scheme }} {{ if not (hasPrefix $item_link "#") }} {{ $item_link = $item_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $item_scheme }} {{ $item_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $name }} {{ partial "functions/get_icon" (dict "name" "hero/arrow-top-right-on-square" "attributes" "class=\"inline-block w-4 h-4 ml-1\"") }} {{ else }} {{ $name }} {{ end }}

{{ $description | $page.RenderString }}

{{/* Key Topics/Keywords */}} {{ with $topics }}
{{ range first 3 . }} {{ . }} {{ end }} {{ if gt (len .) 3 }} +{{ sub (len .) 3 }} more {{ end }}
{{ end }}
{{/* Footer Section - Always at bottom */}}
{{/* Stats/Metrics */}} {{ if or $team_size $publications $funding }}
{{ with $team_size }}
{{ partial "functions/get_icon" (dict "name" "hero/user-group" "attributes" "class=\"w-4 h-4 mx-auto mb-1\"") }} {{ . | replaceRE " researchers" "" }} team
{{ end }} {{ with $publications }}
{{ partial "functions/get_icon" (dict "name" "hero/document-text" "attributes" "class=\"w-4 h-4 mx-auto mb-1\"") }} {{ . | replaceRE " papers" "" }} papers
{{ end }} {{ with $funding }}
{{ partial "functions/get_icon" (dict "name" "hero/currency-dollar" "attributes" "class=\"w-4 h-4 mx-auto mb-1\"") }} {{ . }} funding
{{ end }}
{{ end }} {{/* Call to Action */}} {{ if and $item_cta_link $item_cta_text }} {{ $item_cta_text }} {{ partial "functions/get_icon" (dict "name" "hero/arrow-right" "attributes" "class=\"ml-1 w-4 h-4\"") }} {{ end }}
{{ end }}
{{/* Hexagon Layout */}} {{ else if eq $layout "hexagon" }}
{{ range $idx, $item := $items }} {{ $name := index $item "name" }} {{ $description := index $item "description" }} {{ $icon := index $item "icon" }} {{ $gradient := index $item "gradient" | default "from-primary-400 to-secondary-400" }}
{{ if $icon }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-12 h-12 text-white mb-3\"") }} {{ end }}

{{ $name }}

{{ $description | truncate 60 }}

{{ end }}
{{/* Timeline Layout */}} {{ else if eq $layout "timeline" }}
{{/* Vertical Line */}}
{{ range $idx, $item := $items }} {{ $name := index $item "name" }} {{ $description := index $item "description" }} {{ $icon := index $item "icon" }}
{{/* Timeline dot */}}
{{ if $icon }}
{{ partial "functions/get_icon" (dict "name" $icon "attributes" "class=\"w-5 h-5 text-primary-600 dark:text-primary-400\"") }}
{{ end }}

{{ $name }}

{{ $description | $page.RenderString }}

{{ end }}
{{ end }} {{/* Global Call to Action */}} {{ if and $cta_link $cta_text }} {{ $cta_target := "" }} {{ $cta_scheme := (urls.Parse $cta_link).Scheme }} {{ if not $cta_scheme }} {{ if not (hasPrefix $cta_link "#") }} {{ $cta_link = $cta_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $cta_scheme }} {{ $cta_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }}
{{/* Custom CSS for Hexagon Layout */}} {{ if eq $layout "hexagon" }} {{ end }} ================================================ FILE: modules/blox/blox/research-areas/manifest.json ================================================ { "id": "research-areas", "name": "Research Areas", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["research", "areas", "focus", "topics", "science", "lab", "academic", "showcase"], "description": "Display research focus areas with rich visuals, metrics, and interactive layouts", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "static-site", "research", "areas", "academic", "lab", "science"] } ================================================ FILE: modules/blox/blox/resume-awards/README.md ================================================ # Resume Awards Block **Highlight your achievements with professional elegance** Showcase your professional accomplishments, certifications, and awards with the Resume Awards block - a sophisticated component that presents your credentials in an organized, visually appealing format that builds trust and demonstrates expertise. ## ✨ Key Features - **Professional Cards**: Clean, shadowed card design for each award or certification - **Icon Integration**: Add per-award icons (e.g., trophy, badge) for instant visual cues - **Certificate Links**: Direct links to verify credentials with proper external link handling - **Date Formatting**: Customizable date display (month/year format by default) - **Markdown Support**: Rich text formatting for award titles and descriptions - **Chronological Sorting**: Automatic sorting by date (newest first) - **Responsive Layout**: Perfect display across all screen sizes ## 🎯 Perfect For - **Academic Professionals**: Showcase research awards, grants, and honors - **Industry Experts**: Display professional certifications and recognitions - **Corporate Leaders**: Highlight leadership awards and company recognitions - **Freelancers**: Build credibility with client awards and industry recognition - **Consultants**: Demonstrate expertise through professional certifications - **Creative Professionals**: Feature competition wins and industry awards ## 🚀 Why Choose Resume Awards Block? **Credibility Building**: Professional presentation of achievements builds immediate trust **Verification Ready**: Direct links to certificates enable easy credential verification **Visual Organization**: Card-based layout makes achievements easy to scan and understand **Professional Standards**: Consistent formatting that meets CV and portfolio standards ## 📊 Professional Benefits - **Enhanced Credibility**: Visual display of achievements builds professional authority - **Easy Verification**: Certificate links provide transparency and trust - **Organized Presentation**: Clean layout prevents information overload - **Mobile Professional**: Responsive design ensures professional appearance on all devices ## 💡 Strategic Advantages - **Competitive Edge**: Prominent credential display differentiates you from competitors - **Trust Signals**: Awards and certifications reduce client hesitation - **Expertise Proof**: Concrete evidence of your skills and knowledge - **Professional Brand**: Consistent, polished presentation reinforces your personal brand ## 🎨 Design Philosophy - **Visual Hierarchy**: Most recent and important awards get prominence - **Clean Aesthetics**: Professional card design that doesn't distract from content - **Information Balance**: Right amount of detail without overwhelming visitors - **Brand Integration**: Certifying organization icons add visual interest and authenticity Perfect for professionals, academics, consultants, and anyone who wants to showcase their achievements in a format that builds confidence and demonstrates expertise. Your accomplishments deserve professional presentation. ================================================ FILE: modules/blox/blox/resume-awards/block.html ================================================ {{/* Hugo Blox: Awards */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $username }} {{ $awards_raw := $profile.awards }} {{ $date_format := "January 2006" }} {{ $date_format_raw := index $design "date_format" }} {{ if eq (printf "%T" $date_format_raw) "string" }} {{ $date_format = strings.TrimSpace $date_format_raw | default "January 2006" }} {{ end }} {{ $awards_iter := slice }} {{ if reflect.IsSlice $awards_raw }} {{ $awards_iter = $awards_raw }} {{ else if reflect.IsMap $awards_raw }} {{ range $awards_raw }} {{ $awards_iter = $awards_iter | append . }} {{ end }} {{ end }} {{ $awards := slice }} {{ if gt (len $awards_iter) 0 }} {{ range $awards_iter }} {{ if reflect.IsMap . }} {{ $title := "" }} {{ $icon := "" }} {{ $url := "" }} {{ $awarder := "" }} {{ $date := "" }} {{ $date_start := "" }} {{ $summary := "" }} {{ $certificate_url := "" }} {{ with index . "title" }}{{ $title = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "url" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "awarder" }}{{ $awarder = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "date" }}{{ $date = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "date_start" }}{{ $date_start = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "summary" }}{{ $summary = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "certificate_url" }}{{ $certificate_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if $title }} {{ $date_sort := $date | default $date_start }} {{ $awards = $awards | append (dict "title" $title "icon" $icon "url" $url "awarder" $awarder "date" $date "date_start" $date_start "summary" $summary "certificate_url" $certificate_url "date_sort" $date_sort) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }} {{ $title = strings.TrimSpace (printf "%v" $title_raw) }} {{ end }} {{ $text := "" }} {{ $text_raw := index $content "text" }} {{ if $text_raw }} {{ $text = strings.TrimSpace (printf "%v" $text_raw) }} {{ end }}
{{ $title | markdownify | emojify }}
{{ with $text }}

{{ . | markdownify | emojify }}

{{ end }}
{{ if gt (len $awards) 0 }} {{ range $idx, $award := sort $awards "date_sort" "desc" }}
{{- $icon := index $award "icon" }} {{ $award_url := index $award "url" }} {{ $award_link := "" }} {{ $award_target := "" }} {{ if $award_url }} {{ $award_link = $award_url }} {{ $scheme := (urls.Parse $award_link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $award_link "#") }} {{ $award_link = $award_link | relLangURL }} {{ end }} {{ if eq (path.Ext $award_link) ".pdf" }}{{ $award_target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $award_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ if $award_link }}{{ end }}
{{ with $icon }} {{ partial "functions/get_icon" (dict "name" . "attributes" "class='w-6 h-6'") }} {{ end }} {{ index $award "title" | markdownify | emojify }}
{{ if $award_link }}
{{ end }}
{{ $awarder := index $award "awarder" }} {{ if $awarder }}{{ $awarder }} ∙{{ end }} {{ $date_value := index $award "date" }} {{ $date_start_value := index $award "date_start" }} {{ if $date_value }} {{ $parsed := try (time $date_value) }} {{ if not $parsed.Err }} {{ $parsed.Value | time.Format $date_format }} {{ else }} {{ $date_value }} {{ end }} {{ else if $date_start_value }} {{ $parsed := try (time $date_start_value) }} {{ if not $parsed.Err }} {{ $parsed.Value | time.Format $date_format }} {{ else }} {{ $date_start_value }} {{ end }} {{ else }} {{ i18n "present" | default "Present" }} {{ end }}
{{ with index $award "summary" }}
{{ . | markdownify | emojify }}
{{end}} {{ $certificate_url := index $award "certificate_url" }} {{ if $certificate_url }} {{ $certificate_link := $certificate_url }} {{ $certificate_target := "" }} {{ $certificate_scheme := (urls.Parse $certificate_link).Scheme }} {{ if not $certificate_scheme }} {{ if not (hasPrefix $certificate_link "#") }} {{ $certificate_link = $certificate_link | relLangURL }} {{ end }} {{ if eq (path.Ext $certificate_link) ".pdf" }}{{ $certificate_target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $certificate_scheme }} {{ $certificate_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ i18n "see_certificate" | default "See certificate" }} {{ end }}
{{end}} {{end}}
================================================ FILE: modules/blox/blox/resume-awards/manifest.json ================================================ { "id": "resume-awards", "name": "Resume Awards", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "awards", "certifications", "achievements", "credentials", "professional", "cv"], "description": "Showcase professional awards and certifications with elegant card layouts and certificate links", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "awards", "certifications", "cv", "professional"] } ================================================ FILE: modules/blox/blox/resume-biography/README.md ================================================ # Resume Biography Block **Make a powerful personal first impression** Present yourself professionally with the Resume Biography block - a comprehensive profile component that combines your photo, personal details, social presence, and biography into one compelling, trust-building section. ## ✨ Key Features - **High-Quality Avatar**: Retina-optimized profile photos with multiple size options (small to xxl) - **Flexible Shapes**: Choose from circle, square, or rounded avatar styles - **Social Integration**: Beautiful social media links with icon support - **Banner Support**: Optional header banner for additional visual impact - **Name Pronunciation**: Ruby annotation displays pronunciation guides above your name (set `name.pronunciation` in your author YAML) - **Pronoun Support**: Inclusive pronoun display for professional clarity - **Organization Links**: Clickable organization affiliations - **Download Button**: Optional CV/resume download functionality ## 🎯 Perfect For - **Academic Profiles**: Researchers, professors, and graduate students - **Professional Portfolios**: Consultants, freelancers, and industry experts - **Corporate Leadership**: Executive profiles and team member pages - **Personal Branding**: Entrepreneurs and thought leaders - **Creative Professionals**: Designers, writers, and artists - **Job Seekers**: Professional online presence for career opportunities ## 🚀 Why Choose Resume Biography Block? **Professional Standards**: Meets modern professional profile expectations with comprehensive information display **Visual Impact**: High-quality imagery and clean layout create strong first impressions **Social Connectivity**: Integrated social links help build professional networks **Accessibility First**: Inclusive features like pronunciation guides and pronoun support ## 📊 Personal Branding Benefits - **Immediate Recognition**: Professional photo creates memorable personal brand - **Credibility Signals**: Organization affiliations and social links build trust - **Accessibility**: Pronunciation guides (Pinyin, furigana, IPA) displayed above your name help visitors remember and pronounce it correctly - **Professional Network**: Social links facilitate professional connections ## 💡 Customization Options - **Avatar Sizing**: From subtle small avatars to prominent xxl displays - **Shape Variety**: Match your brand aesthetic with circle, square, or rounded styles - **Banner Integration**: Add context with professional background images - **Content Control**: Use custom biography text or pull from author page content ## 🎨 Design Excellence - **High-Resolution Ready**: 2x retina support ensures crisp images on all screens - **Typography Hierarchy**: Clear information structure from name to details - **Generous Whitespace**: Clean layout that doesn't overwhelm visitors - **Dark Mode Support**: Beautiful presentation in both light and dark themes ## 💼 Professional Impact Perfect for building authority, establishing credibility, and creating memorable personal brands. Whether you're building a personal website, company profile, or professional portfolio, the Resume Biography block ensures you make the right first impression. Your professional story deserves professional presentation - create a biography section that opens doors and builds connections. ================================================ FILE: modules/blox/blox/resume-biography/block.html ================================================ {{/* Hugo Blox: Biography */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $username }} {{ $avatar := $profile.avatar }} {{/* Avatar customization parameters */}} {{ $avatar_size := "medium" }} {{ $avatar_shape := "circle" }} {{ $avatar_design := index $design "avatar" }} {{ if reflect.IsMap $avatar_design }} {{ $size_raw := index $avatar_design "size" }} {{ if eq (printf "%T" $size_raw) "string" }} {{ $size_candidate := lower (strings.TrimSpace $size_raw) }} {{ if in (slice "small" "medium" "large" "xl" "xxl") $size_candidate }} {{ $avatar_size = $size_candidate }} {{ end }} {{ end }} {{ $shape_raw := index $avatar_design "shape" }} {{ if eq (printf "%T" $shape_raw) "string" }} {{ $shape_candidate := lower (strings.TrimSpace $shape_raw) }} {{ if in (slice "circle" "square" "rounded") $shape_candidate }} {{ $avatar_shape = $shape_candidate }} {{ end }} {{ end }} {{ end }} {{/* Size mappings optimized for 2025 standards: display_size -> [display_px, generation_px] */}} {{ $size_map := dict "small" (slice "150" "300") "medium" (slice "200" "400") "large" (slice "320" "640") "xl" (slice "400" "800") "xxl" (slice "500" "1000") }} {{ $size_config := index $size_map $avatar_size | default (index $size_map "medium") }} {{ $display_size := index $size_config 0 }} {{ $generation_size := index $size_config 1 }} {{/* Shape class mappings */}} {{ $shape_classes := dict "circle" "rounded-full" "square" "rounded-none" "rounded" "rounded-lg" }} {{ $shape_class := index $shape_classes $avatar_shape | default "rounded-full" }} {{ $img := "" }} {{ $banner := index $design "banner" }} {{ $banner_filename := "" }} {{ if reflect.IsMap $banner }} {{ with index $banner "filename" }}{{ $banner_filename = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ if $banner_filename }} {{/* Resolve image from page bundle, site assets, remote, or static URLs */}} {{ $image_resource := false }} {{ $image_url := "" }} {{ if $banner_filename }} {{ $image_path := strings.TrimSpace (printf "%v" $banner_filename) }} {{ $is_remote := or (strings.HasPrefix $image_path "http://") (strings.HasPrefix $image_path "https://") }} {{ if $is_remote }} {{ $remote := try (resources.GetRemote $image_path) }} {{ if and $remote (not $remote.Err) }} {{ $image_resource = $remote.Value }} {{ else }} {{/* If remote fetch fails, fall back to the original URL */}} {{ $image_url = $image_path }} {{ end }} {{ else }} {{/* Normalize common prefixes and dot paths */}} {{ $image_path = strings.TrimPrefix "/" $image_path }} {{ $image_path = strings.TrimPrefix "./" $image_path }} {{ $image_path = strings.TrimPrefix "assets/" $image_path }} {{ $image_path = strings.TrimPrefix "media/" $image_path }} {{ $normalized := path.Clean $image_path }} {{ if and $normalized (ne $normalized ".") }} {{/* Prefer page bundle image resources */}} {{ with $page }} {{ $image_resource = (.Resources.ByType "image").GetMatch $normalized }} {{ end }} {{ if not $image_resource }} {{/* Look in global assets/media - use resources.Get for exact path matching */}} {{ $image_resource = resources.Get (path.Join "media" $normalized) }} {{ end }} {{ if not $image_resource }} {{/* Static fallback (serves original size) */}} {{ $image_url = printf "/media/%s" $normalized }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $img = $image_resource }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ $isGIF := eq $img.MediaType.SubType "gif" }} {{ if not (or $isSVG $isGIF) }} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $img "mode" "fill" "aspect_ratio" "16:9" "sizes" (slice 768 1024 1366 1920 2560) ) }}
{{ else }} {{/* Handle SVG/GIF without processing */}} {{ if not $isSVG }}{{ $img = $img.Process "webp" }}{{ end }}
{{ end }} {{ else if $image_url }} {{/* Static fallback for remote/unprocessed images */}} {{ $is_external := or (strings.HasPrefix $image_url "http://") (strings.HasPrefix $image_url "https://") }}
{{ end }} {{ end }} {{ $profile_title := "" }} {{ with $profile.title }}{{ $profile_title = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $profile_pronouns := "" }} {{ with $profile.pronouns }}{{ $profile_pronouns = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $profile_role := "" }} {{ with $profile.role }}{{ $profile_role = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $profile_bio := "" }} {{ with $profile.bio }}{{ $profile_bio = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $status_icon := "" }} {{ with $profile.status }} {{ if reflect.IsMap . }} {{ $icon_raw := index . "icon" }} {{ if eq (printf "%T" $icon_raw) "string" }} {{ $status_icon = strings.TrimSpace $icon_raw }} {{ end }} {{ end }} {{ end }} {{ $affiliations := slice }} {{ $affiliations_raw := $profile.affiliations }} {{ if reflect.IsSlice $affiliations_raw }} {{ range $affiliations_raw }} {{ if reflect.IsMap . }} {{ $name := "" }} {{ $url := "" }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "url" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if $name }} {{ $affiliations = $affiliations | append (dict "name" $name "url" $url) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $links := slice }} {{ $links_raw := $profile.links }} {{ $links_iter := slice }} {{ if reflect.IsSlice $links_raw }} {{ $links_iter = $links_raw }} {{ else if and $links_raw (reflect.IsMap $links_raw) }} {{ $links_iter = slice $links_raw }} {{ end }} {{ if gt (len $links_iter) 0 }} {{ range $links_iter }} {{ $url := "" }} {{ $icon := "" }} {{ $label := "" }} {{ if reflect.IsMap . }} {{ with index . "url" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $url }} {{ with index . "link" }}{{ $url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ with index . "icon" }}{{ $icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "label" }}{{ $label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $url = strings.TrimSpace . }} {{ end }} {{ if $url }} {{ if not $icon }}{{ $icon = "hero/link" }}{{ end }} {{ $links = $links | append (dict "url" $url "icon" $icon "label" $label) }} {{ end }} {{ end }} {{ end }} {{ $bio_style := "" }} {{ $bio_design := index $design "biography" }} {{ if reflect.IsMap $bio_design }} {{ with index $bio_design "style" }}{{ $bio_style = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ $bio_override := "" }} {{ $bio_raw := index $content "text" }} {{ if $bio_raw }} {{ $bio_override = strings.TrimSpace (printf "%v" $bio_raw) }} {{ end }} {{ $bio_content := $profile_bio }} {{ if $bio_override }}{{ $bio_content = $bio_override }}{{ end }} {{ $button := index $content "button" }} {{ if not (reflect.IsMap $button) }}{{ $button = dict }}{{ end }} {{ $button_text := "" }} {{ $button_link := "" }} {{ with index $button "text" }}{{ $button_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $button "url" }}{{ $button_link = strings.TrimSpace (printf "%v" .) }}{{ end }}
{{ if $avatar }}
{{ $avatar_image := $avatar.Fill (printf "%sx%s Center" $generation_size $generation_size) }} {{ $profile_title }} {{ with $status_icon }}{{ . | emojify }}{{ end }}
{{ end }} {{/* Extract pronunciation for ruby annotation */}} {{ $name_pronunciation := "" }} {{ with $profile.name_pronunciation }} {{ if eq (printf "%T" .) "string" }} {{ $name_pronunciation = strings.TrimSpace . }} {{ end }} {{ end }} {{/* Name with optional ruby pronunciation */}} {{ if and $profile_title $name_pronunciation }}

{{ $profile_title }}{{ $name_pronunciation }}

{{ else }}
{{- $profile_title -}}
{{ end }} {{- with $profile_pronouns -}}
({{ . }})
{{- end -}} {{ with $profile_role }}

{{ . | markdownify | emojify }}

{{ end }} {{ range $affiliations }}
{{ $name := index . "name" }} {{ $url := index . "url" }} {{ if $url }} {{ $link := $url }} {{ $target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }}
{{ $name }}
{{ else }}
{{ $name }}
{{ end }}
{{ end }} {{ if gt (len $links) 0 }}
    {{ range $links }} {{ $link := index . "url" }} {{ $icon := index . "icon" | default "hero/link" }} {{ $label := index . "label" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $aria := $label | default $icon | default "link" }}
  • {{ partial "functions/get_icon" (dict "name" $icon "attributes" "style=\"height: 1.5rem;\"") }}
  • {{ end }}
{{ end }} {{ if $bio_content }}
{{ $bio_content | emojify | $page.RenderString }}
{{ end }} {{ if and $button_text $button_link }} {{ $button_href := $button_link }} {{ $button_target := "" }} {{ $button_scheme := (urls.Parse $button_href).Scheme }} {{ if not $button_scheme }} {{ if not (hasPrefix $button_href "#") }} {{ $button_href = $button_href | relLangURL }} {{ end }} {{ if eq (path.Ext $button_href) ".pdf" }}{{ $button_target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $button_scheme }} {{ $button_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $button_text }} {{ end }}
================================================ FILE: modules/blox/blox/resume-biography/manifest.json ================================================ { "id": "resume-biography", "name": "Resume Biography", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "biography", "profile", "avatar", "social", "about", "personal", "cv"], "description": "Professional biography section with customizable avatar, social links, and personal information", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "biography", "profile", "avatar", "social", "cv"] } ================================================ FILE: modules/blox/blox/resume-biography-3/README.md ================================================ # Resume Biography 3 Block **Comprehensive professional profile with integrated academic details** Present a complete professional picture with the Resume Biography 3 block - an expanded biography layout that combines personal information, social presence, education history, and interests in one cohesive, horizontally-oriented section. ## 🛠️ Customization - **Name sizing**: Adjust the profile heading size to accommodate long names using `design.name.size`: - `compact`: space-friendly for long names - `balanced` (default): matches the demo style - `display`: extra-large for short names - **Section heading overrides**: Customize any of the three main section headings using `content.headings`: - `about`: Biography section heading (default: "Professional Summary" from i18n `about_me`) - `education`: Education section heading (default: from i18n `education`) - `interests`: Interests section heading (default: from i18n `interests`) Example front matter: ```yaml block: resume-biography-3 content: headings: about: Research Profile education: Academic Background interests: Research Areas design: name: size: compact ``` ## ✨ Key Features - **Horizontal Layout**: Desktop-optimized side-by-side arrangement for better space utilization - **Integrated Education**: Built-in education timeline with institution details - **Interests Section**: Personal interests display for a well-rounded professional image - **Name Pronunciation**: Ruby annotation displays pronunciation guides above your name (set `name.pronunciation` in your author YAML) - **Social Integration**: Complete social media profile links with proper external handling - **Avatar Flexibility**: Multiple size and shape options for personal branding - **Academic Icons**: Beautiful education and achievement icons - **Responsive Stack**: Gracefully converts to vertical layout on mobile devices ## 🎯 Perfect For - **Academic Professionals**: Researchers who need education prominently featured - **Career Changers**: Professionals highlighting diverse educational backgrounds - **Consultants**: Comprehensive profiles that establish expertise across domains - **Thought Leaders**: Complete professional picture including personal interests - **Graduate Students**: Academic profiles with research interests and education - **Multi-Disciplinary Experts**: Professionals with diverse backgrounds and interests ## 🚀 Why Choose Resume Biography 3? **Complete Picture**: Combines biography, education, and interests for comprehensive professional presentation **Space Efficient**: Horizontal layout maximizes content display while maintaining readability **Academic Focus**: Integrated education section perfect for academic and research professionals **Personal Touch**: Interests section adds humanity to professional profiles ## 📊 Professional Advantages - **Comprehensive Credibility**: Education and interests create complete professional narrative - **Better Engagement**: Personal interests create conversation starters and connections - **Academic Authority**: Prominent education display builds academic credibility - **Professional Networking**: Complete profile facilitates meaningful professional connections ## 💡 Layout Benefits - **Desktop Optimization**: Horizontal layout makes excellent use of wider screens - **Content Density**: More information displayed in less vertical space - **Visual Balance**: Side-by-side layout creates pleasing visual composition - **Mobile Adaptation**: Responsive design ensures great experience on all devices ## 🎨 Educational Excellence - **Institution Recognition**: Clear display of educational credentials - **Timeline Clarity**: Chronological education history with proper date formatting - **Academic Icons**: Beautiful visual elements that reinforce educational achievements - **Degree Emphasis**: Prominent display of areas of study and qualifications Perfect for academics, researchers, consultants, and professionals who want to present a complete picture of their background, education, and interests in one comprehensive, beautifully designed section. Create a professional profile that tells your complete story and opens doors to new opportunities. ================================================ FILE: modules/blox/blox/resume-biography-3/block.html ================================================ {{/* Hugo Blox: Biography 3 */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $author := "me" }} {{ $authorRaw := index $content "username" }} {{ if eq (printf "%T" $authorRaw) "string" }} {{ $author = $authorRaw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $author }} {{ $avatar := $profile.avatar }} {{ $headings := index $content "headings" }} {{ if not (reflect.IsMap $headings) }}{{ $headings = dict }}{{ end }} {{/* Avatar customization parameters */}} {{ $avatar_size := "large" }} {{ $avatar_shape := "circle" }} {{ $avatar_config := index $design "avatar" }} {{ if and $avatar_config (reflect.IsMap $avatar_config) }} {{ $avatar_size_raw := index $avatar_config "size" }} {{ if eq (printf "%T" $avatar_size_raw) "string" }} {{ $avatar_size = $avatar_size_raw }} {{ end }} {{ $avatar_shape_raw := index $avatar_config "shape" }} {{ if eq (printf "%T" $avatar_shape_raw) "string" }} {{ $avatar_shape = $avatar_shape_raw }} {{ end }} {{ end }} {{/* Profile name typography */}} {{ $name_size := "lg" }} {{ $name_config := index $design "name" }} {{ if and $name_config (reflect.IsMap $name_config) }} {{ $name_size_raw := index $name_config "size" }} {{ if eq (printf "%T" $name_size_raw) "string" }} {{ $name_size = $name_size_raw }} {{ end }} {{ end }} {{ $name_class_map := dict "xs" "text-xl sm:text-2xl lg:text-3xl" "sm" "text-2xl sm:text-3xl lg:text-4xl" "md" "text-3xl sm:text-4xl lg:text-5xl" "lg" "text-4xl sm:text-5xl lg:text-6xl" "xl" "text-5xl sm:text-6xl lg:text-7xl" }} {{ $name_class := index $name_class_map $name_size | default (index $name_class_map "lg") }} {{/* Size mappings optimized for 2025 standards: display_size -> [display_px, generation_px] */}} {{ $size_map := dict "small" (slice "150" "300") "medium" (slice "200" "400") "large" (slice "320" "640") "xl" (slice "400" "800") "xxl" (slice "500" "1000") }} {{ $size_config := index $size_map $avatar_size | default (index $size_map "large") }} {{ $display_size := index $size_config 0 }} {{ $generation_size := index $size_config 1 }} {{/* Shape class mappings */}} {{ $shape_classes := dict "circle" "rounded-full" "square" "rounded-none" "rounded" "rounded-lg" }} {{ $shape_class := index $shape_classes $avatar_shape | default "rounded-full" }} {{ $banner_filename := "" }} {{ $banner_config := index $design "banner" }} {{ if and $banner_config (reflect.IsMap $banner_config) }} {{ $banner_raw := index $banner_config "filename" }} {{ if eq (printf "%T" $banner_raw) "string" }} {{ $banner_filename = $banner_raw }} {{ end }} {{ end }} {{ $bio_style := "" }} {{ $bio_config := index $design "biography" }} {{ if and $bio_config (reflect.IsMap $bio_config) }} {{ $bio_style_raw := index $bio_config "style" }} {{ if eq (printf "%T" $bio_style_raw) "string" }} {{ $bio_style = $bio_style_raw }} {{ end }} {{ end }}
{{/* Add subtle top gradient for navbar transition */}}
{{/* Left Column: Flexible span */}}
{{/* Banner Image */}} {{ $img := "" }} {{/* Resolve image from page bundle, site assets, remote, or static URLs */}} {{ $image_resource := false }} {{ $image_url := "" }} {{ if $banner_filename }} {{ $image_path := strings.TrimSpace (printf "%v" $banner_filename) }} {{ $is_remote := or (strings.HasPrefix $image_path "http://") (strings.HasPrefix $image_path "https://") }} {{ if $is_remote }} {{ $remote := try (resources.GetRemote $image_path) }} {{ if and $remote (not $remote.Err) }} {{ $image_resource = $remote.Value }} {{ else }} {{ $image_url = $image_path }} {{ end }} {{ else }} {{ $image_path = strings.TrimPrefix "/" $image_path }} {{ $image_path = strings.TrimPrefix "./" $image_path }} {{ $image_path = strings.TrimPrefix "assets/" $image_path }} {{ $image_path = strings.TrimPrefix "media/" $image_path }} {{ $normalized := path.Clean $image_path }} {{ if and $normalized (ne $normalized ".") }} {{ with $page }} {{ $image_resource = (.Resources.ByType "image").GetMatch $normalized }} {{ end }} {{ if not $image_resource }} {{ $image_resource = resources.Get (path.Join "media" $normalized) }} {{ end }} {{ if not $image_resource }} {{ $image_url = printf "/media/%s" $normalized }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $img = $image_resource }} {{ if $img }} {{ $isSVG := eq $img.MediaType.SubType "svg" }} {{ $isGIF := eq $img.MediaType.SubType "gif" }}
{{ if not (or $isSVG $isGIF) }} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $img "mode" "fill" "aspect_ratio" "16:9" "sizes" (slice 768 1024 1366 1920 2560) ) }} {{ else }} {{ if not $isSVG }}{{ $img = $img.Process "webp" }}{{ end }} {{ end }}
{{ else if $image_url }} {{ $is_external := or (strings.HasPrefix $image_url "http://") (strings.HasPrefix $image_url "https://") }}
{{ end }} {{/* Avatar */}} {{ $status_icon := "" }} {{ $status := $profile.status }} {{ if and $status (reflect.IsMap $status) }} {{ $status_icon_raw := index $status "icon" }} {{ if eq (printf "%T" $status_icon_raw) "string" }} {{ $status_icon = strings.TrimSpace $status_icon_raw }} {{ end }} {{ end }} {{ if $avatar }}
{{ $avatar_image := $avatar.Fill (printf "%sx%s Center" $generation_size $generation_size) }} {{$profile.title}} {{ with $status_icon }}{{ . | emojify }}{{ end }}
{{ end }} {{/* Name and Role - Centered */}}
{{/* Extract pronunciation for ruby annotation */}} {{ $name_pronunciation := "" }} {{ with $profile.name_pronunciation }} {{ if eq (printf "%T" .) "string" }} {{ $name_pronunciation = strings.TrimSpace . }} {{ end }} {{ end }} {{/* Name with optional ruby pronunciation */}} {{ if and $profile.title $name_pronunciation }}

{{ $profile.title }}{{ $name_pronunciation }}

{{ else }}

{{ $profile.title }}

{{ end }} {{ $pronouns := "" }} {{ with $profile.pronouns }} {{ if eq (printf "%T" .) "string" }} {{ $pronouns = . }} {{ end }} {{ end }} {{ with $pronouns }}

({{ . }})

{{ end }} {{ $role_text := "" }} {{ with $profile.role }} {{ if eq (printf "%T" .) "string" }} {{ $role_text = . }} {{ end }} {{ end }} {{ with $role_text }}

{{ . | markdownify | emojify }}

{{ end }} {{ $affiliations_raw := $profile.affiliations }} {{ $affiliations := slice }} {{ if reflect.IsSlice $affiliations_raw }} {{ $affiliations = $affiliations_raw }} {{ else if eq (printf "%T" $affiliations_raw) "string" }} {{ $affiliations = slice $affiliations_raw }} {{ end }} {{ range $affiliations }} {{ $aff_name := "" }} {{ $aff_url := "" }} {{ if reflect.IsMap . }} {{ $nameRaw := index . "name" | default (index . "title") }} {{ if ne $nameRaw nil }} {{ $aff_name = printf "%v" $nameRaw }} {{ end }} {{ $urlRaw := index . "url" }} {{ if eq (printf "%T" $urlRaw) "string" }} {{ $aff_url = $urlRaw }} {{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $aff_name = . }} {{ end }} {{ $aff_name = strings.TrimSpace $aff_name }} {{ $aff_url = strings.TrimSpace $aff_url }} {{ if $aff_name }}

{{ if $aff_url }} {{ $link := $aff_url }} {{ $scheme := (urls.Parse $link).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $aff_name }} {{ else }} {{ $aff_name }} {{ end }}

{{ end }} {{ end }}
{{/* Social Icons */}} {{ $links_raw := $profile.links }} {{ $links := slice }} {{ if reflect.IsSlice $links_raw }} {{ $links = $links_raw }} {{ else if eq (printf "%T" $links_raw) "string" }} {{ $links = slice $links_raw }} {{ end }} {{ if gt (len $links) 0 }}
{{ range $links }} {{ $linkUrl := "" }} {{ $iconName := "hero/link" }} {{ $linkLabel := "" }} {{ if reflect.IsMap . }} {{ $urlRaw := index . "url" | default (index . "link") }} {{ if eq (printf "%T" $urlRaw) "string" }} {{ $linkUrl = $urlRaw }} {{ end }} {{ $iconRaw := index . "icon" }} {{ if eq (printf "%T" $iconRaw) "string" }} {{ $iconName = $iconRaw }} {{ end }} {{ $labelRaw := index . "label" }} {{ if eq (printf "%T" $labelRaw) "string" }} {{ $linkLabel = $labelRaw }} {{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $linkUrl = . }} {{ end }} {{ $linkUrl = strings.TrimSpace $linkUrl }} {{ if $linkUrl }} {{ $scheme := (urls.Parse $linkUrl).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $linkUrl "#") }} {{ $linkUrl = $linkUrl | relLangURL }} {{ end }} {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-6 h-6\"") }} {{ end }} {{ end }}
{{ end }}
{{/* Right Column: Flexible span */}}
{{/* Bio Section */}} {{ $bio_content := "" }} {{ $bio_override_raw := index $content "text" }} {{ if ne $bio_override_raw nil }} {{ $bio_content = printf "%v" $bio_override_raw | emojify | $page.RenderString }} {{ end }} {{ if not $bio_content }} {{ with $profile.bio }}{{ $bio_content = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ end }} {{ with $bio_content }}
{{ partial "functions/get_icon" (dict "name" "identification" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }}
{{ $i18n_about := i18n "about_me" }} {{ $about_default := cond (eq $i18n_about "about_me") "Professional Summary" $i18n_about }} {{ $about_heading := $about_default }} {{ $about_heading_raw := index $headings "about" }} {{ if eq (printf "%T" $about_heading_raw) "string" }} {{ $about_heading_raw = strings.TrimSpace $about_heading_raw }} {{ if ne $about_heading_raw "" }} {{ $about_heading = $about_heading_raw }} {{ end }} {{ end }}

{{ $about_heading }}

{{ . }}
{{ end }} {{/* CV Download Button */}} {{ $button_raw := index $content "button" }} {{ if and $button_raw (reflect.IsMap $button_raw) }} {{ $button_text := "" }} {{ $button_url := "" }} {{ with index $button_raw "text" }}{{ $button_text = printf "%v" . }}{{ end }} {{ with index $button_raw "url" }}{{ $button_url = printf "%v" . }}{{ end }} {{ $button_text = strings.TrimSpace $button_text }} {{ $button_url = strings.TrimSpace $button_url }} {{ if and $button_text $button_url }} {{ $button_link := $button_url }} {{ $scheme := (urls.Parse $button_link).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $button_link "#") }} {{ $button_link = $button_link | relLangURL }} {{ end }} {{ if eq (path.Ext $button_link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ end }} {{/* Education Section */}} {{ $education_raw := $profile.education }} {{ $education := slice }} {{ if reflect.IsSlice $education_raw }} {{ $education = $education_raw }} {{ end }} {{ if gt (len $education) 0 }}
{{ partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }}
{{ $education_heading := i18n "education" }} {{ $education_heading_raw := index $headings "education" }} {{ if eq (printf "%T" $education_heading_raw) "string" }} {{ $education_heading_raw = strings.TrimSpace $education_heading_raw }} {{ if ne $education_heading_raw "" }} {{ $education_heading = $education_heading_raw }} {{ end }} {{ end }}

{{ $education_heading | markdownify }}

{{ range $education }} {{ if reflect.IsMap . }} {{ $degree := "" }} {{ $degreeRaw := index . "degree" | default (index . "area") }} {{ if ne $degreeRaw nil }}{{ $degree = printf "%v" $degreeRaw }}{{ end }} {{ $year := "" }} {{ with index . "year" }}{{ $year = printf "%v" . }}{{ end }} {{ $start := "" }} {{ with index . "start" }}{{ $start = printf "%v" . }}{{ end }} {{ $end := "" }} {{ with index . "end" }}{{ $end = printf "%v" . }}{{ end }} {{ $institution := "" }} {{ with index . "institution" }}{{ $institution = printf "%v" . }}{{ end }} {{ $icon := "" }} {{ $iconRaw := index . "icon" }} {{ if eq (printf "%T" $iconRaw) "string" }} {{ $icon = $iconRaw }} {{ end }}
{{ if $icon }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }} {{ else }} {{ partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }} {{ end }}
{{ if $degree }}

{{ $degree }}

{{ end }} {{ if $year }}

{{ $year }}

{{ else if $start }}

{{ $start }} {{ if $end }}
{{ $end }}{{ end }}

{{ end }} {{ if $institution }}

{{ $institution }}

{{ end }}
{{ end }} {{ end }}
{{ end }} {{/* Interests Section */}} {{ $interests_raw := $profile.interests }} {{ $interests := slice }} {{ if reflect.IsSlice $interests_raw }} {{ $interests = $interests_raw }} {{ else if eq (printf "%T" $interests_raw) "string" }} {{ $interests = slice $interests_raw }} {{ end }} {{ if gt (len $interests) 0 }}
{{ partial "functions/get_icon" (dict "name" "sparkles" "attributes" "class='w-6 h-6 text-primary-600 dark:text-primary-400'") }}
{{ $interests_heading := i18n "interests" }} {{ $interests_heading_raw := index $headings "interests" }} {{ if eq (printf "%T" $interests_heading_raw) "string" }} {{ $interests_heading_raw = strings.TrimSpace $interests_heading_raw }} {{ if ne $interests_heading_raw "" }} {{ $interests_heading = $interests_heading_raw }} {{ end }} {{ end }}

{{ $interests_heading | markdownify }}

{{ range $interests }} {{ $interest := strings.TrimSpace (printf "%v" .) }} {{ if $interest }} {{ $interest | markdownify | emojify }} {{ end }} {{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/resume-biography-3/manifest.json ================================================ { "id": "resume-biography-3", "name": "Resume Biography 3", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "biography", "profile", "horizontal", "education", "interests", "cv", "layout"], "description": "Horizontal biography layout with integrated education and interests sections", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "biography", "horizontal", "education", "interests", "cv"] } ================================================ FILE: modules/blox/blox/resume-experience/README.md ================================================ # Resume Experience Block **Tell your professional journey with timeline elegance** Present your career progression and educational background with the Resume Experience block - a sophisticated timeline component that showcases your professional journey in a visually compelling, chronologically organized format. ## ✨ Key Features - **Dual Timeline**: Separate sections for work experience and education - **Visual Timeline**: Beautiful vertical timeline with connection lines and icons - **Date Flexibility**: Customizable date formatting with "Present" support for current roles - **Rich Content**: Markdown support for detailed position descriptions - **Download Links**: Optional buttons for certificates, portfolios, or additional resources - **Responsive Design**: Timeline adapts perfectly from desktop to mobile - **Order Control**: Option to display education before experience ## 🎯 Perfect For - **Job Seekers**: Comprehensive career history for potential employers - **Career Professionals**: Showcase progression and diverse experience - **Academic Professionals**: Combined academic and professional timeline - **Consultants**: Demonstrate expertise across various roles and industries - **Freelancers**: Highlight diverse project experience and education - **Recent Graduates**: Emphasize education with growing professional experience ## 🚀 Why Choose Resume Experience Block? **Visual Storytelling**: Timeline format makes career progression easy to follow and understand **Professional Standard**: Meets modern resume and CV expectations with comprehensive detail **Flexible Organization**: Control whether education or experience appears first based on your background **Rich Detail Support**: Markdown formatting allows for detailed role descriptions and achievements ## 📊 Career Presentation Benefits - **Clear Progression**: Visual timeline shows career growth and development - **Comprehensive View**: Both work and education in one cohesive presentation - **Easy Scanning**: Timeline format allows quick review of career highlights - **Professional Polish**: Clean, modern design that makes great first impressions ## 💡 Timeline Psychology - **Sequential Understanding**: Chronological order helps viewers understand your journey - **Achievement Focus**: Timeline format naturally highlights career milestones - **Story Narrative**: Creates compelling career story that engages viewers - **Future Projection**: Shows trajectory that helps employers envision your potential ## 🎨 Visual Excellence - **Beautiful Icons**: Work and education icons that immediately communicate section type - **Color Coordination**: Primary brand colors create cohesive, professional appearance - **Typography Hierarchy**: Clear information structure from position titles to descriptions - **Responsive Timeline**: Maintains visual appeal across all screen sizes ## 💼 Strategic Advantages - **Comprehensive Coverage**: One block covers your entire professional and educational background - **Flexible Emphasis**: Choose whether to lead with education or experience based on your strengths - **Detail Control**: Include as much or as little detail as appropriate for your audience - **Modern Format**: Timeline presentation feels current and engaging Perfect for professionals at any career stage who want to present their experience and education in a format that's both comprehensive and visually engaging. Your career journey deserves professional presentation that opens doors to new opportunities. ================================================ FILE: modules/blox/blox/resume-experience/block.html ================================================ {{/* Hugo Blox: Experience - 2026 Redesign */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $text := "" }} {{ $text_raw := index $content "text" }} {{ if $text_raw }}{{ $text = strings.TrimSpace (printf "%v" $text_raw) }}{{ end }} {{ if $text }}{{ $text = $text | emojify | $page.RenderString }}{{ end }} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $username }} {{ $is_education_first := partial "functions/coerce_bool" (dict "value" (index $design "is_education_first") "default" false) }} {{ $date_format := "Jan 2006" }} {{ $date_format_raw := index $design "date_format" }} {{ if eq (printf "%T" $date_format_raw) "string" }} {{ $date_format = strings.TrimSpace $date_format_raw | default "Jan 2006" }} {{ end }} {{ $experience_raw := or $profile.experience $profile.work }} {{ $experience_iter := slice }} {{ if reflect.IsSlice $experience_raw }} {{ $experience_iter = $experience_raw }} {{ else if and $experience_raw (reflect.IsMap $experience_raw) }} {{ $experience_iter = slice $experience_raw }} {{ end }} {{ $experience := slice }} {{ if gt (len $experience_iter) 0 }} {{ range $experience_iter }} {{ if reflect.IsMap . }} {{ $role := "" }} {{ $org := "" }} {{ $start := "" }} {{ $end := "" }} {{ $summary := "" }} {{ $icon := "" }} {{ $tags := slice }} {{ $button_url := "" }} {{ $button_text := "" }} {{ $button_icon := "" }} {{ with index . "role" }}{{ $role = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $role }}{{ with index . "position" }}{{ $role = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "org" }}{{ $org = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $org }}{{ with index . "company_name" }}{{ $org = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "start" }}{{ $start = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $start }}{{ with index . "date_start" }}{{ $start = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "end" }}{{ $end = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $end }}{{ with index . "date_end" }}{{ $end = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "summary" }}{{ $summary = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $tags_raw := index . "tags" }} {{ if reflect.IsSlice $tags_raw }} {{ range $tags_raw }} {{ $tag := strings.TrimSpace (printf "%v" .) }} {{ if $tag }}{{ $tags = $tags | append $tag }}{{ end }} {{ end }} {{ else if eq (printf "%T" $tags_raw) "string" }} {{ $tag_string := strings.TrimSpace $tags_raw }} {{ if $tag_string }} {{ if strings.Contains $tag_string "," }} {{ range (split $tag_string ",") }} {{ $tag := strings.TrimSpace . }} {{ if $tag }}{{ $tags = $tags | append $tag }}{{ end }} {{ end }} {{ else }} {{ $tags = slice $tag_string }} {{ end }} {{ end }} {{ end }} {{ $button_raw := index . "button" }} {{ if reflect.IsMap $button_raw }} {{ with index $button_raw "url" }}{{ $button_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $button_raw "text" }}{{ $button_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $button_raw "icon" }}{{ $button_icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ if or $role $org }} {{ $experience = $experience | append (dict "role" $role "org" $org "start" $start "end" $end "summary" $summary "icon" $icon "tags" $tags "button" (dict "url" $button_url "text" $button_text "icon" $button_icon)) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $education_raw := $profile.education }} {{ $education_iter := slice }} {{ if reflect.IsSlice $education_raw }} {{ $education_iter = $education_raw }} {{ else if and $education_raw (reflect.IsMap $education_raw) }} {{ $education_iter = slice $education_raw }} {{ end }} {{ $education := slice }} {{ if gt (len $education_iter) 0 }} {{ range $education_iter }} {{ if reflect.IsMap . }} {{ $degree := "" }} {{ $institution := "" }} {{ $start := "" }} {{ $end := "" }} {{ $summary := "" }} {{ $icon := "" }} {{ $button_url := "" }} {{ $button_text := "" }} {{ $button_icon := "" }} {{ with index . "degree" }}{{ $degree = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $degree }}{{ with index . "area" }}{{ $degree = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "institution" }}{{ $institution = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "start" }}{{ $start = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $start }}{{ with index . "date_start" }}{{ $start = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "end" }}{{ $end = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if not $end }}{{ with index . "date_end" }}{{ $end = strings.TrimSpace (printf "%v" .) }}{{ end }}{{ end }} {{ with index . "summary" }}{{ $summary = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $button_raw := index . "button" }} {{ if reflect.IsMap $button_raw }} {{ with index $button_raw "url" }}{{ $button_url = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $button_raw "text" }}{{ $button_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $button_raw "icon" }}{{ $button_icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ end }} {{ if or $degree $institution }} {{ $education = $education | append (dict "degree" $degree "institution" $institution "start" $start "end" $end "summary" $summary "icon" $icon "button" (dict "url" $button_url "text" $button_text "icon" $button_icon)) }} {{ end }} {{ end }} {{ end }} {{ end }}
{{ if gt (len $experience) 0 }}

{{ i18n "experience" | default "Experience" }}

{{/* Timeline container */}}
{{/* Gradient timeline line */}}
{{/* Experience items */}}
{{ range $idx, $item := $experience }} {{/* Card wrapper */}}
{{/* Timeline marker */}}
{{/* Glowing dot */}}
{{ $icon := index $item "icon" }} {{ if $icon }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class='w-4 h-4 text-primary-600 dark:text-primary-400'") }} {{else}} {{end}}
{{/* Content card */}}
{{/* Header row */}}
{{/* Role/Position */}}

{{ index $item "role" }}

{{/* Company */}}

{{ index $item "org" }}

{{/* Date badge */}}
{{/* Description */}} {{ with index $item "summary" }}
{{ . | emojify | $page.RenderString }}
{{ end }} {{/* Tags/Skills */}} {{ with index $item "tags" }}
{{ range . }} {{ . }} {{ end }}
{{ end }} {{/* Action button */}} {{ $button := index $item "button" }} {{ if reflect.IsMap $button }} {{ $button_url := index $button "url" }} {{ $button_text := index $button "text" | default "Learn more" }} {{ $button_icon := index $button "icon" }} {{ if $button_url }} {{ $button_link := $button_url }} {{ $button_target := "" }} {{ $button_scheme := (urls.Parse $button_link).Scheme }} {{ if not $button_scheme }} {{ if not (hasPrefix $button_link "#") }} {{ $button_link = $button_link | relLangURL }} {{ end }} {{ if eq (path.Ext $button_link) ".pdf" }}{{ $button_target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $button_scheme }} {{ $button_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ end }}
{{ end }}
{{ end }} {{ if gt (len $education) 0 }}

{{ i18n "education" | default "Education" }}

{{/* Timeline container */}}
{{/* Gradient timeline line */}}
{{/* Education items */}}
{{ range $idx, $item := $education }} {{/* Card wrapper */}}
{{/* Timeline marker */}}
{{/* Glowing dot */}}
{{ $icon := index $item "icon" }} {{ if $icon }} {{ partial "functions/get_icon" (dict "name" $icon "attributes" "class='w-4 h-4 text-secondary-600 dark:text-secondary-400'") }} {{else}} {{end}}
{{/* Content card */}}
{{/* Header row */}}
{{/* Degree */}}

{{ index $item "degree" }}

{{/* Institution */}}

{{ index $item "institution" }}

{{/* Date badge */}}
{{/* Description */}} {{ with index $item "summary" }}
{{ . | emojify | $page.RenderString }}
{{ end }} {{/* Action button */}} {{ $button := index $item "button" }} {{ if reflect.IsMap $button }} {{ $button_url := index $button "url" }} {{ $button_text := index $button "text" | default "Learn more" }} {{ $button_icon := index $button "icon" }} {{ if $button_url }} {{ $button_link := $button_url }} {{ $button_target := "" }} {{ $button_scheme := (urls.Parse $button_link).Scheme }} {{ if not $button_scheme }} {{ if not (hasPrefix $button_link "#") }} {{ $button_link = $button_link | relLangURL }} {{ end }} {{ if eq (path.Ext $button_link) ".pdf" }}{{ $button_target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $button_scheme }} {{ $button_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ end }}
{{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/resume-experience/manifest.json ================================================ { "id": "resume-experience", "name": "Resume Experience", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "experience", "timeline", "work", "education", "career", "professional", "cv"], "description": "Professional timeline displaying work experience and education history in chronological order", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "experience", "timeline", "work", "education", "career"] } ================================================ FILE: modules/blox/blox/resume-languages/README.md ================================================ # Resume Languages Block **Showcase your multilingual capabilities with visual elegance** Highlight your language skills with the Resume Languages block - a visually striking component that uses beautiful circular progress indicators to display language proficiency levels in an immediately understandable, professional format. ## ✨ Key Features - **Circular Progress Bars**: Stunning circular indicators that show proficiency at a glance - **Percentage Display**: Clear numerical representation of language fluency levels - **Responsive Layout**: Adapts from vertical (mobile) to horizontal (desktop) arrangement - **Brand Colors**: Progress bars use your primary brand colors for visual consistency - **Clean Typography**: Professional language name display with generous spacing - **Flexible Grid**: Accommodates any number of languages with graceful layout adaptation ## 🎯 Perfect For - **International Professionals**: Showcase multilingual capabilities for global opportunities - **Translators & Interpreters**: Professional language service providers - **Academic Researchers**: Demonstrate language skills for international collaboration - **Travel & Tourism**: Professionals in hospitality and travel industries - **Global Consultants**: International business professionals and consultants - **Job Seekers**: Stand out in competitive markets with language advantages ## 🚀 Why Choose Resume Languages Block? **Instant Understanding**: Circular progress bars communicate proficiency levels immediately **Professional Credibility**: Visual representation demonstrates serious commitment to language learning **Global Appeal**: Multilingual capabilities signal international readiness and cultural awareness **Modern Presentation**: Contemporary design that feels current and engaging ## 📊 Visual Communication Benefits - **Quick Assessment**: Employers can instantly gauge your language capabilities - **Professional Standards**: Percentage-based system aligns with common proficiency frameworks - **Visual Impact**: Circular progress bars are more engaging than simple text lists - **Space Efficient**: Compact design accommodates multiple languages without clutter ## 💡 Proficiency Psychology - **Confidence Signaling**: Visual progress indicators demonstrate self-awareness and honesty - **Competitive Advantage**: Language skills differentiate you in global job markets - **Cultural Intelligence**: Multilingual display signals adaptability and cultural sensitivity - **Learning Mindset**: Shows commitment to continuous learning and development ## 🎨 Design Excellence - **Mathematical Precision**: Accurate circular progress calculations with smooth animations - **Brand Integration**: Primary colors create cohesive visual identity - **Responsive Behavior**: Transitions elegantly from vertical to horizontal layouts - **Clean Aesthetics**: Generous whitespace prevents overwhelming appearance ## 🌍 Global Market Advantages Perfect for professionals in increasingly connected global markets where language skills provide significant competitive advantages. Whether you're seeking international opportunities, working with diverse teams, or serving multilingual customers, the Resume Languages block presents your linguistic capabilities with the professionalism they deserve. Transform your language skills into visual assets that open doors to global opportunities and demonstrate your readiness for international collaboration. ================================================ FILE: modules/blox/blox/resume-languages/block.html ================================================ {{/* Hugo Blox: Languages */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $username }} {{ $langs_raw := $profile.languages }} {{ $langs_iter := slice }} {{ if reflect.IsSlice $langs_raw }} {{ $langs_iter = $langs_raw }} {{ else if and $langs_raw (reflect.IsMap $langs_raw) }} {{ $langs_iter = slice $langs_raw }} {{ end }} {{ $langs := slice }} {{ if gt (len $langs_iter) 0 }} {{ range $langs_iter }} {{ if reflect.IsMap . }} {{ $name := "" }} {{ $level_text := "" }} {{ $label := "" }} {{ $percent_raw := "" }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "level" }}{{ $level_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "label" }}{{ $label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "percent" }}{{ $percent_raw = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $percent := 100.0 }} {{ $numeric_level := gt (len (findRE "^[0-9]+(?:\\.[0-9]+)?$" $level_text)) 0 }} {{ if $numeric_level }} {{ $percent = mul (float $level_text) 20 }} {{ else if $percent_raw }} {{ if gt (len (findRE "^[0-9]+(?:\\.[0-9]+)?$" $percent_raw)) 0 }} {{ $percent = float $percent_raw }} {{ end }} {{ end }} {{ if gt $percent 100 }}{{ $percent = 100 }}{{ end }} {{ if lt $percent 0 }}{{ $percent = 0 }}{{ end }} {{ if $name }} {{ $langs = $langs | append (dict "name" $name "level" $level_text "label" $label "percent" $percent "numeric_level" $numeric_level) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }}{{ $title = strings.TrimSpace (printf "%v" $title_raw) }}{{ end }} {{ $text := "" }} {{ $text_raw := index $content "text" }} {{ if $text_raw }}{{ $text = strings.TrimSpace (printf "%v" $text_raw) }}{{ end }}
{{ $title | markdownify | emojify }}
{{ with $text }}

{{ . | markdownify | emojify }}

{{ end }}
{{ range $langs }} {{ $percent := index . "percent" }} {{ $level_text := index . "level" }} {{ $label := index . "label" }} {{ $numeric_level := index . "numeric_level" }}
{{ $percent }}%
{{ index . "name" }} {{ if $label }} {{ $label }} {{ else if and $level_text (not $numeric_level) }} {{ $level_text }} {{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/resume-languages/manifest.json ================================================ { "id": "resume-languages", "name": "Resume Languages", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "languages", "multilingual", "skills", "fluency", "international", "cv", "circular-progress"], "description": "Showcase language proficiency with beautiful circular progress indicators and percentage displays", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "languages", "multilingual", "fluency", "skills", "cv"] } ================================================ FILE: modules/blox/blox/resume-skills/README.md ================================================ # Resume Skills Block **Demonstrate expertise with organized skill categories and visual progress** Present your technical and professional competencies with the Resume Skills block - a comprehensive component that organizes your skills into clear categories with optional visual progress indicators that immediately communicate your expertise levels. ## ✨ Key Features - **Skill Categories**: Organize skills into logical groups (Technical, Soft Skills, Tools, etc.) - **Progress Visualization**: Optional progress bars show proficiency levels at a glance - **Icon Integration**: Beautiful icons for each skill that enhance visual recognition - **Flexible Layout**: Side-by-side categories on larger screens, stacked on mobile - **Custom Colors**: Configurable progress bar colors to match your brand - **Automatic Bars**: Bars appear when a skill has a level (1–5) - **Markdown Support**: Rich text formatting for skill names and descriptions ## 🎯 Perfect For - **Software Developers**: Showcase programming languages, frameworks, and tools - **Designers**: Display creative software proficiency and design skills - **Data Professionals**: Highlight analytics tools, programming languages, and methodologies - **Marketing Professionals**: Present digital marketing tools and strategic capabilities - **Project Managers**: Demonstrate methodologies, tools, and soft skills - **Technical Consultants**: Comprehensive skill display across multiple domains ## 🚀 Why Choose Resume Skills Block? **Clear Organization**: Skill categories help employers quickly find relevant expertise **Visual Proficiency**: Progress bars provide immediate understanding of skill levels **Comprehensive Coverage**: Support both technical and soft skills in one organized presentation **Professional Standards**: Clean, modern layout that meets current resume expectations ## 📊 Skill Presentation Benefits - **Quick Scanning**: Organized categories allow rapid skill assessment - **Honest Communication**: Progress bars encourage accurate self-assessment - **Visual Engagement**: Icons and progress bars are more engaging than text lists - **Comprehensive View**: Categories ensure no important skills are overlooked ## 💡 Professional Psychology - **Expertise Signaling**: Visual progress bars demonstrate self-awareness and competence - **Category Logic**: Organized presentation shows systematic thinking - **Skill Balance**: Mix of technical and soft skills presents well-rounded professional - **Growth Mindset**: Percentage-based system implies commitment to skill development ## 🎨 Customization Excellence - **Brand Colors**: Progress bars and icons can match your personal or company branding - **Icon Flexibility**: Support for various icon packs to match your aesthetic - **Layout Control**: Choose between progress bars or simple lists based on your preference - **Content Freedom**: Unlimited skill categories and items for comprehensive coverage ## 💼 Strategic Applications - **Career Positioning**: Clearly communicate your unique skill combination - **Job Matching**: Help employers quickly identify relevant expertise - **Skill Gaps**: Identify areas for professional development - **Team Fit**: Demonstrate how your skills complement team needs Perfect for technical professionals, creative experts, and anyone who wants to present their skills in an organized, visually appealing format that helps employers quickly understand their capabilities and expertise levels. Turn your skill set into a competitive advantage with professional presentation that clearly communicates your value proposition. ================================================ FILE: modules/blox/blox/resume-skills/block.html ================================================ {{/* Hugo Blox: Skills */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $username := "me" }} {{ $username_raw := index $content "username" }} {{ if eq (printf "%T" $username_raw) "string" }} {{ $username = strings.TrimSpace $username_raw }} {{ end }} {{ $profile := partial "functions/get_author_profile" $username }} {{ $skills_raw := $profile.skills }} {{ $skills_iter := slice }} {{ if reflect.IsSlice $skills_raw }} {{ $skills_iter = $skills_raw }} {{ else if and $skills_raw (reflect.IsMap $skills_raw) }} {{ $skills_iter = slice $skills_raw }} {{ end }} {{ $skills := slice }} {{ if gt (len $skills_iter) 0 }} {{ range $skills_iter }} {{ if reflect.IsMap . }} {{ $name := "" }} {{ $description := "" }} {{ $color := "" }} {{ $color_border := "" }} {{ $items_raw := index . "items" }} {{ $items_iter := slice }} {{ if reflect.IsSlice $items_raw }} {{ $items_iter = $items_raw }} {{ else if and $items_raw (reflect.IsMap $items_raw) }} {{ $items_iter = slice $items_raw }} {{ end }} {{ $items := slice }} {{ with index . "name" }}{{ $name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "description" }}{{ $description = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "color" }}{{ $color = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "color_border" }}{{ $color_border = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if gt (len $items_iter) 0 }} {{ range $items_iter }} {{ if reflect.IsMap . }} {{ $item_label := "" }} {{ $item_name := "" }} {{ $item_desc := "" }} {{ $item_icon := "" }} {{ $level := "" }} {{ with index . "label" }}{{ $item_label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "name" }}{{ $item_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "description" }}{{ $item_desc = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $item_icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "level" }}{{ $level = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if or $item_label $item_name }} {{ $items = $items | append (dict "label" $item_label "name" $item_name "description" $item_desc "icon" $item_icon "level" $level) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if and $name (gt (len $items) 0) }} {{ $skills = $skills | append (dict "name" $name "description" $description "color" $color "color_border" $color_border "items" $items) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }}{{ $title = strings.TrimSpace (printf "%v" $title_raw) }}{{ end }} {{ $text := "" }} {{ $text_raw := index $content "text" }} {{ if $text_raw }}{{ $text = strings.TrimSpace (printf "%v" $text_raw) }}{{ end }} {{ $columns := partial "functions/coerce_int" (dict "value" (index $design "columns") "default" 2 "min" 1 "max" 5) }}
{{ $title | markdownify | emojify }}
{{ with $text }}

{{ . | markdownify | emojify }}

{{ end }}
{{ range $skills }} {{ $color := index . "color" | default "" }} {{ $color_border := index . "color_border" | default "" }}
{{ index . "name" | markdownify | emojify }} {{ with index . "description" }}

{{ . | markdownify | emojify }}

{{ end }}
{{ range (index . "items") }}
{{ with index . "icon" }} {{ partial "functions/get_icon" (dict "name" . "attributes" "style=\"height: 1em;\"") }} {{ end }} {{ $label := index . "label" | default (index . "name") }} {{ $label | markdownify | emojify }} {{ with index . "description" }}

{{ . | markdownify | emojify }}

{{ end }}
{{/* Numeric level (1-5) only. */}} {{ $level := 0.0 }} {{ $level_raw := index . "level" }} {{ if $level_raw }} {{ $level_str := strings.TrimSpace (printf "%v" $level_raw) }} {{ if gt (len (findRE "^[0-9]+(?:\\.[0-9]+)?$" $level_str)) 0 }} {{ $level = float $level_str }} {{ end }} {{ end }} {{ if gt $level 5 }}{{ $level = 5 }}{{ end }} {{ if lt $level 0 }}{{ $level = 0 }}{{ end }} {{ if gt $level 0 }} {{ $levelPercent := mul $level 20 }}
{{ end }}
{{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/resume-skills/manifest.json ================================================ { "id": "resume-skills", "name": "Resume Skills", "version": "1.0.0", "license": "MIT", "category": "resume", "tags": ["resume", "skills", "technical", "progress-bars", "expertise", "professional", "competencies", "cv"], "description": "Display technical and professional skills with optional progress bars and organized categories", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "resume", "skills", "technical", "progress", "expertise", "cv"] } ================================================ FILE: modules/blox/blox/search-hero/README.md ================================================ # Search Hero Block A modern hero section with prominent search functionality, perfect for knowledge bases and documentation sites. ## Features - 🔍 **Integrated Search** - Opens Hugo Blox search modal - 💎 **Gradient Text Highlighting** - Eye-catching emphasized text - 🎨 **Animated Backgrounds** - Gradient mesh with pulsing orbs - 📊 **Stats Display** - Showcase key metrics - 🏷️ **Badge Support** - With optional pulsing indicator - 🔥 **Popular Searches** - Quick suggestion pills - 📱 **Fully Responsive** - Beautiful on all devices ## Basic Usage ```yaml sections: - block: search-hero content: title: "Your Knowledge Hub" subtitle: "Find answers to all your questions" ``` ## Title Highlighting Use `==text==` syntax to apply gradient highlighting to any words or phrases: ### Single Highlight ```yaml title: "Master ==AI Tools==" ``` **Result**: "Master" in regular text, "AI Tools" with gradient ### Multiple Highlights ```yaml title: "Master ==AI Tools==. ==Boost Your Productivity.==" ``` **Result**: Both "AI Tools" and "Boost Your Productivity" highlighted ### Mid-Sentence Highlighting ```yaml title: "Build ==amazing== websites with ==Hugo Blox==" ``` **Result**: "amazing" and "Hugo Blox" highlighted within the sentence ### i18n-Friendly ```yaml # en.yaml - id: hero_title translation: "Master ==AI Tools==. ==Boost Productivity.==" # es.yaml - id: hero_title translation: "Domina ==Herramientas IA==. ==Aumenta Productividad.==" ``` Each language can highlight naturally! ## Complete Example ```yaml sections: - block: search-hero content: badge: text: "500+ AI answers added this week" show_pulse: true # Shows pulsing dot indicator title: "Master ==AI Tools==. ==Boost Your Productivity.==" subtitle: "Get instant answers to your AI questions from our comprehensive knowledge base." search_placeholder: "Ask anything about AI tools, prompts, or workflows..." suggestions: - "ChatGPT prompts" - "Midjourney tips" - "AI automation" - "Claude vs GPT-4" stats: - value: "2,500+" label: "Expert Answers" - value: "50K+" label: "Monthly Users" - value: "4.9/5" label: "User Rating" design: background: gradient_mesh: enable: true style: "orbs" # orbs, waves, dots, grid animation: "pulse" # pulse, float, rotate, none intensity: "subtle" # subtle, medium, bold colors: - "primary-500/20" - "primary-600/20" spacing: padding: ["8rem", "0", "6rem", "0"] ``` ## Properties ### Content #### `badge` - **Type**: Object - **Optional** - **Properties**: - `text` (string): Badge text - `show_pulse` (boolean): Show pulsing dot indicator #### `title` - **Type**: String - **Required** - **Description**: Main heading. Use `==text==` for gradient highlighting - **Example**: `"Build ==Amazing== Websites"` #### `subtitle` - **Type**: String - **Optional** - **Description**: Supporting text below title #### `search_placeholder` - **Type**: String - **Optional** - **Default**: "Search for answers..." - **Description**: Placeholder text in search box #### `suggestions` - **Type**: Array of strings - **Optional** - **Description**: Quick search suggestion pills - **Example**: `["Topic 1", "Topic 2"]` #### `stats` - **Type**: Array of objects - **Optional** - **Description**: Metrics displayed below search - **Properties**: - `value` (string): Metric value (e.g., "2,500+") - `label` (string): Metric description ### Design See [Gradient Mesh Guide](../../../../GRADIENT_MESH_GUIDE.md) for complete background options. ## Styling Tips ### Gradient Colors The `==text==` highlighting uses: ```css background: linear-gradient(to-right, primary-600, primary-500); background-clip: text; ``` This automatically adapts to your site's primary color theme. ### Stat Layout Stats automatically: - Display in 3-column grid - Center-aligned - Responsive on mobile ### Search Integration The search button automatically: - Opens Hugo Blox search modal - Works with Cmd+K shortcut - Supports pre-filled queries from suggestions ## Examples ### Knowledge Base (Current) ```yaml title: "Master ==AI Tools==. ==Boost Your Productivity.==" ``` ### Documentation Site ```yaml title: "==Comprehensive== Documentation for ==Developers==" ``` ### Product Landing ```yaml title: "Build ==Faster==. Ship ==Better==. Scale ==Effortlessly.==" ``` ### Academic/Research ```yaml title: "Advancing ==Science== Through ==Collaboration==" ``` ## Best Practices ### 1. Highlight Key Value Props ✅ **Good**: Highlight unique value or action words ```yaml title: "Learn ==Faster== with AI" ``` ❌ **Bad**: Highlight common words ```yaml title: "Learn Faster ==with== AI" ``` ### 2. Don't Over-Highlight ✅ **Good**: 1-3 highlighted phrases max ```yaml title: "Master ==AI Tools==. Boost ==Productivity==." ``` ❌ **Bad**: Everything highlighted ```yaml title: "==Master== ==AI== ==Tools==. ==Boost== ==Your== ==Productivity==." ``` ### 3. Keep Highlights Meaningful Highlighted text should be: - **Scannable** - Key phrases users notice first - **Actionable** - Words that convey benefit - **Brief** - 1-4 words per highlight ## Advanced Examples ### Corporate Landing ```yaml title: "Transform ==Your Business== with AI" ``` ### Educational Platform ```yaml title: "Learn ==Smarter==, Not ==Harder==" ``` ## Technical Notes - **Regex Pattern**: `==([^=]+)==` matches text between double equals - **Processing**: Applied before markdownify, so Markdown works inside highlights - **Output**: `text` - **Performance**: No runtime cost, processed at build time --- **Part of HugoBlox Kit** - https://hugoblox.com ================================================ FILE: modules/blox/blox/search-hero/block.html ================================================ {{- $wcPage := .wcPage -}} {{- $wcBlock := .wcBlock -}} {{- $wcIdentifier := .wcIdentifier -}} {{/* Enable Alpine.js for interactivity */}} {{ $wcPage.Page.Store.Set "has_alpine" true }} {{ $content := $wcBlock.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $badge := index $content "badge" }} {{ if not (reflect.IsMap $badge) }}{{ $badge = dict }}{{ end }} {{ $badge_text := "" }} {{ with index $badge "text" }}{{ $badge_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $show_pulse := partial "functions/coerce_bool" (dict "value" (index $badge "show_pulse") "default" false) }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }}{{ $title = strings.TrimSpace (printf "%v" $title_raw) }}{{ end }} {{ if $title }} {{ $title = replaceRE "==([^=]+)==" "$1" $title }} {{ end }} {{ $subtitle := "" }} {{ $subtitle_raw := index $content "subtitle" }} {{ if $subtitle_raw }}{{ $subtitle = strings.TrimSpace (printf "%v" $subtitle_raw) }}{{ end }} {{ $search_placeholder := "" }} {{ $placeholder_raw := index $content "search_placeholder" }} {{ if eq (printf "%T" $placeholder_raw) "string" }} {{ $search_placeholder = strings.TrimSpace $placeholder_raw }} {{ end }} {{ if not $search_placeholder }}{{ $search_placeholder = "Search for answers..." }}{{ end }} {{ $suggestions_raw := index $content "suggestions" }} {{ $suggestions := slice }} {{ if reflect.IsSlice $suggestions_raw }} {{ range $suggestions_raw }} {{ $suggestion := strings.TrimSpace (printf "%v" .) }} {{ if $suggestion }}{{ $suggestions = $suggestions | append $suggestion }}{{ end }} {{ end }} {{ else if eq (printf "%T" $suggestions_raw) "string" }} {{ $suggestion := strings.TrimSpace $suggestions_raw }} {{ if $suggestion }}{{ $suggestions = slice $suggestion }}{{ end }} {{ end }} {{ $stats_raw := index $content "stats" }} {{ $stats_iter := slice }} {{ if reflect.IsSlice $stats_raw }} {{ $stats_iter = $stats_raw }} {{ else if and $stats_raw (reflect.IsMap $stats_raw) }} {{ $stats_iter = slice $stats_raw }} {{ end }} {{ $stats := slice }} {{ if gt (len $stats_iter) 0 }} {{ range $stats_iter }} {{ if reflect.IsMap . }} {{ $value := "" }} {{ $label := "" }} {{ with index . "value" }}{{ $value = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "label" }}{{ $label = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if or $value $label }} {{ $stats = $stats | append (dict "value" $value "label" $label) }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* Background is now handled by parse_block_v3.html gradient_mesh system */}} {{/* Content only - wrapper and styling applied by framework */}}
{{/* Badge */}} {{ if $badge_text }}
{{ if $show_pulse }} {{ end }} {{ $badge_text | markdownify }}
{{ end }} {{/* Title - supports ==highlight== syntax for gradient text */}}

{{ $title | markdownify | emojify | safeHTML }}

{{/* Subtitle */}} {{ with $subtitle }}

{{ . | markdownify | emojify }}

{{ end }} {{/* Search Box - Integrates with Pagefind */}}
{{/* Quick search suggestions - Now trigger Pagefind with pre-filled query */}} {{ if gt (len $suggestions) 0 }}
Popular: {{ range $suggestions }} {{ end }}
{{ end }}
{{/* Stats */}} {{ if gt (len $stats) 0 }}
{{ range $stats }}
{{ index . "value" }}
{{ index . "label" }}
{{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/search-hero/manifest.json ================================================ { "name": "search-hero", "version": "1", "title": "Search Hero", "description": "Hero section with prominent search for knowledge bases", "categories": ["hero", "search"], "preview": "preview.svg" } ================================================ FILE: modules/blox/blox/shared/js/components/Icon.jsx ================================================ // biome-ignore lint/correctness/noUnusedImports: Classic Preact JSX runtime may require 'h' for JSX transform import {h} from "preact"; /** * Icon component * Renders an SVG icon from a raw SVG string passed from Hugo. * Decodes JSON-escaped sequences (\u003c) and HTML entities (<, ", "). * * SVG sizing strategy: * - By default, icons size to 1em (matching current font size) — works universally * for inline icons in buttons, text, lists, etc. * - If the caller provides explicit height via style attribute (e.g. style="height: 36px"), * the SVG fills that container with height:100%;width:auto instead. * - If the caller provides explicit w-/h- Tailwind classes, those take precedence. */ export const Icon = ({svg, attributes}) => { if (!svg) return null; // Clean the SVG string: decode HTML entities and TRIM whitespace let decoded = String(svg) .replace(/\\u003c/gi, "<") .replace(/\\u003e/gi, ">") .replace(/</gi, "<") .replace(/>/gi, ">") .replace(/"/gi, '"') .replace(/"/gi, '"') .replace(/\\u0026/gi, "&") .replace(/&/gi, "&") .trim(); const hasWrapper = /]/i.test(decoded); if (hasWrapper) { // Determine SVG sizing: if caller provides explicit height (via style attr), // use 100% to fill the container; otherwise default to 1em for self-sizing. const callerStyle = attributes?.style || ""; const hasExplicitHeight = /height\s*:/i.test(String(callerStyle)); const svgStyle = hasExplicitHeight ? "height:100%;width:auto" : "height:1em;width:auto"; decoded = decoded.replace(/^(; } const finalAttributes = { class: "inline-block w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", ...(attributes || {}), }; const attrs = Object.entries(finalAttributes) .map(([k, v]) => `${k}="${String(v)}"`) .join(" "); // eslint-disable-next-line lint/security/noDangerouslySetInnerHtml return ${decoded}`}} />; }; ================================================ FILE: modules/blox/blox/stats/README.md ================================================ # Stats Block Display impressive statistics with modern animations, icons, and engaging visual effects. Perfect for showcasing lab achievements, research metrics, and organizational highlights. ## Key Features - **🎬 Counter Animations**: Numbers count up on scroll with easing - **📊 Visual Icons**: Icons for each statistic enhance comprehension - **🎨 Multiple Layouts**: Cards, compact, or minimal display modes - **📱 Responsive Design**: Adapts beautifully to all screen sizes - **🌙 Dark Mode Ready**: Seamless theme switching - **⚡ Performance**: CSS-first animations with minimal JavaScript - **🎯 Intersection Observer**: Animations trigger when scrolled into view - **✨ Hover Effects**: Subtle interactions for engagement ## Layout Options ### Cards Layout (Default) Modern card-based design featuring: - Individual cards with shadows and hover effects - Icons with background circles - Gradient hover states - Staggered animation entry - Optimal for 2-4 statistics ### Compact Layout Single card with divided sections: - Unified background - Bordered divisions - Space-efficient - Good for 3-6 statistics ### Minimal Layout Clean, icon-centric design: - No backgrounds or borders - Focus on typography - Suitable for headers/footers - Works well with many statistics ## Usage Examples ### Research Lab Metrics (Enhanced) ```yaml sections: - block: stats content: title: Impact by the Numbers text: Driving scientific discovery through measurable achievements items: - statistic: "150+" description: Publications in top-tier journals sub_metric: Nature, Science, Cell, PNAS icon: hero/document-text - statistic: "25" description: Brilliant researchers and scientists sub_metric: From 12 countries worldwide icon: hero/user-group - statistic: "$12M" description: Active research funding sub_metric: NSF, NIH, DOE grants icon: hero/currency-dollar - statistic: "8" description: Breakthrough discoveries sub_metric: Patent applications filed icon: hero/light-bulb design: layout: cards css_class: "bg-gradient-to-b from-primary-50 to-white dark:from-primary-900/20 dark:to-gray-800" ``` ### University Department Stats ```yaml content: items: - statistic: "2,500" description: Students enrolled icon: hero/academic-cap - statistic: "95%" description: Graduation rate icon: hero/chart-bar - statistic: "40+" description: Countries represented icon: hero/globe-alt design: layout: compact ``` ### Startup Metrics ```yaml content: items: - statistic: "$2.5M" description: Funding raised icon: hero/banknotes - statistic: "10K+" description: Active users icon: hero/users - statistic: "98.5%" description: Uptime reliability icon: hero/chart-line design: layout: minimal ``` ## Animation Features ### Counter Animation - **Easing**: Smooth ease-out cubic function - **Duration**: 2 seconds for optimal viewing - **Trigger**: Intersection Observer when 50% visible - **Number Extraction**: Automatically extracts numbers from text ### Entrance Animation - **Staggered Entry**: Items animate in sequence - **Fade + Slide**: Combines opacity and translateY - **Delay Timing**: 150ms between items - **Threshold**: Triggers 100px before entering viewport ### Hover Effects - **Scale Transform**: Icons scale 110% on hover - **Color Transitions**: Text color changes - **Background Glow**: Subtle gradient overlay - **Shadow Enhancement**: Deeper shadows on hover ## Configuration Options ### Content Fields - **title**: Optional section heading - **text**: Optional description - **items**: Array of statistics - `statistic`: Number or value (required) - `description`: What the number represents (required) - `icon`: Icon identifier (optional) - `sub_metric`: Additional context (optional) ### Design Options - **layout**: Visual layout - `cards`: Individual cards (default) - `compact`: Single divided card - `minimal`: Clean typography focus ## Icon Guidelines ### Recommended Icons for Common Stats **Publications/Research:** - `hero/document-text` - Publications - `hero/beaker` - Research projects - `hero/light-bulb` - Discoveries/innovations - `hero/trophy` - Awards/recognition **People/Team:** - `hero/user-group` - Team members - `hero/academic-cap` - Students/graduates - `hero/users` - Community/users - `hero/heart` - Satisfaction ratings **Financial/Business:** - `hero/currency-dollar` - Funding/revenue - `hero/banknotes` - Investments - `hero/chart-bar` - Growth metrics - `hero/building-office` - Locations **Technology/Digital:** - `hero/cpu-chip` - Computing power - `hero/globe-alt` - Global reach - `hero/chart-line` - Performance metrics - `hero/server` - Infrastructure ## Performance Notes ### JavaScript Usage Minimal JavaScript for: - Intersection Observer (viewport detection) - Counter animation (number progression) - Modern browser APIs only ### CSS Animations - Hardware accelerated transforms - Optimized for 60fps - Respects `prefers-reduced-motion` - Fallbacks for older browsers ### Image Optimization - SVG icons preferred (scalable, fast) - WebP fallbacks for raster images - Lazy loading for non-critical images ## Best Practices 1. **Number Selection**: Choose impactful, verifiable metrics 2. **Descriptions**: Keep concise but descriptive 3. **Icons**: Match icons to metric meaning 4. **Sub-metrics**: Add credibility with specific details 5. **Layout**: Choose based on number of items (2-4: cards, 5+: compact) 6. **Consistency**: Use similar metric types (all percentages, all counts) 7. **Context**: Include timeframes where relevant ## Advanced Customization ### Custom Animations Override animation timing: ```css .stats-item { transition-duration: 1s; transition-delay: 0.2s; } ``` ### Custom Counters For complex number formatting: ```yaml statistic: "99.9%" # Will animate 0 → 99 statistic: "$2.5M" # Will animate 0 → 2.5 statistic: "1st" # Will animate 0 → 1 ``` ### Accessibility - Numbers are announced by screen readers - Animations respect motion preferences - High contrast maintained - Keyboard navigation supported The enhanced Stats block creates visual impact while maintaining professional credibility - essential for research lab websites targeting academic and industry audiences. ================================================ FILE: modules/blox/blox/stats/client.jsx ================================================ /** * Stats Block - Client-side Hydration * Uses the shared StatsBlock component for consistency */ import {render} from "preact"; import {StatsBlock} from "./component.jsx"; function renderStatsBlocks() { const statsBlocks = document.querySelectorAll('[data-block-type="stats"]'); statsBlocks.forEach((block) => { const propsData = block.dataset.props; if (propsData) { try { const props = JSON.parse(propsData); render(, block); console.debug(`✓ Stats block "${block.id}" rendered with Preact`); } catch (error) { console.error(`Failed to render Stats block "${block.id}":`, error); } } }); if (statsBlocks.length > 0) { console.debug(`✓ ${statsBlocks.length} Stats blocks initialized with Preact`); } } // Initialize immediately — script is already deferred renderStatsBlocks(); ================================================ FILE: modules/blox/blox/stats/component.jsx ================================================ /** * Stats Block Component - Single source of truth * Used for both SSR (via preact-wrapper) and SaaS live preview * * Layouts: cards | compact | minimal * Features: counter animation, per-item icons, stagger reveal */ import {useEffect, useRef} from "preact/hooks"; import {Icon} from "../../shared/components/Icon.jsx"; // Simple markdown renderer (shared with Hero) function renderText(text) { if (!text) return ""; return text .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1"); } // Extract numeric target from a statistic string like "10,000+" → 10000 function parseTarget(statistic) { if (!statistic) return 0; const raw = String(statistic).replace(/[^0-9.]/g, ""); const num = Number(raw); return Number.isNaN(num) ? 0 : num; } // Extract prefix, number, suffix from "~10,000+" → { prefix: "~", number: "10,000", suffix: "+" } function extractParts(text) { if (!text) return {prefix: "", numberPart: "", suffix: ""}; const parts = String(text).match(/([^0-9]*)([0-9][0-9,.]*)(.*)/); return { prefix: parts ? parts[1] : "", numberPart: parts ? parts[2] : "", suffix: parts ? parts[3] : "", }; } // Counter animation hook function useCounterAnimation(containerRef) { useEffect(() => { const container = containerRef.current; if (!container) return; const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; function animateCounters(el) { el.classList.add("animate"); const counters = el.querySelectorAll(".counter"); counters.forEach((counter) => { const target = parseTarget(counter.getAttribute("data-target")); if (target <= 0) return; const {prefix, numberPart, suffix} = extractParts(counter.textContent); const decimals = (numberPart.split(".")[1] || "").length; const formatter = new Intl.NumberFormat(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals, }); if (prefersReducedMotion) { counter.textContent = `${prefix}${formatter.format(target)}${suffix}`; return; } const duration = 2000; const start = Date.now(); function update() { const now = Date.now(); const progress = Math.min((now - start) / duration, 1); const easeOut = 1 - (1 - progress) ** 3; const current = target * easeOut; counter.textContent = `${prefix}${formatter.format(current)}${suffix}`; if (progress < 1) requestAnimationFrame(update); } requestAnimationFrame(update); }); } const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { animateCounters(entry.target); observer.unobserve(entry.target); } }); }, {threshold: 0.2, rootMargin: "0px 0px -10% 0px"}, ); // Observe each stat item const items = container.querySelectorAll(".stats-item"); items.forEach((item) => { const rect = item.getBoundingClientRect(); const vh = window.innerHeight; if (rect.top < vh * 0.9 && rect.bottom > 0) { animateCounters(item); } else { observer.observe(item); } }); return () => observer.disconnect(); }, []); } // Grid columns class based on item count function gridColsClass(count) { if (count <= 1) return "lg:grid-cols-1"; if (count === 2) return "lg:grid-cols-2"; if (count >= 4) return "lg:grid-cols-4"; return "lg:grid-cols-3"; } // ─── Stat Item (Cards) ─────────────────────────────────────────────── function StatCard({item, iconSvg}) { return (
{/* Hover gradient */}
{/* Icon */} {iconSvg && (
)} {/* Statistic */}

{/* Description */}

{/* Sub-metric */} {item.sub_metric &&

{item.sub_metric}

}
); } // ─── Stat Item (Compact) ───────────────────────────────────────────── function StatCompact({item, iconSvg}) { return (
{iconSvg && (
)}

); } // ─── Stat Item (Minimal) ───────────────────────────────────────────── function StatMinimal({item, iconSvg}) { return (
{iconSvg && (
)}

); } // ─── Main Stats Block ──────────────────────────────────────────────── export const StatsBlock = ({content, design, _id, icon_svgs}) => { const containerRef = useRef(null); useCounterAnimation(containerRef); const title = content?.title; const text = content?.text; const items = Array.isArray(content?.items) ? content.items : []; const layout = (design?.layout || "cards").toLowerCase(); const count = Math.max(1, Math.min(items.length, 4)); const lgCols = gridColsClass(count); const baseCols = count === 1 ? "grid-cols-1" : "grid-cols-2"; // icon_svgs is a dict keyed by icon name, provided by preact-wrapper const iconMap = icon_svgs || {}; return (
{/* Section Header */} {(title || text) && (
{title && (

)} {text &&

}

)} {/* Cards Layout */} {layout === "cards" && (
{items.map((item, idx) => ( ))}
)} {/* Compact Layout */} {layout === "compact" && (
{items.map((item, idx) => ( ))}
)} {/* Minimal Layout */} {layout === "minimal" && (
{items.map((item, idx) => ( ))}
)}
{/* Animation styles (scoped via container ref) */}
); }; ================================================ FILE: modules/blox/blox/stats/manifest.json ================================================ { "id": "stats", "name": "Stats", "version": "2.0.0", "license": "MIT", "category": "content", "tags": ["statistics", "numbers", "metrics", "achievements", "data", "showcase", "grid", "animated", "counters", "icons"], "description": "Showcase impressive statistics with modern animations, icons, and multiple layout options - enhanced for 2025/2026", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "statistics", "metrics", "achievements", "data", "numbers"] } ================================================ FILE: modules/blox/blox/team-showcase/README.md ================================================ # Team Showcase Block Display your team members with a beautiful, responsive grid layout featuring rich profiles, social links, and customizable grouping. ## Features - **Responsive Grid Layout**: Automatically adjusts from 1-4 columns based on screen size - **User Groups**: Organize team members by role (e.g., Principal Investigators, PhD Students) - **Rich Profiles**: Display avatar, name, role, bio, interests, and social links - **Customizable Display**: Toggle visibility of role, organization, interests, and social links - **Sorting**: Sort by last name, graduation year, weight, or any author field (no `Params.` prefix needed); per-group sorting supported - **Hover Effects**: Smooth image zoom and shadow effects on hover - **Call to Action**: Optional button to recruitment or team page ## Usage ```yaml sections: - block: team-showcase content: title: Meet Our Team subtitle: World-class researchers advancing science text: Our diverse team brings together expertise from multiple disciplines. user_groups: - Principal Investigators - Postdoctoral Researchers - PhD Students - name: Alumni # optional per-group sort override sort_by: graduation_year sort_ascending: false sort_by: 'graduation_year' # legacy 'Params.' prefix optional sort_ascending: false cta: text: Join Our Team url: /opportunities icon: user-plus design: show_role: true show_organizations: true show_interests: true max_interests: 3 # set 0 to hide interests even if provided align: center # or "left" to align header + CTA left max_columns: 4 # 2, 3, or 4 show_social: true show_empty_groups: false # show a placeholder when a group has no members # Section background color (CSS class) css_class: "bg-gray-50 dark:bg-gray-900" ``` ## Content Structure Team members are defined in `data/authors/.yaml`. All fields in the data file can be sorted on directly—no `Params.` prefix is required. ```yaml # data/authors/jane-doe.yaml name: display: Dr. Jane Doe role: Postdoctoral Researcher bio: Research interests include machine learning and computational biology. interests: - Machine Learning - Computational Biology - Data Science affiliations: - name: University of Excellence url: https://example.edu links: - icon: envelope url: 'mailto:jane@example.edu' - icon: twitter url: https://x.com/janedoe - icon: github url: https://github.com/janedoe user_groups: - Postdoctoral Researchers graduation_year: 2024 ``` ## Options ### Content Options - **title**: Main heading for the team section - **subtitle**: Optional subtitle - **text**: Optional description text (supports Markdown) - **user_groups**: Array of group names to display, or objects `{ name, sort_by?, sort_ascending? }` for per-group sorting - **sort_by**: Field to sort by (default: "name_family", falling back to the last word of `title`). Use plain field names from `data/authors`—the legacy `Params.` prefix is optional for backwards compatibility. Recommended: `name_family` (last name), `graduation_year` (alumni), `weight` (manual order). - **sort_ascending**: Sort direction (default: true) - **cta**: Optional call-to-action button with text, url, and icon ### Design Options - **show_role**: Display team member roles (default: true) - **show_organizations**: Display affiliated organizations (default: true) - **show_interests**: Display research interests (default: false) - **max_interests**: Maximum number of interests to show (default: 3; 0 hides interests) - **show_social**: Display social media links (default: true) - **align**: Align header and CTA (`center` or `left`, default `center`) - **max_columns**: Limit grid columns on wide screens (2, 3, or 4; default 4) - **show_empty_groups**: If true, render an empty-state message for groups with no members ## Recipes - **Lab alumni list**: `user_groups: ['Alumni']`, `sort_by: graduation_year`, `sort_ascending: false`, set `graduation_year` in each author file. - **Startup leadership-first**: set `weight` on leadership (e.g., 1–10), `sort_by: weight`, `sort_ascending: true`, leave others empty or higher. - **Classic last-name sort**: ensure `name.family` is set; leave defaults or set `sort_by: name_family`. - **Hide interests but keep data**: `show_interests: true`, `max_interests: 0`. - **Left-aligned hero style**: `design.align: left` (header + CTA). - **Per-group sorting**: mix strings and objects in `user_groups`, e.g. `- name: Alumni; sort_by: graduation_year; sort_ascending: false`. ## Best Practices - Keep `data/authors/.yaml` tidy: set `name.display`, `name.family`, `role`, short `bio`, `affiliations` (first shown), `links` with icons (`github`, `linkedin`, `orcid`, `google-scholar`), and `user_groups`. - Use square WebP avatars in `assets/media/authors/.*`, ~400×400px, optimized (<200 KB). Names center-cropped. - Prefer high-signal interests (3 or fewer); longer lists belong on the profile page. - For credibility, show organizations (default on) and keep roles concise. - Review people data each semester/quarter to keep roles and photos fresh. - Use valid icon names for `links.icon` (e.g., `github`, `linkedin`, `orcid`, `google-scholar`, `twitter`) to avoid broken social icons. ## Styling The block uses Tailwind CSS classes and supports: - Dark mode - Custom background colors via `css_class` - Responsive breakpoints - Smooth hover transitions ## Tips 1. **Optimize Images**: Use square avatar images (minimum 400x400px) for best results 2. **User Groups**: Create logical groupings that reflect your organization structure 3. **Bio Length**: Keep bios concise (2-3 lines) for the card view 4. **Social Links**: Include relevant professional networks (ORCID, Google Scholar, GitHub) ================================================ FILE: modules/blox/blox/team-showcase/block.html ================================================ {{/* Hugo Blox: Team Showcase */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $show_social := partial "functions/coerce_bool" (dict "value" (index $design "show_social") "default" true) }} {{ $show_interests := partial "functions/coerce_bool" (dict "value" (index $design "show_interests") "default" false) }} {{ $show_role := partial "functions/coerce_bool" (dict "value" (index $design "show_role") "default" true) }} {{ $show_organizations := partial "functions/coerce_bool" (dict "value" (index $design "show_organizations") "default" true) }} {{ $show_empty_groups := partial "functions/coerce_bool" (dict "value" (index $design "show_empty_groups") "default" false) }} {{ $max_interests_int := partial "functions/coerce_int" (dict "value" (index $design "max_interests") "default" 3 "min" 0) }} {{ $max_columns_int := partial "functions/coerce_int" (dict "value" (index $design "max_columns") "default" 4 "min" 2 "max" 4) }} {{ $align := "center" }} {{ $align_raw := index $design "align" }} {{ if eq (printf "%T" $align_raw) "string" }} {{ $align_candidate := lower (strings.TrimSpace $align_raw) }} {{ if in (slice "center" "left") $align_candidate }} {{ $align = $align_candidate }} {{ end }} {{ end }} {{ $sort_field := "name_family" }} {{ $sort_field_raw := index $content "sort_by" }} {{ if eq (printf "%T" $sort_field_raw) "string" }} {{ $sort_field_raw = strings.TrimSpace $sort_field_raw }} {{ if ne $sort_field_raw "" }} {{ $sort_field = $sort_field_raw }} {{ end }} {{ end }} {{ $sort_asc := partial "functions/coerce_bool" (dict "value" (index $content "sort_ascending") "default" true) }} {{ $sort_field_lc := lower $sort_field }} {{ if hasPrefix $sort_field_lc "params." }} {{/* Backwards compatibility with Params.* used when authors were pages */}} {{ $sort_field = substr $sort_field 7 }} {{ $sort_field_lc = lower $sort_field }} {{ end }} {{ $title := "" }} {{ with index $content "title" }}{{ $title = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $subtitle := "" }} {{ with index $content "subtitle" }}{{ $subtitle = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $text := "" }} {{ with index $content "text" }}{{ $text = printf "%v" . | emojify | $page.RenderString }}{{ end }} {{ $alignClass := cond (eq $align "left") "items-start text-left" "items-center text-center" }} {{ $headerContainerClass := cond (eq $align "left") "flex flex-col gap-4 items-start text-left w-full max-w-5xl" "flex flex-col gap-3 items-center text-center max-w-prose mx-auto justify-center px-6" }} {{ $ctaAlignClass := cond (eq $align "left") "text-left" "text-center" }} {{ $columnsClasses := dict "2" "grid grid-cols-1 gap-8 sm:grid-cols-2" "3" "grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3" "4" "grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4" }} {{ $max_columns_key := printf "%d" $max_columns_int }} {{ $gridClass := index $columnsClasses $max_columns_key | default "grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4" }}
{{/* Section Header */}}
{{ with $title }}
{{ . }}
{{ end }} {{ with $subtitle }}

{{ . }}

{{ end }} {{ with $text }}
{{ . }}
{{ end }}
{{/* Build profiles from data/authors */}} {{ $allProfiles := slice }} {{ $authors := partialCached "functions/get_authors_data" $page site.Language.Lang }} {{ range $slug, $_ := $authors }} {{ $profile := partial "functions/get_author_profile" (dict "slug" $slug) }} {{ $profileData := index $authors $slug }} {{ $allProfiles = $allProfiles | append (dict "profile" $profile "profileData" $profileData) }} {{ end }} {{ $groups_raw := index $content "user_groups" }} {{ $groups := slice }} {{ if reflect.IsSlice $groups_raw }} {{ $groups = $groups_raw }} {{ else if eq (printf "%T" $groups_raw) "string" }} {{ $groups = slice $groups_raw }} {{ else if and $groups_raw (reflect.IsMap $groups_raw) }} {{ $groups = slice $groups_raw }} {{ end }} {{ if gt (len $groups) 0 }} {{ range $i, $groupItem := $groups }} {{ $groupName := "" }} {{ $groupSortField := $sort_field }} {{ $groupSortAsc := $sort_asc }} {{ $groupSortFieldLc := "" }} {{ $itemIsMap := reflect.IsMap $groupItem }} {{ if $itemIsMap }} {{ $groupNameRaw := index $groupItem "name" | default (index $groupItem "title") }} {{ if ne $groupNameRaw nil }} {{ $groupName = printf "%v" $groupNameRaw }} {{ end }} {{ $groupSortFieldRaw := index $groupItem "sort_by" }} {{ if eq (printf "%T" $groupSortFieldRaw) "string" }} {{ $groupSortFieldRaw = strings.TrimSpace $groupSortFieldRaw }} {{ if ne $groupSortFieldRaw "" }} {{ $groupSortField = $groupSortFieldRaw }} {{ end }} {{ end }} {{ $groupSortAsc = partial "functions/coerce_bool" (dict "value" (index $groupItem "sort_ascending") "default" $groupSortAsc) }} {{ else }} {{ $groupName = printf "%v" $groupItem }} {{ end }} {{ $groupName = strings.TrimSpace $groupName }} {{ if eq (trim $groupName " ") "" }} {{/* Skip groups with empty names to avoid matching everything */}} {{ continue }} {{ end }} {{ $groupSortFieldLc = lower $groupSortField }} {{ if hasPrefix $groupSortFieldLc "params." }} {{ $groupSortField = substr $groupSortField 7 }} {{ $groupSortFieldLc = lower $groupSortField }} {{ end }} {{ $groupIsNumeric := or (eq $groupSortFieldLc "weight") (eq $groupSortFieldLc "graduation_year") }} {{ $groupOrder := cond $groupSortAsc "asc" "desc" }} {{ $groupProfiles := slice }} {{ range $allProfiles }} {{ $profile := .profile }} {{ $u := slice }} {{ $uRaw := $profile.user_groups }} {{ if reflect.IsSlice $uRaw }} {{ range $uRaw }} {{ $u = $u | append (printf "%v" .) }} {{ end }} {{ else if eq (printf "%T" $uRaw) "string" }} {{ $trimmedGroup := strings.TrimSpace $uRaw }} {{ if ne $trimmedGroup "" }} {{ $u = slice $trimmedGroup }} {{ end }} {{ end }} {{ if gt (len (intersect $u (slice (printf "%v" $groupName)))) 0 }} {{ $profileData := .profileData }} {{ $family := $profile.name_family_pref | default $profile.name_family | default (delimit (last 1 (split $profile.title " ")) "") | default $profile.title }} {{ $familyLower := lower $family }} {{ $raw := index $profile $groupSortField | default (index $profileData $groupSortField) }} {{ $rawType := printf "%T" $raw }} {{ $isNumeric := $groupIsNumeric }} {{ $primary := "" }} {{ if or (eq $groupSortFieldLc "name.family") (eq $groupSortFieldLc "family") (eq $groupSortFieldLc "last_name") (eq $groupSortFieldLc "name_family") (eq $groupSortFieldLc "family_name") }} {{ $primary = $familyLower }} {{ else if $isNumeric }} {{ $missingSentinel := cond $groupSortAsc 999999 -999999 }} {{ $primary = $missingSentinel }} {{ if or (eq $rawType "int") (eq $rawType "int64") (eq $rawType "float64") (eq $rawType "float32") (eq $rawType "uint") (eq $rawType "uint64") }} {{ $primary = int $raw }} {{ else if and (eq $rawType "string") (gt (len (findRE "^[0-9]+$" $raw)) 0) }} {{ $primary = int $raw }} {{ end }} {{ else if ne $raw nil }} {{ $primary = lower (printf "%v" $raw) }} {{ else }} {{ $primary = lower $profile.title }} {{ end }} {{ $sortKey := "" }} {{ if $isNumeric }} {{ $missingSentinel := cond $groupSortAsc 999999 -999999 }} {{ $num := $primary | default $missingSentinel }} {{ $sortKey = printf "%010d|%s" $num $familyLower }} {{ else }} {{ $sortKey = printf "%s|%s" $primary $familyLower }} {{ end }} {{ $groupProfiles = $groupProfiles | append (dict "profile" $profile "sort_val" $sortKey) }} {{ end }} {{ end }} {{ $groupProfiles = sort $groupProfiles "sort_val" $groupOrder }} {{ $hasGroupContent := or (gt (len $groupProfiles) 0) $show_empty_groups }} {{ if and $hasGroupContent (gt (len $groups) 1) }}

{{ $groupName | markdownify }}

{{ end }} {{ if $hasGroupContent }}
{{ if eq (len $groupProfiles) 0 }} {{ if $show_empty_groups }}
{{ i18n "no_entries" | default "No entries yet." }}
{{ end }} {{ end }} {{ range $groupProfile := $groupProfiles }} {{ $profile := $groupProfile.profile }} {{ $avatar := $profile.avatar }} {{ $link := printf "/authors/%s/" $profile.slug }} {{ $nameSource := $profile.name_given | default $profile.title | default "?" }} {{ $initial := cond (gt (len $nameSource) 0) (upper (substr $nameSource 0 1)) "?" }}
{{ if $avatar }} {{ $image := $avatar.Fit "600x600 Center q90" }} {{ $profile.title }} {{ else }}
{{ $initial }}
{{ end }}

{{ $profile.title }}

{{ $affiliations_raw := $profile.affiliations }} {{ $affiliations := slice }} {{ if reflect.IsSlice $affiliations_raw }} {{ $affiliations = $affiliations_raw }} {{ else if eq (printf "%T" $affiliations_raw) "string" }} {{ $affiliations = slice $affiliations_raw }} {{ end }} {{ $first_affiliation := "" }} {{ if gt (len $affiliations) 0 }} {{ $aff := index $affiliations 0 }} {{ if reflect.IsMap $aff }} {{ $affNameRaw := index $aff "name" | default (index $aff "title") }} {{ if ne $affNameRaw nil }} {{ $first_affiliation = printf "%v" $affNameRaw }} {{ end }} {{ else if eq (printf "%T" $aff) "string" }} {{ $first_affiliation = $aff }} {{ end }} {{ $first_affiliation = strings.TrimSpace $first_affiliation }} {{ end }} {{ if $show_role }}
{{ $roleText := "" }} {{ with $profile.role }} {{ if eq (printf "%T" .) "string" }} {{ $roleText = . }} {{ end }} {{ end }} {{ if and (not $roleText) $first_affiliation }} {{ $roleText = $first_affiliation }} {{ end }} {{ with $roleText }}

{{ . }}

{{ end }} {{ if and $show_organizations $first_affiliation }}

{{ $first_affiliation }}

{{ end }}
{{ end }} {{ $bio := "" }} {{ with $profile.bio }}{{ $bio = printf "%v" . }}{{ end }} {{ with $bio }}

{{ . }}

{{ end }} {{ $interests_raw := $profile.interests }} {{ $interests := slice }} {{ if reflect.IsSlice $interests_raw }} {{ $interests = $interests_raw }} {{ else if eq (printf "%T" $interests_raw) "string" }} {{ $interests = slice $interests_raw }} {{ end }} {{ if and $show_interests (gt (len $interests) 0) }}
{{ if gt $max_interests_int 0 }} {{ range first $max_interests_int $interests }} {{ printf "%v" . }} {{ end }} {{ end }}
{{ end }} {{ $links_raw := $profile.links }} {{ $links := slice }} {{ if reflect.IsSlice $links_raw }} {{ $links = $links_raw }} {{ else if eq (printf "%T" $links_raw) "string" }} {{ $links = slice $links_raw }} {{ end }} {{ if and $show_social (gt (len $links) 0) }}
{{ range $links }} {{ $linkUrl := "" }} {{ $iconName := "hero/link" }} {{ $linkLabel := "" }} {{ if reflect.IsMap . }} {{ $urlRaw := index . "url" | default (index . "link") }} {{ if eq (printf "%T" $urlRaw) "string" }} {{ $linkUrl = $urlRaw }} {{ end }} {{ $iconRaw := index . "icon" }} {{ if eq (printf "%T" $iconRaw) "string" }} {{ $iconName = $iconRaw }} {{ end }} {{ $labelRaw := index . "label" }} {{ if eq (printf "%T" $labelRaw) "string" }} {{ $linkLabel = $labelRaw }} {{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $linkUrl = . }} {{ end }} {{ $linkUrl = strings.TrimSpace $linkUrl }} {{ if $linkUrl }} {{ $scheme := (urls.Parse $linkUrl).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $linkUrl "#") }} {{ $linkUrl = $linkUrl | relLangURL }} {{ end }} {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-5 h-5\"") }} {{ end }} {{ end }}
{{ end }}
{{ end }}
{{ end }} {{ end }} {{ else }} {{ $isNumeric := or (eq $sort_field_lc "weight") (eq $sort_field_lc "graduation_year") }} {{ $order := cond $sort_asc "asc" "desc" }} {{ $sorted := slice }} {{ range $allProfiles }} {{ $profile := .profile }} {{ $profileData := .profileData }} {{ $family := $profile.name_family_pref | default $profile.name_family | default (delimit (last 1 (split $profile.title " ")) "") | default $profile.title }} {{ $familyLower := lower $family }} {{ $raw := index $profile $sort_field | default (index $profileData $sort_field) }} {{ $rawType := printf "%T" $raw }} {{ $primary := "" }} {{ if or (eq $sort_field_lc "name.family") (eq $sort_field_lc "family") (eq $sort_field_lc "last_name") (eq $sort_field_lc "name_family") (eq $sort_field_lc "family_name") }} {{ $primary = $familyLower }} {{ else if $isNumeric }} {{ $missingSentinel := cond $sort_asc 999999 -999999 }} {{ $primary = $missingSentinel }} {{ if or (eq $rawType "int") (eq $rawType "int64") (eq $rawType "float64") (eq $rawType "float32") (eq $rawType "uint") (eq $rawType "uint64") }} {{ $primary = int $raw }} {{ else if and (eq $rawType "string") (gt (len (findRE "^[0-9]+$" $raw)) 0) }} {{ $primary = int $raw }} {{ end }} {{ else if ne $raw nil }} {{ $primary = lower (printf "%v" $raw) }} {{ else }} {{ $primary = lower $profile.title }} {{ end }} {{ $sortKey := "" }} {{ if $isNumeric }} {{ $missingSentinel := cond $sort_asc 999999 -999999 }} {{ $num := $primary | default $missingSentinel }} {{ $sortKey = printf "%010d|%s" $num $familyLower }} {{ else }} {{ $sortKey = printf "%s|%s" $primary $familyLower }} {{ end }} {{ $sorted = $sorted | append (dict "profile" $profile "sort_val" $sortKey) }} {{ end }} {{ $sorted = sort $sorted "sort_val" $order }}
{{ range $sortedProfile := $sorted }} {{ $profile := $sortedProfile.profile }} {{ $avatar := $profile.avatar }} {{ $link := printf "/authors/%s/" $profile.slug }} {{ $nameSource := $profile.name_given | default $profile.title | default "?" }} {{ $initial := cond (gt (len $nameSource) 0) (upper (substr $nameSource 0 1)) "?" }}
{{ if $avatar }} {{ $image := $avatar.Fit "600x600 Center q90" }} {{ $profile.title }} {{ else }}
{{ $initial }}
{{ end }}

{{ $profile.title }}

{{ $affiliations_raw := $profile.affiliations }} {{ $affiliations := slice }} {{ if reflect.IsSlice $affiliations_raw }} {{ $affiliations = $affiliations_raw }} {{ else if eq (printf "%T" $affiliations_raw) "string" }} {{ $affiliations = slice $affiliations_raw }} {{ end }} {{ $first_affiliation := "" }} {{ if gt (len $affiliations) 0 }} {{ $aff := index $affiliations 0 }} {{ if reflect.IsMap $aff }} {{ $affNameRaw := index $aff "name" | default (index $aff "title") }} {{ if ne $affNameRaw nil }} {{ $first_affiliation = printf "%v" $affNameRaw }} {{ end }} {{ else if eq (printf "%T" $aff) "string" }} {{ $first_affiliation = $aff }} {{ end }} {{ $first_affiliation = strings.TrimSpace $first_affiliation }} {{ end }} {{ if $show_role }}
{{ $roleText := "" }} {{ with $profile.role }} {{ if eq (printf "%T" .) "string" }} {{ $roleText = . }} {{ end }} {{ end }} {{ if and (not $roleText) $first_affiliation }} {{ $roleText = $first_affiliation }} {{ end }} {{ with $roleText }}

{{ . }}

{{ end }} {{ if and $show_organizations $first_affiliation }}

{{ $first_affiliation }}

{{ end }}
{{ end }} {{ $bio := "" }} {{ with $profile.bio }}{{ $bio = printf "%v" . }}{{ end }} {{ with $bio }}

{{ . }}

{{ end }} {{ $interests_raw := $profile.interests }} {{ $interests := slice }} {{ if reflect.IsSlice $interests_raw }} {{ $interests = $interests_raw }} {{ else if eq (printf "%T" $interests_raw) "string" }} {{ $interests = slice $interests_raw }} {{ end }} {{ if and $show_interests (gt (len $interests) 0) }}
{{ if gt $max_interests_int 0 }} {{ range first $max_interests_int $interests }} {{ printf "%v" . }} {{ end }} {{ end }}
{{ end }} {{ $links_raw := $profile.links }} {{ $links := slice }} {{ if reflect.IsSlice $links_raw }} {{ $links = $links_raw }} {{ else if eq (printf "%T" $links_raw) "string" }} {{ $links = slice $links_raw }} {{ end }} {{ if and $show_social (gt (len $links) 0) }}
{{ range $links }} {{ $linkUrl := "" }} {{ $iconName := "hero/link" }} {{ $linkLabel := "" }} {{ if reflect.IsMap . }} {{ $urlRaw := index . "url" | default (index . "link") }} {{ if eq (printf "%T" $urlRaw) "string" }} {{ $linkUrl = $urlRaw }} {{ end }} {{ $iconRaw := index . "icon" }} {{ if eq (printf "%T" $iconRaw) "string" }} {{ $iconName = $iconRaw }} {{ end }} {{ $labelRaw := index . "label" }} {{ if eq (printf "%T" $labelRaw) "string" }} {{ $linkLabel = $labelRaw }} {{ end }} {{ else if eq (printf "%T" .) "string" }} {{ $linkUrl = . }} {{ end }} {{ $linkUrl = strings.TrimSpace $linkUrl }} {{ if $linkUrl }} {{ $scheme := (urls.Parse $linkUrl).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $linkUrl "#") }} {{ $linkUrl = $linkUrl | relLangURL }} {{ end }} {{ if eq (path.Ext $linkUrl) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" $iconName "attributes" "class=\"w-5 h-5\"") }} {{ end }} {{ end }}
{{ end }}
{{ end }}
{{ end }} {{/* Call to Action */}} {{ $cta_raw := index $content "cta" }} {{ if and $cta_raw (reflect.IsMap $cta_raw) }} {{ $cta_text := "" }} {{ $cta_url := "" }} {{ $cta_icon := "" }} {{ with index $cta_raw "text" }}{{ $cta_text = printf "%v" . }}{{ end }} {{ with index $cta_raw "url" }}{{ $cta_url = printf "%v" . }}{{ end }} {{ with index $cta_raw "icon" }} {{ if eq (printf "%T" .) "string" }} {{ $cta_icon = . }} {{ end }} {{ end }} {{ $cta_text = strings.TrimSpace $cta_text }} {{ $cta_url = strings.TrimSpace $cta_url }} {{ if and $cta_text $cta_url }} {{ $cta_link := $cta_url }} {{ $scheme := (urls.Parse $cta_link).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ if not (hasPrefix $cta_link "#") }} {{ $cta_link = $cta_link | relLangURL }} {{ end }} {{ if eq (path.Ext $cta_link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }} {{ end }}
================================================ FILE: modules/blox/blox/team-showcase/manifest.json ================================================ { "id": "team-showcase", "name": "Team Showcase", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["team", "people", "members", "staff", "lab", "research", "organization"], "description": "Display team members with customizable grouping, filtering, and rich profiles", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "static-site", "team", "people", "organization", "research-lab"] } ================================================ FILE: modules/blox/blox/tech-stack/README.md ================================================ # Tech Stack Block A visual grid display of technologies and skills organized by category, with icon support and optional proficiency indicators. ## Features - **Category Organization**: Group technologies by type (Languages, Frontend, Backend, etc.) - **Icon Support**: DevIcon, brand icons, or Heroicons integration - **Proficiency Levels**: Optional skill level indicators (expert, advanced, intermediate, beginner) - **Glass Morphism**: Modern card design with hover effects - **Responsive Grid**: Adapts from 2 to 6 columns based on screen size - **Multiple Styles**: Grid or flat list layout options ## Usage ```yaml - block: tech-stack id: skills content: title: "Tech Stack" subtitle: "Technologies I use to build things" categories: - name: Languages items: - name: TypeScript icon: devicon/typescript level: expert - name: Python icon: devicon/python level: advanced - name: Go icon: devicon/go level: intermediate - name: Frontend items: - name: React icon: devicon/react - name: Next.js icon: devicon/nextjs - name: Tailwind CSS icon: devicon/tailwindcss - name: Backend items: - name: Node.js icon: devicon/nodejs - name: PostgreSQL icon: devicon/postgresql - name: Redis icon: devicon/redis - name: DevOps items: - name: Docker icon: devicon/docker - name: AWS icon: devicon/amazonwebservices - name: GitHub Actions icon: brands/github design: style: grid show_levels: true ``` ## Parameters ### Content | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `title` | string | - | Section title | | `subtitle` | string | - | Section subtitle | | `categories` | array | required | Array of category objects | | `categories[].name` | string | - | Category heading | | `categories[].items` | array | required | Technologies in category | | `categories[].items[].name` | string | required | Technology name | | `categories[].items[].icon` | string | - | Icon identifier | | `categories[].items[].level` | string | - | Proficiency level | ### Design | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `style` | string | `grid` | Display style (`grid` or `list`) | | `show_levels` | boolean | `false` | Show proficiency indicators | ## Icon Support The block supports multiple icon sources: - **DevIcon**: `devicon/react`, `devicon/typescript`, `devicon/nodejs` - **Brand Icons**: `brands/github`, `brands/linkedin` - **Heroicons**: `code-bracket`, `server`, `cloud` ## Proficiency Levels | Level | Color | Bar Width | |-------|-------|-----------| | `expert` | Emerald | 100% | | `advanced` | Primary | 75% | | `intermediate` | Amber | 50% | | `beginner` | Gray | 25% | ## Styling The block uses glass morphism styling with: - Semi-transparent backgrounds - Backdrop blur effects - Subtle borders that glow on hover - Gradient hover effects ================================================ FILE: modules/blox/blox/tech-stack/block.html ================================================ {{/* Hugo Blox: Tech Stack */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialise */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $content := $block.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $block.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{/* Enable animations */}} {{ $animations := partial "functions/coerce_bool" (dict "value" (index $design "animations") "default" true) }} {{ if $animations }} {{ $page.Store.Set "has_animations" true }} {{ $page.Store.Set "has_alpine" true }} {{ end }} {{/* Style */}} {{ $style := "grid" }} {{ $style_raw := index $design "style" }} {{ if eq (printf "%T" $style_raw) "string" }} {{ $style_candidate := lower (strings.TrimSpace $style_raw) }} {{ if in (slice "grid" "list") $style_candidate }} {{ $style = $style_candidate }} {{ end }} {{ end }} {{ $show_levels := partial "functions/coerce_bool" (dict "value" (index $design "show_levels") "default" false) }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }}{{ $title = strings.TrimSpace (printf "%v" $title_raw) }}{{ end }} {{ $subtitle := "" }} {{ $subtitle_raw := index $content "subtitle" }} {{ if $subtitle_raw }}{{ $subtitle = strings.TrimSpace (printf "%v" $subtitle_raw) }}{{ end }} {{ $categories_raw := index $content "categories" }} {{ $categories_iter := slice }} {{ if reflect.IsSlice $categories_raw }} {{ $categories_iter = $categories_raw }} {{ else if and $categories_raw (reflect.IsMap $categories_raw) }} {{ $categories_iter = slice $categories_raw }} {{ end }} {{ $categories := slice }} {{ if gt (len $categories_iter) 0 }} {{ range $categories_iter }} {{ if reflect.IsMap . }} {{ $cat_name := "" }} {{ with index . "name" }}{{ $cat_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $items_raw := index . "items" }} {{ $items_iter := slice }} {{ if reflect.IsSlice $items_raw }} {{ $items_iter = $items_raw }} {{ else if and $items_raw (reflect.IsMap $items_raw) }} {{ $items_iter = slice $items_raw }} {{ end }} {{ $items := slice }} {{ if gt (len $items_iter) 0 }} {{ range $items_iter }} {{ if reflect.IsMap . }} {{ $item_name := "" }} {{ $item_icon := "" }} {{ $item_level := "" }} {{ with index . "name" }}{{ $item_name = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "icon" }}{{ $item_icon = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "level" }}{{ $item_level = lower (strings.TrimSpace (printf "%v" .)) }}{{ end }} {{ if $item_name }} {{ $items = $items | append (dict "name" $item_name "icon" $item_icon "level" $item_level) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if gt (len $items) 0 }} {{ $categories = $categories | append (dict "name" $cat_name "items" $items) }} {{ end }} {{ end }} {{ end }} {{ end }}
{{/* Header */}}
{{ with $title }}

{{ . | emojify | $page.RenderString }}

{{ end }} {{ with $subtitle }}

{{ . | emojify | $page.RenderString }}

{{ end }}
{{/* Categories */}} {{ if ne $style "list" }}
{{ range $categories }}
{{/* Category Title */}} {{ with index . "name" }}

{{ . }}

{{ end }} {{/* Tech Items - Centered flex layout */}}
{{ range $idx, $item := (index . "items") }} {{ $level := index $item "level" | default "" }} {{ $level_width := "0%" }} {{ $level_color := "bg-gray-500" }} {{ if eq $level "expert" }} {{ $level_width = "100%" }} {{ $level_color = "bg-emerald-500" }} {{ else if eq $level "advanced" }} {{ $level_width = "75%" }} {{ $level_color = "bg-primary-500" }} {{ else if eq $level "intermediate" }} {{ $level_width = "50%" }} {{ $level_color = "bg-amber-500" }} {{ else if eq $level "beginner" }} {{ $level_width = "25%" }} {{ $level_color = "bg-gray-400" }} {{ end }}
{{/* Icon */}}
{{ with index $item "icon" }} {{/* Add dark-icon class for icons that need inversion in dark mode */}} {{ $dark_icons := slice "express" "vercel" "github" "nextjs" }} {{ $icon_name := . }} {{ $needs_invert := false }} {{ range $dark_icons }} {{ if in $icon_name . }}{{ $needs_invert = true }}{{ end }} {{ end }}
{{ partial "functions/get_icon" (dict "name" . "attributes" "class=\"w-10 h-10\"") }}
{{ end }} {{/* Name */}} {{ index $item "name" }} {{/* Level Indicator */}} {{ if and $show_levels $level }}
{{ $level }}
{{ end }}
{{/* Hover glow effect */}}
{{ end }}
{{ end }}
{{ end }} {{/* Simple flat list style alternative */}} {{ if eq $style "list" }}
{{ range $categories }} {{ range $i, $tech := (index . "items") }}
{{ with index $tech "icon" }} {{ partial "functions/get_icon" (dict "name" . "attributes" "class=\"w-5 h-5\"") }} {{ end }} {{ index $tech "name" }}
{{ end }} {{ end }}
{{ end }}
================================================ FILE: modules/blox/blox/tech-stack/manifest.json ================================================ { "id": "tech-stack", "name": "Tech Stack", "version": "1.0.0", "license": "MIT", "category": "content", "tags": ["tech-stack", "skills", "technologies", "icons", "developer", "showcase"], "description": "Display technologies and skills with icons organized by category, featuring hover effects and optional proficiency indicators", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "tech-stack", "skills", "technologies", "developer", "portfolio"] } ================================================ FILE: modules/blox/blox/testimonials/README.md ================================================ # Testimonials Block **Transform customer voices into powerful social proof** Build unshakeable trust and credibility with the Testimonials block - a sophisticated component that presents authentic customer feedback in a professional, visually appealing format that converts skeptical visitors into confident buyers. ## ✨ Key Features - **Professional Quote Styling**: Beautiful quotation marks and elegant typography - **Customer Photos**: High-quality avatar display with optimized 2x retina images - **Complete Attribution**: Customer names and roles for authentic credibility - **Responsive Layout**: Perfect presentation across all device sizes - **Multiple Testimonials**: Stack multiple testimonials in a clean, organized format - **Markdown Support**: Rich text formatting for testimonial content - **Lazy Loading**: Optimized image loading for better performance ## 🎯 Perfect For - **SaaS Platforms**: Showcase customer success stories and satisfaction - **Service Providers**: Display client feedback and project results - **E-commerce**: Build buyer confidence with authentic product reviews - **Consultants**: Demonstrate expertise through client testimonials - **Agencies**: Highlight successful partnerships and outcomes - **Course Creators**: Share student success stories and transformations ## 🚀 Why Choose Testimonials Block? **Social Proof Power**: Authentic customer voices carry more weight than any marketing message **Visual Credibility**: Photos and names make testimonials feel genuine and trustworthy **Professional Presentation**: Elegant design elevates customer feedback to marketing gold **Conversion Catalyst**: Well-placed testimonials can dramatically increase conversion rates ## 📊 Trust Building Elements - **Visual Quote Marks**: Classic quotation styling that signals authentic feedback - **Human Connection**: Real photos create emotional connection with potential customers - **Authority Indicators**: Customer roles and companies add context and credibility - **Clean Layout**: Professional presentation that feels premium and trustworthy ## 💡 Psychological Impact - **Bandwagon Effect**: Seeing others' success motivates similar action - **Risk Reduction**: Real customer experiences reduce perceived purchase risk - **Emotional Resonance**: Stories connect with visitors on an emotional level - **Credibility Transfer**: Customer authority transfers to your brand ## 🎨 Best Practices - Use high-quality, professional customer photos - Include specific details and outcomes in testimonials - Add customer roles and companies for context - Keep quotes authentic and conversational - Mix different types of customers and use cases - Update testimonials regularly to maintain freshness Transform your happiest customers into your best marketing team with testimonials that build trust, reduce friction, and drive conversions. ================================================ FILE: modules/blox/blox/testimonials/client.jsx ================================================ /** * Testimonials Block - Client-side Hydration */ import {render} from "preact"; import {TestimonialsBlock} from "./component.jsx"; function renderTestimonialsBlocks() { const blocks = document.querySelectorAll('[data-block-type="testimonials"]'); blocks.forEach((block) => { const propsData = block.dataset.props; if (propsData) { try { const props = JSON.parse(propsData); render(, block); console.debug(`✓ Testimonials block "${block.id}" rendered with Preact`); } catch (error) { console.error(`Failed to render Testimonials block "${block.id}":`, error); } } }); } renderTestimonialsBlocks(); ================================================ FILE: modules/blox/blox/testimonials/component.jsx ================================================ /** * Testimonials Block Component - Single source of truth * Quote cards with avatar, name, and role * Avatars are pre-processed by Hugo's image pipeline (passed as item_images prop) */ // Quote mark SVG (inline for zero dependencies) const QuoteSvg = () => ( ); // Simple markdown renderer function renderText(text) { if (!text) return ""; return String(text) .replace(/\*\*(.*?)\*\*/g, "$1") .replace(/\*(.*?)\*/g, "$1") .replace(/`(.*?)`/g, "$1"); } function TestimonialItem({item, avatarUrl, isLast}) { return (

{/* Avatar */} {avatarUrl ? ( {item.name ) : (
)}
{item.name &&
{item.name}
} {item.role &&
{item.role}
}
); } export const TestimonialsBlock = ({content, _design, _id, item_images}) => { const title = content?.title; const text = content?.text; const items = Array.isArray(content?.items) ? content.items : []; const imageMap = item_images || {}; return (
{/* Section Header */} {title && (

{text &&

}

)} {/* Testimonial Items */} {items.map((item, idx) => ( ))}
); }; ================================================ FILE: modules/blox/blox/testimonials/manifest.json ================================================ { "id": "testimonials", "name": "Testimonials", "version": "1.0.0", "license": "MIT", "category": "marketing", "tags": ["testimonials", "reviews", "social-proof", "quotes", "customers", "trust", "credibility"], "description": "Build trust with authentic customer testimonials featuring quotes, names, and profile photos", "author": "Hugo Blox", "homepage": "https://hugoblox.com/blocks/", "repository": "https://github.com/HugoBlox/kit", "keywords": ["hugo", "testimonials", "social-proof", "reviews", "customers", "trust"] } ================================================ FILE: modules/blox/blox/trending-questions/block.html ================================================ {{- $wcPage := .wcPage -}} {{- $wcBlock := .wcBlock -}} {{- $wcIdentifier := .wcIdentifier -}} {{ $content := $wcBlock.content }} {{ if not (reflect.IsMap $content) }}{{ $content = dict }}{{ end }} {{ $design := $wcBlock.design }} {{ if not (reflect.IsMap $design) }}{{ $design = dict }}{{ end }} {{ $spacing := index $design "spacing" }} {{ if not (reflect.IsMap $spacing) }}{{ $spacing = dict }}{{ end }} {{ $pad_raw := index $spacing "padding" }} {{ $pad := slice "4rem" "0" "4rem" "0" }} {{ if reflect.IsSlice $pad_raw }} {{ $pad_values := slice }} {{ range $pad_raw }} {{ $val := strings.TrimSpace (printf "%v" .) }} {{ if $val }}{{ $pad_values = $pad_values | append $val }}{{ end }} {{ end }} {{ if eq (len $pad_values) 4 }}{{ $pad = $pad_values }}{{ end }} {{ end }} {{ $background := index $design "background" }} {{ if not (reflect.IsMap $background) }}{{ $background = dict }}{{ end }} {{ $bg_color := "" }} {{ with index $background "color" }}{{ $bg_color = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $title := "" }} {{ $title_raw := index $content "title" }} {{ if $title_raw }}{{ $title = strings.TrimSpace (printf "%v" $title_raw) }}{{ end }} {{ $subtitle := "" }} {{ $subtitle_raw := index $content "subtitle" }} {{ if $subtitle_raw }}{{ $subtitle = strings.TrimSpace (printf "%v" $subtitle_raw) }}{{ end }} {{ $view_all := index $content "view_all" }} {{ if not (reflect.IsMap $view_all) }}{{ $view_all = dict }}{{ end }} {{ $view_all_text := "" }} {{ $view_all_link := "" }} {{ with index $view_all "text" }}{{ $view_all_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $view_all "link" }}{{ $view_all_link = strings.TrimSpace (printf "%v" .) }}{{ end }}
{{ with $title }}

{{ . | markdownify }}

{{ end }} {{ with $subtitle }}

{{ . | markdownify }}

{{ end }}
{{ if and $view_all_text $view_all_link }} {{ $view_link := $view_all_link }} {{ $view_target := "" }} {{ $view_scheme := (urls.Parse $view_link).Scheme }} {{ if not $view_scheme }} {{ if not (hasPrefix $view_link "#") }} {{ $view_link = $view_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $view_scheme }} {{ $view_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }}
{{/* Get trending questions dynamically or from static config */}} {{ $questions := slice }} {{/* Method 1: Dynamic - Pull from pages with trending: true */}} {{ $count := partial "functions/coerce_int" (dict "value" (index $content "count") "default" 4 "min" 0) }} {{ $trending_pages := where site.RegularPages "Params.trending" true }} {{ $trending_pages = $trending_pages.ByParam "trending_weight" | default ($trending_pages.ByDate.Reverse) }} {{ $trending_pages = first $count $trending_pages }} {{ if $trending_pages }} {{ range $trending_pages }} {{ $question := "" }} {{ $question_raw := .Params.question | default .Title }} {{ if $question_raw }}{{ $question = strings.TrimSpace (printf "%v" $question_raw) }}{{ end }} {{ $link := .RelPermalink }} {{ $answer_preview := "" }} {{ $answer_raw := .Params.answer_preview | default .Params.answer | default .Summary }} {{ if $answer_raw }}{{ $answer_preview = (printf "%v" $answer_raw) | plainify | truncate 150 }}{{ end }} {{ $author := "" }} {{ with .Params.author }}{{ $author = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $views := "" }} {{ with .Params.views }}{{ $views = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $upvotes := "" }} {{ with .Params.upvote_count }}{{ $upvotes = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $badge := dict }} {{ $badge_raw := .Params.badge }} {{ if reflect.IsMap $badge_raw }} {{ $badge_text := "" }} {{ $badge_color := "" }} {{ with index $badge_raw "text" }}{{ $badge_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $badge_raw "color" }}{{ $badge_color = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if $badge_text }} {{ $badge = dict "text" $badge_text "color" $badge_color }} {{ end }} {{ else if $badge_raw }} {{ $badge_text := strings.TrimSpace (printf "%v" $badge_raw) }} {{ if $badge_text }} {{ $badge = dict "text" $badge_text "color" "" }} {{ end }} {{ end }} {{ if eq (len $badge) 0 }} {{ $upvote_count := partial "functions/coerce_int" (dict "value" .Params.upvote_count "default" 0 "min" 0) }} {{ $featured := partial "functions/coerce_bool" (dict "value" .Params.featured "default" false) }} {{ if gt $upvote_count 50 }} {{ $badge = dict "text" "🔥 Popular" "color" "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-200" }} {{ else if $featured }} {{ $badge = dict "text" "⭐ Featured" "color" "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-200" }} {{ else if (time .Date).After (now.AddDate 0 0 -7) }} {{ $badge = dict "text" "✨ New" "color" "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200" }} {{ else }} {{ $badge = dict "text" "🔥 Trending" "color" "bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-200" }} {{ end }} {{ end }} {{ if $question }} {{ $questions = $questions | append (dict "question" $question "link" $link "answer_preview" $answer_preview "author" $author "views" $views "upvotes" $upvotes "badge" $badge) }} {{ end }} {{ end }} {{ end }} {{/* Method 2: Static fallback - Use config if no trending pages found */}} {{ if not $questions }} {{ $questions_raw := index $content "questions" }} {{ $questions_iter := slice }} {{ if reflect.IsSlice $questions_raw }} {{ $questions_iter = $questions_raw }} {{ else if and $questions_raw (reflect.IsMap $questions_raw) }} {{ $questions_iter = slice $questions_raw }} {{ end }} {{ if gt (len $questions_iter) 0 }} {{ range $questions_iter }} {{ if reflect.IsMap . }} {{ $question := "" }} {{ $link := "" }} {{ $answer_preview := "" }} {{ $author := "" }} {{ $views := "" }} {{ $upvotes := "" }} {{ with index . "question" }}{{ $question = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "link" }}{{ $link = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "answer_preview" }}{{ $answer_preview = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "author" }}{{ $author = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "views" }}{{ $views = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index . "upvotes" }}{{ $upvotes = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ $badge := dict }} {{ $badge_raw := index . "badge" }} {{ if reflect.IsMap $badge_raw }} {{ $badge_text := "" }} {{ $badge_color := "" }} {{ with index $badge_raw "text" }}{{ $badge_text = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ with index $badge_raw "color" }}{{ $badge_color = strings.TrimSpace (printf "%v" .) }}{{ end }} {{ if $badge_text }} {{ $badge = dict "text" $badge_text "color" $badge_color }} {{ end }} {{ else if $badge_raw }} {{ $badge_text := strings.TrimSpace (printf "%v" $badge_raw) }} {{ if $badge_text }} {{ $badge = dict "text" $badge_text "color" "" }} {{ end }} {{ end }} {{ if $question }} {{ $questions = $questions | append (dict "question" $question "link" $link "answer_preview" $answer_preview "author" $author "views" $views "upvotes" $upvotes "badge" $badge) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* Questions list or carousel */}}
{{ range $index, $question := $questions }}
{{/* Badge */}} {{ $badge := index $question "badge" }} {{ if reflect.IsMap $badge }} {{ $badge_text := index $badge "text" }} {{ $badge_color := index $badge "color" | default "bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-200" }} {{ if $badge_text }}
{{ $badge_text }}
{{ end }} {{ end }} {{/* Question */}}

{{ $question_link := index $question "link" }} {{ $link := $question_link }} {{ if not $link }}{{ $link = "#" }}{{ end }} {{ $link_target := "" }} {{ $scheme := (urls.Parse $link).Scheme }} {{ if not $scheme }} {{ if not (hasPrefix $link "#") }} {{ $link = $link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $link_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ index $question "question" }}

{{/* Answer preview */}} {{ with index $question "answer_preview" }}

{{ . }}

{{ end }} {{/* Meta info */}}
{{ with index $question "author" }} {{ . }} {{ end }} {{ with index $question "views" }} {{ . }} {{ end }} {{ with index $question "upvotes" }} {{ . }} helpful {{ end }}
Read →
{{ end }}
{{/* Mobile view all link */}} {{ if and $view_all_text $view_all_link }} {{ $mobile_link := $view_all_link }} {{ $mobile_target := "" }} {{ $mobile_scheme := (urls.Parse $mobile_link).Scheme }} {{ if not $mobile_scheme }} {{ if not (hasPrefix $mobile_link "#") }} {{ $mobile_link = $mobile_link | relLangURL }} {{ end }} {{ else if in (slice "http" "https") $mobile_scheme }} {{ $mobile_target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ end }}
================================================ FILE: modules/blox/blox/trending-questions/manifest.json ================================================ { "name": "trending-questions", "version": "1", "title": "Trending Questions", "description": "Display trending or featured questions", "categories": ["content"], "preview": "preview.svg" } ================================================ FILE: modules/blox/data/address_formats.toml ================================================ # Address formats. en-ca = {order = ['street', 'city', 'region', 'postcode', 'country'], delimiters = ['
', ', ', '
', '
']} en-us = {order = ['street', 'city', 'region', 'postcode'], delimiters = [', ', ', ', ' ', '']} en-gb = {order = ['street', 'city', 'region', 'postcode'], delimiters = [', ', ', ', ', ', '']} de = {order = ['street', 'postcode', 'city'], delimiters = ['
', ' ', '']} fr-ca = {order = ['street', 'city', 'region', 'postcode', 'country'], delimiters = ['
', ', ', '
', '
']} fr-fr = {order = ['street', 'postcode', 'city'], delimiters = ['
', ' ', '']} nl = {order = ['street', 'postcode', 'city', 'country'], delimiters = ['
', ' ', '
', '']} zh = {order = ['postcode', 'region', 'city', 'street'], delimiters = [' ', ' ', ' ', '']} pt-br = {order = ['street', 'city', 'region', 'postcode', 'country'], delimiters = ['
', ', ', '
', '
']} il = {order = ['street', 'city', 'postcode', 'country'], delimiters = [', ', ' ', ' ', '']} fi = {order = ['street', 'postcode', 'city', 'country'], delimiters = [', ', ' ', ', ']} ================================================ FILE: modules/blox/data/blox_aliases.yaml ================================================ renames: - old: awards new: resume-awards - old: biography new: resume-biography - old: experience new: resume-experience - old: languages new: resume-languages - old: skills new: resume-skills ================================================ FILE: modules/blox/data/fonts/academic.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Academic" vendor: "hugoblox" version: "1.0.0" license: "MIT" style: "serif" description: "Traditional serif pairing for academic, research, and institutional sites" families: heading: "Lora" body: "Source Serif 4" code: "Source Code Pro" weights: heading: [500, 600, 700] body: [400, 600] code: [400] leading: heading: 1.2 body: 1.7 code: 1.5 tracking: heading: "0" body: "0" variable: heading: true body: true code: false ================================================ FILE: modules/blox/data/fonts/developer.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Developer" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Technical, code-forward pairing for developer portfolios and docs" families: heading: "Space Grotesk" body: "IBM Plex Sans" code: "Fira Code" weights: heading: [500, 700] body: [400, 500, 600] code: [400, 700] leading: heading: 1.2 body: 1.6 code: 1.5 tracking: heading: "-0.02em" body: "0" variable: heading: true body: false code: true ================================================ FILE: modules/blox/data/fonts/editorial.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Editorial" vendor: "hugoblox" version: "1.0.0" license: "MIT" style: "serif" description: "Elegant serif pairing for magazines, blogs, and long-form content" families: heading: "Playfair Display" body: "Merriweather" code: "Source Code Pro" weights: heading: [600, 700, 800] body: [300, 400, 700] code: [400] leading: heading: 1.15 body: 1.7 code: 1.5 tracking: heading: "-0.01em" body: "0" variable: heading: true body: false code: false ================================================ FILE: modules/blox/data/fonts/geometric.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Geometric" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Bold, modern geometric sans-serif for startups and SaaS landing pages" families: heading: "Montserrat" body: "Poppins" code: "JetBrains Mono" weights: heading: [600, 700, 800] body: [300, 400, 500, 600] code: [400] leading: heading: 1.15 body: 1.6 code: 1.5 tracking: heading: "-0.01em" body: "0" ================================================ FILE: modules/blox/data/fonts/humanist.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Humanist" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Friendly, approachable rounded sans-serif for community and personal sites" families: heading: "Nunito" body: "Open Sans" code: "Ubuntu Mono" weights: heading: [600, 700, 800] body: [400, 600] code: [400, 700] leading: heading: 1.25 body: 1.65 code: 1.5 tracking: heading: "0" body: "0" variable: heading: true body: true code: false ================================================ FILE: modules/blox/data/fonts/modern.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "Modern" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Clean, modern sans-serif pairing — the default HugoBlox look" families: heading: "Inter" body: "Inter" code: "JetBrains Mono" weights: heading: [600, 700] body: [400, 500] code: [400] leading: heading: 1.2 body: 1.6 code: 1.5 tracking: heading: "-0.02em" body: "0" variable: heading: true body: true code: true ================================================ FILE: modules/blox/data/fonts/system.yaml ================================================ # HugoBlox Font Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-font@1" name: "System" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "System fonts only — zero network requests, maximum performance" families: heading: "system-sans" body: "system-sans" code: "system-mono" weights: heading: [600, 700] body: [400, 500] code: [400] leading: heading: 1.2 body: 1.6 code: 1.5 tracking: heading: "-0.02em" body: "0" ================================================ FILE: modules/blox/data/hugoblox.yaml ================================================ # Hugo Blox metadata version: '0.11.0' ================================================ FILE: modules/blox/data/icons/academicons.json ================================================ { "prefix": "academicons", "info": { "name": "Academicons", "total": 157, "version": "1.9.4", "author": { "name": "James Walsh", "url": "https://github.com/jpswalsh/academicons" }, "license": { "title": "Open Font License", "spdx": "OFL-1.1", "url": "https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL" }, "samples": ["conversation", "crossref-square", "stackoverflow"], "height": 32, "displayHeight": 16, "category": "Thematic", "palette": false }, "lastModified": 1701155440, "icons": { "academia": { "body": "" }, "academia-square": { "body": "" }, "acclaim": { "body": "", "width": 384 }, "acclaim-square": { "body": "" }, "acm": { "body": "", "width": 512 }, "acm-square": { "body": "" }, "acmdl": { "body": "", "width": 512 }, "acmdl-square": { "body": "" }, "ads": { "body": "", "width": 512 }, "ads-square": { "body": "" }, "africarxiv": { "body": "" }, "africarxiv-square": { "body": "" }, "archive": { "body": "" }, "archive-square": { "body": "" }, "arxiv": { "body": "" }, "arxiv-square": { "body": "" }, "biorxiv": { "body": "", "width": 512 }, "biorxiv-square": { "body": "" }, "ceur": { "body": "", "width": 512 }, "ceur-square": { "body": "" }, "ciencia-vitae": { "body": "", "width": 512 }, "ciencia-vitae-square": { "body": "" }, "clarivate": { "body": "", "width": 512 }, "clarivate-square": { "body": "" }, "closed-access": { "body": "", "width": 256 }, "closed-access-square": { "body": "" }, "conversation": { "body": "", "width": 484 }, "conversation-square": { "body": "" }, "coursera": { "body": "", "width": 512 }, "coursera-square": { "body": "" }, "crossref": { "body": "", "width": 320 }, "crossref-square": { "body": "" }, "cv": { "body": "", "width": 512 }, "cv-square": { "body": "" }, "datacite": { "body": "", "width": 512 }, "datacite-square": { "body": "" }, "dataverse": { "body": "", "width": 320 }, "dataverse-square": { "body": "" }, "dblp": { "body": "", "width": 384 }, "dblp-square": { "body": "" }, "depsy": { "body": "", "width": 512 }, "depsy-square": { "body": "" }, "doi": { "body": "", "width": 512 }, "doi-square": { "body": "" }, "dryad": { "body": "", "width": 512 }, "dryad-square": { "body": "" }, "elsevier": { "body": "", "width": 320 }, "elsevier-square": { "body": "" }, "figshare": { "body": "", "width": 512 }, "figshare-square": { "body": "" }, "google-scholar": { "body": "", "width": 384 }, "google-scholar-square": { "body": "" }, "hal": { "body": "", "width": 512 }, "hal-square": { "body": "" }, "hypothesis": { "body": "", "width": 512 }, "hypothesis-square": { "body": "" }, "ideas-repec": { "body": "", "width": 384 }, "ideas-repec-square": { "body": "" }, "ieee": { "body": "", "width": 512 }, "ieee-square": { "body": "" }, "impactstory": { "body": "", "width": 512 }, "impactstory-square": { "body": "" }, "inaturalist": { "body": "" }, "inaturalist-square": { "body": "" }, "inpn": { "body": "" }, "inpn-square": { "body": "" }, "inspire": { "body": "", "width": 512 }, "inspire-square": { "body": "" }, "isidore": { "body": "" }, "isidore-square": { "body": "" }, "isni": { "body": "", "width": 512 }, "isni-square": { "body": "" }, "jstor": { "body": "", "width": 512 }, "jstor-square": { "body": "" }, "lattes": { "body": "" }, "lattes-square": { "body": "" }, "mathoverflow": { "body": "", "width": 512 }, "mathoverflow-square": { "body": "" }, "mendeley": { "body": "", "width": 512 }, "mendeley-square": { "body": "" }, "moodle": { "body": "", "width": 512 }, "moodle-square": { "body": "" }, "mtmt": { "body": "", "width": 512 }, "mtmt-square": { "body": "" }, "nakala": { "body": "", "width": 512 }, "nakala-square": { "body": "" }, "obp": { "body": "" }, "obp-square": { "body": "" }, "open-access": { "body": "", "width": 256 }, "open-access-square": { "body": "" }, "open-data": { "body": "", "width": 512 }, "open-data-square": { "body": "" }, "open-materials": { "body": "", "width": 512 }, "open-materials-square": { "body": "" }, "openedition": { "body": "", "width": 384 }, "openedition-square": { "body": "" }, "orcid": { "body": "", "width": 512 }, "orcid-square": { "body": "" }, "osf": { "body": "", "width": 512 }, "osf-square": { "body": "" }, "overleaf": { "body": "", "width": 384 }, "overleaf-square": { "body": "" }, "philpapers": { "body": "", "width": 512 }, "philpapers-square": { "body": "" }, "piazza": { "body": "", "width": 320 }, "piazza-square": { "body": "" }, "preregistered": { "body": "", "width": 512 }, "preregistered-de": { "body": "", "width": 512 }, "preregistered-de-plus": { "body": "", "width": 512 }, "preregistered-de-plus-square": { "body": "" }, "preregistered-de-square": { "body": "" }, "preregistered-de-tc": { "body": "", "width": 512 }, "preregistered-de-tc-plus": { "body": "", "width": 512 }, "preregistered-de-tc-plus-square": { "body": "" }, "preregistered-de-tc-square": { "body": "" }, "preregistered-square": { "body": "" }, "preregistered-tc": { "body": "", "width": 512 }, "preregistered-tc-plus": { "body": "", "width": 512 }, "preregistered-tc-plus-square": { "body": "" }, "preregistered-tc-square": { "body": "" }, "protocols": { "body": "" }, "protocols-square": { "body": "" }, "psyarxiv": { "body": "", "width": 512 }, "psyarxiv-square": { "body": "" }, "publons": { "body": "", "width": 320 }, "publons-square": { "body": "" }, "pubmed": { "body": "", "width": 384 }, "pubmed-square": { "body": "" }, "pubpeer": { "body": "", "width": 320 }, "pubpeer-square": { "body": "" }, "researcherid": { "body": "", "width": 320 }, "researcherid-square": { "body": "" }, "researchgate": { "body": "", "width": 384 }, "researchgate-square": { "body": "" }, "ror": { "body": "", "width": 576 }, "ror-square": { "body": "" }, "sci-hub": { "body": "", "width": 320 }, "sci-hub-square": { "body": "" }, "scirate": { "body": "", "width": 512 }, "scirate-square": { "body": "" }, "scopus": { "body": "", "width": 512 }, "scopus-square": { "body": "" }, "semantic-scholar": { "body": "", "width": 512 }, "semantic-scholar-square": { "body": "" }, "springer": { "body": "", "width": 320 }, "springer-square": { "body": "" }, "ssrn": { "body": "", "width": 512 }, "ssrn-square": { "body": "" }, "stackoverflow": { "body": "", "width": 384 }, "stackoverflow-square": { "body": "" }, "viaf": { "body": "", "width": 512 }, "viaf-square": { "body": "" }, "wiley": { "body": "", "width": 512 }, "wiley-square": { "body": "" }, "zenodo": { "body": "", "width": 640 }, "zotero": { "body": "", "width": 320 }, "zotero-square": { "body": "" } }, "suffixes": { "": "Regular", "square": "Square" }, "width": 448, "height": 512 } ================================================ FILE: modules/blox/data/icons/brands.yaml ================================================ icons: github: instagram: facebook: discord: twitter: bluesky: mastodon: youtube: x: linkedin: cv: telegram: whatsapp: weixin: arxiv: google-scholar: orcid: reddit: # AI/ML Platforms huggingface: # Development hugo: ================================================ FILE: modules/blox/data/icons/devicon.json ================================================ { "prefix": "devicon", "info": { "name": "Devicon", "total": 764, "author": { "name": "konpa", "url": "https://github.com/devicons/devicon/tree/master" }, "license": { "title": "MIT", "spdx": "MIT", "url": "https://github.com/devicons/devicon/blob/master/LICENSE" }, "samples": [ "windows8", "tensorflow", "logstash" ], "height": 32, "displayHeight": 16, "category": "Brands / Social", "palette": true }, "lastModified": 1704871196, "icons": { "aarch64": { "body": "" }, "adonisjs": { "body": "" }, "adonisjs-wordmark": { "body": "" }, "aftereffects": { "body": "" }, "akka": { "body": "" }, "akka-wordmark": { "body": "" }, "algolia": { "body": "" }, "algolia-wordmark": { "body": "" }, "alpinejs": { "body": "" }, "alpinejs-wordmark": { "body": "" }, "amazonwebservices-wordmark": { "body": "" }, "anaconda": { "body": "" }, "anaconda-wordmark": { "body": "" }, "android": { "body": "" }, "android-wordmark": { "body": "" }, "androidstudio": { "body": "" }, "androidstudio-wordmark": { "body": "" }, "angular": { "body": "" }, "angular-wordmark": { "body": "" }, "angularjs": { "body": "" }, "angularjs-wordmark": { "body": "" }, "angularmaterial": { "body": "" }, "ansible": { "body": "" }, "ansible-wordmark": { "body": "" }, "antdesign": { "body": "" }, "antdesign-wordmark": { "body": "" }, "apache": { "body": "" }, "apache-wordmark": { "body": "" }, "apacheairflow": { "body": "" }, "apacheairflow-wordmark": { "body": "" }, "apachekafka": { "body": "" }, "apachekafka-wordmark": { "body": "" }, "apachespark": { "body": "" }, "apachespark-wordmark": { "body": "" }, "apl": { "body": "" }, "appcelerator": { "body": "" }, "appcelerator-wordmark": { "body": "" }, "apple": { "body": "" }, "appwrite": { "body": "" }, "appwrite-wordmark": { "body": "" }, "archlinux": { "body": "" }, "archlinux-wordmark": { "body": "" }, "arduino": { "body": "" }, "arduino-wordmark": { "body": "" }, "argocd": { "body": "" }, "argocd-wordmark": { "body": "" }, "astro": { "body": "" }, "astro-wordmark": { "body": "" }, "atom": { "body": "" }, "atom-wordmark": { "body": "" }, "awk-wordmark": { "body": "" }, "azure": { "body": "" }, "azure-wordmark": { "body": "" }, "azuredevops": { "body": "" }, "azuresqldatabase": { "body": "" }, "babel": { "body": "" }, "backbonejs": { "body": "" }, "backbonejs-wordmark": { "body": "" }, "ballerina": { "body": "" }, "ballerina-wordmark": { "body": "" }, "bamboo": { "body": "" }, "bamboo-wordmark": { "body": "" }, "bash": { "body": "" }, "beats": { "body": "" }, "behance": { "body": "" }, "behance-wordmark": { "body": "" }, "bitbucket": { "body": "" }, "bitbucket-wordmark": { "body": "" }, "blazor": { "body": "" }, "blender": { "body": "" }, "blender-wordmark": { "body": "" }, "bootstrap": { "body": "" }, "bootstrap-wordmark": { "body": "" }, "bower": { "body": "" }, "bower-wordmark": { "body": "" }, "browserstack": { "body": "" }, "browserstack-wordmark": { "body": "" }, "bun": { "body": "" }, "c": { "body": "" }, "cairo": { "body": "" }, "cairo-wordmark": { "body": "" }, "cakephp": { "body": "" }, "cakephp-wordmark": { "body": "" }, "canva": { "body": "" }, "capacitor": { "body": "" }, "capacitor-wordmark": { "body": "" }, "carbon": { "body": "" }, "cassandra": { "body": "" }, "cassandra-wordmark": { "body": "" }, "centos": { "body": "" }, "centos-wordmark": { "body": "" }, "ceylon": { "body": "" }, "ceylon-wordmark": { "body": "" }, "chrome": { "body": "" }, "chrome-wordmark": { "body": "" }, "clarity": { "body": "" }, "clarity-wordmark": { "body": "" }, "clion": { "body": "" }, "clion-wordmark": { "body": "" }, "clojure": { "body": "" }, "clojurescript": { "body": "" }, "cloudflare": { "body": "" }, "cloudflare-wordmark": { "body": "" }, "cloudflareworkers": { "body": "" }, "cloudflareworkers-wordmark": { "body": "" }, "cmake": { "body": "" }, "cmake-wordmark": { "body": "" }, "codeac": { "body": "" }, "codepen": { "body": "" }, "codepen-wordmark": { "body": "" }, "coffeescript": { "body": "" }, "coffeescript-wordmark": { "body": "" }, "composer": { "body": "" }, "confluence": { "body": "" }, "confluence-wordmark": { "body": "" }, "consul": { "body": "" }, "consul-wordmark": { "body": "" }, "contao": { "body": "" }, "contao-wordmark": { "body": "" }, "corejs": { "body": "" }, "corejs-wordmark": { "body": "" }, "cosmosdb": { "body": "" }, "cosmosdb-wordmark": { "body": "" }, "couchbase": { "body": "" }, "couchbase-wordmark": { "body": "" }, "couchdb": { "body": "" }, "couchdb-wordmark": { "body": "" }, "cplusplus": { "body": "" }, "crystal": { "body": "" }, "crystal-wordmark": { "body": "" }, "csharp": { "body": "" }, "css3": { "body": "" }, "css3-wordmark": { "body": "" }, "cypressio": { "body": "" }, "cypressio-wordmark": { "body": "" }, "d3js": { "body": "" }, "dart": { "body": "" }, "dart-wordmark": { "body": "" }, "datagrip": { "body": "" }, "dataspell": { "body": "" }, "dataspell-wordmark": { "body": "" }, "dbeaver": { "body": "" }, "debian": { "body": "" }, "debian-wordmark": { "body": "" }, "denojs": { "body": "" }, "denojs-wordmark": { "body": "" }, "devicon": { "body": "" }, "devicon-wordmark": { "body": "" }, "digitalocean": { "body": "" }, "digitalocean-wordmark": { "body": "" }, "discordjs": { "body": "" }, "discordjs-wordmark": { "body": "" }, "djangorest": { "body": "" }, "djangorest-wordmark": { "body": "" }, "docker": { "body": "" }, "docker-wordmark": { "body": "" }, "doctrine": { "body": "" }, "doctrine-wordmark": { "body": "" }, "dot-net": { "body": "" }, "dot-net-wordmark": { "body": "" }, "dotnetcore": { "body": "" }, "dreamweaver": { "body": "" }, "dropwizard": { "body": "" }, "drupal": { "body": "" }, "drupal-wordmark": { "body": "" }, "dynamodb": { "body": "" }, "eclipse": { "body": "" }, "eclipse-wordmark": { "body": "" }, "ecto": { "body": "" }, "ecto-wordmark": { "body": "" }, "elasticsearch": { "body": "" }, "elasticsearch-wordmark": { "body": "" }, "electron": { "body": "" }, "electron-wordmark": { "body": "" }, "eleventy": { "body": "" }, "elixir": { "body": "" }, "elixir-wordmark": { "body": "" }, "elm": { "body": "" }, "elm-wordmark": { "body": "" }, "emacs": { "body": "" }, "embeddedc": { "body": "" }, "embeddedc-wordmark": { "body": "" }, "ember": { "body": "" }, "ember-wordmark": { "body": "" }, "envoy": { "body": "" }, "envoy-wordmark": { "body": "" }, "erlang": { "body": "" }, "erlang-wordmark": { "body": "" }, "eslint": { "body": "" }, "eslint-wordmark": { "body": "" }, "express": { "body": "" }, "express-wordmark": { "body": "" }, "facebook": { "body": "" }, "fastapi": { "body": "" }, "fastapi-wordmark": { "body": "" }, "fastify": { "body": "" }, "fastify-wordmark": { "body": "" }, "faunadb": { "body": "" }, "faunadb-wordmark": { "body": "" }, "feathersjs": { "body": "" }, "fedora": { "body": "" }, "figma": { "body": "" }, "filezilla": { "body": "" }, "filezilla-wordmark": { "body": "" }, "firebase": { "body": "" }, "firebase-wordmark": { "body": "" }, "firefox": { "body": "" }, "firefox-wordmark": { "body": "" }, "flask": { "body": "" }, "flask-wordmark": { "body": "" }, "flutter": { "body": "" }, "fortran": { "body": "" }, "foundation": { "body": "" }, "foundation-wordmark": { "body": "" }, "framermotion": { "body": "" }, "framermotion-wordmark": { "body": "" }, "framework7": { "body": "" }, "framework7-wordmark": { "body": "" }, "fsharp": { "body": "" }, "gatling": { "body": "" }, "gatling-wordmark": { "body": "" }, "gatsby": { "body": "" }, "gatsby-wordmark": { "body": "" }, "gazebo": { "body": "" }, "gazebo-wordmark": { "body": "" }, "gcc": { "body": "" }, "gentoo": { "body": "" }, "gentoo-wordmark": { "body": "" }, "ghost": { "body": "" }, "ghost-wordmark": { "body": "" }, "gimp": { "body": "" }, "gimp-wordmark": { "body": "" }, "git": { "body": "" }, "git-wordmark": { "body": "" }, "gitbook": { "body": "" }, "gitbook-wordmark": { "body": "" }, "github": { "body": "" }, "github-wordmark": { "body": "" }, "githubactions": { "body": "" }, "githubcodespaces": { "body": "" }, "gitlab": { "body": "" }, "gitlab-wordmark": { "body": "" }, "gitpod": { "body": "" }, "gitpod-wordmark": { "body": "" }, "go": { "body": "" }, "go-wordmark": { "body": "" }, "godot": { "body": "" }, "godot-wordmark": { "body": "" }, "goland": { "body": "" }, "google": { "body": "" }, "google-wordmark": { "body": "" }, "googlecloud": { "body": "" }, "googlecloud-wordmark": { "body": "" }, "gradle": { "body": "" }, "gradle-wordmark": { "body": "" }, "grafana": { "body": "" }, "grafana-wordmark": { "body": "" }, "grails": { "body": "" }, "groovy": { "body": "" }, "grpc": { "body": "" }, "grunt": { "body": "" }, "grunt-wordmark": { "body": "" }, "hadoop": { "body": "" }, "hadoop-wordmark": { "body": "" }, "handlebars": { "body": "" }, "handlebars-wordmark": { "body": "" }, "hardhat": { "body": "" }, "hardhat-wordmark": { "body": "" }, "harvester": { "body": "" }, "harvester-wordmark": { "body": "" }, "haskell": { "body": "" }, "haskell-wordmark": { "body": "" }, "haxe": { "body": "" }, "helm": { "body": "" }, "heroku": { "body": "" }, "heroku-wordmark": { "body": "" }, "hibernate": { "body": "" }, "hibernate-wordmark": { "body": "" }, "homebrew": { "body": "" }, "homebrew-wordmark": { "body": "" }, "html5": { "body": "" }, "html5-wordmark": { "body": "" }, "hugo": { "body": "" }, "hugo-wordmark": { "body": "" }, "ie10": { "body": "" }, "ifttt": { "body": "" }, "influxdb": { "body": "" }, "influxdb-wordmark": { "body": "" }, "inkscape": { "body": "" }, "inkscape-wordmark": { "body": "" }, "insomnia": { "body": "" }, "insomnia-wordmark": { "body": "" }, "intellij": { "body": "" }, "ionic": { "body": "" }, "ionic-wordmark": { "body": "" }, "jaegertracing": { "body": "" }, "jaegertracing-wordmark": { "body": "" }, "jamstack": { "body": "" }, "jamstack-wordmark": { "body": "" }, "jasmine": { "body": "" }, "jasmine-wordmark": { "body": "" }, "java": { "body": "" }, "java-wordmark": { "body": "" }, "javascript": { "body": "" }, "jeet": { "body": "" }, "jeet-wordmark": { "body": "" }, "jekyll": { "body": "" }, "jenkins": { "body": "" }, "jetbrains": { "body": "" }, "jetpackcompose": { "body": "" }, "jetpackcompose-wordmark": { "body": "" }, "jira": { "body": "" }, "jira-wordmark": { "body": "" }, "jiraalign": { "body": "" }, "jiraalign-wordmark": { "body": "" }, "jquery": { "body": "" }, "jquery-wordmark": { "body": "" }, "json": { "body": "" }, "jule": { "body": "" }, "jule-wordmark": { "body": "" }, "julia": { "body": "" }, "julia-wordmark": { "body": "" }, "junit": { "body": "" }, "junit-wordmark": { "body": "" }, "jupyter": { "body": "" }, "jupyter-wordmark": { "body": "" }, "k3os": { "body": "" }, "k3os-wordmark": { "body": "" }, "k3s": { "body": "" }, "k3s-wordmark": { "body": "" }, "k6": { "body": "" }, "kaggle": { "body": "" }, "kaggle-wordmark": { "body": "" }, "karatelabs": { "body": "" }, "karatelabs-wordmark": { "body": "" }, "karma": { "body": "" }, "kdeneon": { "body": "" }, "keras": { "body": "" }, "keras-wordmark": { "body": "" }, "kibana": { "body": "" }, "kibana-wordmark": { "body": "" }, "knexjs": { "body": "" }, "knexjs-wordmark": { "body": "" }, "kotlin": { "body": "" }, "kotlin-wordmark": { "body": "" }, "krakenjs": { "body": "" }, "krakenjs-wordmark": { "body": "" }, "ktor": { "body": "" }, "ktor-wordmark": { "body": "" }, "kubernetes": { "body": "" }, "kubernetes-wordmark": { "body": "" }, "labview": { "body": "" }, "labview-wordmark": { "body": "" }, "laravel": { "body": "" }, "laravel-wordmark": { "body": "" }, "latex": { "body": "" }, "linkedin": { "body": "" }, "linkedin-wordmark": { "body": "" }, "linux": { "body": "" }, "liquibase": { "body": "" }, "liquibase-wordmark": { "body": "" }, "livewire": { "body": "" }, "livewire-wordmark": { "body": "" }, "llvm": { "body": "" }, "lodash": { "body": "" }, "logstash": { "body": "" }, "logstash-wordmark": { "body": "" }, "lua": { "body": "" }, "lua-wordmark": { "body": "", "hidden": true }, "lumen": { "body": "" }, "magento": { "body": "" }, "magento-wordmark": { "body": "" }, "mariadb": { "body": "" }, "mariadb-wordmark": { "body": "" }, "markdown": { "body": "" }, "materializecss": { "body": "" }, "materialui": { "body": "" }, "matlab": { "body": "" }, "matplotlib": { "body": "" }, "matplotlib-wordmark": { "body": "" }, "maven": { "body": "" }, "maven-wordmark": { "body": "" }, "maya": { "body": "" }, "maya-wordmark": { "body": "" }, "meteor": { "body": "" }, "meteor-wordmark": { "body": "" }, "microsoftsqlserver": { "body": "" }, "microsoftsqlserver-wordmark": { "body": "" }, "minitab": { "body": "" }, "mithril": { "body": "" }, "mobx": { "body": "" }, "mocha": { "body": "" }, "modx": { "body": "" }, "modx-wordmark": { "body": "" }, "moleculer": { "body": "" }, "moleculer-wordmark": { "body": "" }, "mongodb": { "body": "" }, "mongodb-wordmark": { "body": "" }, "mongoose": { "body": "" }, "mongoose-wordmark": { "body": "" }, "moodle": { "body": "" }, "moodle-wordmark": { "body": "" }, "msdos": { "body": "" }, "mysql": { "body": "" }, "mysql-wordmark": { "body": "" }, "nano": { "body": "" }, "nano-wordmark": { "body": "", "hidden": true }, "neo4j": { "body": "" }, "neo4j-wordmark": { "body": "" }, "neovim": { "body": "" }, "neovim-wordmark": { "body": "" }, "nestjs": { "body": "" }, "nestjs-wordmark": { "body": "" }, "netlify": { "body": "" }, "netlify-wordmark": { "body": "" }, "networkx": { "body": "" }, "networkx-wordmark": { "body": "" }, "nextjs": { "body": "" }, "nextjs-wordmark": { "body": "" }, "nginx": { "body": "" }, "ngrx": { "body": "" }, "nhibernate": { "body": "" }, "nhibernate-wordmark": { "body": "" }, "nim": { "body": "" }, "nim-wordmark": { "body": "" }, "nimble": { "body": "" }, "nixos": { "body": "" }, "nixos-wordmark": { "body": "" }, "nodejs": { "body": "" }, "nodejs-wordmark": { "body": "" }, "nodemon": { "body": "" }, "nodewebkit": { "body": "" }, "nodewebkit-wordmark": { "body": "" }, "nomad": { "body": "" }, "nomad-wordmark": { "body": "" }, "norg": { "body": "" }, "notion": { "body": "" }, "npm-wordmark": { "body": "" }, "nuget": { "body": "" }, "nuget-wordmark": { "body": "" }, "numpy": { "body": "" }, "numpy-wordmark": { "body": "" }, "nuxtjs": { "body": "" }, "nuxtjs-wordmark": { "body": "" }, "oauth": { "body": "" }, "ocaml": { "body": "" }, "ocaml-wordmark": { "body": "" }, "ohmyzsh": { "body": "" }, "okta": { "body": "" }, "okta-wordmark": { "body": "" }, "openal": { "body": "" }, "openapi": { "body": "" }, "openapi-wordmark": { "body": "" }, "opencl": { "body": "" }, "opencv": { "body": "" }, "opencv-wordmark": { "body": "" }, "opengl": { "body": "" }, "openstack": { "body": "" }, "openstack-wordmark": { "body": "" }, "opensuse": { "body": "" }, "opensuse-wordmark": { "body": "" }, "opentelemetry": { "body": "" }, "opentelemetry-wordmark": { "body": "" }, "opera": { "body": "" }, "opera-wordmark": { "body": "" }, "oracle": { "body": "" }, "ory": { "body": "" }, "ory-wordmark": { "body": "" }, "p5js": { "body": "" }, "packer": { "body": "" }, "packer-wordmark": { "body": "" }, "pandas": { "body": "" }, "pandas-wordmark": { "body": "" }, "perl": { "body": "" }, "pfsense": { "body": "" }, "pfsense-wordmark": { "body": "" }, "phalcon": { "body": "" }, "phoenix": { "body": "" }, "phoenix-wordmark": { "body": "" }, "photonengine": { "body": "" }, "photoshop": { "body": "" }, "php": { "body": "" }, "phpstorm": { "body": "" }, "playwright": { "body": "" }, "plotly": { "body": "" }, "plotly-wordmark": { "body": "" }, "pnpm": { "body": "" }, "pnpm-wordmark": { "body": "" }, "podman": { "body": "" }, "podman-wordmark": { "body": "" }, "poetry": { "body": "" }, "polygon": { "body": "" }, "polygon-wordmark": { "body": "" }, "portainer": { "body": "" }, "portainer-wordmark": { "body": "" }, "postcss": { "body": "" }, "postcss-wordmark": { "body": "" }, "postgresql": { "body": "" }, "postgresql-wordmark": { "body": "" }, "postman": { "body": "" }, "postman-wordmark": { "body": "" }, "powershell": { "body": "" }, "premierepro": { "body": "" }, "prisma": { "body": "" }, "prisma-wordmark": { "body": "" }, "processing": { "body": "" }, "processing-wordmark": { "body": "" }, "prolog": { "body": "" }, "prolog-wordmark": { "body": "" }, "prometheus": { "body": "" }, "prometheus-wordmark": { "body": "" }, "protractor": { "body": "" }, "protractor-wordmark": { "body": "" }, "pulsar": { "body": "" }, "pulsar-wordmark": { "body": "" }, "pulumi": { "body": "" }, "pulumi-wordmark": { "body": "" }, "puppeteer": { "body": "" }, "purescript": { "body": "" }, "purescript-wordmark": { "body": "" }, "putty": { "body": "" }, "pycharm": { "body": "" }, "pycharm-wordmark": { "body": "" }, "pypi": { "body": "" }, "pypi-wordmark": { "body": "" }, "pyscript-wordmark": { "body": "" }, "pytest": { "body": "" }, "pytest-wordmark": { "body": "" }, "python": { "body": "" }, "python-wordmark": { "body": "" }, "pytorch": { "body": "" }, "pytorch-wordmark": { "body": "" }, "qodana": { "body": "" }, "qt": { "body": "" }, "quarkus": { "body": "" }, "quarkus-wordmark": { "body": "" }, "quasar": { "body": "" }, "quasar-wordmark": { "body": "" }, "qwik": { "body": "" }, "qwik-wordmark": { "body": "" }, "r": { "body": "" }, "rabbitmq": { "body": "" }, "rabbitmq-wordmark": { "body": "" }, "rails-wordmark": { "body": "" }, "railway": { "body": "" }, "railway-wordmark": { "body": "" }, "rancher": { "body": "" }, "rancher-wordmark": { "body": "" }, "raspberrypi": { "body": "" }, "raspberrypi-wordmark": { "body": "" }, "reach": { "body": "" }, "react": { "body": "" }, "react-wordmark": { "body": "" }, "reactbootstrap": { "body": "" }, "reactnavigation": { "body": "" }, "reactrouter": { "body": "" }, "reactrouter-wordmark": { "body": "" }, "readthedocs": { "body": "" }, "readthedocs-wordmark": { "body": "" }, "realm": { "body": "" }, "realm-wordmark": { "body": "" }, "rect": { "body": "" }, "redhat": { "body": "" }, "redhat-wordmark": { "body": "" }, "redis": { "body": "" }, "redis-wordmark": { "body": "" }, "redux": { "body": "" }, "renpy": { "body": "" }, "replit": { "body": "" }, "replit-wordmark": { "body": "" }, "rider": { "body": "" }, "rider-wordmark": { "body": "" }, "rocksdb": { "body": "" }, "rockylinux": { "body": "" }, "rockylinux-wordmark": { "body": "" }, "rollup": { "body": "" }, "rollup-wordmark": { "body": "" }, "ros": { "body": "" }, "ros-wordmark": { "body": "" }, "rspec": { "body": "" }, "rspec-wordmark": { "body": "" }, "rstudio": { "body": "" }, "ruby": { "body": "" }, "ruby-wordmark": { "body": "" }, "rubymine": { "body": "" }, "rubymine-wordmark": { "body": "" }, "rust": { "body": "" }, "rxjs": { "body": "" }, "safari": { "body": "" }, "safari-wordmark": { "body": "" }, "salesforce": { "body": "" }, "sanity": { "body": "" }, "sass": { "body": "" }, "scala": { "body": "" }, "scala-wordmark": { "body": "" }, "scalingo": { "body": "" }, "scalingo-wordmark": { "body": "" }, "scikitlearn": { "body": "" }, "sdl": { "body": "" }, "selenium": { "body": "" }, "sema": { "body": "" }, "sema-wordmark": { "body": "" }, "sentry": { "body": "" }, "sentry-wordmark": { "body": "" }, "sequelize": { "body": "" }, "sequelize-wordmark": { "body": "" }, "shopware": { "body": "" }, "shopware-wordmark": { "body": "" }, "shotgrid": { "body": "" }, "shotgrid-wordmark": { "body": "" }, "sketch": { "body": "" }, "sketch-wordmark": { "body": "" }, "slack": { "body": "" }, "slack-wordmark": { "body": "" }, "socketio": { "body": "" }, "socketio-wordmark": { "body": "" }, "solidity": { "body": "" }, "solidjs": { "body": "" }, "solidjs-wordmark": { "body": "" }, "sonarqube": { "body": "" }, "sonarqube-wordmark": { "body": "" }, "sourcetree": { "body": "" }, "sourcetree-wordmark": { "body": "" }, "spack": { "body": "" }, "splunk-wordmark": { "body": "" }, "spring": { "body": "" }, "spring-wordmark": { "body": "" }, "spss": { "body": "" }, "spyder": { "body": "" }, "spyder-wordmark": { "body": "" }, "sqlalchemy": { "body": "" }, "sqlalchemy-wordmark": { "body": "" }, "sqldeveloper": { "body": "" }, "sqlite": { "body": "" }, "sqlite-wordmark": { "body": "" }, "ssh": { "body": "" }, "ssh-wordmark": { "body": "" }, "stackoverflow": { "body": "" }, "stackoverflow-wordmark": { "body": "" }, "stata-wordmark": { "body": "" }, "storybook": { "body": "" }, "storybook-wordmark": { "body": "" }, "streamlit": { "body": "" }, "streamlit-wordmark": { "body": "" }, "stylus": { "body": "" }, "subversion": { "body": "" }, "subversion-wordmark": { "body": "" }, "supabase": { "body": "" }, "supabase-wordmark": { "body": "" }, "svelte": { "body": "" }, "svelte-wordmark": { "body": "" }, "swagger": { "body": "" }, "swagger-wordmark": { "body": "" }, "swift": { "body": "" }, "swift-wordmark": { "body": "" }, "swiper": { "body": "" }, "symfony": { "body": "" }, "symfony-wordmark": { "body": "" }, "tailwindcss": { "body": "" }, "tailwindcss-wordmark": { "body": "" }, "tauri": { "body": "" }, "tauri-wordmark": { "body": "" }, "tensorflow": { "body": "" }, "tensorflow-wordmark": { "body": "" }, "terraform": { "body": "" }, "terraform-wordmark": { "body": "" }, "tex": { "body": "" }, "thealgorithms": { "body": "" }, "thealgorithms-wordmark": { "body": "" }, "threedsmax": { "body": "" }, "threejs": { "body": "" }, "threejs-wordmark": { "body": "" }, "titaniumsdk": { "body": "" }, "tomcat": { "body": "" }, "tomcat-wordmark": { "body": "" }, "tortoisegit": { "body": "" }, "towergit": { "body": "" }, "towergit-wordmark": { "body": "" }, "traefikmesh": { "body": "" }, "traefikmesh-wordmark": { "body": "" }, "traefikproxy": { "body": "" }, "traefikproxy-wordmark": { "body": "" }, "travis": { "body": "" }, "travis-wordmark": { "body": "" }, "trello": { "body": "" }, "trello-wordmark": { "body": "" }, "trpc": { "body": "" }, "trpc-wordmark": { "body": "" }, "twitter": { "body": "" }, "typescript": { "body": "" }, "typo3": { "body": "" }, "typo3-wordmark": { "body": "" }, "ubuntu": { "body": "" }, "ubuntu-wordmark": { "body": "" }, "unifiedmodelinglanguage": { "body": "" }, "unifiedmodelinglanguage-wordmark": { "body": "" }, "unity": { "body": "" }, "unity-wordmark": { "body": "" }, "unix": { "body": "" }, "unrealengine": { "body": "" }, "unrealengine-wordmark": { "body": "" }, "uwsgi": { "body": "" }, "v8": { "body": "" }, "vagrant": { "body": "" }, "vagrant-wordmark": { "body": "" }, "vala": { "body": "" }, "vala-wordmark": { "body": "" }, "vault": { "body": "" }, "vault-wordmark": { "body": "" }, "vercel": { "body": "" }, "vercel-wordmark": { "body": "" }, "vertx": { "body": "" }, "vertx-wordmark": { "body": "" }, "vim": { "body": "" }, "visualbasic": { "body": "" }, "visualstudio": { "body": "" }, "visualstudio-wordmark": { "body": "" }, "vite": { "body": "" }, "vite-wordmark": { "body": "" }, "vitejs": { "body": "" }, "vitess": { "body": "" }, "vitess-wordmark": { "body": "", "width": 256, "height": 256 }, "vitest": { "body": "" }, "vscode": { "body": "" }, "vscode-wordmark": { "body": "" }, "vsphere": { "body": "" }, "vsphere-wordmark": { "body": "" }, "vuejs": { "body": "" }, "vuejs-wordmark": { "body": "" }, "vuestorefront": { "body": "" }, "vuetify": { "body": "" }, "vyper": { "body": "" }, "vyper-wordmark": { "body": "" }, "wasm": { "body": "" }, "wasm-wordmark": { "body": "" }, "webflow": { "body": "" }, "weblate": { "body": "" }, "weblate-wordmark": { "body": "" }, "webpack": { "body": "" }, "webpack-wordmark": { "body": "" }, "webstorm": { "body": "" }, "webstorm-wordmark": { "body": "" }, "windows11": { "body": "" }, "windows11-wordmark": { "body": "" }, "windows8": { "body": "" }, "windows8-wordmark": { "body": "" }, "woocommerce": { "body": "" }, "woocommerce-wordmark": { "body": "" }, "wordpress": { "body": "" }, "xamarin": { "body": "" }, "xamarin-wordmark": { "body": "" }, "xcode": { "body": "" }, "xd": { "body": "" }, "xml": { "body": "" }, "yaml": { "body": "" }, "yarn": { "body": "" }, "yarn-wordmark": { "body": "" }, "yii": { "body": "" }, "yii-wordmark": { "body": "" }, "yugabytedb": { "body": "" }, "yugabytedb-wordmark": { "body": "" }, "yunohost": { "body": "" }, "zend": { "body": "" }, "zend-wordmark": { "body": "" }, "zig": { "body": "" }, "zig-wordmark": { "body": "" } }, "aliases": { "3dsmax": { "parent": "threedsmax" } }, "width": 128, "height": 128 } ================================================ FILE: modules/blox/data/icons/hb.yaml ================================================ # HugoBlox Kit Icon Library icons: # Callouts exclamation-triangle: # Skills python: # Extras markdown: warning: card: folder-tree: one: code-bracket: circle-stack: magnifying-glass: # Phosphor icons cat: person-simple-walk: # Git icons git-fork: ================================================ FILE: modules/blox/data/icons/hero.json ================================================ { "prefix": "heroicons", "info": { "name": "HeroIcons", "total": 885, "version": "2.0.18", "author": { "name": "Refactoring UI Inc", "url": "https://github.com/tailwindlabs/heroicons" }, "license": { "title": "MIT", "spdx": "MIT", "url": "https://github.com/tailwindlabs/heroicons/blob/master/LICENSE" }, "samples": ["camera", "building-library", "receipt-refund"], "height": [24, 20], "category": "General", "palette": false }, "lastModified": 1702312600, "icons": { "academic-cap": { "body": "" }, "academic-cap-20-solid": { "body": "", "width": 20, "height": 20 }, "academic-cap-solid": { "body": "" }, "adjustments-horizontal": { "body": "" }, "adjustments-horizontal-20-solid": { "body": "", "width": 20, "height": 20 }, "adjustments-horizontal-solid": { "body": "" }, "adjustments-vertical": { "body": "" }, "adjustments-vertical-20-solid": { "body": "", "width": 20, "height": 20 }, "adjustments-vertical-solid": { "body": "" }, "archive-box": { "body": "" }, "archive-box-20-solid": { "body": "", "width": 20, "height": 20 }, "archive-box-arrow-down": { "body": "" }, "archive-box-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "archive-box-arrow-down-solid": { "body": "" }, "archive-box-solid": { "body": "" }, "archive-box-x-mark": { "body": "" }, "archive-box-x-mark-20-solid": { "body": "", "width": 20, "height": 20 }, "archive-box-x-mark-solid": { "body": "" }, "arrow-down": { "body": "" }, "arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-circle": { "body": "" }, "arrow-down-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-circle-solid": { "body": "" }, "arrow-down-left": { "body": "" }, "arrow-down-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-left-solid": { "body": "" }, "arrow-down-on-square": { "body": "" }, "arrow-down-on-square-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-on-square-solid": { "body": "" }, "arrow-down-on-square-stack": { "body": "" }, "arrow-down-on-square-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-on-square-stack-solid": { "body": "" }, "arrow-down-right": { "body": "" }, "arrow-down-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-right-solid": { "body": "" }, "arrow-down-solid": { "body": "" }, "arrow-down-tray": { "body": "" }, "arrow-down-tray-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-down-tray-solid": { "body": "" }, "arrow-left": { "body": "" }, "arrow-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-left-circle": { "body": "" }, "arrow-left-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-left-circle-solid": { "body": "" }, "arrow-left-on-rectangle": { "body": "" }, "arrow-left-on-rectangle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-left-on-rectangle-solid": { "body": "" }, "arrow-left-solid": { "body": "" }, "arrow-long-down": { "body": "" }, "arrow-long-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-long-down-solid": { "body": "" }, "arrow-long-left": { "body": "" }, "arrow-long-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-long-left-solid": { "body": "" }, "arrow-long-right": { "body": "" }, "arrow-long-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-long-right-solid": { "body": "" }, "arrow-long-up": { "body": "" }, "arrow-long-up-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-long-up-solid": { "body": "" }, "arrow-path": { "body": "" }, "arrow-path-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-path-rounded-square": { "body": "" }, "arrow-path-rounded-square-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-path-rounded-square-solid": { "body": "" }, "arrow-path-solid": { "body": "" }, "arrow-right": { "body": "" }, "arrow-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-right-circle": { "body": "" }, "arrow-right-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-right-circle-solid": { "body": "" }, "arrow-right-on-rectangle": { "body": "" }, "arrow-right-on-rectangle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-right-on-rectangle-solid": { "body": "" }, "arrow-right-solid": { "body": "" }, "arrow-small-down": { "body": "" }, "arrow-small-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-small-down-solid": { "body": "" }, "arrow-small-left": { "body": "" }, "arrow-small-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-small-left-solid": { "body": "" }, "arrow-small-right": { "body": "" }, "arrow-small-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-small-right-solid": { "body": "" }, "arrow-small-up": { "body": "" }, "arrow-small-up-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-small-up-solid": { "body": "" }, "arrow-top-right-on-square": { "body": "" }, "arrow-top-right-on-square-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-top-right-on-square-solid": { "body": "" }, "arrow-trending-down": { "body": "" }, "arrow-trending-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-trending-down-solid": { "body": "" }, "arrow-trending-up": { "body": "" }, "arrow-trending-up-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-trending-up-solid": { "body": "" }, "arrow-up": { "body": "" }, "arrow-up-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-circle": { "body": "" }, "arrow-up-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-circle-solid": { "body": "" }, "arrow-up-left": { "body": "" }, "arrow-up-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-left-solid": { "body": "" }, "arrow-up-on-square": { "body": "" }, "arrow-up-on-square-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-on-square-solid": { "body": "" }, "arrow-up-on-square-stack": { "body": "" }, "arrow-up-on-square-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-on-square-stack-solid": { "body": "" }, "arrow-up-right": { "body": "" }, "arrow-up-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-right-solid": { "body": "" }, "arrow-up-solid": { "body": "" }, "arrow-up-tray": { "body": "" }, "arrow-up-tray-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-up-tray-solid": { "body": "" }, "arrow-uturn-down": { "body": "" }, "arrow-uturn-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-uturn-down-solid": { "body": "" }, "arrow-uturn-left": { "body": "" }, "arrow-uturn-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-uturn-left-solid": { "body": "" }, "arrow-uturn-right": { "body": "" }, "arrow-uturn-right-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-uturn-right-solid": { "body": "" }, "arrow-uturn-up": { "body": "" }, "arrow-uturn-up-20-solid": { "body": "", "width": 20, "height": 20 }, "arrow-uturn-up-solid": { "body": "" }, "arrows-pointing-in": { "body": "" }, "arrows-pointing-in-20-solid": { "body": "", "width": 20, "height": 20 }, "arrows-pointing-in-solid": { "body": "" }, "arrows-pointing-out": { "body": "" }, "arrows-pointing-out-20-solid": { "body": "", "width": 20, "height": 20 }, "arrows-pointing-out-solid": { "body": "" }, "arrows-right-left": { "body": "" }, "arrows-right-left-20-solid": { "body": "", "width": 20, "height": 20 }, "arrows-right-left-solid": { "body": "" }, "arrows-up-down": { "body": "" }, "arrows-up-down-20-solid": { "body": "", "width": 20, "height": 20 }, "arrows-up-down-solid": { "body": "" }, "at-symbol": { "body": "" }, "at-symbol-20-solid": { "body": "", "width": 20, "height": 20 }, "at-symbol-solid": { "body": "" }, "backspace": { "body": "" }, "backspace-20-solid": { "body": "", "width": 20, "height": 20 }, "backspace-solid": { "body": "" }, "backward": { "body": "" }, "backward-20-solid": { "body": "", "width": 20, "height": 20 }, "backward-solid": { "body": "" }, "banknotes": { "body": "" }, "banknotes-20-solid": { "body": "", "width": 20, "height": 20 }, "banknotes-solid": { "body": "" }, "bars-2": { "body": "" }, "bars-2-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-2-solid": { "body": "" }, "bars-3": { "body": "" }, "bars-3-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-3-bottom-left": { "body": "" }, "bars-3-bottom-left-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-3-bottom-left-solid": { "body": "" }, "bars-3-bottom-right": { "body": "" }, "bars-3-bottom-right-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-3-bottom-right-solid": { "body": "" }, "bars-3-center-left": { "body": "" }, "bars-3-center-left-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-3-center-left-solid": { "body": "" }, "bars-3-solid": { "body": "" }, "bars-4": { "body": "" }, "bars-4-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-4-solid": { "body": "" }, "bars-arrow-down": { "body": "" }, "bars-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-arrow-down-solid": { "body": "" }, "bars-arrow-up": { "body": "" }, "bars-arrow-up-20-solid": { "body": "", "width": 20, "height": 20 }, "bars-arrow-up-solid": { "body": "" }, "battery-0": { "body": "" }, "battery-0-20-solid": { "body": "", "width": 20, "height": 20 }, "battery-0-solid": { "body": "" }, "battery-100": { "body": "" }, "battery-100-20-solid": { "body": "", "width": 20, "height": 20 }, "battery-100-solid": { "body": "" }, "battery-50": { "body": "" }, "battery-50-20-solid": { "body": "", "width": 20, "height": 20 }, "battery-50-solid": { "body": "" }, "beaker": { "body": "" }, "beaker-20-solid": { "body": "", "width": 20, "height": 20 }, "beaker-solid": { "body": "" }, "bell": { "body": "" }, "bell-20-solid": { "body": "", "width": 20, "height": 20 }, "bell-alert": { "body": "" }, "bell-alert-20-solid": { "body": "", "width": 20, "height": 20 }, "bell-alert-solid": { "body": "" }, "bell-slash": { "body": "" }, "bell-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "bell-slash-solid": { "body": "" }, "bell-snooze": { "body": "" }, "bell-snooze-20-solid": { "body": "", "width": 20, "height": 20 }, "bell-snooze-solid": { "body": "" }, "bell-solid": { "body": "" }, "bold": { "body": "" }, "bold-20-solid": { "body": "", "width": 20, "height": 20 }, "bold-solid": { "body": "" }, "bolt": { "body": "" }, "bolt-20-solid": { "body": "", "width": 20, "height": 20 }, "bolt-slash": { "body": "" }, "bolt-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "bolt-slash-solid": { "body": "" }, "bolt-solid": { "body": "" }, "book-open": { "body": "" }, "book-open-20-solid": { "body": "", "width": 20, "height": 20 }, "book-open-solid": { "body": "" }, "bookmark": { "body": "" }, "bookmark-20-solid": { "body": "", "width": 20, "height": 20 }, "bookmark-slash": { "body": "" }, "bookmark-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "bookmark-slash-solid": { "body": "" }, "bookmark-solid": { "body": "" }, "bookmark-square": { "body": "" }, "bookmark-square-20-solid": { "body": "", "width": 20, "height": 20 }, "bookmark-square-solid": { "body": "" }, "briefcase": { "body": "" }, "briefcase-20-solid": { "body": "", "width": 20, "height": 20 }, "briefcase-solid": { "body": "" }, "bug-ant": { "body": "" }, "bug-ant-20-solid": { "body": "", "width": 20, "height": 20 }, "bug-ant-solid": { "body": "" }, "building-library": { "body": "" }, "building-library-20-solid": { "body": "", "width": 20, "height": 20 }, "building-library-solid": { "body": "" }, "building-office": { "body": "" }, "building-office-2": { "body": "" }, "building-office-2-20-solid": { "body": "", "width": 20, "height": 20 }, "building-office-2-solid": { "body": "" }, "building-office-20-solid": { "body": "", "width": 20, "height": 20 }, "building-office-solid": { "body": "" }, "building-storefront": { "body": "" }, "building-storefront-20-solid": { "body": "", "width": 20, "height": 20 }, "building-storefront-solid": { "body": "" }, "cake": { "body": "" }, "cake-20-solid": { "body": "", "width": 20, "height": 20 }, "cake-solid": { "body": "" }, "calculator": { "body": "" }, "calculator-20-solid": { "body": "", "width": 20, "height": 20 }, "calculator-solid": { "body": "" }, "calendar": { "body": "" }, "calendar-20-solid": { "body": "", "width": 20, "height": 20 }, "calendar-days": { "body": "" }, "calendar-days-20-solid": { "body": "", "width": 20, "height": 20 }, "calendar-days-solid": { "body": "" }, "calendar-solid": { "body": "" }, "camera": { "body": "" }, "camera-20-solid": { "body": "", "width": 20, "height": 20 }, "camera-solid": { "body": "" }, "chart-bar": { "body": "" }, "chart-bar-20-solid": { "body": "", "width": 20, "height": 20 }, "chart-bar-solid": { "body": "" }, "chart-bar-square": { "body": "" }, "chart-bar-square-20-solid": { "body": "", "width": 20, "height": 20 }, "chart-bar-square-solid": { "body": "" }, "chart-pie": { "body": "" }, "chart-pie-20-solid": { "body": "", "width": 20, "height": 20 }, "chart-pie-solid": { "body": "" }, "chat-bubble-bottom-center": { "body": "" }, "chat-bubble-bottom-center-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-bottom-center-solid": { "body": "" }, "chat-bubble-bottom-center-text": { "body": "" }, "chat-bubble-bottom-center-text-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-bottom-center-text-solid": { "body": "" }, "chat-bubble-left": { "body": "" }, "chat-bubble-left-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-left-ellipsis": { "body": "" }, "chat-bubble-left-ellipsis-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-left-ellipsis-solid": { "body": "" }, "chat-bubble-left-right": { "body": "" }, "chat-bubble-left-right-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-left-right-solid": { "body": "" }, "chat-bubble-left-solid": { "body": "" }, "chat-bubble-oval-left": { "body": "" }, "chat-bubble-oval-left-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-oval-left-ellipsis": { "body": "" }, "chat-bubble-oval-left-ellipsis-20-solid": { "body": "", "width": 20, "height": 20 }, "chat-bubble-oval-left-ellipsis-solid": { "body": "" }, "chat-bubble-oval-left-solid": { "body": "" }, "check": { "body": "" }, "check-20-solid": { "body": "", "width": 20, "height": 20 }, "check-badge": { "body": "" }, "check-badge-20-solid": { "body": "", "width": 20, "height": 20 }, "check-badge-solid": { "body": "" }, "check-circle": { "body": "" }, "check-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "check-circle-solid": { "body": "" }, "check-solid": { "body": "" }, "chevron-double-down": { "body": "" }, "chevron-double-down-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-double-down-solid": { "body": "" }, "chevron-double-left": { "body": "" }, "chevron-double-left-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-double-left-solid": { "body": "" }, "chevron-double-right": { "body": "" }, "chevron-double-right-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-double-right-solid": { "body": "" }, "chevron-double-up": { "body": "" }, "chevron-double-up-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-double-up-solid": { "body": "" }, "chevron-down": { "body": "" }, "chevron-down-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-down-solid": { "body": "" }, "chevron-left": { "body": "" }, "chevron-left-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-left-solid": { "body": "" }, "chevron-right": { "body": "" }, "chevron-right-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-right-solid": { "body": "" }, "chevron-up": { "body": "" }, "chevron-up-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-up-down": { "body": "" }, "chevron-up-down-20-solid": { "body": "", "width": 20, "height": 20 }, "chevron-up-down-solid": { "body": "" }, "chevron-up-solid": { "body": "" }, "circle-stack": { "body": "" }, "circle-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "circle-stack-solid": { "body": "" }, "clipboard": { "body": "" }, "clipboard-20-solid": { "body": "", "width": 20, "height": 20 }, "clipboard-document": { "body": "" }, "clipboard-document-20-solid": { "body": "", "width": 20, "height": 20 }, "clipboard-document-check": { "body": "" }, "clipboard-document-check-20-solid": { "body": "", "width": 20, "height": 20 }, "clipboard-document-check-solid": { "body": "" }, "clipboard-document-list": { "body": "" }, "clipboard-document-list-20-solid": { "body": "", "width": 20, "height": 20 }, "clipboard-document-list-solid": { "body": "" }, "clipboard-document-solid": { "body": "" }, "clipboard-solid": { "body": "" }, "clock": { "body": "" }, "clock-20-solid": { "body": "", "width": 20, "height": 20 }, "clock-solid": { "body": "" }, "cloud": { "body": "" }, "cloud-20-solid": { "body": "", "width": 20, "height": 20 }, "cloud-arrow-down": { "body": "" }, "cloud-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "cloud-arrow-down-solid": { "body": "" }, "cloud-arrow-up": { "body": "" }, "cloud-arrow-up-20-solid": { "body": "", "width": 20, "height": 20 }, "cloud-arrow-up-solid": { "body": "" }, "cloud-solid": { "body": "" }, "code-bracket": { "body": "" }, "code-bracket-20-solid": { "body": "", "width": 20, "height": 20 }, "code-bracket-solid": { "body": "" }, "code-bracket-square": { "body": "" }, "code-bracket-square-20-solid": { "body": "", "width": 20, "height": 20 }, "code-bracket-square-solid": { "body": "" }, "cog": { "body": "" }, "cog-20-solid": { "body": "", "width": 20, "height": 20 }, "cog-6-tooth": { "body": "" }, "cog-6-tooth-20-solid": { "body": "", "width": 20, "height": 20 }, "cog-6-tooth-solid": { "body": "" }, "cog-8-tooth": { "body": "" }, "cog-8-tooth-20-solid": { "body": "", "width": 20, "height": 20 }, "cog-8-tooth-solid": { "body": "" }, "cog-solid": { "body": "" }, "command-line": { "body": "" }, "command-line-20-solid": { "body": "", "width": 20, "height": 20 }, "command-line-solid": { "body": "" }, "computer-desktop": { "body": "" }, "computer-desktop-20-solid": { "body": "", "width": 20, "height": 20 }, "computer-desktop-solid": { "body": "" }, "cpu-chip": { "body": "" }, "cpu-chip-20-solid": { "body": "", "width": 20, "height": 20 }, "cpu-chip-solid": { "body": "" }, "credit-card": { "body": "" }, "credit-card-20-solid": { "body": "", "width": 20, "height": 20 }, "credit-card-solid": { "body": "" }, "cube": { "body": "" }, "cube-20-solid": { "body": "", "width": 20, "height": 20 }, "cube-solid": { "body": "" }, "cube-transparent": { "body": "" }, "cube-transparent-20-solid": { "body": "", "width": 20, "height": 20 }, "cube-transparent-solid": { "body": "" }, "currency-bangladeshi": { "body": "" }, "currency-bangladeshi-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-bangladeshi-solid": { "body": "" }, "currency-dollar": { "body": "" }, "currency-dollar-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-dollar-solid": { "body": "" }, "currency-euro": { "body": "" }, "currency-euro-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-euro-solid": { "body": "" }, "currency-pound": { "body": "" }, "currency-pound-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-pound-solid": { "body": "" }, "currency-rupee": { "body": "" }, "currency-rupee-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-rupee-solid": { "body": "" }, "currency-yen": { "body": "" }, "currency-yen-20-solid": { "body": "", "width": 20, "height": 20 }, "currency-yen-solid": { "body": "" }, "cursor-arrow-rays": { "body": "" }, "cursor-arrow-rays-20-solid": { "body": "", "width": 20, "height": 20 }, "cursor-arrow-rays-solid": { "body": "" }, "cursor-arrow-ripple": { "body": "" }, "cursor-arrow-ripple-20-solid": { "body": "", "width": 20, "height": 20 }, "cursor-arrow-ripple-solid": { "body": "" }, "device-phone-mobile": { "body": "" }, "device-phone-mobile-20-solid": { "body": "", "width": 20, "height": 20 }, "device-phone-mobile-solid": { "body": "" }, "device-tablet": { "body": "" }, "device-tablet-20-solid": { "body": "", "width": 20, "height": 20 }, "device-tablet-solid": { "body": "" }, "document": { "body": "" }, "document-20-solid": { "body": "", "width": 20, "height": 20 }, "document-arrow-down": { "body": "" }, "document-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "document-arrow-down-solid": { "body": "" }, "document-arrow-up": { "body": "" }, "document-arrow-up-20-solid": { "body": "", "width": 20, "height": 20 }, "document-arrow-up-solid": { "body": "" }, "document-chart-bar": { "body": "" }, "document-chart-bar-20-solid": { "body": "", "width": 20, "height": 20 }, "document-chart-bar-solid": { "body": "" }, "document-check": { "body": "" }, "document-check-20-solid": { "body": "", "width": 20, "height": 20 }, "document-check-solid": { "body": "" }, "document-duplicate": { "body": "" }, "document-duplicate-20-solid": { "body": "", "width": 20, "height": 20 }, "document-duplicate-solid": { "body": "" }, "document-magnifying-glass": { "body": "" }, "document-magnifying-glass-20-solid": { "body": "", "width": 20, "height": 20 }, "document-magnifying-glass-solid": { "body": "" }, "document-minus": { "body": "" }, "document-minus-20-solid": { "body": "", "width": 20, "height": 20 }, "document-minus-solid": { "body": "" }, "document-plus": { "body": "" }, "document-plus-20-solid": { "body": "", "width": 20, "height": 20 }, "document-plus-solid": { "body": "" }, "document-solid": { "body": "" }, "document-text": { "body": "" }, "document-text-20-solid": { "body": "", "width": 20, "height": 20 }, "document-text-solid": { "body": "" }, "ellipsis-horizontal": { "body": "" }, "ellipsis-horizontal-20-solid": { "body": "", "width": 20, "height": 20 }, "ellipsis-horizontal-circle": { "body": "" }, "ellipsis-horizontal-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "ellipsis-horizontal-circle-solid": { "body": "" }, "ellipsis-horizontal-solid": { "body": "" }, "ellipsis-vertical": { "body": "" }, "ellipsis-vertical-20-solid": { "body": "", "width": 20, "height": 20 }, "ellipsis-vertical-solid": { "body": "" }, "envelope": { "body": "" }, "envelope-20-solid": { "body": "", "width": 20, "height": 20 }, "envelope-open": { "body": "" }, "envelope-open-20-solid": { "body": "", "width": 20, "height": 20 }, "envelope-open-solid": { "body": "" }, "envelope-solid": { "body": "" }, "exclamation-circle": { "body": "" }, "exclamation-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "exclamation-circle-solid": { "body": "" }, "exclamation-triangle": { "body": "" }, "exclamation-triangle-20-solid": { "body": "", "width": 20, "height": 20 }, "exclamation-triangle-solid": { "body": "" }, "eye": { "body": "" }, "eye-20-solid": { "body": "", "width": 20, "height": 20 }, "eye-dropper": { "body": "" }, "eye-dropper-20-solid": { "body": "", "width": 20, "height": 20 }, "eye-dropper-solid": { "body": "" }, "eye-slash": { "body": "" }, "eye-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "eye-slash-solid": { "body": "" }, "eye-solid": { "body": "" }, "face-frown": { "body": "" }, "face-frown-20-solid": { "body": "", "width": 20, "height": 20 }, "face-frown-solid": { "body": "" }, "face-smile": { "body": "" }, "face-smile-20-solid": { "body": "", "width": 20, "height": 20 }, "face-smile-solid": { "body": "" }, "film": { "body": "" }, "film-20-solid": { "body": "", "width": 20, "height": 20 }, "film-solid": { "body": "" }, "finger-print": { "body": "" }, "finger-print-20-solid": { "body": "", "width": 20, "height": 20 }, "finger-print-solid": { "body": "" }, "fire": { "body": "" }, "fire-20-solid": { "body": "", "width": 20, "height": 20 }, "fire-solid": { "body": "" }, "flag": { "body": "" }, "flag-20-solid": { "body": "", "width": 20, "height": 20 }, "flag-solid": { "body": "" }, "folder": { "body": "" }, "folder-20-solid": { "body": "", "width": 20, "height": 20 }, "folder-arrow-down": { "body": "" }, "folder-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "folder-arrow-down-solid": { "body": "" }, "folder-minus": { "body": "" }, "folder-minus-20-solid": { "body": "", "width": 20, "height": 20 }, "folder-minus-solid": { "body": "" }, "folder-open": { "body": "" }, "folder-open-20-solid": { "body": "", "width": 20, "height": 20 }, "folder-open-solid": { "body": "" }, "folder-plus": { "body": "" }, "folder-plus-20-solid": { "body": "", "width": 20, "height": 20 }, "folder-plus-solid": { "body": "" }, "folder-solid": { "body": "" }, "forward": { "body": "" }, "forward-20-solid": { "body": "", "width": 20, "height": 20 }, "forward-solid": { "body": "" }, "funnel": { "body": "" }, "funnel-20-solid": { "body": "", "width": 20, "height": 20 }, "funnel-solid": { "body": "" }, "gif": { "body": "" }, "gif-20-solid": { "body": "", "width": 20, "height": 20 }, "gif-solid": { "body": "" }, "gift": { "body": "" }, "gift-20-solid": { "body": "", "width": 20, "height": 20 }, "gift-solid": { "body": "" }, "gift-top": { "body": "" }, "gift-top-20-solid": { "body": "", "width": 20, "height": 20 }, "gift-top-solid": { "body": "" }, "globe-alt": { "body": "" }, "globe-alt-20-solid": { "body": "", "width": 20, "height": 20 }, "globe-alt-solid": { "body": "" }, "globe-americas": { "body": "" }, "globe-americas-20-solid": { "body": "", "width": 20, "height": 20 }, "globe-americas-solid": { "body": "" }, "globe-asia-australia": { "body": "" }, "globe-asia-australia-20-solid": { "body": "", "width": 20, "height": 20 }, "globe-asia-australia-solid": { "body": "" }, "globe-europe-africa": { "body": "" }, "globe-europe-africa-20-solid": { "body": "", "width": 20, "height": 20 }, "globe-europe-africa-solid": { "body": "" }, "hand-raised": { "body": "" }, "hand-raised-20-solid": { "body": "", "width": 20, "height": 20 }, "hand-raised-solid": { "body": "" }, "hand-thumb-down": { "body": "" }, "hand-thumb-down-20-solid": { "body": "", "width": 20, "height": 20 }, "hand-thumb-down-solid": { "body": "" }, "hand-thumb-up": { "body": "" }, "hand-thumb-up-20-solid": { "body": "", "width": 20, "height": 20 }, "hand-thumb-up-solid": { "body": "" }, "hashtag": { "body": "" }, "hashtag-20-solid": { "body": "", "width": 20, "height": 20 }, "hashtag-solid": { "body": "" }, "heart": { "body": "" }, "heart-20-solid": { "body": "", "width": 20, "height": 20 }, "heart-solid": { "body": "" }, "home": { "body": "" }, "home-20-solid": { "body": "", "width": 20, "height": 20 }, "home-modern": { "body": "" }, "home-modern-20-solid": { "body": "", "width": 20, "height": 20 }, "home-modern-solid": { "body": "" }, "home-solid": { "body": "" }, "identification": { "body": "" }, "identification-20-solid": { "body": "", "width": 20, "height": 20 }, "identification-solid": { "body": "" }, "inbox": { "body": "" }, "inbox-20-solid": { "body": "", "width": 20, "height": 20 }, "inbox-arrow-down": { "body": "" }, "inbox-arrow-down-20-solid": { "body": "", "width": 20, "height": 20 }, "inbox-arrow-down-solid": { "body": "" }, "inbox-solid": { "body": "" }, "inbox-stack": { "body": "" }, "inbox-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "inbox-stack-solid": { "body": "" }, "information-circle": { "body": "" }, "information-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "information-circle-solid": { "body": "" }, "italic": { "body": "" }, "italic-20-solid": { "body": "", "width": 20, "height": 20 }, "italic-solid": { "body": "" }, "key": { "body": "" }, "key-20-solid": { "body": "", "width": 20, "height": 20 }, "key-solid": { "body": "" }, "language": { "body": "" }, "language-20-solid": { "body": "", "width": 20, "height": 20 }, "language-solid": { "body": "" }, "lifebuoy": { "body": "" }, "lifebuoy-20-solid": { "body": "", "width": 20, "height": 20 }, "lifebuoy-solid": { "body": "" }, "light-bulb": { "body": "" }, "light-bulb-20-solid": { "body": "", "width": 20, "height": 20 }, "light-bulb-solid": { "body": "" }, "link": { "body": "" }, "link-20-solid": { "body": "", "width": 20, "height": 20 }, "link-solid": { "body": "" }, "list-bullet": { "body": "" }, "list-bullet-20-solid": { "body": "", "width": 20, "height": 20 }, "list-bullet-solid": { "body": "" }, "lock-closed": { "body": "" }, "lock-closed-20-solid": { "body": "", "width": 20, "height": 20 }, "lock-closed-solid": { "body": "" }, "lock-open": { "body": "" }, "lock-open-20-solid": { "body": "", "width": 20, "height": 20 }, "lock-open-solid": { "body": "" }, "magnifying-glass": { "body": "" }, "magnifying-glass-20-solid": { "body": "", "width": 20, "height": 20 }, "magnifying-glass-circle": { "body": "" }, "magnifying-glass-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "magnifying-glass-circle-solid": { "body": "" }, "magnifying-glass-minus": { "body": "" }, "magnifying-glass-minus-20-solid": { "body": "", "width": 20, "height": 20 }, "magnifying-glass-minus-solid": { "body": "" }, "magnifying-glass-plus": { "body": "" }, "magnifying-glass-plus-20-solid": { "body": "", "width": 20, "height": 20 }, "magnifying-glass-plus-solid": { "body": "" }, "magnifying-glass-solid": { "body": "" }, "map": { "body": "" }, "map-20-solid": { "body": "", "width": 20, "height": 20 }, "map-pin": { "body": "" }, "map-pin-20-solid": { "body": "", "width": 20, "height": 20 }, "map-pin-solid": { "body": "" }, "map-solid": { "body": "" }, "megaphone": { "body": "" }, "megaphone-20-solid": { "body": "", "width": 20, "height": 20 }, "megaphone-solid": { "body": "" }, "microphone": { "body": "" }, "microphone-20-solid": { "body": "", "width": 20, "height": 20 }, "microphone-solid": { "body": "" }, "minus": { "body": "" }, "minus-20-solid": { "body": "", "width": 20, "height": 20 }, "minus-circle": { "body": "" }, "minus-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "minus-circle-solid": { "body": "" }, "minus-small": { "body": "" }, "minus-small-20-solid": { "body": "", "width": 20, "height": 20 }, "minus-small-solid": { "body": "" }, "minus-solid": { "body": "" }, "moon": { "body": "" }, "moon-20-solid": { "body": "", "width": 20, "height": 20 }, "moon-solid": { "body": "" }, "musical-note": { "body": "" }, "musical-note-20-solid": { "body": "", "width": 20, "height": 20 }, "musical-note-solid": { "body": "" }, "newspaper": { "body": "" }, "newspaper-20-solid": { "body": "", "width": 20, "height": 20 }, "newspaper-solid": { "body": "" }, "no-symbol": { "body": "" }, "no-symbol-20-solid": { "body": "", "width": 20, "height": 20 }, "no-symbol-solid": { "body": "" }, "paint-brush": { "body": "" }, "paint-brush-20-solid": { "body": "", "width": 20, "height": 20 }, "paint-brush-solid": { "body": "" }, "paper-airplane": { "body": "" }, "paper-airplane-20-solid": { "body": "", "width": 20, "height": 20 }, "paper-airplane-solid": { "body": "" }, "paper-clip": { "body": "" }, "paper-clip-20-solid": { "body": "", "width": 20, "height": 20 }, "paper-clip-solid": { "body": "" }, "pause": { "body": "" }, "pause-20-solid": { "body": "", "width": 20, "height": 20 }, "pause-circle": { "body": "" }, "pause-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "pause-circle-solid": { "body": "" }, "pause-solid": { "body": "" }, "pencil": { "body": "" }, "pencil-20-solid": { "body": "", "width": 20, "height": 20 }, "pencil-solid": { "body": "" }, "pencil-square": { "body": "" }, "pencil-square-20-solid": { "body": "", "width": 20, "height": 20 }, "pencil-square-solid": { "body": "" }, "phone": { "body": "" }, "phone-20-solid": { "body": "", "width": 20, "height": 20 }, "phone-arrow-down-left": { "body": "" }, "phone-arrow-down-left-20-solid": { "body": "", "width": 20, "height": 20 }, "phone-arrow-down-left-solid": { "body": "" }, "phone-arrow-up-right": { "body": "" }, "phone-arrow-up-right-20-solid": { "body": "", "width": 20, "height": 20 }, "phone-arrow-up-right-solid": { "body": "" }, "phone-solid": { "body": "" }, "phone-x-mark": { "body": "" }, "phone-x-mark-20-solid": { "body": "", "width": 20, "height": 20 }, "phone-x-mark-solid": { "body": "" }, "photo": { "body": "" }, "photo-20-solid": { "body": "", "width": 20, "height": 20 }, "photo-solid": { "body": "" }, "play": { "body": "" }, "play-20-solid": { "body": "", "width": 20, "height": 20 }, "play-circle": { "body": "" }, "play-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "play-circle-solid": { "body": "" }, "play-pause": { "body": "" }, "play-pause-20-solid": { "body": "", "width": 20, "height": 20 }, "play-pause-solid": { "body": "" }, "play-solid": { "body": "" }, "plus": { "body": "" }, "plus-20-solid": { "body": "", "width": 20, "height": 20 }, "plus-circle": { "body": "" }, "plus-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "plus-circle-solid": { "body": "" }, "plus-small": { "body": "" }, "plus-small-20-solid": { "body": "", "width": 20, "height": 20 }, "plus-small-solid": { "body": "" }, "plus-solid": { "body": "" }, "power": { "body": "" }, "power-20-solid": { "body": "", "width": 20, "height": 20 }, "power-solid": { "body": "" }, "presentation-chart-bar": { "body": "" }, "presentation-chart-bar-20-solid": { "body": "", "width": 20, "height": 20 }, "presentation-chart-bar-solid": { "body": "" }, "presentation-chart-line": { "body": "" }, "presentation-chart-line-20-solid": { "body": "", "width": 20, "height": 20 }, "presentation-chart-line-solid": { "body": "" }, "printer": { "body": "" }, "printer-20-solid": { "body": "", "width": 20, "height": 20 }, "printer-solid": { "body": "" }, "puzzle-piece": { "body": "" }, "puzzle-piece-20-solid": { "body": "", "width": 20, "height": 20 }, "puzzle-piece-solid": { "body": "" }, "qr-code": { "body": "" }, "qr-code-20-solid": { "body": "", "width": 20, "height": 20 }, "qr-code-solid": { "body": "" }, "question-mark-circle": { "body": "" }, "question-mark-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "question-mark-circle-solid": { "body": "" }, "queue-list": { "body": "" }, "queue-list-20-solid": { "body": "", "width": 20, "height": 20 }, "queue-list-solid": { "body": "" }, "radio": { "body": "" }, "radio-20-solid": { "body": "", "width": 20, "height": 20 }, "radio-solid": { "body": "" }, "receipt-percent": { "body": "" }, "receipt-percent-20-solid": { "body": "", "width": 20, "height": 20 }, "receipt-percent-solid": { "body": "" }, "receipt-refund": { "body": "" }, "receipt-refund-20-solid": { "body": "", "width": 20, "height": 20 }, "receipt-refund-solid": { "body": "" }, "rectangle-group": { "body": "" }, "rectangle-group-20-solid": { "body": "", "width": 20, "height": 20 }, "rectangle-group-solid": { "body": "" }, "rectangle-stack": { "body": "" }, "rectangle-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "rectangle-stack-solid": { "body": "" }, "rocket-launch": { "body": "" }, "rocket-launch-20-solid": { "body": "", "width": 20, "height": 20 }, "rocket-launch-solid": { "body": "" }, "rss": { "body": "" }, "rss-20-solid": { "body": "", "width": 20, "height": 20 }, "rss-solid": { "body": "" }, "scale": { "body": "" }, "scale-20-solid": { "body": "", "width": 20, "height": 20 }, "scale-solid": { "body": "" }, "scissors": { "body": "" }, "scissors-20-solid": { "body": "", "width": 20, "height": 20 }, "scissors-solid": { "body": "" }, "server": { "body": "" }, "server-20-solid": { "body": "", "width": 20, "height": 20 }, "server-solid": { "body": "" }, "server-stack": { "body": "" }, "server-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "server-stack-solid": { "body": "" }, "share": { "body": "" }, "share-20-solid": { "body": "", "width": 20, "height": 20 }, "share-solid": { "body": "" }, "shield-check": { "body": "" }, "shield-check-20-solid": { "body": "", "width": 20, "height": 20 }, "shield-check-solid": { "body": "" }, "shield-exclamation": { "body": "" }, "shield-exclamation-20-solid": { "body": "", "width": 20, "height": 20 }, "shield-exclamation-solid": { "body": "" }, "shopping-bag": { "body": "" }, "shopping-bag-20-solid": { "body": "", "width": 20, "height": 20 }, "shopping-bag-solid": { "body": "" }, "shopping-cart": { "body": "" }, "shopping-cart-20-solid": { "body": "", "width": 20, "height": 20 }, "shopping-cart-solid": { "body": "" }, "signal": { "body": "" }, "signal-20-solid": { "body": "", "width": 20, "height": 20 }, "signal-slash": { "body": "" }, "signal-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "signal-slash-solid": { "body": "" }, "signal-solid": { "body": "" }, "sparkles": { "body": "" }, "sparkles-20-solid": { "body": "", "width": 20, "height": 20 }, "sparkles-solid": { "body": "" }, "speaker-wave": { "body": "" }, "speaker-wave-20-solid": { "body": "", "width": 20, "height": 20 }, "speaker-wave-solid": { "body": "" }, "speaker-x-mark": { "body": "" }, "speaker-x-mark-20-solid": { "body": "", "width": 20, "height": 20 }, "speaker-x-mark-solid": { "body": "" }, "square-2-stack": { "body": "" }, "square-2-stack-20-solid": { "body": "", "width": 20, "height": 20 }, "square-2-stack-solid": { "body": "" }, "square-3-stack-3d": { "body": "" }, "square-3-stack-3d-20-solid": { "body": "", "width": 20, "height": 20 }, "square-3-stack-3d-solid": { "body": "" }, "squares-2x2": { "body": "" }, "squares-2x2-20-solid": { "body": "", "width": 20, "height": 20 }, "squares-2x2-solid": { "body": "" }, "squares-plus": { "body": "" }, "squares-plus-20-solid": { "body": "", "width": 20, "height": 20 }, "squares-plus-solid": { "body": "" }, "star": { "body": "" }, "star-20-solid": { "body": "", "width": 20, "height": 20 }, "star-solid": { "body": "" }, "stop": { "body": "" }, "stop-20-solid": { "body": "", "width": 20, "height": 20 }, "stop-circle": { "body": "" }, "stop-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "stop-circle-solid": { "body": "" }, "stop-solid": { "body": "" }, "sun": { "body": "" }, "sun-20-solid": { "body": "", "width": 20, "height": 20 }, "sun-solid": { "body": "" }, "swatch": { "body": "" }, "swatch-20-solid": { "body": "", "width": 20, "height": 20 }, "swatch-solid": { "body": "" }, "table-cells": { "body": "" }, "table-cells-20-solid": { "body": "", "width": 20, "height": 20 }, "table-cells-solid": { "body": "" }, "tag": { "body": "" }, "tag-20-solid": { "body": "", "width": 20, "height": 20 }, "tag-solid": { "body": "" }, "ticket": { "body": "" }, "ticket-20-solid": { "body": "", "width": 20, "height": 20 }, "ticket-solid": { "body": "" }, "trash": { "body": "" }, "trash-20-solid": { "body": "", "width": 20, "height": 20 }, "trash-solid": { "body": "" }, "trophy": { "body": "" }, "trophy-20-solid": { "body": "", "width": 20, "height": 20 }, "trophy-solid": { "body": "" }, "truck": { "body": "" }, "truck-20-solid": { "body": "", "width": 20, "height": 20 }, "truck-solid": { "body": "" }, "tv": { "body": "" }, "tv-20-solid": { "body": "", "width": 20, "height": 20 }, "tv-solid": { "body": "" }, "underline": { "body": "" }, "underline-20-solid": { "body": "", "width": 20, "height": 20 }, "underline-solid": { "body": "" }, "user": { "body": "" }, "user-20-solid": { "body": "", "width": 20, "height": 20 }, "user-circle": { "body": "" }, "user-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "user-circle-solid": { "body": "" }, "user-group": { "body": "" }, "user-group-20-solid": { "body": "", "width": 20, "height": 20 }, "user-group-solid": { "body": "" }, "user-minus": { "body": "" }, "user-minus-20-solid": { "body": "", "width": 20, "height": 20 }, "user-minus-solid": { "body": "" }, "user-plus": { "body": "" }, "user-plus-20-solid": { "body": "", "width": 20, "height": 20 }, "user-plus-solid": { "body": "" }, "user-solid": { "body": "" }, "users": { "body": "" }, "users-20-solid": { "body": "", "width": 20, "height": 20 }, "users-solid": { "body": "" }, "variable": { "body": "" }, "variable-20-solid": { "body": "", "width": 20, "height": 20 }, "variable-solid": { "body": "" }, "video-camera": { "body": "" }, "video-camera-20-solid": { "body": "", "width": 20, "height": 20 }, "video-camera-slash": { "body": "" }, "video-camera-slash-20-solid": { "body": "", "width": 20, "height": 20 }, "video-camera-slash-solid": { "body": "" }, "video-camera-solid": { "body": "" }, "view-columns": { "body": "" }, "view-columns-20-solid": { "body": "", "width": 20, "height": 20 }, "view-columns-solid": { "body": "" }, "viewfinder-circle": { "body": "" }, "viewfinder-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "viewfinder-circle-solid": { "body": "" }, "wallet": { "body": "" }, "wallet-20-solid": { "body": "", "width": 20, "height": 20 }, "wallet-solid": { "body": "" }, "wifi": { "body": "" }, "wifi-20-solid": { "body": "", "width": 20, "height": 20 }, "wifi-solid": { "body": "" }, "window": { "body": "" }, "window-20-solid": { "body": "", "width": 20, "height": 20 }, "window-solid": { "body": "" }, "wrench": { "body": "" }, "wrench-20-solid": { "body": "", "width": 20, "height": 20 }, "wrench-screwdriver": { "body": "" }, "wrench-screwdriver-20-solid": { "body": "", "width": 20, "height": 20 }, "wrench-screwdriver-solid": { "body": "" }, "wrench-solid": { "body": "" }, "x-circle": { "body": "" }, "x-circle-20-solid": { "body": "", "width": 20, "height": 20 }, "x-circle-solid": { "body": "" }, "x-mark": { "body": "" }, "x-mark-20-solid": { "body": "", "width": 20, "height": 20 }, "x-mark-solid": { "body": "" } }, "aliases": { "code-solid": { "parent": "code-bracket-solid" }, "code-square-solid": { "parent": "code-bracket-square-solid" }, "exclaimation-circle": { "parent": "exclamation-circle" }, "exclaimation-circle-solid": { "parent": "exclamation-circle-solid" }, "exclaimation-triangle": { "parent": "exclamation-triangle" }, "exclaimation-triangle-solid": { "parent": "exclamation-triangle-solid" } }, "suffixes": { "": "Outline 24x24", "solid": "Solid 24x24", "20-solid": "Solid 20x20" }, "width": 24, "height": 24 } ================================================ FILE: modules/blox/data/languages.yaml ================================================ 'ar': 'عربي' 'bn': 'বাংলা' 'ca': 'Català' 'cs': 'Česky' 'da': 'Dansk' 'de': 'Deutsch' 'el': 'Ελληνικά' 'en': 'English' 'es': 'Español' 'et': 'Eesti' 'eu': 'Euskara' 'fa': 'فارسی' 'fi': 'Suomi' 'fr': 'Français' 'he': 'עברית' 'hr': 'Hrvatski' 'hu': 'Magyar' 'ht': 'kréyol' 'id': 'Bahasa Indonesia' 'it': 'Italiano' 'ja': '日本語' 'km': 'ភាសាខ្មែរ' 'ko': '한국어' 'lt': 'Lietuvių' 'lv': 'Latviešu' 'mg': 'Malagasy' 'ms': 'Bahasa Melayu (Rumi)' 'ms-Arab': 'بهاس ملايو (جاوي)' 'nb': 'Norsk bokmål' 'nl': 'Nederlands' 'pl': 'Polski' 'pt': 'Português' 'ro': 'Română' 'ru': 'Русский' 'so': 'Soomaali' 'sv': 'Svenska' 'tr': 'Türkçe' 'uk': 'Українська' 'vi': 'Tiếng Việt' 'zh': '中文 (简体)' 'zh-hant': '中文 (繁體)' ================================================ FILE: modules/blox/data/link_types.yaml ================================================ types: pdf: label_i18n: btn_pdf icon: hero/document-text preprint: label_i18n: btn_preprint icon: hero/document-text doi: label_i18n: btn_doi icon: hero/link code: label_i18n: btn_code icon: hero/code-bracket dataset: label_i18n: btn_dataset icon: hero/circle-stack model: label_i18n: btn_model icon: hero/link slides: label_i18n: btn_slides icon: hero/presentation-chart-bar video: label_i18n: btn_video icon: hero/video-camera poster: label_i18n: btn_poster icon: hero/photo project: label_i18n: btn_project icon: hero/link site: label_i18n: btn_site icon: hero/link source: label_i18n: btn_source icon: hero/document bibtex: label_i18n: btn_cite icon: hero/document-duplicate canonical: label_i18n: btn_canonical icon: hero/link crosspost: label_i18n: btn_crosspost icon: hero/link discussion: label_i18n: btn_discussion icon: hero/link event: label_i18n: btn_event icon: hero/calendar calendar: label_i18n: btn_calendar icon: hero/calendar registration: label_i18n: btn_registration icon: hero/link demo: label_i18n: btn_demo icon: hero/link # Mapping of identifier keys under `hugoblox.ids` to derived links derived: doi: type: doi label_i18n: btn_doi icon: hero/link url_template: "https://doi.org/{id}" arxiv: type: preprint label_i18n: btn_preprint icon: hero/document-text url_template: "https://arxiv.org/abs/{id}" openreview: type: preprint label_i18n: btn_preprint icon: hero/document-text url_template: "https://openreview.net/forum?id={id}" acl_id: type: source label_i18n: btn_source icon: hero/document url_template: "https://aclanthology.org/{id}" hal: type: source label_i18n: btn_hal icon: hero/document url_template: "https://hal.science/{id}" dblp: type: source label_i18n: btn_dblp icon: hero/document url_template: "https://dblp.org/rec/{id}.html" isbn: type: source label_i18n: btn_isbn icon: hero/document url_template: "https://openlibrary.org/isbn/{id}" osf: type: source label_i18n: btn_osf icon: hero/document url_template: "https://osf.io/{id}" zenodo: type: source label_i18n: btn_zenodo icon: hero/document url_template: "https://zenodo.org/records/{id}" kaggle_dataset: type: dataset label_i18n: btn_kaggle icon: hero/circle-stack url_template: "https://www.kaggle.com/datasets/{id}" kaggle_competition: type: site label_i18n: btn_kaggle icon: hero/link url_template: "https://www.kaggle.com/competitions/{id}" openalex: type: source label_i18n: btn_openalex icon: hero/document url_template: "https://openalex.org/{id}" semanticscholar: type: source label_i18n: btn_semanticscholar icon: hero/document url_template: "https://www.semanticscholar.org/paper/{id}" pwc: type: site label_i18n: btn_pwc icon: hero/link url_template: "https://paperswithcode.com/paper/{id}" huggingface_model: type: model label_i18n: btn_model icon: hero/link url_template: "https://huggingface.co/{id}" huggingface_dataset: type: dataset label_i18n: btn_dataset icon: hero/circle-stack url_template: "https://huggingface.co/datasets/{id}" huggingface_space: type: demo label_i18n: btn_demo icon: hero/link url_template: "https://huggingface.co/spaces/{id}" ================================================ FILE: modules/blox/data/page_sharer.yaml ================================================ # Hugo Blox # Social sharing links # Docs: https://docs.hugoblox.com/reference/page-sharer/ links: - id: x url: 'https://x.com/intent/tweet?url={url}&text={title}' title: X icon: brands/x enable: true - id: facebook url: 'https://www.facebook.com/sharer.php?u={url}&t={title}' title: Facebook icon: brands/facebook enable: true - id: email url: 'mailto:?subject={title}&body={url}' title: Email icon: hero/at-symbol enable: true - id: linkedin url: 'https://www.linkedin.com/shareArticle?url={url}&title={title}' title: LinkedIn icon: brands/linkedin enable: true - id: whatsapp url: 'whatsapp://send?text={title}%20{url}' title: WhatsApp icon: brands/whatsapp enable: true # - id: weibo # url: 'https://service.weibo.com/share/share.php?url={url}&title={title}' # title: Weibo # icon: weibo # enable: true # - id: reddit # url: 'https://reddit.com/submit?url={url}&title={title}' # title: Reddit # icon: brands/reddit # enable: false # - id: pinterest # url: 'https://pinterest.com/pin/create/link/?url={url}&description={title}' # title: Pinterest # icon: pinterest # enable: false # - id: xing # url: 'https://www.xing.com/spi/shares/new?url={url}&title={title}' # title: Xing # icon: xing # enable: false # - id: tumblr # url: 'https://www.tumblr.com/widgets/share/tool?canonicalUrl={url}&title={title}' # title: Tumblr # icon: tumblr # enable: false ================================================ FILE: modules/blox/data/themes/coffee.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Coffee" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Warm latte light mode, deep americano dark mode" type: "dual" light: # "Latte" - Warm, creamy, light colors: primary: "#3b2313" # Mocha/Coffee bean secondary: "#d97706" # Caramel/Amber neutral: "#78716c" # Stone surfaces: background: "#fffaf5" # Warm cream/milk foam foreground: "#3b2313" # Espresso text header: background: "#f5efe9" # Visible header band (same as footer) foreground: "#3b2313" footer: background: "#f5efe9" # Slightly darker latte foam foreground: "#5c4033" dark: # "Americano" - Deep, dark, intense colors: primary: "#d49255" # Warm Orange/Brown crema secondary: "#395260" # Cool Slate Blue neutral: "#2b262b" # Deep Espresso (Dark Neutral) surfaces: background: "#2b262b" # Deep Espresso foreground: "#e0cab6" # Crema header: background: "#2b262b" foreground: "#e0cab6" footer: background: "#231f23" # Darker roast foreground: "#9ca3af" ================================================ FILE: modules/blox/data/themes/contrast.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Contrast" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "High contrast with inverted header" type: "dual" light: colors: primary: "indigo" secondary: "blue" surfaces: background: "#ffffff" foreground: "#111827" header: foreground: "#ffffff" background: "#0f172a" footer: background: "#f3f4f6" foreground: "#0f172a" dark: colors: primary: "blue" secondary: "teal" surfaces: background: "#0f172a" foreground: "#f8fafc" header: foreground: "#0f172a" background: "#f8fafc" footer: background: "#111827" foreground: "#e5e7eb" ================================================ FILE: modules/blox/data/themes/cupcake.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Cupcake" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Sweet pastry pinks and berry accents" type: "dual" light: colors: primary: "#e779c1" # Frosting Pink secondary: "#d946ef" # Deep Purple/Fuchsia neutral: "#5c4033" # Chocolate/Dark Brown surfaces: background: "#faf7f5" # Vanilla/Sugar foreground: "#7d1f39" # Berry Jam header: background: "#fff0f5" # LavenderBlush - slight pink tint foreground: "#7d1f39" footer: background: "#f3e8e8" # Light Pink Foam foreground: "#7d1f39" dark: # "Dark Berry" - Rich, vibrant, fruity colors: primary: "#f472b6" # Bright Icing Pink (Pink-400) secondary: "#c084fc" # Purple Sprinkle (Purple-400) neutral: "#831843" # Deep Berry (Pink-900) surfaces: background: "#4c0519" # Deep Red Velvet / Rose-950 foreground: "#fce7f3" # Sweet Cream / Pink-100 header: background: "#831843" # Vibrant Berry Header / Pink-900 foreground: "#fce7f3" footer: background: "#881337" # Rose-900 foreground: "#fbcfe8" # Pink-200 ================================================ FILE: modules/blox/data/themes/default.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Default" vendor: "hugoblox" version: "1.0.0" license: "MIT" type: "dual" light: colors: primary: "indigo" secondary: "blue" surfaces: background: "#ffffff" foreground: "#111827" header: background: "#f1f5f9" # Slate-100 for definition against white content foreground: "#0f172a" footer: background: "#f3f4f6" foreground: "#0f172a" dark: colors: primary: "blue" secondary: "teal" surfaces: background: "#0f172a" foreground: "#f8fafc" header: background: "#0f172a" foreground: "#f8fafc" footer: background: "#111827" foreground: "#e5e7eb" ================================================ FILE: modules/blox/data/themes/dracula.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Dracula" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "The iconic dark theme with a light Buffy variant" type: "dual" dark: # Official Dracula Dark colors: primary: "#ff79c6" # Pink secondary: "#bd93f9" # Purple neutral: "#6272a4" # Comment surfaces: background: "#282a36" # Background foreground: "#f8f8f2" # Foreground header: background: "#282a36" foreground: "#f8f8f2" footer: background: "#21222c" # Selection foreground: "#f8f8f2" light: # Dracula Light (Buffy inspired) - Inverted aesthetic colors: primary: "#d03282" # Darker Pink for contrast secondary: "#9259d6" # Darker Purple for contrast neutral: "#44475a" # Current Line (Dark Gray) surfaces: background: "#f8f8f2" # Light Gray foreground: "#282a36" # Dark Gray header: background: "#e4e4db" # Slightly darker band foreground: "#282a36" footer: background: "#e4e4db" foreground: "#282a36" ================================================ FILE: modules/blox/data/themes/marine.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Marine" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Deep ocean blues with teal accents" type: "dual" dark: colors: primary: "#2dd4bf" # Teal/Cyan secondary: "#a855f7" # Purple neutral: "#1e3a8a" # Deep Blue surfaces: background: "#1e3a8a" # Deep Ocean Blue foreground: "#e0f2fe" # Light Sky header: background: "#1e3a8a" foreground: "#e0f2fe" footer: background: "#172554" # Darker depth foreground: "#93c5fd" light: # A "Beach Day" pairing colors: primary: "#2dd4bf" secondary: "#a855f7" surfaces: background: "#f0f9ff" foreground: "#0c4a6e" header: background: "#e0f2fe" # Sky-100 for visible header bar foreground: "#0c4a6e" ================================================ FILE: modules/blox/data/themes/matcha.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Matcha" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Fresh, organic greens inspired by Japanese tea" type: "dual" light: # "Matcha Latte" - Creamy, fresh, organic colors: primary: "#65a30d" # Fresh Tea Leaf (Lime-600) secondary: "#15803d" # Deep Herbal Green (Green-700) neutral: "#3f6212" # Olive text (Lime-800) surfaces: background: "#f7fee7" # Very pale lime cream (Lime-50) foreground: "#1a2e05" # Dark moss text header: background: "#ecfccb" # Light Matcha Foam (Lime-100) foreground: "#365314" # Deep olive footer: background: "#d9f99d" # Stronger tea green (Lime-200) foreground: "#14532d" dark: # "Ceremonial Grade" - Deep, rich, meditative colors: primary: "#a3e635" # Vibrant Matcha Powder (Lime-400) secondary: "#4ade80" # Soft green light (Green-400) neutral: "#1a2f23" # Deep Forest Background surfaces: background: "#14281d" # Deep Nori Green foreground: "#ecfccb" # Pale tea green text header: background: "#0f1f16" # Darker leaf foreground: "#d9f99d" footer: background: "#052e16" # Deepest green (Green-950) foreground: "#86efac" ================================================ FILE: modules/blox/data/themes/minimal.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Minimal" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Clean, GitHub-inspired design" type: "dual" light: # Inspired by GitHub Light colors: primary: "#0969da" # GitHub Blue secondary: "#1f883d" # GitHub Green neutral: "#24292f" # GitHub Dark Gray (Text) surfaces: background: "#ffffff" foreground: "#24292f" header: background: "#f6f8fa" # GitHub Header Gray foreground: "#24292f" footer: background: "#ffffff" # Clean foreground: "#57606a" # Muted text dark: # Inspired by GitHub Dark colors: primary: "#58a6ff" # GitHub Blue (Dark Mode) secondary: "#238636" # GitHub Green (Dark Mode) neutral: "#c9d1d9" # GitHub Light Gray (Text) surfaces: background: "#0d1117" # GitHub Dimmed BG foreground: "#c9d1d9" header: background: "#161b22" # GitHub Dark Header foreground: "#f0f6fc" footer: background: "#0d1117" foreground: "#8b949e" # Muted text ================================================ FILE: modules/blox/data/themes/retro.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Retro" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Vintage paper meets midnight arcade" type: "dual" light: # "Vintage Paper" - Sepia, warm, nostalgic colors: primary: "#e38c89" # Desaturated Red/Pink secondary: "#b4e9d6" # Mint Green neutral: "#79726b" # Warm Stone surfaces: background: "#ebe6d9" # Vintage Paper / Beige foreground: "#7d5e3c" # Sepia/Brown header: background: "#e3dbcd" # Slightly darker paper foreground: "#7d5e3c" footer: background: "#dcd3c3" foreground: "#5c4033" dark: # "Midnight Arcade" - Deep petrol, mustard, and neon accents colors: primary: "#fbbf24" # Mustard Gold (Amber-400) secondary: "#f472b6" # Retro Pink (Pink-400) neutral: "#134e4a" # Dark Teal (Teal-900) surfaces: background: "#042f2e" # Deep Petrol / Teal-950 foreground: "#ccfbf1" # Pale Mint / Teal-50 header: background: "#115e59" # Lighter Petrol / Teal-800 foreground: "#ccfbf1" footer: background: "#0f393b" # Muted Teal foreground: "#99f6e4" # Teal-200 ================================================ FILE: modules/blox/data/themes/solar.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Solar" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Solarized-inspired, easy on the eyes" type: "dual" light: # Inspired by Solarized Light - Low contrast, warm, easy on the eyes colors: primary: "#b58900" # Yellow (Solarized) secondary: "#2aa198" # Cyan (Solarized) neutral: "#657b83" # Base00 (Primary Content) surfaces: background: "#fdf6e3" # Base3 (Creamy Background) foreground: "#586e75" # Base01 (Optional darker text for contrast) header: background: "#eee8d5" # Base2 (Slightly darker highlights) foreground: "#586e75" footer: background: "#eee8d5" foreground: "#657b83" dark: # Inspired by Solarized Dark - Deep, cool, high precision colors: primary: "#268bd2" # Blue (Solarized) secondary: "#859900" # Green (Solarized) neutral: "#839496" # Base0 (Primary Content) surfaces: background: "#002b36" # Base03 (Deep Teal Background) foreground: "#93a1a1" # Base1 (Light Content) header: background: "#073642" # Base02 (Lighter Teal Highlights) foreground: "#93a1a1" footer: background: "#073642" foreground: "#839496" ================================================ FILE: modules/blox/data/themes/synthwave.yaml ================================================ # HugoBlox Theme Pack # https://docs.hugoblox.com hugoblox: meta: format: "hugoblox-theme@1" name: "Synthwave" vendor: "hugoblox" version: "1.0.0" license: "MIT" description: "Neon-drenched 80s retrowave aesthetic" type: "dual" dark: colors: primary: "#e779c1" # Neon Pink secondary: "#58c7f3" # Cyan neutral: "#2a2e37" # Dark Blue-Gray surfaces: background: "#1a103d" # Deep Purple foreground: "#f9f7fd" # Light Lavender header: background: "rgba(26, 16, 61, 0.9)" # Deep Purple foreground: "#f9f7fd" footer: background: "#110a28" # Darker Deep Purple foreground: "#b8b2cc" light: # "Vaporwave" - A bright, pastel-neon day dream colors: primary: "#d946ef" # Electric Fuchsia secondary: "#06b6d4" # Neon Cyan neutral: "#701a75" # Deep Magenta (for text utilities) surfaces: background: "#fff0f5" # Lavender Blush foreground: "#2e1065" # Deep Violet Ink header: background: "#fae8ff" # Light Fuchsia Mist foreground: "#86198f" # Vibrant Purple footer: background: "#f0abfc" # Sunset Pink foreground: "#2e1065" # Dark Violet ================================================ FILE: modules/blox/go.mod ================================================ module github.com/HugoBlox/kit/modules/blox go 1.19 require github.com/HugoBlox/kit/modules/analytics v0.3.1 ================================================ FILE: modules/blox/hugo.yaml ================================================ build: buildStats: enable: true cachebusters: - source: assets/hugo_stats\.json target: css - source: (postcss|tailwind)\.config\.js target: css markup: defaultMarkdownHandler: goldmark goldmark: renderHooks: link: # Process backlinks hook useEmbedded: fallback renderer: # Render HTML in Markdown unsafe: true parser: # Support Latex math(?) attribute: block: true # For callouts as quote blocks title: true extensions: # Support Latex math passthrough: enable: true delimiters: block: - - \[ - \] - - $$ - $$ inline: - - \( - \) - - $ - $ extras: # Enable subscript, superscript, and highlighting with ~,^, and == wrappers insert: enable: false mark: enable: true subscript: enable: true superscript: enable: true highlight: # Enable code highlighting codeFences: true noHl: false lineNumbersInTable: false noClasses: false guessSyntax: true tableOfContents: startLevel: 2 endLevel: 3 minify: minifyOutput: true tdewolff: html: keepComments: true keepSpecialComments: true sitemap: changefreq: weekly security: funcs: getenv: # Allow HUGO_ and HUGO_BLOX_ vars - ^HUGO_ # Allow continuous integration vars - ^CI$ outputFormats: backlinks: mediaType: application/json baseName: backlinks isPlainText: true notAlternative: true LLM: mediaType: text/plain baseName: llms isPlainText: true notAlternative: true permalinkable: true outputs: home: - HTML - RSS - LLM imaging: # High quality defaults for crisp avatar display quality: 90 resampleFilter: lanczos anchor: smart hint: picture params: locale: date_format: 'Jan 2, 2006' time_format: '3:04 PM' address_format: en-us module: hugoVersion: min: '0.153.0' extended: true imports: - path: github.com/HugoBlox/kit/modules/analytics mounts: - source: content target: content - source: static target: static - source: layouts target: layouts - source: data target: data - source: assets target: assets - source: i18n target: i18n - source: archetypes target: archetypes - disableWatch: true source: hugo_stats.json target: assets/hugo_stats.json # BLOX A) Server-rendered block templates (Go HTML) - source: blox target: layouts/_partials/hbx/blocks files: - '**/block.html' # BLOX B) Client islands (compiled with js.Build/js.Batch) - source: blox target: assets/js/hbx/blocks files: - '**/*.js' - '**/*.ts' - '**/*.jsx' - '**/*.tsx' # BLOX C) Block-specific CSS - source: blox target: assets/css/hbx/blocks files: - '**/*.css' # BLOX D) Shared assets (optional) - source: blox/shared/js target: assets/js/hbx/shared - source: blox/shared/css target: assets/css/hbx/shared - source: blox target: assets/img/hbx/blocks files: - '**/*.png' - '**/*.jpg' - '**/*.jpeg' - '**/*.svg' - '**/*.webp' ================================================ FILE: modules/blox/i18n/ar.yaml ================================================ # Navigation - id: toggle_navigation translation: قائمة - id: table_of_contents translation: فهرس المحتويات - id: on_this_page translation: المحتويات - id: back_to_top translation: الرجوع لأعلى الصفحة - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: ذات صلة - id: minute_read translation: دقيقة قراءة - id: previous translation: السابق - id: next translation: التالي - id: figure translation: 'شكل %d:' - id: edit_page translation: عدل هذه الصفحة # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: الوضع العادي - id: theme_dark translation: الوضع الليلي - id: theme_auto translation: تلقائي # Buttons - id: btn_preprint translation: المسودة - id: btn_pdf translation: بي دي اف - id: btn_cite translation: استشهاد - id: btn_slides translation: شرائح - id: btn_video translation: فيديو - id: btn_code translation: تمريز - id: btn_dataset translation: البيانات - id: btn_project translation: مشروع - id: btn_poster translation: ملصق - id: btn_source translation: مستند أصلي - id: btn_copy translation: نسخ - id: btn_copied translation: Copied - id: btn_download translation: تحميل # About widget - id: interests translation: الإهتمامات - id: education translation: التعليم - id: user_profile_latest translation: اخر # Accomplishments widget - id: see_certificate translation: الشهادات # Experience widget - id: present translation: حتى الأن # Pages widget - id: more_pages translation: شاهد الكل - id: more_posts translation: شاهد جميع التعليقات - id: more_talks translation: شاهد جميع المحاضرات - id: more_publications translation: شاهد جميع المنشورات # Contact widget - id: contact_name translation: الأسم - id: contact_email translation: البريد الإلكتروني - id: contact_message translation: رسالة - id: contact_attachment translation: Attach file - id: contact_send translation: إرسل الرسالة - id: book_appointment translation: حجز موعد # Publication/Event details - id: abstract translation: مقدمة - id: publication translation: منشور - id: publication_type translation: نوع - id: date translation: التاريخ - id: last_updated translation: اخر تحيث في - id: event translation: حدث - id: location translation: موقع - id: pub_paper_conference translation: ورقة مؤتمر - id: pub_article_journal translation: مجلة محكمه - id: pub_article translation: مسودة - id: pub_report translation: تقرير - id: pub_book translation: كتاب - id: pub_chapter translation: قسم من كتاب - id: pub_thesis translation: أطروحة - id: pub_patent translation: براءة الإختراع # Project details - id: open_project_site translation: أذهب لموقع المشروع # Content types for default archive page titles and search results - id: posts translation: التعليقات - id: publications translation: المنشورات - id: talks translation: المحاضرات - id: projects translation: المشروعات - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: بحث - id: search_placeholder translation: ابحث هنا‫...‬ - id: search_results translation: نتائج البحث - id: search_no_results translation: لم يتم العثور على نتائج - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: الصفحة غير موجودة - id: 404_recommendations translation: هل تبحث عن أحد الصفحات التالية؟ # Cookie consent - id: cookie_message translation: هذا الموقع يستخدم ملفات تعريف الارتباط "الكوكيز" لنمنحك أفضل تجربة مستخدم ممكنة - id: cookie_dismiss translation: أوافق‫!‬ - id: cookie_learn translation: تعرف على المزيد # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/bn.yaml ================================================ # Navigation - id: toggle_navigation # Toggle navigation translation: নেভিগেশন পরিবর্তন করুন # Alternatively: নেভিগেশন টগল করুন - id: table_of_contents # Table of Contents translation: সুচিপত্র - id: on_this_page # Contents translation: বিষয়বস্তু - id: back_to_top # Back to top translation: উপরে ফিরে যান - id: home # Home translation: হোম পেজ - id: close # Close translation: বন্ধ করুন - id: languages # Languages translation: ভাষা # Alternatively: ভাষা সমূহ # General - id: related # Related translation: সংশ্লিষ্ট - id: minute_read # min read translation: মিনিটের পড়া - id: previous # Previous translation: পূর্ববর্তী - id: next # Next translation: পরবর্তী - id: figure # 'Figure %d:' translation: 'চিত্র %d:' - id: edit_page # Edit this page translation: পেজটি সম্পাদনা করুন # Themes - id: theme_selector # Display preferences translation: প্রদর্শন পছন্দসমূহ - id: theme_light # Light translation: উজ্জ্বল - id: theme_dark # Dark translation: অন্ধকার - id: theme_auto # Automatic translation: অটোমেটিক # Buttons - id: btn_preprint # Preprint translation: প্রিপ্রিন্ট - id: btn_pdf # PDF translation: পিডিএফ # Alternatively: PDF - id: btn_cite # Cite translation: উদ্ধৃত করুন - id: btn_slides # Slides translation: স্লাইড সমূহ - id: btn_video # Video translation: ভিডিও - id: btn_code # Code translation: কোড - id: btn_dataset # Dataset translation: ডেটাসেট - id: btn_project # Project translation: প্রকল্প - id: btn_poster # Poster translation: পোস্টার - id: btn_source # Source Document translation: উৎস নথি - id: btn_copy # Copy translation: কপি করুন - id: btn_copied # Copied translation: কপি করা হয়েছে - id: btn_download # Download translation: ডাউনলোড করুন # About widget - id: interests # Interests translation: আগ্রহ - id: education # Education translation: শিক্ষা - id: user_profile_latest # Latest translation: সর্বশেষ # Accomplishments widget - id: see_certificate # See certificate translation: সার্টিফিকেট দেখুন # Experience widget - id: present # Present translation: বর্তমান # Pages widget - id: more_pages # See all translation: সবগুলি দেখুন - id: more_posts # See all posts translation: সব পোস্ট দেখুন - id: more_talks # See all events translation: সব সংঘটনা দেখুন - id: more_publications # See all publications translation: সব প্রকাশনা দেখুন # Contact widget - id: contact_name # Name translation: নাম - id: contact_email # Email translation: ইমেইল - id: contact_message # Message translation: বার্তা - id: contact_attachment # Attach file translation: ফাইল সংযুক্ত করুন - id: contact_send # Send translation: পাঠান - id: book_appointment # Book an appointment translation: সাক্ষাৎকার বুক করুন # Alternatively: সাক্ষাৎকার লিপিবদ্ধ করুন # Publication/Event details - id: abstract # Abstract translation: সারাংশ - id: publication # Publication translation: প্রকাশনা - id: publication_type # Type translation: প্রকাশনার ধরন # Note: In English, it reads "Type" but is actually "Publication type". - id: date # Date translation: তারিখ - id: last_updated # Last updated on translation: 'সর্বশেষ আপডেট:' - id: event # Event translation: ঘটনা - id: location # Location translation: অবস্থান - id: pub_paper_conference # Conference paper translation: সম্মেলন নিবন্ধ - id: pub_article_journal # Journal article translation: জার্নাল নিবন্ধ - id: pub_article # Preprint translation: প্রিপ্রিন্ট - id: pub_report # Report translation: রিপোর্ট - id: pub_book # Book translation: বই # Alternatively: পুস্তক - id: pub_chapter # Book section translation: পুস্তক বিভাগ - id: pub_thesis # Thesis translation: থিসিস - id: pub_patent # Patent translation: পেটেন্ট # Project details - id: open_project_site # Go to Project Site translation: প্রকল্প সাইটে যান # Content types for default archive page titles and search results - id: posts # Posts translation: পোস্ট সমূহ - id: publications # Publications translation: প্রকাশনা সমূহ - id: talks # Events translation: ঘটনাবলী - id: projects # Projects translation: প্রকল্প সমূহ - id: slides # Slides translation: স্লাইড সমূহ - id: authors # Authors translation: লেখকগন # Search - id: search # Search translation: অনুসন্ধান - id: search_placeholder # Search... translation: অনুসন্ধান করুন... - id: search_results # results found translation: ফলাফল পাওয়া গেছে - id: search_no_results # No results found translation: কোন ফলাফল পাওয়া যায়নি - id: search_common_queries # Common searches translation: প্রচলিত অনুসন্ধান প্রশ্ন # Error 404 - id: page_not_found # Page not found translation: পেজটি খুঁজে পাওয়া যায়নি - id: 404_recommendations # Perhaps you were looking for one of these? translation: সম্ভবত আপনি এর মধ্যে একটিকে খুঁজছিলেন? # Cookie consent - id: cookie_message # This website uses cookies to ensure you get the best experience on our website. translation: আপনি যাতে এই ওয়েবসাইটে সেরা অভিজ্ঞতা পান তা নিশ্চিত করতে এই ওয়েবসাইটটি কুকিজ ব্যবহার করে। - id: cookie_dismiss # Got it! translation: বুঝেছি! - id: cookie_learn # Learn more translation: আরও জানুন # Published with - id: published_with translation: '{hugoblox}-এর সাথে প্রকাশিত – বিনামূল্যে, {repo_link}ওপেন সোর্স{/repo_link} ওয়েবসাইট নির্মাতা যা সৃজনকারীদের ক্ষমতায়ন করে।' # Contact info block - id: block_contact_follow_me translation: আমাকে খুঁজুন # Dev Hero block - id: scroll_to_content translation: কনটেন্টে স্ক্রোল করুন - id: developer translation: ডেভেলপার # Portfolio block - id: portfolio_link_code translation: কোড - id: portfolio_link_live translation: লাইভ - id: portfolio_link_demo translation: ডেমো - id: portfolio_link_default translation: লিংক - id: portfolio_view_all translation: সমস্ত প্রকল্প দেখুন # Additional translations - id: about_me translation: পেশাগত সারসংক্ষেপ - id: ai_insight translation: এআই অন্তর্দৃষ্টি - id: content_type translation: বিষয়ের ধরন - id: difficulty translation: কঠিনতা - id: prerequisites translation: পূর্বশর্ত - id: trending translation: ট্রেন্ডিং - id: article translation: প্রবন্ধ - id: articles translation: প্রবন্ধসমূহ - id: all translation: সব - id: helpful translation: সহায়ক # Buttons and links - id: btn_site translation: সাইট - id: btn_canonical translation: ক্যানোনিকাল - id: btn_crosspost translation: ক্রসপোস্ট - id: btn_discussion translation: আলোচনা - id: btn_event translation: ইভেন্ট - id: btn_calendar translation: ক্যালেন্ডার - id: btn_registration translation: নিবন্ধন - id: btn_demo translation: ডেমো - id: btn_model translation: মডেল - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_note translation: নোট - id: callout_abstract translation: সারাংশ - id: callout_summary translation: সারসংক্ষেপ - id: callout_info translation: তথ্য - id: callout_todo translation: করনীয় - id: callout_tip translation: টিপস - id: callout_question translation: প্রশ্ন - id: callout_quote translation: উদ্ধৃতি - id: callout_warning translation: সতর্কতা - id: callout_caution translation: সতর্কতা - id: callout_danger translation: বিপদ - id: callout_bug translation: বাগ - id: callout_example translation: উদাহরণ - id: callout_failure translation: ব্যর্থতা - id: callout_success translation: সাফল্য - id: callout_important translation: গুরুত্বপূর্ণ # Slides - id: back_to_slides translation: স্লাইডে ফিরে যান - id: present_slides translation: প্রেজেন্ট - id: present_fullscreen translation: প্রেজেন্ট (পূর্ণস্ক্রিন) - id: export_pdf_print translation: পিডিএফ রপ্তানি (প্রিন্ট) - id: slides_print_hint translation: প্রিন্ট মোডে খোলে - ব্রাউজার প্রিন্ট > PDF হিসেবে সেভ করুন - id: slides_search_placeholder translation: শিরোনাম দিয়ে ডেক খুঁজুন... - id: slides_no_decks translation: কোন স্লাইড ডেক পাওয়া যায়নি - id: slides_no_matches translation: কোন ডেক ফিল্টারের সাথে মেলে না - id: clear_filters translation: ফিল্টার মুছুন - id: topics translation: বিষয় - id: details translation: বিস্তারিত - id: related_resources translation: সম্পর্কিত রিসোর্স - id: copy_link translation: লিঙ্ক কপি করুন - id: copy_citation translation: উদ্ধৃতি কপি করুন - id: how_to_cite translation: কীভাবে উদ্ধৃতি দিবেন - id: citation translation: উদ্ধৃতি - id: bibtex translation: BibTeX - id: download_cite_bib translation: cite.bib ডাউনলোড করুন - id: lecture translation: লেকচার - id: enter_fullscreen translation: পূর্ণস্ক্রিনে যান - id: exit_fullscreen translation: পূর্ণস্ক্রিন থেকে বের হন - id: speaker_notes_hint translation: বক্তার নোটের জন্য - id: slides_not_found translation: স্লাইড পাওয়া যায়নি # Q&A - id: qa translation: প্রশ্নোত্তর - id: question translation: প্রশ্ন - id: answer translation: উত্তর - id: accepted_answer translation: গৃহীত উত্তর - id: other_answers translation: অন্যান্য উত্তর - id: questions translation: প্রশ্নসমূহ - id: questions_count translation: প্রশ্ন - id: related_questions translation: সম্পর্কিত প্রশ্ন - id: search_questions translation: প্রশ্ন অনুসন্ধান... - id: no_questions_yet translation: এখনও কোনো প্রশ্ন নেই - id: faq translation: FAQ - id: faqs translation: FAQs - id: browse_by_category translation: বিভাগ অনুযায়ী দেখুন # General extras - id: backlinks translation: ব্যাকলিঙ্কস - id: blog translation: ব্লগ - id: browse translation: ব্রাউজ - id: days translation: দিন - id: hours translation: ঘণ্টা - id: minutes translation: মিনিট - id: seconds translation: সেকেন্ড - id: experience translation: অভিজ্ঞতা - id: read_more translation: আরও পড়ুন - id: docs translation: ডকুমেন্টেশন - id: featured translation: বৈশিষ্ট্যযুক্ত - id: events translation: ইভেন্ট - id: poweredby_button translation: 'নিজেরটি বানান →' - id: block_contact_title translation: যোগাযোগ করুন - id: block_contact_visit_title translation: আমাদের দেখুন - id: block_contact_office_hours translation: অফিস সময় - id: block_contact_view_on_map translation: মানচিত্রে দেখুন - id: block_contact_connect_title translation: সংযুক্ত হন - id: block_contact_follow_us translation: আমাদের অনুসরণ করুন - id: block_contact_prospective_title translation: সম্ভাব্য সদস্যরা - id: block_contact_form_title translation: আমাদের বার্তা পাঠান - id: block_contact_form_name translation: নাম - id: block_contact_form_email translation: ইমেইল - id: block_contact_form_subject translation: বিষয় - id: block_contact_form_message translation: বার্তা - id: block_contact_form_submit translation: বার্তা পাঠান # Feedback widget - id: feedback_widget_title translation: মতামত - id: feedback_widget_question translation: এই পেজটি কি সহায়ক ছিল? - id: feedback_widget_answer_positive translation: 😍 হ্যাঁ - id: feedback_widget_answer_negative translation: 😡 না ================================================ FILE: modules/blox/i18n/ca.yaml ================================================ # Navigation - id: toggle_navigation translation: Barra de navegació - id: table_of_contents translation: Index - id: on_this_page translation: On this page - id: back_to_top translation: Back to top - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Relacionat - id: minute_read translation: min de lectura - id: previous translation: Anterior - id: next translation: Següent - id: figure translation: 'Figura %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preimpresió - id: btn_pdf translation: PDF - id: btn_cite translation: Cita - id: btn_slides translation: Diapositives - id: btn_video translation: Vídeo - id: btn_code translation: Códi - id: btn_dataset translation: Dades - id: btn_project translation: Projecte - id: btn_poster translation: Poster - id: btn_source translation: Font - id: btn_copy translation: Copia - id: btn_copied translation: Copied - id: btn_download translation: Baixa # About widget - id: interests translation: Interessos - id: education translation: Educació - id: user_profile_latest translation: Latest # Accomplishments widget - id: see_certificate translation: See certificate # Experience widget - id: present translation: Present # Pages widget - id: more_pages translation: See all - id: more_posts translation: Més entrades - id: more_talks translation: Més xerrades - id: more_publications translation: Més publicacions # Contact widget - id: contact_name translation: Nom - id: contact_email translation: Email - id: contact_message translation: Missatge - id: contact_attachment translation: Adjunt - id: contact_send translation: Enviar - id: book_appointment translation: Book an appointment # Publication/Event details - id: abstract translation: Resum - id: publication translation: Publicació - id: publication_type translation: Tipus - id: date translation: Data - id: last_updated translation: Última actualizació el - id: event translation: Event - id: location translation: Ubicació - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Book - id: pub_chapter translation: Book section - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Obre el lloc del web del projecte # Content types for default archive page titles and search results - id: posts translation: Entrada - id: publications translation: Publicació - id: talks translation: Conferència - id: projects translation: Projectes - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Search - id: search_placeholder translation: Search... - id: search_results translation: results found - id: search_no_results translation: No results found - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: No s'ha trobat la pàgina - id: 404_recommendations translation: Buscaves alguna d'aquestes? # Cookie consent - id: cookie_message translation: Aquet lloc web fa servir cookies per garantitzar una millor experiència. - id: cookie_dismiss translation: D'acord - id: cookie_learn translation: Més informació # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/cs.yaml ================================================ # Navigation - id: toggle_navigation translation: Přepnout navigaci - id: table_of_contents translation: Obsah - id: on_this_page translation: Na stránce - id: back_to_top translation: Nahoru - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Související - id: minute_read translation: min čtení - id: previous translation: Předchozí - id: next translation: Další - id: figure translation: 'Obrázek %d:' - id: edit_page translation: Upravit stránku # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Tisk - id: btn_pdf translation: PDF - id: btn_cite translation: Citace - id: btn_slides translation: Slidy - id: btn_video translation: Video - id: btn_code translation: Kód - id: btn_dataset translation: Dataset - id: btn_project translation: Projekt - id: btn_poster translation: Plakát - id: btn_source translation: Zdrojový dokument - id: btn_copy translation: Kopírovat - id: btn_copied translation: Copied - id: btn_download translation: Stáhnout # About widget - id: interests translation: Zájmy - id: education translation: Vzdělání - id: user_profile_latest translation: Nejnověší # Accomplishments widget - id: see_certificate translation: Stáhnout # Experience widget - id: present translation: Aktuální # Pages widget - id: more_pages translation: Zobrazit všechny - id: more_posts translation: Zobrazit všechny aktuality - id: more_talks translation: Zobrazit všechny přednášky - id: more_publications translation: Zobrazit všechny publikace # Contact widget - id: contact_name translation: Jméno - id: contact_email translation: Email - id: contact_message translation: Zpráva - id: contact_attachment translation: Attach file - id: contact_send translation: Poslat - id: book_appointment translation: Rezervovat schůzku # Publication/Event details - id: abstract translation: Abstrakt - id: publication translation: Publikace - id: publication_type translation: Typ - id: date translation: Datum - id: last_updated translation: Naposledy aktualizováno dne - id: event translation: Událost - id: location translation: Místo - id: pub_paper_conference translation: Materiál ke konferenci - id: pub_article_journal translation: Článek v žurnálu - id: pub_article translation: Tisk předem - id: pub_report translation: Správa - id: pub_book translation: Kniha - id: pub_chapter translation: Sekce knihy - id: pub_thesis translation: Diplomová práce - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Na stánku projektu # Content types for default archive page titles and search results - id: posts translation: Aktuality - id: publications translation: Publikace - id: talks translation: Přednášky - id: projects translation: Projekty - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Hledání - id: search_placeholder translation: Hledání... - id: search_results translation: nalezených výsledků - id: search_no_results translation: Nic nelalezeno - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Stránka neexistuje - id: 404_recommendations translation: Nehledáte náhodou jednu z těchto stránek? # Cookie consent - id: cookie_message translation: Tyto stránky používají cookies k zajištění co možná nejlepší zkušenosti na našem webu. - id: cookie_dismiss translation: Rozumím! - id: cookie_learn translation: Zjistit více # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/da.yaml ================================================ # Navigation - id: toggle_navigation translation: Vis/skjul navigation - id: table_of_contents translation: Indholdsfortegnelse - id: on_this_page translation: På denne side - id: back_to_top translation: Til toppen - id: home translation: Hjem - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Relaterede - id: minute_read translation: min læsning - id: previous translation: Forrige - id: next translation: Næste - id: figure translation: 'Figur %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Eksempel - id: btn_pdf translation: PDF - id: btn_cite translation: Citer - id: btn_slides translation: Præsentation - id: btn_video translation: Video - id: btn_code translation: Kode - id: btn_dataset translation: Datasæt - id: btn_project translation: Projekt - id: btn_poster translation: Plakat - id: btn_source translation: Kilde kode - id: btn_copy translation: Kopier - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: Interesser - id: education translation: Uddannelse - id: user_profile_latest translation: Seneste # Accomplishments widget - id: see_certificate translation: Certifikat # Experience widget - id: present translation: Nuværende # Pages widget - id: more_pages translation: Se alle - id: more_posts translation: Se alle indlæg - id: more_talks translation: Se alle foredrag - id: more_publications translation: Se alle udgivelser # Contact widget - id: contact_name translation: Navn - id: contact_email translation: Email - id: contact_message translation: Besked - id: contact_attachment translation: Attach file - id: contact_send translation: Send - id: book_appointment translation: Reserver en aftale # Publication/Event details - id: abstract translation: Abstrakt - id: publication translation: Udgivelse - id: publication_type translation: Type - id: date translation: Dato - id: last_updated translation: Sidst opdateret - id: event translation: Begivenhed - id: location translation: Lokation - id: pub_paper_conference translation: Konference artikel - id: pub_article_journal translation: Videnskablig artikel - id: pub_article translation: Preprint - id: pub_report translation: Rapport - id: pub_book translation: Bog - id: pub_chapter translation: Bøger - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Gå til projekt side # Content types for default archive page titles and search results - id: posts translation: Indlæg - id: publications translation: Udgivelser - id: talks translation: Foredrag - id: projects translation: Projekter - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Søg - id: search_placeholder translation: Søg... - id: search_results translation: resultater fundet - id: search_no_results translation: Ingen resultater fundet - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Side blev ikke fundet - id: 404_recommendations translation: Måske du ledte efter dette? # Cookie consent - id: cookie_message translation: Denne side benytter cookies for at sikre den bedste oplevelse. - id: cookie_dismiss translation: Accepter - id: cookie_learn translation: Læs mere # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/de.yaml ================================================ # Navigation - id: toggle_navigation translation: Navigation einblenden - id: table_of_contents translation: Inhaltsverzeichnis - id: on_this_page translation: Auf dieser Seite - id: back_to_top translation: Zurück zum Anfang - id: home translation: Home - id: close translation: Schließen - id: languages translation: Sprachen # General - id: related translation: Ähnliches # Callouts - id: callout_note translation: Hinweis - id: callout_tip translation: Tipp - id: callout_important translation: Wichtig - id: callout_warning translation: Warnung - id: callout_caution translation: Vorsicht - id: backlinks translation: Backlinks - id: minute_read translation: Min Lesezeit - id: previous translation: Zurück - id: next translation: Weiter - id: figure translation: 'Abbildung %d:' - id: edit_page translation: Seite bearbeiten # Themes - id: theme_selector translation: Einstellungen anzeigen - id: theme_light translation: Hell - id: theme_dark translation: Dunkel - id: theme_auto translation: Automatisch # Buttons - id: btn_preprint translation: Vorabdruck - id: btn_pdf translation: PDF - id: btn_cite translation: Zitieren - id: btn_slides translation: Folien - id: btn_video translation: Video - id: btn_code translation: Code - id: btn_dataset translation: Datensatz - id: btn_project translation: Projekt - id: btn_poster translation: Poster - id: btn_source translation: Quelldokument - id: btn_copy translation: Kopie - id: btn_copied translation: Kopiert - id: btn_download translation: Download # About widget - id: interests translation: Interessen - id: education translation: Bildung - id: user_profile_latest translation: Aktuellste # Countdown widget - id: days translation: Tage - id: hours translation: Stunden - id: minutes translation: Minuten - id: seconds translation: Sekunden # Accomplishments widget - id: see_certificate translation: Zertifikat anzeigen # Experience widget - id: experience translation: Erfahrung - id: present translation: Aktuell # Pages widget - id: read_more translation: Mehr lesen - id: more_pages translation: Alle anzeigen - id: more_posts translation: Weitere Blogbeiträge - id: more_talks translation: Weitere Vorträge - id: more_publications translation: Weitere Publikationen # Contact widget - id: contact_name translation: Name - id: contact_email translation: E-Mail - id: contact_message translation: Nachricht - id: contact_attachment translation: Anhang - id: contact_send translation: Senden - id: book_appointment translation: Termin vereinbaren # Contact info block - id: block_contact_title translation: Kontaktieren Sie uns - id: block_contact_visit_title translation: Besuchen Sie uns - id: block_contact_office_hours translation: Öffnungszeiten - id: block_contact_view_on_map translation: Auf der Karte ansehen - id: block_contact_connect_title translation: Kontakt - id: block_contact_follow_us translation: Folgen Sie uns - id: block_contact_prospective_title translation: Potenzielle Mitglieder - id: block_contact_form_title translation: Senden Sie uns eine Nachricht - id: block_contact_form_name translation: Name - id: block_contact_form_email translation: E-Mail - id: block_contact_form_subject translation: Betreff - id: block_contact_form_message translation: Nachricht - id: block_contact_form_submit translation: Nachricht senden # Publication/Event details - id: abstract translation: Zusammenfassung - id: publication translation: Publikation - id: publication_type translation: Typ - id: date translation: Datum - id: last_updated translation: Zuletzt aktualisiert am - id: event translation: Veranstaltung - id: location translation: Ort - id: pub_paper_conference translation: Konferenzpapier - id: pub_article_journal translation: Journalartikel - id: pub_article translation: Vordruck - id: pub_report translation: Bericht - id: pub_book translation: Buch - id: pub_chapter translation: Buchkapitel - id: pub_thesis translation: Abschlussarbeit - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Zur Projektseite # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publikationen - id: events translation: Veranstaltungen - id: projects translation: Projekte - id: slides translation: Slides - id: authors translation: Autoren # Search - id: search translation: Suche - id: search_placeholder translation: Suche... - id: search_results translation: Suchergebnisse - id: search_no_results translation: Nichts gefunden - id: search_common_queries translation: Allgemeine Suche # Error 404 - id: page_not_found translation: Seite nicht gefunden - id: 404_recommendations translation: Suchen Sie vielleicht nach einer der folgenden Seiten? # Cookie consent - id: cookie_message translation: Um unsere Webseite für Sie passend zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. - id: cookie_dismiss translation: Verstanden! - id: cookie_learn translation: Mehr erfahren # Published with - id: published_with translation: Veröffentlicht mit {hugoblox} - dem kostenlosen, {repo_link}Open Source{/repo_link} Website-Builder, der Kreative fördert. - id: poweredby_button translation: 'Erstelle deine →' # Contact info block - id: block_contact_follow_me translation: Finde mich auf # Dev Hero block - id: scroll_to_content translation: Zum Inhalt scrollen - id: developer translation: Entwickler # Portfolio block - id: portfolio_link_code translation: Code - id: portfolio_link_live translation: Live - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Link - id: portfolio_view_all translation: Alle Projekte anzeigen # Feedback widget - id: feedback_widget_title translation: Feedback - id: feedback_widget_question translation: War diese Seite hilfreich? - id: feedback_widget_answer_positive translation: 😍 Ja - id: feedback_widget_answer_negative translation: 😡 Nein # AI Features - id: ai_insight translation: KI-Einblick # Content Metadata - id: content_type translation: Inhaltstyp - id: difficulty translation: Schwierigkeitsgrad - id: prerequisites translation: Voraussetzungen # Card metadata - id: trending translation: Im Trend - id: article translation: Artikel - id: articles translation: Artikel - id: browse translation: Durchsuchen - id: all translation: Alle - id: helpful translation: hilfreich # Additional buttons - id: btn_site translation: Website - id: btn_canonical translation: Kanonisch - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Diskussion - id: btn_event translation: Event - id: btn_calendar translation: Kalender - id: btn_registration translation: Anmeldung - id: btn_demo translation: Demo - id: btn_model translation: Modell - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_abstract translation: Abstract - id: callout_summary translation: Zusammenfassung - id: callout_info translation: Info - id: callout_todo translation: To-do - id: callout_tip translation: Tipp - id: callout_question translation: Frage - id: callout_quote translation: Zitat - id: callout_warning translation: Warnung - id: callout_danger translation: Gefahr - id: callout_bug translation: Bug - id: callout_example translation: Beispiel - id: callout_failure translation: Fehlschlag - id: callout_success translation: Erfolg # Slides - id: back_to_slides translation: Zurück zu Slides - id: present_slides translation: Präsentieren - id: present_fullscreen translation: Präsentieren (Vollbild) - id: export_pdf_print translation: PDF exportieren (Druck) - id: slides_print_hint translation: Öffnet im Druckmodus – Browser Drucken > Als PDF speichern - id: slides_search_placeholder translation: Decks nach Titel suchen... - id: slides_no_decks translation: Keine Foliensätze gefunden - id: slides_no_matches translation: Keine Sätze entsprechen deinen Filtern - id: clear_filters translation: Filter zurücksetzen - id: topics translation: Themen - id: details translation: Details - id: related_resources translation: Verwandte Ressourcen - id: copy_link translation: Link kopieren - id: copy_citation translation: Zitat kopieren - id: how_to_cite translation: So zitieren - id: citation translation: Zitat - id: bibtex translation: BibTeX - id: download_cite_bib translation: cite.bib herunterladen - id: lecture translation: Vorlesung - id: enter_fullscreen translation: Vollbildmodus starten - id: exit_fullscreen translation: Vollbildmodus beenden - id: speaker_notes_hint translation: für Sprechernotizen - id: slides_not_found translation: Folien nicht gefunden # Q&A - id: qa translation: Q&A - id: question translation: Frage - id: answer translation: Antwort - id: accepted_answer translation: Akzeptierte Antwort - id: other_answers translation: Weitere Antworten - id: questions translation: Fragen - id: questions_count translation: Fragen - id: related_questions translation: Ähnliche Fragen - id: search_questions translation: Fragen durchsuchen... - id: no_questions_yet translation: Noch keine Fragen vorhanden - id: faq translation: FAQ - id: faqs translation: FAQs - id: browse_by_category translation: Nach Kategorie durchsuchen # General extras - id: about_me translation: Berufliches Profil - id: docs translation: Dokumentation - id: featured translation: Empfohlen ================================================ FILE: modules/blox/i18n/el.yaml ================================================ # Navigation - id: toggle_navigation translation: Εναλλαγή πλοήγησης - id: table_of_contents translation: Πίνακας περιεχομένων - id: on_this_page translation: On this page - id: back_to_top translation: Back to top - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Σχετικά - id: minute_read translation: λεπτά διαβάσματος - id: previous translation: Προηγούμενο - id: next translation: Επόμενο - id: figure translation: 'Figure %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Προ-δημοσίευση - id: btn_pdf translation: PDF - id: btn_cite translation: Βιβλιογραφική αναφορά - id: btn_slides translation: Διαφάνεια - id: btn_video translation: Βίντεο - id: btn_code translation: Κώδικας - id: btn_dataset translation: Δεδομένα - id: btn_project translation: Ερευνητικό πρόγραμμα - id: btn_poster translation: Ανακοίνωση συνεδρίου - id: btn_source translation: Πηγαίος κώδικας - id: btn_copy translation: Αντιγραφή - id: btn_copied translation: Copied - id: btn_download translation: Λήψη # About widget - id: interests translation: Ενδιαφέροντα - id: education translation: Εκπαίδευση - id: user_profile_latest translation: Latest # Accomplishments widget - id: see_certificate translation: See certificate # Experience widget - id: present translation: Present # Pages widget - id: more_pages translation: See all - id: more_posts translation: Περισσότερες αναρτήσεις - id: more_talks translation: Περισσότερες ομιλίες - id: more_publications translation: Περισσότερες δημοσιεύσεις # Contact widget - id: contact_name translation: Name - id: contact_email translation: Email - id: contact_message translation: Message - id: contact_attachment translation: Attach file - id: contact_send translation: Send - id: book_appointment translation: Book an appointment # Publication/Event details - id: abstract translation: Περίληψη - id: publication translation: Δημοσίευση - id: publication_type translation: Τύπος - id: date translation: Ημερομηνία - id: last_updated translation: Τελευταία ενημέρωση - id: event translation: Συμβάν - id: location translation: Τοποθεσία - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Book - id: pub_chapter translation: Book section - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Προς ιστοσελίδα ερευνητικού προγράμματος # Content types for default archive page titles and search results - id: posts translation: Αναρτήσεις - id: publications translation: Δημοσιεύσεις - id: talks translation: Ομιλίες - id: projects translation: Ερευνητικά προγράμματα - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Search - id: search_placeholder translation: Search... - id: search_results translation: results found - id: search_no_results translation: No results found - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Η ιστοσελίδα δεν βρέθηκε - id: 404_recommendations translation: Μήπως ψάχνατε για μια από αυτές; # Cookie consent - id: cookie_message translation: This website uses cookies to ensure you get the best experience on our website. - id: cookie_dismiss translation: Got it! - id: cookie_learn translation: Learn more # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/en.yaml ================================================ # Navigation - id: toggle_navigation translation: Toggle navigation - id: table_of_contents translation: Table of Contents - id: on_this_page translation: On this page - id: back_to_top translation: Back to top - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Related # Callouts - All Obsidian-compatible types - id: callout_note translation: Note - id: callout_abstract translation: Abstract - id: callout_summary translation: Summary - id: callout_info translation: Info - id: callout_todo translation: Todo - id: callout_tip translation: Tip - id: callout_success translation: Success - id: callout_question translation: Question - id: callout_warning translation: Warning - id: callout_failure translation: Failure - id: callout_danger translation: Danger - id: callout_bug translation: Bug - id: callout_example translation: Example - id: callout_quote translation: Quote - id: callout_important translation: Important - id: callout_caution translation: Caution - id: backlinks translation: Backlinks - id: minute_read translation: min read - id: previous translation: Previous - id: next translation: Next - id: figure translation: 'Figure %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Cite - id: btn_slides translation: Slides - id: btn_video translation: Video - id: btn_code translation: Code - id: btn_dataset translation: Dataset - id: btn_project translation: Project - id: btn_poster translation: Poster - id: btn_source translation: Source Document # New link types - id: btn_doi translation: DOI - id: btn_site translation: Site - id: btn_canonical translation: Canonical - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Discussion - id: btn_event translation: Event - id: btn_calendar translation: Calendar - id: btn_registration translation: Registration - id: btn_demo translation: Demo - id: btn_model translation: Model - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code - id: btn_copy translation: Copy - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: Interests - id: education translation: Education - id: about_me translation: Professional Summary - id: user_profile_latest translation: Latest # Countdown widget - id: days translation: Days - id: hours translation: Hours - id: minutes translation: Minutes - id: seconds translation: Seconds # Accomplishments widget - id: see_certificate translation: See certificate # Experience widget - id: experience translation: Experience - id: present translation: Present # Pages widget - id: read_more translation: Read more - id: more_pages translation: See all - id: more_posts translation: See all posts - id: more_talks translation: See all events - id: more_publications translation: See all publications # Contact widget - id: contact_name translation: Name - id: contact_email translation: Email - id: contact_message translation: Message - id: contact_attachment translation: Attach file - id: contact_send translation: Send - id: book_appointment translation: Book an appointment # Contact info block - id: block_contact_title translation: Contact Us - id: block_contact_visit_title translation: Visit Us - id: block_contact_office_hours translation: Office Hours - id: block_contact_view_on_map translation: View on Map - id: block_contact_connect_title translation: Connect - id: block_contact_follow_us translation: Follow Us - id: block_contact_follow_me translation: Find me on - id: block_contact_prospective_title translation: Prospective Members - id: block_contact_form_title translation: Send us a Message - id: block_contact_form_name translation: Name - id: block_contact_form_email translation: Email - id: block_contact_form_subject translation: Subject - id: block_contact_form_message translation: Message - id: block_contact_form_submit translation: Send Message # Publication/Event details - id: abstract translation: Abstract - id: publication translation: Publication - id: publication_type translation: Type - id: date translation: Date - id: last_updated translation: Last updated on - id: event translation: Event - id: location translation: Location - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Book - id: pub_chapter translation: Book section - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Go to Project Site # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publications - id: events translation: Events - id: projects translation: Projects - id: slides translation: Slides - id: authors translation: Authors - id: qa translation: Q&A - id: questions translation: Questions - id: faq translation: FAQ - id: faqs translation: FAQs - id: docs translation: Documentation - id: question translation: Question - id: answer translation: Answer - id: accepted_answer translation: Accepted Answer - id: other_answers translation: Other Answers - id: related_questions translation: Related Questions - id: browse_by_category translation: Browse by Category - id: search_questions translation: Search questions... - id: no_questions_yet translation: No questions yet. Check back soon! - id: questions_count translation: questions # Slides - id: back_to_slides translation: Back to Slides - id: featured translation: Featured - id: details translation: Details - id: present_slides translation: Present - id: present_fullscreen translation: Present (fullscreen) - id: export_pdf_print translation: Export PDF (print) - id: slides_print_hint translation: Opens in print mode - use browser Print > Save as PDF - id: slides_search_placeholder translation: Search decks by title... - id: slides_no_decks translation: No slide decks found - id: slides_no_matches translation: No decks match your filters - id: clear_filters translation: Clear filters - id: topics translation: Topics - id: related_resources translation: Related Resources - id: copy_link translation: Copy Link - id: copy_citation translation: Copy citation - id: how_to_cite translation: How to cite - id: citation translation: Citation - id: bibtex translation: BibTeX - id: download_cite_bib translation: Download cite.bib - id: lecture translation: Lecture - id: enter_fullscreen translation: Enter fullscreen - id: exit_fullscreen translation: Exit fullscreen - id: speaker_notes_hint translation: for speaker notes - id: slides_not_found translation: Slides not found # Search - id: search translation: Search - id: search_placeholder translation: Search... - id: search_results translation: results found - id: search_no_results translation: No results found - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Page not found - id: 404_recommendations translation: Perhaps you were looking for one of these? # Cookie consent - id: cookie_message translation: This website uses cookies to ensure you get the best experience on our website. - id: cookie_dismiss translation: Got it! - id: cookie_learn translation: Learn more # Published with - id: published_with translation: Made with {hugoblox}. - id: poweredby_button translation: 'Build yours →' # Dev Hero block - id: scroll_to_content translation: Scroll to content - id: developer translation: Developer # Portfolio block - id: portfolio_link_code translation: Code - id: portfolio_link_live translation: Live - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Link - id: portfolio_view_all translation: View All Projects # Feedback widget - id: feedback_widget_title translation: Feedback - id: feedback_widget_question translation: Was this page helpful? - id: feedback_widget_answer_positive translation: 😍 Yes - id: feedback_widget_answer_negative translation: 😡 No # AI Features - id: ai_insight translation: AI Insight # Content Metadata - id: content_type translation: Content Type - id: difficulty translation: Difficulty - id: prerequisites translation: Prerequisites # Card metadata - id: trending translation: Trending - id: article translation: article - id: articles translation: articles - id: browse translation: Browse - id: all translation: All - id: helpful translation: helpful ================================================ FILE: modules/blox/i18n/es.yaml ================================================ # Navigation - id: toggle_navigation translation: Barra de navegación - id: table_of_contents translation: Índice - id: on_this_page translation: En esta página - id: back_to_top translation: Regreso al inicio - id: home translation: Inicio - id: close translation: Cerrar - id: languages translation: Idiomas # General - id: related translation: Relacionado # Callouts - All Obsidian-compatible types - id: callout_note translation: Nota - id: callout_abstract translation: Resumen - id: callout_summary translation: Resumen - id: callout_info translation: Info - id: callout_todo translation: Pendiente - id: callout_tip translation: Consejo - id: callout_success translation: Éxito - id: callout_question translation: Pregunta - id: callout_warning translation: Advertencia - id: callout_failure translation: Fallo - id: callout_danger translation: Peligro - id: callout_bug translation: Error - id: callout_example translation: Ejemplo - id: callout_quote translation: Cita - id: callout_important translation: Importante - id: callout_caution translation: Precaución - id: minute_read translation: min de lectura - id: previous translation: Anterior - id: next translation: Siguiente - id: figure translation: 'Figura %d:' - id: edit_page translation: Edita esta página # Themes - id: theme_selector translation: Mostrar preferencias - id: theme_light translation: Claro - id: theme_dark translation: Oscuro - id: theme_auto translation: Automático # Buttons - id: btn_preprint translation: Prepublicación - id: btn_pdf translation: PDF - id: btn_cite translation: Citar - id: btn_slides translation: Diapositivas - id: btn_video translation: Vídeo - id: btn_code translation: Código fuente - id: btn_dataset translation: Datos - id: btn_project translation: Proyecto - id: btn_poster translation: Poster - id: btn_source translation: Documento fuente - id: btn_copy translation: Copiar - id: btn_copied translation: Copied - id: btn_download translation: Descargar # About widget - id: interests translation: Intereses - id: education translation: Educación - id: user_profile_latest translation: Recientes # Accomplishments widget - id: see_certificate translation: Ver certificado # Experience widget - id: present translation: Actualmente # Pages widget - id: more_pages translation: Ver todo - id: more_posts translation: Más posts - id: more_talks translation: Más eventos - id: more_publications translation: Más publicaciones # Contact widget - id: contact_name translation: Nombre - id: contact_email translation: Email - id: contact_message translation: Mensaje - id: contact_attachment translation: Adjunto - id: contact_send translation: Enviar - id: book_appointment translation: Solicitar una cita # Contact info block - id: block_contact_title translation: Contáctanos - id: block_contact_visit_title translation: Visítanos - id: block_contact_office_hours translation: Horario de atención - id: block_contact_view_on_map translation: Ver en el mapa - id: block_contact_connect_title translation: Contacto - id: block_contact_follow_us translation: Síguenos - id: block_contact_prospective_title translation: Miembros potenciales - id: block_contact_form_title translation: Envíanos un mensaje - id: block_contact_form_name translation: Nombre - id: block_contact_form_email translation: Email - id: block_contact_form_subject translation: Asunto - id: block_contact_form_message translation: Mensaje - id: block_contact_form_submit translation: Enviar mensaje # Publication/Event details - id: abstract translation: Resumen - id: publication translation: Publicación - id: publication_type translation: Tipo - id: date translation: Fecha - id: last_updated translation: Última actualización el - id: event translation: Evento - id: location translation: Localización - id: pub_paper_conference translation: Artículo de conferencia - id: pub_article_journal translation: Artículo de revista - id: pub_article translation: Prepublicación - id: pub_report translation: Informe - id: pub_book translation: Libro - id: pub_chapter translation: Capítulo de libro - id: pub_thesis translation: Tesis - id: pub_patent translation: Patente # Project details - id: open_project_site translation: Ir al sitio del proyecto # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publicaciones - id: events translation: Eventos - id: projects translation: Proyectos - id: slides translation: Diapositivas - id: authors translation: Autores # Search - id: search translation: Buscar - id: search_placeholder translation: Buscar... - id: search_results translation: resultados encontrados - id: search_no_results translation: No se encontraron resultados - id: search_common_queries translation: Búsquedas comunes # Error 404 - id: page_not_found translation: Página no encontrada - id: 404_recommendations translation: ¿Buscabas una de éstas? # Cookie consent - id: cookie_message translation: Este sitio web utiliza cookies para garantizarle una mejor experiencia. - id: cookie_dismiss translation: Entendido! - id: cookie_learn translation: Más información # Published with - id: published_with translation: Made with {hugoblox}. - id: poweredby_button translation: 'Crea el tuyo →' # AI Features - id: ai_insight translation: Perspectiva de IA # Content Metadata - id: content_type translation: Tipo de contenido - id: difficulty translation: Dificultad - id: prerequisites translation: Requisitos previos # Card metadata - id: trending translation: Tendencia - id: article translation: artículo - id: articles translation: artículos - id: browse translation: Explorar - id: all translation: Todo - id: helpful translation: útil # Additional buttons - id: btn_site translation: Sitio - id: btn_canonical translation: Canónico - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Discusión - id: btn_event translation: Evento - id: btn_calendar translation: Calendario - id: btn_registration translation: Registro - id: btn_demo translation: Demo - id: btn_model translation: Modelo - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_abstract translation: Resumen - id: callout_summary translation: Resumen - id: callout_info translation: Info - id: callout_todo translation: Tareas - id: callout_tip translation: Consejo - id: callout_question translation: Pregunta - id: callout_quote translation: Cita - id: callout_warning translation: Advertencia - id: callout_danger translation: Peligro - id: callout_bug translation: Error - id: callout_example translation: Ejemplo - id: callout_failure translation: Fallo - id: callout_success translation: Éxito # Slides - id: back_to_slides translation: Volver a diapositivas - id: present_slides translation: Presentar - id: present_fullscreen translation: Presentar (pantalla completa) - id: export_pdf_print translation: Exportar PDF (impresión) - id: slides_print_hint translation: Se abre en modo impresión - usa Imprimir > Guardar como PDF - id: slides_search_placeholder translation: Busca mazos por título... - id: slides_no_decks translation: No se encontraron diapositivas - id: slides_no_matches translation: Ningún mazo coincide con tus filtros - id: clear_filters translation: Borrar filtros - id: topics translation: Temas - id: details translation: Detalles - id: related_resources translation: Recursos relacionados - id: copy_link translation: Copiar enlace - id: copy_citation translation: Copiar cita - id: how_to_cite translation: Cómo citar - id: citation translation: Cita - id: bibtex translation: BibTeX - id: download_cite_bib translation: Descargar cite.bib - id: lecture translation: Clase - id: enter_fullscreen translation: Entrar en pantalla completa - id: exit_fullscreen translation: Salir de pantalla completa - id: speaker_notes_hint translation: para notas del presentador - id: slides_not_found translation: Diapositivas no encontradas # Q&A - id: qa translation: Preguntas y respuestas - id: question translation: Pregunta - id: answer translation: Respuesta - id: accepted_answer translation: Respuesta aceptada - id: other_answers translation: Otras respuestas - id: questions translation: Preguntas - id: questions_count translation: preguntas - id: related_questions translation: Preguntas relacionadas - id: search_questions translation: Buscar preguntas... - id: no_questions_yet translation: Aún no hay preguntas - id: faq translation: FAQ - id: faqs translation: FAQs - id: browse_by_category translation: Navegar por categoría # General extras - id: about_me translation: Resumen profesional - id: backlinks translation: Enlaces de retorno - id: days translation: Días - id: hours translation: Horas - id: minutes translation: Minutos - id: seconds translation: Segundos - id: developer translation: Desarrollador - id: docs translation: Documentación - id: experience translation: Experiencia - id: read_more translation: Leer más - id: featured translation: Destacado - id: block_contact_follow_me translation: Encuéntrame en - id: portfolio_link_code translation: Código - id: portfolio_link_live translation: En vivo - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Enlace - id: portfolio_view_all translation: Ver todos los proyectos - id: scroll_to_content translation: Ir al contenido - id: feedback_widget_title translation: Comentarios - id: feedback_widget_question translation: ¿Esta página fue útil? - id: feedback_widget_answer_positive translation: 😍 Sí - id: feedback_widget_answer_negative translation: 😡 No ================================================ FILE: modules/blox/i18n/et.yaml ================================================ # Navigation - id: toggle_navigation translation: Näita menüüd - id: table_of_contents translation: Sisukord - id: on_this_page translation: Sellel lehel - id: back_to_top translation: Lehe algusse - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Vaata ka - id: minute_read translation: min lugemine - id: previous translation: Tagasi - id: next translation: Edasi - id: figure translation: 'Kujutis %d:' - id: edit_page translation: Muuda seda lehte # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Eeltrükk - id: btn_pdf translation: PDF - id: btn_cite translation: Tsiteeri - id: btn_slides translation: Slaidid - id: btn_video translation: Video - id: btn_code translation: Lähtekood - id: btn_dataset translation: Lähteandmed - id: btn_project translation: Projekt - id: btn_poster translation: Poster - id: btn_source translation: Algdokument - id: btn_copy translation: Koopia - id: btn_copied translation: Copied - id: btn_download translation: Laadi alla # About widget - id: interests translation: Huvid - id: education translation: Haridus - id: user_profile_latest translation: Värske # Accomplishments widget - id: see_certificate translation: Vaata serti # Experience widget - id: present translation: Praegu # Pages widget - id: more_pages translation: Näita kõiki - id: more_posts translation: Näita kõiki postitusi - id: more_talks translation: Näita kõiki esinemisi - id: more_publications translation: Näita kõiki väljaandeid # Contact widget - id: contact_name translation: Nimi - id: contact_email translation: Meil - id: contact_message translation: Sõnum - id: contact_attachment translation: Attach file - id: contact_send translation: Saada - id: book_appointment translation: Lepi kohtumine # Publication/Event details - id: abstract translation: Kokkuvõte - id: publication translation: Väljaanne - id: publication_type translation: Tüüp - id: date translation: Kuupäev - id: last_updated translation: Viimati uuendatud - id: event translation: Sündmus - id: location translation: Asukoht - id: pub_paper_conference translation: Ettekanne - id: pub_article_journal translation: Artikkel - id: pub_article translation: Eeltrükk - id: pub_report translation: Raport - id: pub_book translation: Raamat - id: pub_chapter translation: Peatükk - id: pub_thesis translation: Väitekiri - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Mine projektilehele # Content types for default archive page titles and search results - id: posts translation: Blogi - id: publications translation: Publikatsioonid - id: talks translation: Esinemised - id: projects translation: Projektid - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Otsing - id: search_placeholder translation: Otsimine... - id: search_results translation: tulemust - id: search_no_results translation: Tulemusi pole - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Lehekülge ei leitud - id: 404_recommendations translation: Äkki mõni neist aitab edasi? # Cookie consent - id: cookie_message translation: See veebisait kasutab küpsiseid, et pakkuda sulle isikustatud lehitsemiskogemust. - id: cookie_dismiss translation: Selge! - id: cookie_learn translation: Täpsemalt # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/eu.yaml ================================================ # Navigation - id: toggle_navigation translation: Nabigazio-barra - id: table_of_contents translation: Aurkibidea - id: on_this_page translation: Orrialde honetan - id: back_to_top translation: Hasierara itzuli - id: home translation: Hasiera - id: close translation: Itxi - id: languages translation: Hizkuntzak # General - id: related translation: Erlazionatuta - id: minute_read translation: minutuko irakurketa - id: previous translation: Aurrekoa - id: next translation: Hurrengoa - id: figure translation: 'Figura %d:' - id: edit_page translation: Orrialde hau editatu # Themes - id: theme_selector translation: Bistaratze lehentasunak - id: theme_light translation: Argia - id: theme_dark translation: Iluna - id: theme_auto translation: Automatikoa # Buttons - id: btn_preprint translation: Aurreargitalpena - id: btn_pdf translation: PDF - id: btn_cite translation: Aipuak - id: btn_slides translation: Diapositibak - id: btn_video translation: Bideoa - id: btn_code translation: Kodea - id: btn_dataset translation: Datu-sorta - id: btn_project translation: Proiektua - id: btn_poster translation: Posterra - id: btn_source translation: Jatorrizko dokumentua - id: btn_copy translation: Kopiatu - id: btn_copied translation: Copied - id: btn_download translation: Deskargatu # About widget - id: interests translation: Interesak - id: education translation: Ikasketak - id: user_profile_latest translation: Berriak # Accomplishments widget - id: see_certificate translation: Ikusi ziurtagiria # Experience widget - id: present translation: Gaur egun # Pages widget - id: more_pages translation: Ikusi dena - id: more_posts translation: Post gehiago - id: more_talks translation: Ekitaldi gehiago - id: more_publications translation: Argitalpen gehiago # Contact widget - id: contact_name translation: Izena - id: contact_email translation: Emaila - id: contact_message translation: Mezua - id: contact_attachment translation: Attach file - id: contact_send translation: Bidali - id: book_appointment translation: Hitzordua eskatu # Publication/Event details - id: abstract translation: Laburpena - id: publication translation: Argitalpena - id: publication_type translation: Mota - id: date translation: Data - id: last_updated translation: Azkenengoz editatua - id: event translation: Ekitaldia - id: location translation: Kokalekua - id: pub_paper_conference translation: Konferentzia-artikulua - id: pub_article_journal translation: Aldizkari-artikulua - id: pub_article translation: Aurreargitalpena - id: pub_report translation: Txostena - id: pub_book translation: Liburua - id: pub_chapter translation: Liburu-kapitulua - id: pub_thesis translation: Tesia - id: pub_patent translation: Patentea # Project details - id: open_project_site translation: Joan proiektuaren webgunera # Content types for default archive page titles and search results - id: posts translation: Posts - id: publications translation: Argitalpenak - id: talks translation: Ekitaldiak - id: projects translation: Proiektuak - id: slides translation: Diapositibak - id: authors translation: Authors # Search - id: search translation: Bilatu - id: search_placeholder translation: Bilatu... - id: search_results translation: Bilaketaren emaitzak - id: search_no_results translation: Ez da ezer aurkitu - id: search_common_queries translation: Ohiko bilaketak # Error 404 - id: page_not_found translation: Ezin izan da orrialdea aurkitu - id: 404_recommendations translation: Agian hauetako baten bila zenbiltzan? # Cookie consent - id: cookie_message translation: Webgune honek cookie-ak erabiltzen ditu esperientzia hobea bermatzeko. - id: cookie_dismiss translation: Ulertua! - id: cookie_learn translation: Informazio gehiago # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/fa.yaml ================================================ # Navigation - id: toggle_navigation translation: خاموش/روشن کردن مسیر - id: table_of_contents translation: فهرست مطالب - id: on_this_page translation: محتوا - id: back_to_top translation: بازگشت به بالا - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: مرتبط - id: minute_read translation: زمان خواندن - id: previous translation: قبلی - id: next translation: بعدی - id: figure translation: 'شکل %d:' - id: edit_page translation: ویرایش صفحه # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: روشن - id: theme_dark translation: تاریک - id: theme_auto translation: روشنایی خودکار # Buttons - id: btn_preprint translation: نسخه پیش از چاپ - id: btn_pdf translation: فایل PDF - id: btn_cite translation: رفرنس دادن - id: btn_slides translation: اسلایدها - id: btn_video translation: ویدئو - id: btn_code translation: برنامه - id: btn_dataset translation: داده‌ها - id: btn_project translation: پروژه - id: btn_poster translation: پوستر - id: btn_source translation: متن اصلی - id: btn_copy translation: کپی - id: btn_copied translation: Copied - id: btn_download translation: دانلود # About widget - id: interests translation: موضوعات پژوهشی - id: education translation: تحصیلات - id: user_profile_latest translation: آخرین‌ها # Accomplishments widget - id: see_certificate translation: مشاهده گواهی # Experience widget - id: present translation: اکنون # Pages widget - id: more_pages translation: بقیه صفحات - id: more_posts translation: بقیه پست‌ها - id: more_talks translation: بقیه سخنرانی‌ها - id: more_publications translation: بقیه آثار # Contact widget - id: contact_name translation: نام - id: contact_email translation: ایمیل - id: contact_message translation: پیام - id: contact_attachment translation: Attach file - id: contact_send translation: ارسال - id: book_appointment translation: تعیین قرار ملاقات # Publication/Event details - id: abstract translation: چکیده - id: publication translation: اثر - id: publication_type translation: نوع اثر - id: date translation: تاریخ - id: last_updated translation: آخرین به روز رسانی - id: event translation: رویداد - id: location translation: مکان - id: pub_paper_conference translation: مقاله کنفرانسی - id: pub_article_journal translation: مقاله ژورنالی - id: pub_article translation: پیش‌نویس مقاله - id: pub_report translation: گزارش - id: pub_book translation: کتاب - id: pub_chapter translation: فصل از کتاب - id: pub_thesis translation: پایان‌نامه - id: pub_patent translation: ثبت اختراع # Project details - id: open_project_site translation: باز کردن وب‌سایت پروژه # Content types for default archive page titles and search results - id: posts translation: پست‌ها - id: publications translation: آثار - id: talks translation: سخنرانی‌ها - id: projects translation: پروژه‌ها - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: جستجو - id: search_placeholder translation: جستجو... - id: search_results translation: نتیجه پیدا شد. - id: search_no_results translation: هیچ نتیجه‌ای پیدا نشد. - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: صفحه پیدا نشد. - id: 404_recommendations translation: شاید دنبال یکی از این صفحات بودید؟ # Cookie consent - id: cookie_message translation: این وب‌سایت برای بهبود تجربه کاربری شما از کوکی‌ها استفاده می‌کند. - id: cookie_dismiss translation: باشه! - id: cookie_learn translation: اطلاعات بیشتر... # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/fi.yaml ================================================ # Navigation - id: toggle_navigation translation: Navigointi - id: table_of_contents translation: Sisällys - id: on_this_page translation: Sisältö - id: back_to_top translation: Takaisin ylös - id: home translation: Etusivu - id: close translation: Sulje - id: languages translation: Kielet # General - id: related translation: Aiheeseen liittyvät - id: minute_read translation: min (lukuaika) - id: previous translation: Edellinen - id: next translation: Seuraava - id: figure translation: 'Kuvio %d:' - id: edit_page translation: Muokkaa sivua # Themes - id: theme_selector translation: Valitse teema - id: theme_light translation: Vaalea - id: theme_dark translation: Tumma - id: theme_auto translation: Automaattinen # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Siteeraa - id: btn_slides translation: Diaesitykset - id: btn_video translation: Video - id: btn_code translation: Koodi - id: btn_dataset translation: Tietojoukot - id: btn_project translation: Projekti - id: btn_poster translation: Juliste - id: btn_source translation: Lähdeasiakirja - id: btn_copy translation: Kopioi - id: btn_copied translation: Copied - id: btn_download translation: Lataa # About widget - id: interests translation: Kiinnostukset - id: education translation: Koulutus - id: user_profile_latest translation: Viimeisin # Accomplishments widget - id: see_certificate translation: Katso todistus # Experience widget - id: present translation: Nykyinen # Pages widget - id: more_pages translation: Katso kaikki - id: more_posts translation: Kaikki blogitekstit - id: more_talks translation: Katso kaikki esitelmät - id: more_publications translation: Katso kaikki julkaisut # Contact widget - id: contact_name translation: Nimi - id: contact_email translation: Sähköposti - id: contact_message translation: Viesti - id: contact_attachment translation: Attach file - id: contact_send translation: Lähetä - id: book_appointment translation: Sovi tapaaminen # Publication/Event details - id: abstract translation: Abstrakti - id: publication translation: Julkaisu - id: publication_type translation: Tyyppi - id: date translation: Päivämäärä - id: last_updated translation: Viimeksi päivitetty - id: event translation: Tapahtuma - id: location translation: Sijainti - id: pub_paper_conference translation: Konferenssijulkaisu - id: pub_article_journal translation: Artikkeli - id: pub_article translation: Preprint - id: pub_report translation: Raportti - id: pub_book translation: Kirja - id: pub_chapter translation: Kirjan kohta - id: pub_thesis translation: Opinnäyte - id: pub_patent translation: Patentti # Project details - id: open_project_site translation: Siirry projektisivulle # Content types for default archive page titles and search results - id: posts translation: Blogitekstit - id: publications translation: Julkaisut - id: talks translation: Esitelmät - id: projects translation: Projektit - id: slides translation: Diaesitykset - id: authors translation: Kirjoittajat # Search - id: search translation: Etsi - id: search_placeholder translation: Etsi... - id: search_results translation: tulosta löydetty - id: search_no_results translation: Ei tuloksia - id: search_common_queries translation: Yleiset haut # Error 404 - id: page_not_found translation: Sivua ei löydetty - id: 404_recommendations translation: Ehkä etsit jotain näistä? # Cookie consent - id: cookie_message translation: Tämä verkkosivusto käyttää evästeitä varmistaakseen, että saat parhaan käyttökokemuksen verkkosivustollamme. - id: cookie_dismiss translation: Hyväksytty - id: cookie_learn translation: Lisätietoja # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/fr.yaml ================================================ # Navigation - id: toggle_navigation translation: Ouvrir la barre de navigation - id: table_of_contents translation: Table des matières - id: on_this_page translation: Dans cette page - id: back_to_top translation: Retourner au début - id: home translation: Accueil - id: close translation: Fermer - id: languages translation: Langues # General - id: related translation: Sur le même sujet # Callouts - All Obsidian-compatible types - id: callout_note translation: Note - id: callout_abstract translation: Résumé - id: callout_summary translation: Résumé - id: callout_info translation: Info - id: callout_todo translation: À faire - id: callout_tip translation: Conseil - id: callout_success translation: Succès - id: callout_question translation: Question - id: callout_warning translation: Attention - id: callout_failure translation: Échec - id: callout_danger translation: Danger - id: callout_bug translation: Bug - id: callout_example translation: Exemple - id: callout_quote translation: Citation - id: callout_important translation: Important - id: callout_caution translation: Prudence - id: minute_read translation: min. de lecture - id: previous translation: Précédent - id: next translation: Suivant - id: figure translation: 'Figure %d:' - id: edit_page translation: Editer cette page # Themes - id: theme_selector translation: Préférences d'affichage - id: theme_light translation: Clair - id: theme_dark translation: Sombre - id: theme_auto translation: Automatique # Buttons - id: btn_preprint translation: Pré-impression - id: btn_pdf translation: PDF - id: btn_cite translation: Citation - id: btn_slides translation: Diapositives - id: btn_video translation: Vidéo - id: btn_code translation: Code - id: btn_dataset translation: Jeu de données - id: btn_project translation: Projet - id: btn_poster translation: Poster - id: btn_source translation: Document source - id: btn_copy translation: Copier - id: btn_copied translation: Copié - id: btn_download translation: Télécharger # About widget - id: interests translation: Intérêts - id: education translation: Éducation - id: user_profile_latest translation: Récents # Accomplishments widget - id: see_certificate translation: Voir certificat # Experience widget - id: experience translation: Expériences - id: present translation: Actuellement # Pages widget - id: more_pages translation: Voir tout - id: more_posts translation: Plus de posts - id: more_talks translation: Plus de présentations - id: more_publications translation: Plus de publications # Contact widget - id: contact_name translation: Nom - id: contact_email translation: E-mail - id: contact_message translation: Message - id: contact_attachment translation: Joindre un fichier - id: contact_send translation: Envoyer - id: book_appointment translation: Demander un rendez-vous # Publication/Event details - id: abstract translation: Résumé - id: publication translation: Publication - id: publication_type translation: Type - id: date translation: Date - id: last_updated translation: Dernière mise à jour le - id: event translation: Évènement - id: location translation: Lieu - id: pub_paper_conference translation: Article de conférence - id: pub_article_journal translation: Article de revue - id: pub_article translation: Pré-impression - id: pub_report translation: Rapport - id: pub_book translation: Livre - id: pub_chapter translation: Chapitre de livre - id: pub_thesis translation: Thèse - id: pub_patent translation: Brevet # Project details - id: open_project_site translation: Aller sur le site du projet # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publications - id: events translation: Événements - id: projects translation: Projets - id: slides translation: Slides - id: authors translation: Auteurs # Search - id: search translation: Rechercher - id: search_placeholder translation: Recherche... - id: search_results translation: Résultats trouvés - id: search_no_results translation: Aucun résultat n'a été trouvé - id: search_common_queries translation: Recherches fréquentes # Error 404 - id: page_not_found translation: Page non disponible - id: 404_recommendations translation: Vous cherchiez peut-être une des pages suivantes ? # Cookie consent - id: cookie_message translation: Ce site utilise des cookies pour vous assurer la meilleure expérience. - id: cookie_dismiss translation: Accepter - id: cookie_learn translation: En savoir plus # Published with - id: published_with translation: Publié avec {hugoblox} — le générateur {repo_link}libre{/repo_link} de site web gratuit permettant aux créateurs de s'épanouir. - id: poweredby_button translation: 'Créer le vôtre →' ================================================ FILE: modules/blox/i18n/he.yaml ================================================ # Navigation - id: toggle_navigation translation: ניווט - id: table_of_contents translation: תוכן עניינים - id: on_this_page translation: תוכן - id: back_to_top translation: חזרה למעלה - id: home translation: בית - id: close translation: סגירה - id: languages translation: שפות # General - id: related translation: קשור - id: minute_read translation: דק׳ קריאה - id: previous translation: הקודם - id: next translation: הבא - id: figure translation: 'איור %d:' - id: edit_page translation: עריכת דף זה # Themes - id: theme_selector translation: העדפות תצוגה - id: theme_light translation: בהיר - id: theme_dark translation: כהה - id: theme_auto translation: אוטומטי # Buttons - id: btn_preprint translation: קדם-פרסום - id: btn_pdf translation: PDF - id: btn_cite translation: ציטוט - id: btn_slides translation: שקופיות - id: btn_video translation: וידאו - id: btn_code translation: קוד - id: btn_dataset translation: ערכת נתונים - id: btn_project translation: פרויקט - id: btn_poster translation: פוסטר - id: btn_source translation: מסמך מקור - id: btn_copy translation: העתקה - id: btn_copied translation: Copied - id: btn_download translation: הורדה # About widget - id: interests translation: תחומי עניין - id: education translation: השכלה - id: user_profile_latest translation: פורסם לאחרונה # Accomplishments widget - id: see_certificate translation: תעודה # Experience widget - id: present translation: הווה # Pages widget - id: more_pages translation: הכל - id: more_posts translation: כל הפוסטים - id: more_talks translation: כל האירועים - id: more_publications translation: כל הפרסומים # Contact widget - id: contact_name translation: שם - id: contact_email translation: דוא״ל - id: contact_message translation: הודעה - id: contact_attachment translation: Attach file - id: contact_send translation: שליחה - id: book_appointment translation: קביעת פגישה # Publication/Event details - id: abstract translation: תקציר - id: publication translation: פרסום - id: publication_type translation: סוג - id: date translation: תאריך - id: last_updated translation: עודכן לאחרונה ב- - id: event translation: אירוע - id: location translation: מיקום - id: pub_paper_conference translation: נייר ועידה - id: pub_article_journal translation: מאמר בכתב עת - id: pub_article translation: קדם-פרסום - id: pub_report translation: דו״ח - id: pub_book translation: ספר - id: pub_chapter translation: קטע של ספר - id: pub_thesis translation: תזה - id: pub_patent translation: פטנט # Project details - id: open_project_site translation: אתר הפרויקט # Content types for default archive page titles and search results - id: posts translation: פוסטים - id: publications translation: פרסומים - id: talks translation: אירועים - id: projects translation: פרויקטים - id: slides translation: שקופיות - id: authors translation: מחברים # Search - id: search translation: חיפוש - id: search_placeholder translation: חיפוש... - id: search_results translation: תוצאות חיפוש - id: search_no_results translation: לא נמצאו תוצאות - id: search_common_queries translation: חיפושים נפוצים # Error 404 - id: page_not_found translation: העמוד לא נמצא - id: 404_recommendations translation: אולי חיפשת אחד מאלה? # Cookie consent - id: cookie_message translation: אתר זה משתמש בקובצי Cookie כדי להבטיח שתקבלו את החוויה הטובה ביותר באתר. - id: cookie_dismiss translation: הבנתי! - id: cookie_learn translation: מידע נוסף # Published with - id: published_with translation: פורסם באמצעות {hugoblox} — בונה האתרים החינמי, בעל {repo_link}קוד פתוח{/repo_link}, שמעצים יוצרים. ================================================ FILE: modules/blox/i18n/hi.yaml ================================================ # Navigation - id: toggle_navigation translation: नेविगेशन टॉगल करें - id: table_of_contents translation: सामग्री तालिका - id: on_this_page translation: इस पेज पर - id: back_to_top translation: ऊपर वापस जाएँ - id: home translation: होम - id: close translation: बंद करें - id: languages translation: भाषाएँ # General - id: related translation: संबंधित - id: backlinks translation: बैकलिंक्स # Callouts - All Obsidian-compatible types - id: callout_note translation: नोट - id: callout_abstract translation: सार - id: callout_summary translation: सारांश - id: callout_info translation: जानकारी - id: callout_todo translation: करना है - id: callout_tip translation: सुझाव - id: callout_success translation: सफलता - id: callout_question translation: प्रश्न - id: callout_warning translation: चेतावनी - id: callout_failure translation: विफलता - id: callout_danger translation: खतरा - id: callout_bug translation: बग - id: callout_example translation: उदाहरण - id: callout_quote translation: उद्धरण - id: callout_important translation: महत्वपूर्ण - id: callout_caution translation: सावधानी - id: minute_read translation: मिनट पढ़ें - id: previous translation: पिछला - id: next translation: अगला - id: figure translation: 'चित्र %d:' - id: edit_page translation: इस पेज को संपादित करें # Themes - id: theme_selector translation: प्रदर्शन प्राथमिकताएँ - id: theme_light translation: लाइट - id: theme_dark translation: डार्क - id: theme_auto translation: स्वचालित # Buttons - id: btn_preprint translation: प्रीप्रिंट - id: btn_pdf translation: पीडीएफ - id: btn_cite translation: उद्धृत करें - id: btn_slides translation: स्लाइड्स - id: btn_video translation: वीडियो - id: btn_code translation: कोड - id: btn_dataset translation: डेटासेट - id: btn_project translation: प्रोजेक्ट - id: btn_poster translation: पोस्टर - id: btn_source translation: स्रोत दस्तावेज़ # New link types - id: btn_doi translation: DOI - id: btn_site translation: साइट - id: btn_canonical translation: कैनोनिकल - id: btn_crosspost translation: क्रॉसपोस्ट - id: btn_discussion translation: चर्चा - id: btn_event translation: इवेंट - id: btn_calendar translation: कैलेंडर - id: btn_registration translation: पंजीकरण - id: btn_demo translation: डेमो - id: btn_model translation: मॉडल - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code - id: btn_copy translation: कॉपी करें - id: btn_copied translation: कॉपी किया गया - id: btn_download translation: डाउनलोड # About widget - id: interests translation: रुचियाँ - id: education translation: शिक्षा - id: about_me translation: व्यावसायिक सारांश - id: user_profile_latest translation: नवीनतम # Countdown widget - id: days translation: दिन - id: hours translation: घंटे - id: minutes translation: मिनट - id: seconds translation: सेकंड # Accomplishments widget - id: see_certificate translation: प्रमाणपत्र देखें # Experience widget - id: experience translation: अनुभव - id: present translation: वर्तमान # Pages widget - id: read_more translation: और पढ़ें - id: more_pages translation: सभी देखें - id: more_posts translation: सभी पोस्ट देखें - id: more_talks translation: सभी इवेंट देखें - id: more_publications translation: सभी प्रकाशन देखें # Contact widget - id: contact_name translation: नाम - id: contact_email translation: ईमेल - id: contact_message translation: संदेश - id: contact_attachment translation: फ़ाइल संलग्न करें - id: contact_send translation: भेजें - id: book_appointment translation: अपॉइंटमेंट बुक करें # Contact info block - id: block_contact_title translation: संपर्क करें - id: block_contact_visit_title translation: हमसे मिलें - id: block_contact_office_hours translation: ऑफिस समय - id: block_contact_view_on_map translation: मैप पर देखें - id: block_contact_connect_title translation: कनेक्ट करें - id: block_contact_follow_us translation: हमें फॉलो करें - id: block_contact_follow_me translation: मुझे यहाँ पाएँ - id: block_contact_prospective_title translation: संभावित सदस्य - id: block_contact_form_title translation: हमें संदेश भेजें - id: block_contact_form_name translation: नाम - id: block_contact_form_email translation: ईमेल - id: block_contact_form_subject translation: विषय - id: block_contact_form_message translation: संदेश - id: block_contact_form_submit translation: संदेश भेजें # Publication/Event details - id: abstract translation: सार - id: publication translation: प्रकाशन - id: publication_type translation: प्रकार - id: date translation: तारीख - id: last_updated translation: अंतिम अपडेट - id: event translation: इवेंट - id: location translation: स्थान - id: pub_paper_conference translation: सम्मेलन पेपर - id: pub_article_journal translation: जर्नल लेख - id: pub_article translation: प्रीप्रिंट - id: pub_report translation: रिपोर्ट - id: pub_book translation: पुस्तक - id: pub_chapter translation: पुस्तक अनुभाग - id: pub_thesis translation: थीसिस - id: pub_patent translation: पेटेंट # Project details - id: open_project_site translation: प्रोजेक्ट साइट पर जाएँ # Content types for default archive page titles and search results - id: blog translation: ब्लॉग - id: publications translation: प्रकाशन - id: events translation: इवेंट - id: projects translation: प्रोजेक्ट - id: slides translation: स्लाइड्स - id: authors translation: लेखक - id: qa translation: प्रश्नोत्तर - id: questions translation: प्रश्न - id: faq translation: अक्सर पूछे जाने वाले प्रश्न - id: faqs translation: FAQs - id: docs translation: प्रलेखन - id: question translation: प्रश्न - id: answer translation: उत्तर - id: accepted_answer translation: स्वीकृत उत्तर - id: other_answers translation: अन्य उत्तर - id: related_questions translation: संबंधित प्रश्न - id: browse_by_category translation: श्रेणी के अनुसार ब्राउज़ करें - id: search_questions translation: प्रश्न खोजें... - id: no_questions_yet translation: अभी तक कोई प्रश्न नहीं - id: questions_count translation: प्रश्न # Slides - id: back_to_slides translation: स्लाइड्स पर वापस जाएँ - id: featured translation: विशेष - id: details translation: विवरण - id: present_slides translation: प्रस्तुति करें - id: present_fullscreen translation: प्रस्तुति (फुलस्क्रीन) - id: export_pdf_print translation: पीडीएफ निर्यात (प्रिंट) - id: slides_print_hint translation: प्रिंट मोड में खुलेगा - ब्राउज़र प्रिंट > PDF के रूप में सहेजें - id: slides_search_placeholder translation: शीर्षक से डेक खोजें... - id: slides_no_decks translation: कोई स्लाइड डेक नहीं मिला - id: slides_no_matches translation: कोई डेक आपके फ़िल्टर से मेल नहीं खाता - id: clear_filters translation: फ़िल्टर साफ़ करें - id: topics translation: विषय - id: related_resources translation: संबंधित संसाधन - id: copy_link translation: लिंक कॉपी करें - id: copy_citation translation: उद्धरण कॉपी करें - id: how_to_cite translation: कैसे उद्धृत करें - id: citation translation: उद्धरण - id: bibtex translation: BibTeX - id: download_cite_bib translation: cite.bib डाउनलोड करें - id: lecture translation: व्याख्यान - id: enter_fullscreen translation: फुलस्क्रीन में जाएँ - id: exit_fullscreen translation: फुलस्क्रीन से बाहर निकलें - id: speaker_notes_hint translation: वक्ता नोट्स के लिए - id: slides_not_found translation: स्लाइड्स नहीं मिलीं # Search - id: search translation: खोज - id: search_placeholder translation: खोजें... - id: search_results translation: परिणाम मिले - id: search_no_results translation: कोई परिणाम नहीं मिला - id: search_common_queries translation: सामान्य खोजें # Error 404 - id: page_not_found translation: पेज नहीं मिला - id: 404_recommendations translation: शायद आप इनमें से किसी को ढूँढ रहे थे? # Cookie consent - id: cookie_message translation: यह वेबसाइट सर्वोत्तम अनुभव देने के लिए कुकीज़ का उपयोग करती है। - id: cookie_dismiss translation: समझ गया! - id: cookie_learn translation: और जानें # Published with - id: published_with translation: '{hugoblox} के साथ बनाया गया — मुफ़्त {repo_link}ओपन सोर्स{/repo_link} वेबसाइट बिल्डर जो क्रिएटर्स को सशक्त करता है।' - id: poweredby_button translation: 'अपनी बनाएँ →' # Dev Hero block - id: scroll_to_content translation: सामग्री पर स्क्रॉल करें - id: developer translation: डेवलपर # Portfolio block - id: portfolio_link_code translation: कोड - id: portfolio_link_live translation: लाइव - id: portfolio_link_demo translation: डेमो - id: portfolio_link_default translation: लिंक - id: portfolio_view_all translation: सभी प्रोजेक्ट देखें # Feedback widget - id: feedback_widget_title translation: प्रतिपुष्टि - id: feedback_widget_question translation: क्या यह पेज सहायक था? - id: feedback_widget_answer_positive translation: 😍 हाँ - id: feedback_widget_answer_negative translation: 😡 नहीं # AI Features - id: ai_insight translation: एआई अंतर्दृष्टि # Content Metadata - id: content_type translation: सामग्री प्रकार - id: difficulty translation: कठिनाई - id: prerequisites translation: पूर्वापेक्षाएँ # Card metadata - id: trending translation: ट्रेंडिंग - id: article translation: लेख - id: articles translation: लेख - id: browse translation: ब्राउज़ - id: all translation: सब - id: helpful translation: सहायक ================================================ FILE: modules/blox/i18n/hr.yaml ================================================ # Navigation - id: toggle_navigation translation: Promjeni navigaciju - id: table_of_contents translation: Sadržaj - id: on_this_page translation: Na ovoj stranici - id: back_to_top translation: Natrag na vrh - id: home translation: Početna stranica - id: close translation: Zatvori - id: languages translation: Jezici # General - id: related translation: Povezano - id: minute_read translation: Čitanje u minutama - id: previous translation: Prethodni - id: next translation: Sljedeći - id: figure translation: 'Slika %d:' - id: edit_page translation: Promjeni ovu stranicu # Themes - id: theme_selector translation: Postavke prikaza - id: theme_light translation: Svjetla - id: theme_dark translation: Tamna - id: theme_auto translation: Automatska # Buttons - id: btn_preprint translation: Pretisak - id: btn_pdf translation: PDF - id: btn_cite translation: Citiraj - id: btn_slides translation: Slajdovi - id: btn_video translation: Video - id: btn_code translation: Kod - id: btn_dataset translation: Set podataka - id: btn_project translation: Projekt - id: btn_poster translation: Poster - id: btn_source translation: Izvorni Dokument - id: btn_copy translation: Kopiraj - id: btn_copied translation: Kopirano - id: btn_download translation: Preuzmi # About widget - id: interests translation: Interesi - id: education translation: Obrazovanje - id: user_profile_latest translation: Najnovije # Countdown widget - id: days translation: Dani - id: hours translation: Sati - id: minutes translation: Minute - id: seconds translation: Sekunde # Accomplishments widget - id: see_certificate translation: See certifikat # Experience widget - id: experience translation: Iskustvo - id: present translation: Trenutno # Pages widget - id: read_more translation: Pročitaj više - id: more_pages translation: Vidi sve - id: more_posts translation: Vidi sve objave - id: more_talks translation: Vidi sve događaje - id: more_publications translation: Vidi sve publikacije # Contact widget - id: contact_name translation: Ime - id: contact_email translation: Email - id: contact_message translation: Poruka - id: contact_attachment translation: Dodaj privitak - id: contact_send translation: Pošalji - id: book_appointment translation: Dogovori sastanak # Publication/Event details - id: abstract translation: Sažetak - id: publication translation: Publikacija - id: publication_type translation: Tip - id: date translation: Datum - id: last_updated translation: Zadnji put ažurirano - id: event translation: Događaj - id: location translation: Lokacija - id: pub_paper_conference translation: Rad na konferenciji - id: pub_article_journal translation: Rad u časopisu - id: pub_article translation: Pretisak - id: pub_report translation: Izvještaj - id: pub_book translation: Knjiga - id: pub_chapter translation: Poglavlje u knjizi - id: pub_thesis translation: Doktorski rad - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Idi na Stranicu Projekta # Content types for default archive page titles and search results - id: posts translation: Objave - id: publications translation: Publikacije - id: talks translation: Događaji - id: projects translation: Projekti - id: slides translation: Prezentacije - id: authors translation: Autori # Search - id: search translation: Pretraži - id: search_placeholder translation: Pretraži... - id: search_results translation: pronađeni rezultati - id: search_no_results translation: Nisu pronađeni rezultati - id: search_common_queries translation: Česta pretraživanja # Error 404 - id: page_not_found translation: Stranica nije pronađena - id: 404_recommendations translation: Možda ste tražili nešto od ovoga? # Cookie consent - id: cookie_message translation: Ova web stranica koristi kolačiće kako bi vam osigurala najbolje iskustvo na našoj web stranici. - id: cookie_dismiss translation: Shvaćam! - id: cookie_learn translation: Saznajte više # Published with - id: published_with translation: Objavljeno pomoću {hugoblox} — besplatnog alata za izradu web stranica {repo_link}otvorenog koda{/repo_link} koji osnažuje kreatore. # Feedback widget - id: feedback_widget_title translation: Povratne informacije - id: feedback_widget_question translation: Je li ova stranica bila korisna? - id: feedback_widget_answer_positive translation: 😍 Da - id: feedback_widget_answer_negative translation: 😡 Ne ================================================ FILE: modules/blox/i18n/ht.yaml ================================================ # Navigation - id: toggle_navigation translation: Chanje navigasyon - id: table_of_contents translation: Tablo kontni - id: on_this_page translation: Sou paj sa a - id: back_to_top translation: Tounen anlè paj la - id: home translation: Akèy - id: close translation: Fèmen - id: languages translation: Lang # General - id: related translation: Ki gen rapò # Callouts - All Obsidian-compatible types - id: callout_note translation: Nòt - id: callout_abstract translation: Rezime - id: callout_summary translation: Rezime - id: callout_info translation: Enfòmasyon - id: callout_todo translation: Pou fè - id: callout_tip translation: Konsèy - id: callout_success translation: Siksè - id: callout_question translation: Kesyon - id: callout_warning translation: Avètisman - id: callout_failure translation: Echek - id: callout_danger translation: Danje - id: callout_bug translation: Pinèz - id: callout_example translation: Egzanp - id: callout_quote translation: Sita - id: callout_important translation: Enpòtan - id: callout_caution translation: Pridans - id: backlinks translation: Lyen tounen - id: minute_read translation: minit lekti - id: previous translation: Anvan - id: next translation: Pwochen - id: figure translation: 'Figur %d:' - id: edit_page translation: Modifye paj sa a # Themes - id: theme_selector translation: Preferans afichaj - id: theme_light translation: Klè - id: theme_dark translation: Fènwa - id: theme_auto translation: Otomatik # Buttons - id: btn_preprint translation: Pre-piblikasyon - id: btn_pdf translation: PDF - id: btn_cite translation: Site - id: btn_slides translation: Dias - id: btn_video translation: Videyo - id: btn_code translation: Kòd - id: btn_dataset translation: Done - id: btn_project translation: Pwojè - id: btn_poster translation: Afich - id: btn_source translation: Dokiman sous # New link types - id: btn_doi translation: DOI - id: btn_site translation: Sit - id: btn_canonical translation: Kanonik - id: btn_crosspost translation: Kwoz-piblikasyon - id: btn_discussion translation: Diskisyon - id: btn_event translation: Evènman - id: btn_calendar translation: Kalandriye - id: btn_registration translation: Enskripsyon - id: btn_demo translation: Demo - id: btn_model translation: Modèl - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code - id: btn_copy translation: Kopye - id: btn_copied translation: Kopiye - id: btn_download translation: Telechaje # About widget - id: interests translation: Enterè - id: education translation: Edikasyon - id: about_me translation: Rezime pwofesyonèl - id: user_profile_latest translation: Dènye # Countdown widget - id: days translation: Jou - id: hours translation: Èdtan - id: minutes translation: Minit - id: seconds translation: Segonn # Accomplishments widget - id: see_certificate translation: Gade sètifika # Experience widget - id: experience translation: Eksperyans - id: present translation: Kounye a # Pages widget - id: read_more translation: Li plis - id: more_pages translation: Gade tout - id: more_posts translation: Gade tout pòs yo - id: more_talks translation: Gade tout evènman yo - id: more_publications translation: Gade tout piblikasyon yo # Contact widget - id: contact_name translation: Non - id: contact_email translation: Imèl - id: contact_message translation: Mesaj - id: contact_attachment translation: Atache fichye - id: contact_send translation: Voye - id: book_appointment translation: Rezève randevou # Publication/Event details - id: abstract translation: Rezime - id: publication translation: Piblikasyon - id: publication_type translation: Kalite - id: date translation: Dat - id: last_updated translation: Dènye mizajou sou - id: event translation: Evènman - id: location translation: Kote - id: pub_paper_conference translation: Atik konferans - id: pub_article_journal translation: Atik jounal - id: pub_article translation: Pre-piblikasyon - id: pub_report translation: Rapò - id: pub_book translation: Liv - id: pub_chapter translation: Chapit liv - id: pub_thesis translation: Tèz - id: pub_patent translation: Patant # Project details - id: open_project_site translation: Ale sou sit pwojè a # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Piblikasyon - id: events translation: Evènman - id: projects translation: Pwojè - id: slides translation: Dias - id: authors translation: Otè # Search - id: search translation: Rechèch - id: search_placeholder translation: Chèche... - id: search_results translation: rezilta jwenn - id: search_no_results translation: Pa gen rezilta - id: search_common_queries translation: Rechèch komen # Error 404 - id: page_not_found translation: Paj pa jwenn - id: 404_recommendations translation: Petèt ou t ap chèche youn nan sa yo? # Cookie consent - id: cookie_message translation: Sit entènèt sa a itilize bonbon pou asire w jwenn pi bon eksperyans. - id: cookie_dismiss translation: Mwen konprann! - id: cookie_learn translation: Aprann plis # Published with - id: published_with translation: Fè ak {hugoblox}. - id: poweredby_button translation: 'Kreye pa w →' # Feedback widget - id: feedback_widget_title translation: Fidbak - id: feedback_widget_question translation: Èske paj sa a te itil ou? - id: feedback_widget_answer_positive translation: 😍 Wi - id: feedback_widget_answer_negative translation: 😡 Non # AI Features - id: ai_insight translation: Analiz AI # Content Metadata - id: content_type translation: Kalite kontni - id: difficulty translation: Difikilte - id: prerequisites translation: Kondisyon davans # Card metadata - id: trending translation: Popilè ================================================ FILE: modules/blox/i18n/hu.yaml ================================================ # Navigation - id: toggle_navigation translation: Navigáció - id: table_of_contents translation: Tartalomjegyzék - id: on_this_page translation: Ezen az oldalon - id: back_to_top translation: Vissza felülre - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Kapcsolódó anyagok - id: minute_read translation: perc olvasás - id: previous translation: Előző - id: next translation: Következő - id: figure translation: '%d. ábra:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Megjelenés előtt - id: btn_pdf translation: PDF - id: btn_cite translation: Idézet - id: btn_slides translation: Diák - id: btn_video translation: Videó - id: btn_code translation: Kód - id: btn_dataset translation: Adatcsomag - id: btn_project translation: Projekt - id: btn_poster translation: Poszter - id: btn_source translation: Forrás dokumentum - id: btn_copy translation: Másolat - id: btn_copied translation: Copied - id: btn_download translation: Letöltés # About widget - id: interests translation: Érdeklődési terület - id: education translation: Tanulmányok - id: user_profile_latest translation: Latest # Accomplishments widget - id: see_certificate translation: Lásd a bizonyítányt # Experience widget - id: present translation: Jelenleg # Pages widget - id: more_pages translation: See all - id: more_posts translation: További posztok - id: more_talks translation: Előadások - id: more_publications translation: További publikációk # Contact widget - id: contact_name translation: Név - id: contact_email translation: Email - id: contact_message translation: Üzenet - id: contact_attachment translation: Attach file - id: contact_send translation: Elküldés - id: book_appointment translation: Időpont kérése # Publication/Event details - id: abstract translation: Kivonat - id: publication translation: Publikáció - id: publication_type translation: Típus - id: date translation: Dátum - id: last_updated translation: Utoljára frissítve - id: event translation: Esemény - id: location translation: Helyszín - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Book - id: pub_chapter translation: Book section - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Tovább a projekt oldalára # Content types for default archive page titles and search results - id: posts translation: Posztok - id: publications translation: Publikációk - id: talks translation: Előadások - id: projects translation: Projektek - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Keresés - id: search_placeholder translation: Keresés... - id: search_results translation: találat - id: search_no_results translation: Nincsen találat - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Az oldal nem található - id: 404_recommendations translation: Esetleg ezeket kereste? # Cookie consent - id: cookie_message translation: Ez az oldal a legjobb felhasználói élmény érdekében sütiket használ. - id: cookie_dismiss translation: Rendben - id: cookie_learn translation: További információk # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/id.yaml ================================================ # Navigation - id: toggle_navigation translation: Buka navigasi - id: table_of_contents translation: Daftar isi - id: on_this_page translation: Di halaman ini - id: back_to_top translation: Kembali ke atas - id: home translation: Beranda - id: close translation: Tutup - id: languages translation: Bahasa # General - id: related translation: Terkait - id: minute_read translation: menit untuk membaca - id: previous translation: Sebelumnya - id: next translation: Selanjutnya - id: figure translation: 'Orang %d:' - id: edit_page translation: Sunting halaman ini # Themes - id: theme_selector translation: Preferensi tampilan - id: theme_light translation: Terang - id: theme_dark translation: Gelap - id: theme_auto translation: Tema Otomatis # Buttons - id: btn_preprint translation: Pracetak - id: btn_pdf translation: PDF - id: btn_cite translation: Sitasi - id: btn_slides translation: Presentasi - id: btn_video translation: Video - id: btn_code translation: Kode - id: btn_dataset translation: Dataset - id: btn_project translation: Proyek - id: btn_poster translation: Poster - id: btn_source translation: Sumber - id: btn_copy translation: Salin - id: btn_copied translation: Copied - id: btn_download translation: Unduh # About widget - id: interests translation: Minat - id: education translation: Pendidikan - id: user_profile_latest translation: Terbaru # Accomplishments widget - id: see_certificate translation: Lihat sertifikat # Experience widget - id: present translation: Terkini # Pages widget - id: more_pages translation: Lihat semua - id: more_posts translation: Postingan lainnya - id: more_talks translation: Percakapan lainnya - id: more_publications translation: Publikasi lainnya # Contact widget - id: contact_name translation: Nama - id: contact_email translation: Surel - id: contact_message translation: Pesan - id: contact_attachment translation: Attach file - id: contact_send translation: Kirim - id: book_appointment translation: Menjadwalkan pertemuan # Publication/Event details - id: abstract translation: Abstrak - id: publication translation: Publikasi - id: publication_type translation: Jenis publikasi - id: date translation: Tanggal - id: last_updated translation: Terakhir diperbaharui - id: event translation: Acara - id: location translation: Lokasi - id: pub_paper_conference translation: Kertas konferensi - id: pub_article_journal translation: Artikel Jurnal - id: pub_article translation: Pracetak - id: pub_report translation: Laporan - id: pub_book translation: Buku - id: pub_chapter translation: Bagian buku - id: pub_thesis translation: Tesis - id: pub_patent translation: Paten # Project details - id: open_project_site translation: Ke laman proyek # Content types for default archive page titles and search results - id: posts translation: Postingan - id: publications translation: Publikasi - id: talks translation: Perbincangan - id: projects translation: Proyek - id: slides translation: Slides - id: authors translation: Penulis # Search - id: search translation: Cari - id: search_placeholder translation: Cari... - id: search_results translation: hasil pencarian - id: search_no_results translation: Hasil pencarian tidak ada - id: search_common_queries translation: Pencarian umum # Error 404 - id: page_not_found translation: Laman tidak ditemukan - id: 404_recommendations translation: Apakah ini yang Anda cari? # Cookie consent - id: cookie_message translation: Situs web ini menggunakan cookie untuk memastikan Anda mendapatkan pengalaman terbaik di situs web kami. - id: cookie_dismiss translation: Mengerti! - id: cookie_learn translation: Pelajari # Published with - id: published_with translation: Diterbitkan dengan {hugoblox} — Secara gratis, {repo_link}sumber terbuka{/repo_link} pembuat situs web yang memberdayakan para pembuat konten. # AI Features - id: ai_insight translation: Wawasan AI # Content Metadata - id: content_type translation: Jenis konten - id: difficulty translation: Tingkat kesulitan - id: prerequisites translation: Prasyarat # Card metadata - id: trending translation: Sedang tren - id: article translation: artikel - id: articles translation: artikel - id: browse translation: Jelajahi - id: all translation: Semua - id: helpful translation: bermanfaat # Additional buttons - id: btn_site translation: Situs - id: btn_canonical translation: Kanonikal - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Diskusi - id: btn_event translation: Acara - id: btn_calendar translation: Kalender - id: btn_registration translation: Registrasi - id: btn_demo translation: Demo - id: btn_model translation: Model - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_note translation: Catatan - id: callout_abstract translation: Abstrak - id: callout_summary translation: Ringkasan - id: callout_info translation: Info - id: callout_todo translation: To-do - id: callout_tip translation: Tip - id: callout_question translation: Pertanyaan - id: callout_quote translation: Kutipan - id: callout_warning translation: Peringatan - id: callout_caution translation: Perhatian - id: callout_danger translation: Bahaya - id: callout_bug translation: Bug - id: callout_example translation: Contoh - id: callout_failure translation: Gagal - id: callout_success translation: Sukses - id: callout_important translation: Penting # Slides - id: back_to_slides translation: Kembali ke slides - id: present_slides translation: Presentasi - id: present_fullscreen translation: Presentasi (layar penuh) - id: export_pdf_print translation: Ekspor PDF (cetak) - id: slides_print_hint translation: Membuka mode cetak - gunakan Cetak > Simpan sebagai PDF - id: slides_search_placeholder translation: Cari deck berdasarkan judul... - id: slides_no_decks translation: Tidak ada deck ditemukan - id: slides_no_matches translation: Tidak ada deck sesuai filter - id: clear_filters translation: Hapus filter - id: topics translation: Topik - id: details translation: Detail - id: related_resources translation: Sumber terkait - id: copy_link translation: Salin tautan - id: copy_citation translation: Salin sitasi - id: how_to_cite translation: Cara mengutip - id: citation translation: Sitasi - id: bibtex translation: BibTeX - id: download_cite_bib translation: Unduh cite.bib - id: lecture translation: Kuliah - id: enter_fullscreen translation: Masuk layar penuh - id: exit_fullscreen translation: Keluar layar penuh - id: speaker_notes_hint translation: untuk catatan pembicara - id: slides_not_found translation: Slide tidak ditemukan - id: related translation: Terkait # Q&A - id: qa translation: Tanya Jawab - id: question translation: Pertanyaan - id: answer translation: Jawaban - id: accepted_answer translation: Jawaban diterima - id: other_answers translation: Jawaban lainnya - id: questions translation: Pertanyaan - id: questions_count translation: pertanyaan - id: related_questions translation: Pertanyaan terkait - id: search_questions translation: Cari pertanyaan... - id: no_questions_yet translation: Belum ada pertanyaan - id: faq translation: FAQ - id: faqs translation: FAQ - id: browse_by_category translation: Telusuri per kategori # General extras - id: about_me translation: Ringkasan profesional - id: backlinks translation: Tautan balik - id: days translation: Hari - id: hours translation: Jam - id: minutes translation: Menit - id: seconds translation: Detik - id: experience translation: Pengalaman - id: read_more translation: Baca selengkapnya - id: docs translation: Dokumentasi - id: featured translation: Unggulan # Feedback widget - id: feedback_widget_title translation: Masukan - id: feedback_widget_question translation: Apakah halaman ini membantu? - id: feedback_widget_answer_positive translation: 😍 Ya - id: feedback_widget_answer_negative translation: 😡 Tidak - id: block_contact_title translation: Hubungi Kami - id: block_contact_visit_title translation: Kunjungi Kami - id: block_contact_office_hours translation: Jam kerja - id: block_contact_view_on_map translation: Lihat di Peta - id: block_contact_connect_title translation: Terhubung - id: block_contact_follow_us translation: Ikuti kami - id: block_contact_follow_me translation: Temukan saya di - id: block_contact_prospective_title translation: Calon anggota - id: block_contact_form_title translation: Kirim Pesan - id: block_contact_form_name translation: Nama - id: block_contact_form_email translation: Email - id: block_contact_form_subject translation: Subjek - id: block_contact_form_message translation: Pesan - id: block_contact_form_submit translation: Kirim pesan - id: blog translation: Blog - id: events translation: Acara - id: poweredby_button translation: 'Bangun punyamu →' - id: developer translation: Pengembang - id: scroll_to_content translation: Gulir ke konten - id: portfolio_link_code translation: Kode - id: portfolio_link_live translation: Langsung - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Tautan - id: portfolio_view_all translation: Lihat semua proyek - id: featured translation: Unggulan ================================================ FILE: modules/blox/i18n/it.yaml ================================================ # Navigation - id: toggle_navigation translation: Attiva la navigazione - id: table_of_contents translation: Indice dei Contenuti - id: on_this_page translation: In questa pagina - id: back_to_top translation: Torna su - id: home translation: Home - id: close translation: Chiudi - id: languages translation: Lingue # General - id: related translation: Correlato - id: minute_read translation: min di lettura - id: previous translation: Precedente - id: next translation: Prossimo - id: figure translation: 'Immagine %d:' - id: edit_page translation: Modifica questa pagina # Themes - id: theme_selector translation: Opzioni tema - id: theme_light translation: Chiaro - id: theme_dark translation: Scuro - id: theme_auto translation: Automatico # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Citazione - id: btn_slides translation: Slides - id: btn_video translation: Video - id: btn_code translation: Codice - id: btn_dataset translation: Dataset - id: btn_project translation: Progetti - id: btn_poster translation: Poster - id: btn_source translation: Sorgente - id: btn_copy translation: Copia - id: btn_copied translation: Copiata - id: btn_download translation: Download # About widget - id: interests translation: Interessi - id: education translation: Formazione - id: user_profile_latest translation: Ultime # Accomplishments widget - id: see_certificate translation: Guarda il certificato # Experience widget - id: present translation: Attualmente # Pages widget - id: more_pages translation: Vedi archivio - id: more_posts translation: Altri Post - id: more_talks translation: Altre Conferenze - id: more_publications translation: Altre pubblicazioni # Contact widget - id: contact_name translation: Nome - id: contact_email translation: Email - id: contact_message translation: Messaggio - id: contact_attachment translation: Allegato - id: contact_send translation: Invio - id: book_appointment translation: Richiedi un appuntamento # Publication/Event details - id: abstract translation: Abstract - id: publication translation: Publicazione - id: publication_type translation: Tipo - id: date translation: Data - id: last_updated translation: Aggiornato il - id: event translation: Evento - id: location translation: Luogo - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Libro - id: pub_chapter translation: Sezione Libro - id: pub_thesis translation: Tesi - id: pub_patent translation: Brevetto # Project details - id: open_project_site translation: Apri il sito del Progetto # Content types for default archive page titles and search results - id: posts translation: Post - id: publications translation: Pubblicazioni - id: talks translation: Conferenze - id: projects translation: Progetti - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Cerca - id: search_placeholder translation: Cerca... - id: search_results translation: Risultati della ricerca - id: search_no_results translation: Nessun risultato - id: search_common_queries translation: Ricerche comuni # Error 404 - id: page_not_found translation: Pagina non trovata - id: 404_recommendations translation: Forse stavate carcando uno di questi? # Cookie consent - id: cookie_message translation: Questo sito usa i cookies per garantire la migliore esperienza di navigazione. - id: cookie_dismiss translation: Ok! - id: cookie_learn translation: Leggi i dettagli # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/ja.yaml ================================================ # Navigation - id: toggle_navigation translation: ナビゲーションの切り替え - id: table_of_contents translation: 目次 - id: on_this_page translation: このページの内容 - id: back_to_top translation: トップへ戻る - id: home translation: ホーム - id: close translation: 閉じる - id: languages translation: 言語 # General - id: related translation: 関連項目 - id: minute_read translation: 分で読める - id: previous translation: 前へ - id: next translation: 次へ - id: figure translation: '図 %d:' - id: edit_page translation: このページを編集する # Themes - id: theme_selector translation: 表示設定 - id: theme_light translation: ライト - id: theme_dark translation: ダーク - id: theme_auto translation: 自動 # Buttons - id: btn_preprint translation: プレプリント - id: btn_pdf translation: PDF - id: btn_cite translation: 引用 - id: btn_slides translation: スライド - id: btn_video translation: 動画 - id: btn_code translation: ソースコード - id: btn_dataset translation: データセット - id: btn_project translation: プロジェクト - id: btn_poster translation: ポスター - id: btn_source translation: ソース - id: btn_copy translation: コピー - id: btn_copied translation: Copied - id: btn_download translation: ダウンロード # About widget - id: interests translation: 興味・関心 - id: education translation: 学歴 - id: user_profile_latest translation: 最新 # Accomplishments widget - id: see_certificate translation: 証明書を見る # Experience widget - id: present translation: 現在 # Pages widget - id: more_pages translation: すべて表示 - id: more_posts translation: 投稿一覧 - id: more_talks translation: 登壇一覧 - id: more_publications translation: 発表文献一覧 # Contact widget - id: contact_name translation: 名前 - id: contact_email translation: メールアドレス - id: contact_message translation: メッセージ本文 - id: contact_attachment translation: ファイルを添付 - id: contact_send translation: 送信 - id: book_appointment translation: 予約を取る # Publication/Event details - id: abstract translation: 概要 - id: publication translation: 収録 - id: publication_type translation: タイプ - id: date translation: 日付 - id: last_updated translation: 最終更新 - id: event translation: イベント - id: location translation: 場所 - id: pub_paper_conference translation: 学会論文 - id: pub_article_journal translation: ジャーナル記事 - id: pub_article translation: プレプリント - id: pub_report translation: 報告 - id: pub_book translation: 書籍 - id: pub_chapter translation: Book section - id: pub_thesis translation: 論文 - id: pub_patent translation: 特許 # Project details - id: open_project_site translation: プロジェクトのサイトへ # Content types for default archive page titles and search results - id: posts translation: 投稿 - id: publications translation: 発表文献 - id: talks translation: 登壇 - id: projects translation: プロジェクト - id: slides translation: スライド - id: authors translation: 著者 # Search - id: search translation: 検索 - id: search_placeholder translation: 検索... - id: search_results translation: 件の検索結果 - id: search_no_results translation: 結果が見つかりませんでした - id: search_common_queries translation: よくある検索 # Error 404 - id: page_not_found translation: ページが見つかりませんでした - id: 404_recommendations translation: あなたが探しているものはこれらの中にあるかもしれません # Cookie consent - id: cookie_message translation: このウェブサイトはあなたが最高の体験を得るためにクッキーを使用します。 - id: cookie_dismiss translation: はい - id: cookie_learn translation: 詳細を見る # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/km.yaml ================================================ # Navigation - id: toggle_navigation translation: បិទ/បើក នាវាចរណ៍ - id: table_of_contents translation: តារាងមាតិកា - id: on_this_page translation: នៅក្នុងទំព័រនេះ - id: back_to_top translation: ទៅខាងលើទំព័រ - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: ភាសាខ្មែរ - id: minute_read translation: ពេលចំណាយអាន - id: previous translation: ផ្នែកមុន - id: next translation: ផ្នែកបន្ទាប់ - id: figure translation: 'រូប %d:' - id: edit_page translation: កែប្រែទំព័រ # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: ប៊ូតុងបោះពុម្ព - id: btn_pdf translation: ប៊ូតុងPDF - id: btn_cite translation: ប៊ូតុងដកស្រង់ - id: btn_slides translation: ប៊ូតុងស្លាយ - id: btn_video translation: ប៊ូតុងវីដេអូ - id: btn_code translation: ប៊ូតុងកូដ - id: btn_dataset translation: ប៊ូតុងទិន្នន័យ - id: btn_project translation: ប៊ូតុងគម្រោង - id: btn_poster translation: ប៊ូតុងប័ណ្ណប្រកាស - id: btn_source translation: ប៊ូតុងប្រភព - id: btn_copy translation: ប៊ូតុងចម្លង - id: btn_copied translation: Copied - id: btn_download translation: ប៊ូតុងទាញយក # About widget - id: interests translation: ចំណាប់អារម្មណ៍ - id: education translation: កម្រិតការសិក្សា - id: user_profile_latest translation: ប្រវត្តិរូបចុងក្រោយបង្អស់ # Accomplishments widget - id: see_certificate translation: វិញ្ញាបនបត្រ # Experience widget - id: present translation: បច្ចុប្បន្ន # Pages widget - id: more_pages translation: ទំព័រច្រើនទៀត - id: more_posts translation: ប៉ុស្ដិ៍ច្រើនទៀត - id: more_talks translation: សុន្ទរកថាច្រើនទៀត - id: more_publications translation: ការបោះពុម្ពផ្សាយច្រើនទៀត # Contact widget - id: contact_name translation: ឈ្មោះ​ - id: contact_email translation: អាស័យ​ដ្ឋាន​អ៊ី​ម៉េ​ល - id: contact_message translation: ​សារអ៊ី​ម៉េ​ល - id: contact_attachment translation: Attach file - id: contact_send translation: ផ្ញើអ៊ីមែល - id: book_appointment translation: កក់ការណាត់ជួប # Publication/Event details - id: abstract translation: របាយការណ៍ - id: publication translation: ការបោះពុម្ពផ្សាយ - id: publication_type translation: ប្រភេទការបោះពុម្ពផ្សាយ - id: date translation: កាលបរិច្ឆេទ - id: last_updated translation: ការធ្វើឱ្យទាន់សម័យចុងក្រោយបង្អស់ - id: event translation: ព្រឹត្តិការណ៍ - id: location translation: ទីតាំង - id: pub_paper_conference translation: សន្និសិទ - id: pub_article_journal translation: ទិនានុប្បវត្តិ - id: pub_article translation: បោះពុម្ព - id: pub_report translation: របាយការណ៍ - id: pub_book translation: សៀវភៅបោះពុម្ព - id: pub_chapter translation: ផ្នែកសៀវភៅ - id: pub_thesis translation: និក្ខេបបទ - id: pub_patent translation: ប៉ាតង់ # Project details - id: open_project_site translation: គម្រោងបើក # Content types for default archive page titles and search results - id: posts translation: ប៉ុស្ដិ៍ - id: publications translation: ការបោះពុម្ពផ្សាយ - id: talks translation: សុន្ទរកថា - id: projects translation: គម្រោង - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: ស្វែងរក - id: search_placeholder translation: កន្លែងស្វែងរក - id: search_results translation: លទ្ធផលស្វែងរក - id: search_no_results translation: ស្វែងរកគ្មានលទ្ធផល - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: ទំព័ររក​មិន​ឃើញ - id: 404_recommendations translation: 404_អនុសាសន៍ # Cookie consent - id: cookie_message translation: សារខូឃី - id: cookie_dismiss translation: ខូឃីបណ្តេញចេញ - id: cookie_learn translation: ខូឃីរៀន # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/ko.yaml ================================================ # Navigation - id: toggle_navigation translation: 네비게이션 - id: table_of_contents translation: 차례 - id: on_this_page translation: 이 페이지 - id: back_to_top translation: 맨 위로 - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: 관련문서 - id: minute_read translation: 분 읽기 - id: previous translation: 이전 - id: next translation: 다음 - id: figure translation: '그림 %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: 출판 전 논문 - id: btn_pdf translation: PDF - id: btn_cite translation: 인용 - id: btn_slides translation: 발표자료 - id: btn_video translation: 비디오 - id: btn_code translation: 소스코드 - id: btn_dataset translation: 데이터셋 - id: btn_project translation: 프로젝트 - id: btn_poster translation: 포스터 - id: btn_source translation: 원본문서 - id: btn_copy translation: 복사 - id: btn_copied translation: Copied - id: btn_download translation: 다운로드 # About widget - id: interests translation: 관심분야 - id: education translation: 학위 - id: user_profile_latest translation: 최신 # Accomplishments widget - id: see_certificate translation: 증서 보기 # Experience widget - id: present translation: 현재 # Pages widget - id: more_pages translation: 전체 보기 - id: more_posts translation: 포스트 더 보기 - id: more_talks translation: 강연 더 보기 - id: more_publications translation: 논문 더 보기 # Contact widget - id: contact_name translation: 이름 - id: contact_email translation: 이메일 - id: contact_message translation: 메시지 - id: contact_attachment translation: Attach file - id: contact_send translation: 보내기 - id: book_appointment translation: 일정 약속 # Publication/Event details - id: abstract translation: 초록 - id: publication translation: 발행기관 - id: publication_type translation: 출판유형 - id: date translation: 날짜 - id: last_updated translation: 마지막 업데이트 - id: event translation: 이벤트 - id: location translation: 장소 - id: pub_paper_conference translation: 학술 대회 논문 - id: pub_article_journal translation: 저널 논문 - id: pub_article translation: 출판 전 논문 - id: pub_report translation: 보고서 - id: pub_book translation: 도서 - id: pub_chapter translation: 책 소개 면 - id: pub_thesis translation: 졸업 논문 - id: pub_patent translation: 특허 # Project details - id: open_project_site translation: 프로젝트 사이트 열기 # Content types for default archive page titles and search results - id: posts translation: 포스트 - id: publications translation: 논문 - id: talks translation: 강연 - id: projects translation: 프로젝트 - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: 검색 - id: search_placeholder translation: 검색... - id: search_results translation: 검색 결과 - id: search_no_results translation: 검색 결과 없음 - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: 페이지 없음 - id: 404_recommendations translation: 이 중에 찾는게 있나요? # Cookie consent - id: cookie_message translation: 이 사이트는 최적화된 사용 경험을 제공하기 위해 쿠키를 사용합니다. - id: cookie_dismiss translation: 알겠어! - id: cookie_learn translation: 더 알아보기 # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/lt.yaml ================================================ # Navigation - id: toggle_navigation translation: Perjungti navigaciją - id: table_of_contents translation: Turinys - id: on_this_page translation: Turinys - id: back_to_top translation: Grįžti į puslapio viršų - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Susiję - id: minute_read translation: minučių skaitymo - id: previous translation: Ankstesnis - id: next translation: Tolimesnis - id: figure translation: 'Pav. %d:' - id: edit_page translation: Redaguoti šį puslapį # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Šviesus - id: theme_dark translation: Tamsus - id: theme_auto translation: Automatinis # Buttons - id: btn_preprint translation: Nerecenzuota publikacija - id: btn_pdf translation: PDF - id: btn_cite translation: Citata - id: btn_slides translation: Prezentacija - id: btn_video translation: Video - id: btn_code translation: Kodas - id: btn_dataset translation: Duomenų rinkinys - id: btn_project translation: Projektas - id: btn_poster translation: Plakatas - id: btn_source translation: Šaltinis - id: btn_copy translation: Kopijuoti - id: btn_copied translation: Copied - id: btn_download translation: Parsisiųsti # About widget - id: interests translation: Pomėgiai - id: education translation: Išsilavinimas - id: user_profile_latest translation: Naujausi # Accomplishments widget - id: see_certificate translation: Peržiūrėti sertifikatą # Experience widget - id: present translation: Parodyti # Pages widget - id: more_pages translation: Žiūrėti visus - id: more_posts translation: Žiūrėti visus straipsnius - id: more_talks translation: Žiūrėti visus pranešimus - id: more_publications translation: Žiūrėti visas publikacijas # Contact widget - id: contact_name translation: Vardas - id: contact_email translation: Elektroninis paštas - id: contact_message translation: Žinutė - id: contact_attachment translation: Attach file - id: contact_send translation: Siųsti - id: book_appointment translation: Rezervuoti susitikimą # Publication/Event details - id: abstract translation: Santrauka - id: publication translation: Publikacija - id: publication_type translation: Tipas - id: date translation: Data - id: last_updated translation: Vėliausiai atnaujinti - id: event translation: Renginys - id: location translation: Lokacija - id: pub_paper_conference translation: Konferencijos publikacija - id: pub_article_journal translation: Mokslinis straipsnis - id: pub_article translation: Nerecenzuota publikacija - id: pub_report translation: Ataskaita - id: pub_book translation: Knyga - id: pub_chapter translation: Knygos skyrius - id: pub_thesis translation: Tezė - id: pub_patent translation: Patentas # Project details - id: open_project_site translation: Eiti į projekto puslapį # Content types for default archive page titles and search results - id: posts translation: Straipsniai - id: publications translation: Publikacijos - id: talks translation: Pranešimai - id: projects translation: Projektai - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Paieška - id: search_placeholder translation: Ieškoti... - id: search_results translation: rasta rezultatų - id: search_no_results translation: Nieko nerasta - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Puslapis nerastas - id: 404_recommendations translation: Galbūt jūs ieškojote šių puslapių? # Cookie consent - id: cookie_message translation: Šis puslapis naudoja slapukus, kad užtikrintų geriausią naršymo patirtį. - id: cookie_dismiss translation: Supratau! - id: cookie_learn translation: Sužinoti daugiau # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/lv.yaml ================================================ # Navigation - id: toggle_navigation translation: Pārslēgt navigāciju - id: table_of_contents translation: Satura rādītājs - id: on_this_page translation: Šajā lapā - id: back_to_top translation: Uz augšu - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Līdzīgi - id: minute_read translation: minūtes lasīšanai - id: previous translation: Atpakaļ - id: next translation: Uz priekšu - id: figure translation: 'Attēls %d:' - id: edit_page translation: Rediģēt šo lapu # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprints - id: btn_pdf translation: PDF - id: btn_cite translation: Citēt - id: btn_slides translation: Slaidi - id: btn_video translation: Video - id: btn_code translation: Kods - id: btn_dataset translation: Datu kopa - id: btn_project translation: Projekts - id: btn_poster translation: Plakāts - id: btn_source translation: Pirmavots - id: btn_copy translation: Kopija - id: btn_copied translation: Copied - id: btn_download translation: Lejupielādēt # About widget - id: interests translation: Intereses - id: education translation: Izglītība - id: user_profile_latest translation: Jaunākais # Accomplishments widget - id: see_certificate translation: Skatīt sertifikātu # Experience widget - id: present translation: Šobrīd # Pages widget - id: more_pages translation: Skatīt visu - id: more_posts translation: Skatīt visus rakstus - id: more_talks translation: Skatīt visas runas - id: more_publications translation: Skatīt visas publikācijas # Contact widget - id: contact_name translation: Vārds - id: contact_email translation: E-pasts - id: contact_message translation: Teksts - id: contact_attachment translation: Attach file - id: contact_send translation: Nosūtīt - id: book_appointment translation: Pieteikt tikšanos # Publication/Event details - id: abstract translation: Kopsavilkums - id: publication translation: Publikācija - id: publication_type translation: Veids - id: date translation: Datums - id: last_updated translation: Pēdējais atjauninājums - id: event translation: Notikums - id: location translation: Vieta - id: pub_paper_conference translation: Uzstāšanās konferencē - id: pub_article_journal translation: Raksts žurnālā - id: pub_article translation: Novilkums - id: pub_report translation: Ziņojums - id: pub_book translation: Grāmata - id: pub_chapter translation: Grāmatas nodaļa - id: pub_thesis translation: Disertācija - id: pub_patent translation: Patents # Project details - id: open_project_site translation: Pāriet pie projekta lapas # Content types for default archive page titles and search results - id: posts translation: Blogs - id: publications translation: Publikācijas - id: talks translation: Runas - id: projects translation: Projekti - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Meklēt - id: search_placeholder translation: Meklēt... - id: search_results translation: rezultāti - id: search_no_results translation: Nekas nav atrasts - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Lapa nav atrasta - id: 404_recommendations translation: Iespējams, meklējāt kādu no šiem ierakstiem? # Cookie consent - id: cookie_message translation: Šī vietne izmanto sīkdatnes, lai nodrošinātu Jums vislabāko pieredzi mūsu vietnē. - id: cookie_dismiss translation: Sapratu! - id: cookie_learn translation: Uzzināt vairāk # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/mg.yaml ================================================ # Navigation - id: toggle_navigation translation: Toggle navigation - id: table_of_contents translation: Lohahevitra - id: on_this_page translation: Votoaty - id: back_to_top translation: Miverina eny ambony - id: home translation: Home - id: close translation: Akatona - id: languages translation: Fiteny # General - id: related translation: Mifandraika - id: minute_read translation: minitra vakiana - id: previous translation: Teo aloha - id: next translation: Manaraka - id: figure translation: 'Sary %d:' - id: edit_page translation: Amboary ity pejy ity # Themes - id: theme_selector translation: Asehoy ny safidy - id: theme_light translation: Mazava endrika - id: theme_dark translation: Matroka - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Cite - id: btn_slides translation: Slides - id: btn_video translation: Video - id: btn_code translation: Code - id: btn_dataset translation: Dataset - id: btn_project translation: Tetik’asa - id: btn_poster translation: Afisy - id: btn_source translation: Source Document - id: btn_copy translation: Kopia - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: Mahaliana - id: education translation: Fanabeazana - id: user_profile_latest translation: Farany # Accomplishments widget - id: see_certificate translation: Jereo ny taratasy fanamarinana # Experience widget - id: present translation: Ankehitriny # Pages widget - id: more_pages translation: Jereo daholo - id: more_posts translation: Jereo ny lahatsoratra rehetra - id: more_talks translation: Jereo ny hetsika rehetra - id: more_publications translation: Jereo ny boky rehetra # Contact widget - id: contact_name translation: Anarana - id: contact_email translation: Mailaka - id: contact_message translation: Hafatra - id: contact_attachment translation: Handefa fichier - id: contact_send translation: Alefaso - id: book_appointment translation: Famandrihana fotoana # Publication/Event details - id: abstract translation: Fehinteny - id: publication translation: Publication - id: publication_type translation: Karazana - id: date translation: Daty - id: last_updated translation: Nohavaozina farany tamin'ny - id: event translation: Event - id: location translation: Toerana - id: pub_paper_conference translation: Taratasy fihaonambe - id: pub_article_journal translation: Lahatsoratra amin'ny gazety - id: pub_article translation: Preprint - id: pub_report translation: Tatitra - id: pub_book translation: Boky - id: pub_chapter translation: fizarana boky - id: pub_thesis translation: Thèse - id: pub_patent translation: patanty # Project details - id: open_project_site translation: Mandehana any amin'ny site tetik’asa # Content types for default archive page titles and search results - id: posts translation: Lahatsoratra - id: publications translation: Publications - id: talks translation: Hetsika - id: projects translation: Tetik’asa - id: slides translation: Slides - id: authors translation: Mpanoratra # Search - id: search translation: Fikarohana - id: search_placeholder translation: Fikarohana... - id: search_results translation: valiny hita - id: search_no_results translation: Tsy misy valiny hita - id: search_common_queries translation: Fikarohana mahazatra # Error 404 - id: page_not_found translation: Pejy tsy hita - id: 404_recommendations translation: Angamba iray amin'ireo no tadiavinao? # Cookie consent - id: cookie_message translation: Mampiasa Cookies ity tranokala ity mba hahazoana antoka fa hahazo traikefa tsara indrindra amin'ny tranokalanay ianao. - id: cookie_dismiss translation: Azoko! - id: cookie_learn translation: Mianara bebe kokoa # Published with - id: published_with translation: Navoaka niaraka tamin'ny {hugoblox} — ilay famoronana tranonkala {repo_link}open source{/repo_link} maimaim-poana izay manankahery ny mpamorona. ================================================ FILE: modules/blox/i18n/ms-Arab.yaml ================================================ # Navigation - id: toggle_navigation translation: بوک ڤڠمودين - id: table_of_contents translation: دفتر کندوڠن - id: on_this_page translation: کندوڠن - id: back_to_top translation: کمبالي کأتس - id: home translation: اوتام - id: close translation: توتوڤ - id: languages translation: بهاس # General - id: related translation: ترکاءيت - id: minute_read translation: مينيت اونتوق دباچ - id: previous translation: سبلومڽ - id: next translation: ستروسڽ - id: figure translation: 'اورڠ %d:' - id: edit_page translation: سونتيڠ هالمن اين # Themes - id: theme_selector translation: ڤميليه تيما - id: theme_light translation: چره - id: theme_dark translation: ݢلڤ - id: theme_auto translation: اءوتوماتيک # Buttons - id: btn_preprint translation: ڤراچيتق - id: btn_pdf translation: ڤي.دي.ايف. - id: btn_cite translation: ڤتيق - id: btn_slides translation: ڤرسمبهن - id: btn_video translation: ۏيديو - id: btn_code translation: کود - id: btn_dataset translation: سيت داتا - id: btn_project translation: ڤروجيک - id: btn_poster translation: ڤوستر - id: btn_source translation: سومبر - id: btn_copy translation: سالين - id: btn_copied translation: دسالين - id: btn_download translation: موات تورون # About widget - id: interests translation: مينت - id: education translation: ڤنديديقن - id: user_profile_latest translation: ترکيني # Accomplishments widget - id: see_certificate translation: ليهت سيجيل # Experience widget - id: present translation: ترکيني # Pages widget - id: more_pages translation: ليهت سموا - id: more_posts translation: کيريمن لاءينڽ - id: more_talks translation: ڤربينچڠن لاءينڽ - id: more_publications translation: تربيتن لاءينڽ # Contact widget - id: contact_name translation: نام - id: contact_email translation: إي-ميل - id: contact_message translation: ميسيج - id: contact_attachment translation: سيسيڤ فاءيل - id: contact_send translation: هنتر - id: book_appointment translation: جدوالکنن ڤرتموان # Publication/Event details - id: abstract translation: ابستراک - id: publication translation: تربيتن - id: publication_type translation: جنيس - id: date translation: تاريخ - id: last_updated translation: تراخير دکمس کيني - id: event translation: اچارا - id: location translation: کدودوقن - id: pub_paper_conference translation: کرتس سيدڠ - id: pub_article_journal translation: ارتيکل جورنل - id: pub_article translation: ڤراچيتق - id: pub_report translation: لاڤورنن - id: pub_book translation: بوکو - id: pub_chapter translation: بهاݢين بوکو - id: pub_thesis translation: تيسيس - id: pub_patent translation: ڤاتين # Project details - id: open_project_site translation: کلامان ڤروجيک # Content types for default archive page titles and search results - id: posts translation: کيريمن - id: publications translation: تربيتن - id: talks translation: ڤربينچڠن - id: projects translation: ڤروجيک - id: slides translation: ڤرسمبهن - id: authors translation: ڤنوليس # Search - id: search translation: چاري - id: search_placeholder translation: چاري... - id: search_results translation: هاسيل دجومڤاءي - id: search_no_results translation: تياد هاسيل دجومڤاءي - id: search_common_queries translation: ڤنچارين عموم # Error 404 - id: page_not_found translation: لامن تيدق دتموکن - id: 404_recommendations translation: اداکه اين يڠ اندا چاري؟ # Cookie consent - id: cookie_message translation: لامن اين مڠݢوناکن کوکي اونتوق ممستيکن اندا منداڤتکن ڤڠالمن ترباءيق دري لامن کامي. - id: cookie_dismiss translation: باءيقله! - id: cookie_learn translation: لبيه لنجوت # Published with - id: published_with translation: دتربيتکنن دڠن {hugoblox} — ڤمبوات لامن ويب ڤرچوما {repo_link}برسومبر تربوک{/repo_link} دان برکواس # Feedback widget - id: feedback_widget_title translation: معلوم بالس - id: feedback_widget_question translation: اداکه لامن اين ممبنتو؟ - id: feedback_widget_answer_positive translation: 😍 ي - id: feedback_widget_answer_negative translation: 😡 تيدق ================================================ FILE: modules/blox/i18n/ms.yaml ================================================ # Navigation - id: toggle_navigation translation: Buka pengemudian - id: table_of_contents translation: Daftar kandungan - id: on_this_page translation: Kandungan - id: back_to_top translation: Kembali ke atas - id: home translation: Utama - id: close translation: Tutup - id: languages translation: Bahasa # General - id: related translation: Terkait - id: minute_read translation: minit untuk dibaca - id: previous translation: Sebelumnya - id: next translation: Seterusnya - id: figure translation: 'Orang %d:' - id: edit_page translation: Sunting halaman ini # Themes - id: theme_selector translation: Pemilih tema - id: theme_light translation: Cerah - id: theme_dark translation: Gelap - id: theme_auto translation: Automatik # Buttons - id: btn_preprint translation: Pracetak - id: btn_pdf translation: PDF - id: btn_cite translation: Petik - id: btn_slides translation: Persembahan - id: btn_video translation: Video - id: btn_code translation: Kod - id: btn_dataset translation: Set data - id: btn_project translation: Projek - id: btn_poster translation: Poster - id: btn_source translation: Sumber - id: btn_copy translation: Salin - id: btn_copied translation: Disalin - id: btn_download translation: Muat turun # About widget - id: interests translation: Minat - id: education translation: Pendidikan - id: user_profile_latest translation: Terkini # Accomplishments widget - id: see_certificate translation: Lihat sijil # Experience widget - id: present translation: Terkini # Pages widget - id: more_pages translation: Lihat semua - id: more_posts translation: Kiriman lainnya - id: more_talks translation: Perbincangan lainnya - id: more_publications translation: Terbitan lainnya # Contact widget - id: contact_name translation: Nama - id: contact_email translation: E-mel - id: contact_message translation: Mesej - id: contact_attachment translation: Sisip fail - id: contact_send translation: Hantar - id: book_appointment translation: Jadualkan pertemuan # Publication/Event details - id: abstract translation: Abstrak - id: publication translation: Terbitan - id: publication_type translation: Jenis - id: date translation: Tarikh - id: last_updated translation: Terakhir dikemas kini - id: event translation: Acara - id: location translation: Kedudukan - id: pub_paper_conference translation: Kertas sidang - id: pub_article_journal translation: Artikel jurnal - id: pub_article translation: Pracetak - id: pub_report translation: Laporan - id: pub_book translation: Buku - id: pub_chapter translation: Bahagian buku - id: pub_thesis translation: Tesis - id: pub_patent translation: Paten # Project details - id: open_project_site translation: Ke laman projek # Content types for default archive page titles and search results - id: posts translation: Kiriman - id: publications translation: Terbitan - id: talks translation: Perbincangan - id: projects translation: Projek - id: slides translation: Persembahan - id: authors translation: Penulis # Search - id: search translation: Cari - id: search_placeholder translation: Cari... - id: search_results translation: hasil dijumpai - id: search_no_results translation: Tiada hasil dijumpai - id: search_common_queries translation: Pencarian umum # Error 404 - id: page_not_found translation: Laman tidak ditemukan - id: 404_recommendations translation: Adakah ini yang anda cari? # Cookie consent - id: cookie_message translation: Laman ini menggunakan kuki untuk memastikan anda mendapatkan pengalaman terbaik dari laman web kami. - id: cookie_dismiss translation: Baiklah! - id: cookie_learn translation: Lebih lanjut # Published with - id: published_with translation: Diterbitkan dengan {hugoblox} — pembuat laman web percuma {repo_link}bersumber terbuka{/repo_link} dan berkuasa. # Feedback widget - id: feedback_widget_title translation: Maklum balas - id: feedback_widget_question translation: Adakah laman ini membantu? - id: feedback_widget_answer_positive translation: 😍 Ya - id: feedback_widget_answer_negative translation: 😡 Tidak ================================================ FILE: modules/blox/i18n/nb.yaml ================================================ # Navigation - id: toggle_navigation translation: Bytte navigering - id: table_of_contents translation: Innholdsfortegnelse - id: on_this_page translation: Innhold - id: back_to_top translation: Tilbake til toppen - id: home translation: Hjem - id: close translation: Lukk - id: languages translation: Språk # General - id: related translation: Relatert - id: minute_read translation: min. lesing - id: previous translation: Forrige - id: next translation: Neste - id: figure translation: 'Figur %d:' - id: edit_page translation: Rediger denne siden # Themes - id: theme_selector translation: Vis innstillinger - id: theme_light translation: Lys - id: theme_dark translation: Mørk - id: theme_auto translation: Automatisk # Buttons - id: btn_preprint translation: Upublisert manus (preprint) - id: btn_pdf translation: PDF - id: btn_cite translation: Sitere - id: btn_slides translation: Presentasjoner - id: btn_video translation: Video - id: btn_code translation: Kode - id: btn_dataset translation: Datasett - id: btn_project translation: Prosjekt - id: btn_poster translation: Innlegg - id: btn_source translation: Kildedokument - id: btn_copy translation: Kopi - id: btn_copied translation: Kopiert - id: btn_download translation: Last ned # About widget - id: interests translation: Interesser - id: education translation: Utdanning - id: user_profile_latest translation: Siste # Accomplishments widget - id: see_certificate translation: Se sertifikat # Experience widget - id: present translation: Nå # Pages widget - id: more_pages translation: Se alle - id: more_posts translation: Se alle innlegg - id: more_talks translation: Se alle presentasjoner - id: more_publications translation: See alle publiseringer # Contact widget - id: contact_name translation: Navn - id: contact_email translation: E-post - id: contact_message translation: Melding - id: contact_attachment translation: Legg ved fil - id: contact_send translation: Send - id: book_appointment translation: Be om en avtale # Publication/Event details - id: abstract translation: Sammendrag - id: publication translation: Publisering - id: publication_type translation: Type - id: date translation: Dato - id: last_updated translation: Sist oppdatert den - id: event translation: Arrangement - id: location translation: Sted - id: pub_paper_conference translation: Konferanseartikkel - id: pub_article_journal translation: Tidskriftsartikkel - id: pub_article translation: Upublisert manus (preprint) - id: pub_report translation: Rapport - id: pub_book translation: Bok - id: pub_chapter translation: Bokkapittel - id: pub_thesis translation: Avhandling - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Gå til prosjektside # Content types for default archive page titles and search results - id: posts translation: Innlegg - id: publications translation: Publiseringer - id: talks translation: Foredrag - id: projects translation: Prosjekter - id: slides translation: Presentasjoner - id: authors translation: Forfattere # Search - id: search translation: Søk - id: search_placeholder translation: Søk... - id: search_results translation: resultater funnet - id: search_no_results translation: Ingen resultater funnet - id: search_common_queries translation: Felles søkeord # Error 404 - id: page_not_found translation: Siden ble ikke funnet - id: 404_recommendations translation: Kanskje du lette etter noe av dette? # Cookie consent - id: cookie_message translation: Denne siden bruker informasjonskapsler (cookies) for å bidra til den beste opplevelsen av denne nettsiden. - id: cookie_dismiss translation: Skjønner! - id: cookie_learn translation: Lær mer # Published with - id: published_with translation: Publisert med {hugoblox} — en gratis løsning, {repo_link}basert på åpen kildekode{/repo_link} for å generere nettsider. ================================================ FILE: modules/blox/i18n/nl.yaml ================================================ # Navigation - id: toggle_navigation translation: Navigatiebalk - id: table_of_contents translation: Inhoudsopgave - id: on_this_page translation: Op deze pagina - id: back_to_top translation: Terug naar boven - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Gerelateerd - id: minute_read translation: minuten lezen - id: previous translation: Vorige - id: next translation: Volgende - id: figure translation: 'Figuur %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Citeer - id: btn_slides translation: Dia's - id: btn_video translation: Video - id: btn_code translation: Code - id: btn_dataset translation: Dataset - id: btn_project translation: Project - id: btn_poster translation: Poster - id: btn_source translation: Brondocument - id: btn_copy translation: Kopieer - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: Interesses - id: education translation: Educatie - id: user_profile_latest translation: Nieuwste # Accomplishments widget - id: see_certificate translation: Bekijk certificate # Experience widget - id: present translation: Present # Pages widget - id: more_pages translation: Bekijk alles - id: more_posts translation: Meer Berichten - id: more_talks translation: Meer Presentaties - id: more_publications translation: Meer Publicaties # Contact widget - id: contact_name translation: Naam - id: contact_email translation: E-mailadres - id: contact_message translation: Bericht - id: contact_attachment translation: Attach file - id: contact_send translation: Verzend - id: book_appointment translation: Maak een afspraak # Contact info block - id: block_contact_title translation: Neem contact op - id: block_contact_visit_title translation: Bezoek ons - id: block_contact_office_hours translation: Kantoortijden - id: block_contact_view_on_map translation: Bekijk op kaart - id: block_contact_connect_title translation: Contact - id: block_contact_follow_us translation: Volg ons - id: block_contact_prospective_title translation: Aspirant-leden - id: block_contact_form_title translation: Stuur ons een bericht - id: block_contact_form_name translation: Naam - id: block_contact_form_email translation: E-mailadres - id: block_contact_form_subject translation: Onderwerp - id: block_contact_form_message translation: Bericht - id: block_contact_form_submit translation: Verzend bericht # Publication/Event details - id: abstract translation: Samenvatting - id: publication translation: Publicatie - id: publication_type translation: Type - id: date translation: Datum - id: last_updated translation: Laatst bijgewerkt op - id: event translation: Evenement - id: location translation: Locatie - id: pub_paper_conference translation: Conferentiepaper - id: pub_article_journal translation: Journalartikel - id: pub_article translation: Preprint - id: pub_report translation: Rapport - id: pub_book translation: Boek - id: pub_chapter translation: Boek sectie - id: pub_thesis translation: Proefschrift - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Ga naar Projectenpagina # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publicaties - id: events translation: Evenementen - id: projects translation: Projects - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Search - id: search_placeholder translation: Zoeken... - id: search_results translation: resultaten gevonden - id: search_no_results translation: Geen resultaten gevonden - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Pagina niet gevonden - id: 404_recommendations translation: Misschien was je op zoek naar een van deze pagina's? # Cookie consent - id: cookie_message translation: Deze website gebruikt cookies om je de best mogelijke ervaring te bieden. - id: cookie_dismiss translation: Accepteer cookies - id: cookie_learn translation: Meer informatie # Published with - id: published_with translation: Made with {hugoblox}. - id: poweredby_button translation: 'Bouw de jouwe →' # Contact info block - id: block_contact_follow_me translation: Vind mij op # Dev Hero block - id: scroll_to_content translation: Scroll naar inhoud - id: developer translation: Ontwikkelaar # Portfolio block - id: portfolio_link_code translation: Code - id: portfolio_link_live translation: Live - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Link - id: portfolio_view_all translation: Bekijk alle projecten # AI Features - id: ai_insight translation: AI-inzicht # Content Metadata - id: content_type translation: Contenttype - id: difficulty translation: Moeilijkheidsgraad - id: prerequisites translation: Vereisten # Card metadata - id: trending translation: Populair - id: article translation: artikel - id: articles translation: artikelen - id: browse translation: Bladeren - id: all translation: Alles - id: helpful translation: nuttig # Additional buttons - id: btn_site translation: Site - id: btn_canonical translation: Canoniek - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Discussie - id: btn_event translation: Evenement - id: btn_calendar translation: Kalender - id: btn_registration translation: Registratie - id: btn_demo translation: Demo - id: btn_model translation: Model - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_note translation: Notitie - id: callout_abstract translation: Samenvatting - id: callout_summary translation: Samenvatting - id: callout_info translation: Info - id: callout_todo translation: Te doen - id: callout_tip translation: Tip - id: callout_question translation: Vraag - id: callout_quote translation: Citaat - id: callout_warning translation: Waarschuwing - id: callout_caution translation: Let op - id: callout_danger translation: Gevaar - id: callout_bug translation: Bug - id: callout_example translation: Voorbeeld - id: callout_failure translation: Mislukt - id: callout_success translation: Succes - id: callout_important translation: Belangrijk # Slides - id: back_to_slides translation: Terug naar slides - id: present_slides translation: Presenteren - id: present_fullscreen translation: Presenteren (volledig scherm) - id: export_pdf_print translation: PDF exporteren (print) - id: slides_print_hint translation: Opent in printmodus - browser Afdrukken > Opslaan als PDF - id: slides_search_placeholder translation: Zoek decks op titel... - id: slides_no_decks translation: Geen decks gevonden - id: slides_no_matches translation: Geen decks voldoen aan je filters - id: clear_filters translation: Filters wissen - id: topics translation: Onderwerpen - id: details translation: Details - id: related_resources translation: Gerelateerde bronnen - id: copy_link translation: Link kopiëren - id: copy_citation translation: Citatie kopiëren - id: how_to_cite translation: Hoe te citeren - id: citation translation: Citatie - id: bibtex translation: BibTeX - id: download_cite_bib translation: cite.bib downloaden - id: lecture translation: College - id: enter_fullscreen translation: Volledig scherm - id: exit_fullscreen translation: Volledig scherm afsluiten - id: speaker_notes_hint translation: voor sprekersnotities - id: slides_not_found translation: Slides niet gevonden # Q&A - id: qa translation: Q&A - id: question translation: Vraag - id: answer translation: Antwoord - id: accepted_answer translation: Geaccepteerd antwoord - id: other_answers translation: Andere antwoorden - id: questions translation: Vragen - id: questions_count translation: vragen - id: related_questions translation: Gerelateerde vragen - id: search_questions translation: Zoek vragen... - id: no_questions_yet translation: Nog geen vragen - id: faq translation: FAQ - id: faqs translation: FAQs - id: browse_by_category translation: Blader op categorie # General extras - id: about_me translation: Professionele samenvatting - id: backlinks translation: Backlinks - id: days translation: Dagen - id: hours translation: Uren - id: minutes translation: Minuten - id: seconds translation: Seconden - id: experience translation: Ervaring - id: read_more translation: Lees meer - id: docs translation: Documentatie - id: featured translation: Uitgelicht - id: feedback_widget_title translation: Feedback - id: feedback_widget_question translation: Was deze pagina nuttig? - id: feedback_widget_answer_positive translation: 😍 Ja - id: feedback_widget_answer_negative translation: 😡 Nee ================================================ FILE: modules/blox/i18n/pl.yaml ================================================ # Navigation - id: toggle_navigation translation: Włącz/Wyłącz nawigację - id: table_of_contents translation: Spis treści - id: on_this_page translation: Na tej stronie - id: back_to_top translation: Powrót do góry - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Powiązane - id: minute_read translation: min czytania - id: previous translation: Poprzedni - id: next translation: Następny - id: figure translation: 'Figura %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Cytowanie - id: btn_slides translation: Slajdy - id: btn_video translation: Wideo - id: btn_code translation: Kod - id: btn_dataset translation: Dane - id: btn_project translation: Projekt - id: btn_poster translation: Poster - id: btn_source translation: Dokument źródłowy - id: btn_copy translation: Kopia - id: btn_copied translation: Copied - id: btn_download translation: Pobierz # About widget - id: interests translation: Zainteresowania - id: education translation: Wykształcenie - id: user_profile_latest translation: Ostatnie # Accomplishments widget - id: see_certificate translation: Zobacz certyfikat # Experience widget - id: present translation: Obecnie # Pages widget - id: more_pages translation: Wszystkie - id: more_posts translation: Więcej postów - id: more_talks translation: Więcej wystąpień - id: more_publications translation: Więcej publikacji # Contact widget - id: contact_name translation: Imię i nazwisko - id: contact_email translation: Adres email - id: contact_message translation: Wiadomość - id: contact_attachment translation: Attach file - id: contact_send translation: Wyślij - id: book_appointment translation: Umów spotkanie # Publication/Event details - id: abstract translation: Streszczenie - id: publication translation: Publikacja - id: publication_type translation: Rodzaj - id: date translation: Data - id: last_updated translation: Ostatnia aktualizacja - id: event translation: Wydarzenie - id: location translation: Miejsce - id: pub_paper_conference translation: Prezentacja z konferencji - id: pub_article_journal translation: Artykuł w czasopiśmie - id: pub_article translation: Preprint - id: pub_report translation: Raport - id: pub_book translation: Książka - id: pub_chapter translation: Rozdział książki - id: pub_thesis translation: Praca dyplomowa - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Idź do strony projektu # Content types for default archive page titles and search results - id: posts translation: Posty - id: publications translation: Publikacje - id: talks translation: Wystąpienia - id: projects translation: Projekty - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Szukaj - id: search_placeholder translation: Szukaj... - id: search_results translation: wyników - id: search_no_results translation: Brak wyników - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Strona nie znaleziona - id: 404_recommendations translation: Podobne strony # Cookie consent - id: cookie_message translation: Ta strona używa ciasteczek do poprawnego działania strony. - id: cookie_dismiss translation: Zrozumiałem! - id: cookie_learn translation: Dlaczego? # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/pt.yaml ================================================ # Navigation - id: toggle_navigation translation: Alterar navegação - id: table_of_contents translation: Lista de Conteúdos - id: on_this_page translation: Nesta página - id: back_to_top translation: Voltar para o topo - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Relacionados - id: minute_read translation: minutos de leitura - id: previous translation: Anterior - id: next translation: Próximo - id: figure translation: 'Figura %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Pré-impressão - id: btn_pdf translation: PDF - id: btn_cite translation: Citação - id: btn_slides translation: Slides - id: btn_video translation: Vídeo - id: btn_code translation: Código - id: btn_dataset translation: Dados - id: btn_project translation: Projeto - id: btn_poster translation: Pôster - id: btn_source translation: Documento Fonte - id: btn_copy translation: Copiar - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: Interesses - id: education translation: Formação - id: user_profile_latest translation: Recentes # Accomplishments widget - id: see_certificate translation: Ver certificado # Experience widget - id: present translation: Presente # Pages widget - id: more_pages translation: Ver todas - id: more_posts translation: Mais Posts - id: more_talks translation: Mais Palestras - id: more_publications translation: Mais Publicações # Contact widget - id: contact_name translation: Nome - id: contact_email translation: Email - id: contact_message translation: Mensagem - id: contact_attachment translation: Attach file - id: contact_send translation: Enviar - id: book_appointment translation: Agendar um horário # Contact info block - id: block_contact_title translation: Fale Conosco - id: block_contact_visit_title translation: Visite-nos - id: block_contact_office_hours translation: Horário de atendimento - id: block_contact_view_on_map translation: Ver no mapa - id: block_contact_connect_title translation: Contato - id: block_contact_follow_us translation: Siga-nos - id: block_contact_prospective_title translation: Membros em potencial - id: block_contact_form_title translation: Envie-nos uma mensagem - id: block_contact_form_name translation: Nome - id: block_contact_form_email translation: Email - id: block_contact_form_subject translation: Assunto - id: block_contact_form_message translation: Mensagem - id: block_contact_form_submit translation: Enviar mensagem # Publication/Event details - id: abstract translation: Resumo - id: publication translation: Publicação - id: publication_type translation: Tipo - id: date translation: Data - id: last_updated translation: Última atualização em - id: event translation: Evento - id: location translation: Local - id: pub_paper_conference translation: Artigo de conferência - id: pub_article_journal translation: Artigo de revista - id: pub_article translation: Pré-impressão - id: pub_report translation: Relatório - id: pub_book translation: Livro - id: pub_chapter translation: Seção de livro - id: pub_thesis translation: Tese - id: pub_patent translation: Patente # Project details - id: open_project_site translation: Ir para o site do projeto # Content types for default archive page titles and search results - id: blog translation: Blog - id: publications translation: Publicações - id: events translation: Eventos - id: projects translation: Projetos - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Pesquisar - id: search_placeholder translation: Pesquisar... - id: search_results translation: Resultados encontrados - id: search_no_results translation: Sem resultados - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Página não encontrada - id: 404_recommendations translation: Você está procurando por um desses? # Cookie consent - id: cookie_message translation: Este site contém cookies para garantir que você tenha a melhor experência. - id: cookie_dismiss translation: Entendi! - id: cookie_learn translation: Saiba mais # Published with - id: published_with translation: Made with {hugoblox}. # AI Features - id: ai_insight translation: Insight de IA # Content Metadata - id: content_type translation: Tipo de conteúdo - id: difficulty translation: Dificuldade - id: prerequisites translation: Pré-requisitos # Card metadata - id: trending translation: Em alta - id: article translation: artigo - id: articles translation: artigos - id: browse translation: Navegar - id: all translation: Todos - id: helpful translation: útil # Additional buttons - id: btn_site translation: Site - id: btn_canonical translation: Canônico - id: btn_crosspost translation: Crosspost - id: btn_discussion translation: Discussão - id: btn_event translation: Evento - id: btn_calendar translation: Calendário - id: btn_registration translation: Inscrição - id: btn_demo translation: Demo - id: btn_model translation: Modelo - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_note translation: Nota - id: callout_abstract translation: Resumo - id: callout_summary translation: Sumário - id: callout_info translation: Informação - id: callout_todo translation: Para fazer - id: callout_tip translation: Dica - id: callout_question translation: Pergunta - id: callout_quote translation: Citação - id: callout_warning translation: Aviso - id: callout_caution translation: Cuidado - id: callout_danger translation: Perigo - id: callout_bug translation: Bug - id: callout_example translation: Exemplo - id: callout_failure translation: Falha - id: callout_success translation: Sucesso - id: callout_important translation: Importante # Slides - id: back_to_slides translation: Voltar para slides - id: present_slides translation: Apresentar - id: present_fullscreen translation: Apresentar (tela cheia) - id: export_pdf_print translation: Exportar PDF (impressão) - id: slides_print_hint translation: Abre em modo de impressão - use Imprimir > Salvar como PDF - id: slides_search_placeholder translation: Buscar decks por título... - id: slides_no_decks translation: Nenhum conjunto de slides encontrado - id: slides_no_matches translation: Nenhum deck corresponde aos filtros - id: clear_filters translation: Limpar filtros - id: topics translation: Tópicos - id: details translation: Detalhes - id: related_resources translation: Recursos relacionados - id: copy_link translation: Copiar link - id: copy_citation translation: Copiar citação - id: how_to_cite translation: Como citar - id: citation translation: Citação - id: bibtex translation: BibTeX - id: download_cite_bib translation: Baixar cite.bib - id: lecture translation: Aula - id: enter_fullscreen translation: Entrar em tela cheia - id: exit_fullscreen translation: Sair da tela cheia - id: speaker_notes_hint translation: para notas do apresentador - id: slides_not_found translation: Slides não encontrados # Q&A - id: qa translation: Q&A - id: question translation: Pergunta - id: answer translation: Resposta - id: accepted_answer translation: Resposta aceita - id: other_answers translation: Outras respostas - id: questions translation: Perguntas - id: questions_count translation: perguntas - id: related_questions translation: Perguntas relacionadas - id: search_questions translation: Buscar perguntas... - id: no_questions_yet translation: Ainda não há perguntas - id: faq translation: FAQ - id: faqs translation: FAQs - id: browse_by_category translation: Navegar por categoria # General extras - id: about_me translation: Resumo profissional - id: backlinks translation: Backlinks - id: days translation: Dias - id: hours translation: Horas - id: minutes translation: Minutos - id: seconds translation: Segundos - id: developer translation: Desenvolvedor - id: docs translation: Documentação - id: experience translation: Experiência - id: read_more translation: Leia mais - id: featured translation: Em destaque - id: block_contact_follow_me translation: Encontre-me em - id: portfolio_link_code translation: Código - id: portfolio_link_live translation: Ao vivo - id: portfolio_link_demo translation: Demo - id: portfolio_link_default translation: Link - id: portfolio_view_all translation: Ver todos os projetos - id: scroll_to_content translation: Rolar para o conteúdo - id: feedback_widget_title translation: Feedback - id: feedback_widget_question translation: Esta página foi útil? - id: feedback_widget_answer_positive translation: 😍 Sim - id: feedback_widget_answer_negative translation: 😡 Não - id: poweredby_button translation: 'Construa a sua →' ================================================ FILE: modules/blox/i18n/ro.yaml ================================================ # Navigation - id: toggle_navigation translation: Bara de navigare - id: table_of_contents translation: Indice - id: on_this_page translation: Pe această pagină - id: back_to_top translation: Înapoi la început - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Înrudit - id: minute_read translation: min de citire - id: previous translation: Anterioară - id: next translation: Următor - id: figure translation: 'Imagine %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preimprimare - id: btn_pdf translation: PDF - id: btn_cite translation: Citat - id: btn_slides translation: Diapozitive - id: btn_video translation: Vídeo - id: btn_code translation: Cod - id: btn_dataset translation: Date - id: btn_project translation: Proiect - id: btn_poster translation: Poster - id: btn_source translation: Sursa document - id: btn_copy translation: Copie - id: btn_copied translation: Copied - id: btn_download translation: Descărcare # About widget - id: interests translation: Interese - id: education translation: Educație - id: user_profile_latest translation: Recent # Accomplishments widget - id: see_certificate translation: Vezi certificatul # Experience widget - id: present translation: În prezent # Pages widget - id: more_pages translation: Vezi tot - id: more_posts translation: Mai multe postări - id: more_talks translation: Mai multe discuții - id: more_publications translation: Mai multe publicații # Contact widget - id: contact_name translation: Nume - id: contact_email translation: Email - id: contact_message translation: Mesaj - id: contact_attachment translation: Attach file - id: contact_send translation: Trimiteți - id: book_appointment translation: Solicitați o întâlnire # Publication/Event details - id: abstract translation: Rezumat - id: publication translation: Publicație - id: publication_type translation: Tip - id: date translation: Data - id: last_updated translation: Ultima actualizare la - id: event translation: Eveniment - id: location translation: Localizare - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Articol jurnal - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Carte - id: pub_chapter translation: Secțiunea cărți - id: pub_thesis translation: Teza - id: pub_patent translation: Brevet de invenție # Project details - id: open_project_site translation: Accesați site-ul proiectului # Content types for default archive page titles and search results - id: posts translation: Articole - id: publications translation: Publicații - id: talks translation: Conferințe - id: projects translation: Proiecte - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Căutare - id: search_placeholder translation: Căutare... - id: search_results translation: rezultate găsite - id: search_no_results translation: Nu s-au găsit rezultate - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Pagina nu a fost găsită - id: 404_recommendations translation: Căutați una din acestea? # Cookie consent - id: cookie_message translation: Acest site utilizează cookie-uri pentru a garanta o experiență mai bună. - id: cookie_dismiss translation: Înțeles! - id: cookie_learn translation: Mai multe informații # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/ru.yaml ================================================ # Navigation - id: toggle_navigation translation: Переключить навигацию - id: table_of_contents translation: Содержание - id: on_this_page translation: На этой странице - id: back_to_top translation: На верх - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Похожие - id: minute_read translation: мин. для прочтения - id: previous translation: Предыдущий - id: next translation: Следующий - id: figure translation: 'Схема № %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Предварительная печать - id: btn_pdf translation: PDF - id: btn_cite translation: Процитировать - id: btn_slides translation: Слайды - id: btn_video translation: Видео - id: btn_code translation: Код - id: btn_dataset translation: Набор данных - id: btn_project translation: Проект - id: btn_poster translation: Постер - id: btn_source translation: Исходный документ - id: btn_copy translation: Копия - id: btn_copied translation: Copied - id: btn_download translation: Скачать # About widget - id: interests translation: Интересы - id: education translation: Образование - id: user_profile_latest translation: Последние # Accomplishments widget - id: see_certificate translation: Посмотреть сертификат # Experience widget - id: present translation: Настоящий # Pages widget - id: more_pages translation: Посмотреть всё - id: more_posts translation: Больше статей - id: more_talks translation: Больше выступлений - id: more_publications translation: Больше публикаций # Contact widget - id: contact_name translation: Имя - id: contact_email translation: адрес электронной почты - id: contact_message translation: Сообщение - id: contact_attachment translation: Attach file - id: contact_send translation: Отправить - id: book_appointment translation: Назначить встречу # Publication/Event details - id: abstract translation: Аннотация - id: publication translation: Публикация - id: publication_type translation: Тип публикации - id: date translation: Дата - id: last_updated translation: Обновлено - id: event translation: Событие - id: location translation: Место - id: pub_paper_conference translation: Статья для конференции - id: pub_article_journal translation: Статья для журнала - id: pub_article translation: Предварительная печать - id: pub_report translation: Выступление - id: pub_book translation: Книга - id: pub_chapter translation: Глава книги - id: pub_thesis translation: Тезис - id: pub_patent translation: Патент # Project details - id: open_project_site translation: Перейти на сайт проекта # Content types for default archive page titles and search results - id: posts translation: Статьи - id: publications translation: Публикации - id: talks translation: Выступления - id: projects translation: Проекты - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Поиск - id: search_placeholder translation: Поиск ... - id: search_results translation: результат найден - id: search_no_results translation: результат не найден - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Страница не найдена - id: 404_recommendations translation: Вы наверное искали один из тезисов? # Cookie consent - id: cookie_message translation: Для комфорной навигации на этом сайте используются куки (cookies). - id: cookie_dismiss translation: Понял! - id: cookie_learn translation: Узнать больше # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/so.yaml ================================================ # Navigation - id: toggle_navigation translation: Rog socodka - id: table_of_contents translation: Tusmada Guud - id: on_this_page translation: Boggan ku yaal - id: back_to_top translation: Kor aad - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: La Mida - id: minute_read translation: Akhrisma - id: previous translation: Hore - id: next translation: Xiga - id: figure translation: 'Sawir %d:' - id: edit_page translation: Tifatir Boggan # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Caddee - id: theme_dark translation: Madoobee - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Daabac hore - id: btn_pdf translation: PDF - id: btn_cite translation: Xigso - id: btn_slides translation: Slides - id: btn_video translation: Video - id: btn_code translation: Code - id: btn_dataset translation: Xog - id: btn_project translation: Mashruuc - id: btn_poster translation: Poster - id: btn_source translation: Source Document - id: btn_copy translation: Nuqul - id: btn_copied translation: Copied - id: btn_download translation: Dajiso # About widget - id: interests translation: Hiwaayado - id: education translation: Waxbarasho - id: user_profile_latest translation: Ugu cusub # Accomplishments widget - id: see_certificate translation: Arag Shahaadada # Experience widget - id: present translation: Hadda # Pages widget - id: more_pages translation: Arag dhammaan - id: more_posts translation: Arag dhammaan qoraalada - id: more_talks translation: Arag Qudbadaha - id: more_publications translation: Arag qoraalada oo dhan # Contact widget - id: contact_name translation: Magac - id: contact_email translation: Email - id: contact_message translation: Baaq - id: contact_attachment translation: Attach file - id: contact_send translation: Dir - id: book_appointment translation: Ballan qabso # Publication/Event details - id: abstract translation: Arar - id: publication translation: Qormooyin - id: publication_type translation: Nooc - id: date translation: Goor - id: last_updated translation: La tifatiray - id: event translation: Dhacdo - id: location translation: Meel - id: pub_paper_conference translation: Qoraal Shir - id: pub_article_journal translation: Qoraal Majallad - id: pub_article translation: Daabac Hore - id: pub_report translation: Wargelin - id: pub_book translation: Buug - id: pub_chapter translation: Qayb Buug - id: pub_thesis translation: Buug Qalinjabin - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Tag Bogga Mashruuca # Content types for default archive page titles and search results - id: posts translation: Qoraal - id: publications translation: Publications - id: talks translation: Qudbad - id: projects translation: Mashruuc - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Raadi - id: search_placeholder translation: Raadi... - id: search_results translation: results found - id: search_no_results translation: No results found - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Boggan lama helin - id: 404_recommendations translation: Malaha waxaad raadinaysay? # Cookie consent - id: cookie_message translation: Boggani wuxuu isticmaala "cookies" sii aad u hesho adeegga ugu wacan - id: cookie_dismiss translation: Gartay! - id: cookie_learn translation: Faahfaahin # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/sv.yaml ================================================ # Navigation - id: toggle_navigation translation: Växla navigering - id: table_of_contents translation: Innehållsförteckning - id: on_this_page translation: Innehåll - id: back_to_top translation: Tillbaka till toppen - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Relaterad - id: minute_read translation: Min Läsning - id: previous translation: Föregående - id: next translation: Nästa - id: figure translation: 'Figur %d:' - id: edit_page translation: Redigera den här sidan # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Manuscript - id: btn_pdf translation: PDF - id: btn_cite translation: Citera - id: btn_slides translation: Presentationer - id: btn_video translation: Video - id: btn_code translation: Kod - id: btn_dataset translation: Datauppsättning - id: btn_project translation: Projekt - id: btn_poster translation: Affisch - id: btn_source translation: Källdokument - id: btn_copy translation: Kopia - id: btn_copied translation: Copied - id: btn_download translation: Ladda ner # About widget - id: interests translation: Intressen - id: education translation: Utbildning - id: user_profile_latest translation: Senaste Inläggen # Accomplishments widget - id: see_certificate translation: Se certifikat # Experience widget - id: present translation: Nuvarande # Pages widget - id: more_pages translation: Se allt - id: more_posts translation: Se alla inlägg - id: more_talks translation: Se alla föredrag - id: more_publications translation: Se alla publikationer # Contact widget - id: contact_name translation: Namn - id: contact_email translation: E-post - id: contact_message translation: Meddelande - id: contact_attachment translation: Attach file - id: contact_send translation: Skicka - id: book_appointment translation: Boka ett möte # Publication/Event details - id: abstract translation: Abstrakt - id: publication translation: Publikation - id: publication_type translation: Typ - id: date translation: Datum - id: last_updated translation: Senast uppdaterad - id: event translation: Event - id: location translation: Plats - id: pub_paper_conference translation: Konferensbidrag - id: pub_article_journal translation: Tidskriftsartikel - id: pub_article translation: Manuscript - id: pub_report translation: Rapport - id: pub_book translation: Bok - id: pub_chapter translation: Bok sektion - id: pub_thesis translation: Avhandling - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Gå till projektsidan # Content types for default archive page titles and search results - id: posts translation: Inlägg - id: publications translation: Publikationer - id: talks translation: Föredrag - id: projects translation: Projekt - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Sök - id: search_placeholder translation: Sök... - id: search_results translation: hittade resultat - id: search_no_results translation: Inga resultat funna - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Sidan hittas inte - id: 404_recommendations translation: Kanske letade du efter en av dessa? # Cookie consent - id: cookie_message translation: Denna webbplats använder kakor för att säkerställa att du får den bästa upplevelsen på vår webbplats. - id: cookie_dismiss translation: Jag fattar! - id: cookie_learn translation: Lär dig mer # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/tr.yaml ================================================ # Navigation - id: toggle_navigation translation: Arayüz yönünü değiştir - id: table_of_contents translation: Table of Contents - id: on_this_page translation: On this page - id: back_to_top translation: Back to top - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Related - id: minute_read translation: min read - id: previous translation: Previous - id: next translation: Next - id: figure translation: 'Figure %d:' - id: edit_page translation: Edit this page # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Preprint - id: btn_pdf translation: PDF - id: btn_cite translation: Cite - id: btn_slides translation: Slaytlar - id: btn_video translation: Video - id: btn_code translation: Kod - id: btn_dataset translation: Veri kümesi - id: btn_project translation: Proje - id: btn_poster translation: Poster - id: btn_source translation: Source Document - id: btn_copy translation: Copy - id: btn_copied translation: Copied - id: btn_download translation: Download # About widget - id: interests translation: İlgi alanları - id: education translation: Eğitim - id: user_profile_latest translation: Latest # Accomplishments widget - id: see_certificate translation: See certificate # Experience widget - id: present translation: Present # Pages widget - id: more_pages translation: See all - id: more_posts translation: Daha fazla blog içeriği - id: more_talks translation: Daha fazla konuşma - id: more_publications translation: Daha fazla yayınlar # Contact widget - id: contact_name translation: Name - id: contact_email translation: Email - id: contact_message translation: Message - id: contact_attachment translation: Attach file - id: contact_send translation: Send - id: book_appointment translation: Book an appointment # Publication/Event details - id: abstract translation: Özet - id: publication translation: Yayın - id: publication_type translation: Yayın tipi - id: date translation: Tarih - id: last_updated translation: Last updated on - id: event translation: Etkinlikler - id: location translation: Adres - id: pub_paper_conference translation: Conference paper - id: pub_article_journal translation: Journal article - id: pub_article translation: Preprint - id: pub_report translation: Report - id: pub_book translation: Book - id: pub_chapter translation: Book section - id: pub_thesis translation: Thesis - id: pub_patent translation: Patent # Project details - id: open_project_site translation: Projenin sayfasına git # Content types for default archive page titles and search results - id: posts translation: Blog içerikleri - id: publications translation: Yayınlar - id: talks translation: Konuşmalar - id: projects translation: Projects - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Search - id: search_placeholder translation: Search... - id: search_results translation: results found - id: search_no_results translation: No results found - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Page not found - id: 404_recommendations translation: Perhaps you were looking for one of these? # Cookie consent - id: cookie_message translation: This website uses cookies to ensure you get the best experience on our website. - id: cookie_dismiss translation: Got it! - id: cookie_learn translation: Learn more # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/uk.yaml ================================================ # Navigation - id: toggle_navigation translation: Перемкнути навігацію - id: table_of_contents translation: Зміст - id: on_this_page translation: на сторінці - id: back_to_top translation: Повернутися догори - id: home translation: Home - id: close translation: Close - id: languages translation: Languages # General - id: related translation: Подібні - id: minute_read translation: хв читання - id: previous translation: Попередній - id: next translation: Наступний - id: figure translation: 'Схема %d:' - id: edit_page translation: Редагувати цю сторінку # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: Light - id: theme_dark translation: Dark - id: theme_auto translation: Automatic # Buttons - id: btn_preprint translation: Попередній друк - id: btn_pdf translation: PDF - id: btn_cite translation: Цитувати - id: btn_slides translation: Слайди - id: btn_video translation: Відео - id: btn_code translation: Код - id: btn_dataset translation: Набір даних - id: btn_project translation: Проєкт - id: btn_poster translation: Постер - id: btn_source translation: Вихідний документ - id: btn_copy translation: Копія - id: btn_copied translation: Copied - id: btn_download translation: Завантажити # About widget - id: interests translation: Зацікавлення - id: education translation: Освіта - id: user_profile_latest translation: Останні # Accomplishments widget - id: see_certificate translation: Переглянути сертифікат # Experience widget - id: present translation: Теперішній # Pages widget - id: more_pages translation: Переглянути все - id: more_posts translation: Переглянути всі пости - id: more_talks translation: Переглянути всі бесіди - id: more_publications translation: Переглянути всі публікації # Contact widget - id: contact_name translation: Ім'я - id: contact_email translation: Email - id: contact_message translation: Повідомлення - id: contact_attachment translation: Attach file - id: contact_send translation: Надіслати - id: book_appointment translation: Призначити зустріч # Publication/Event details - id: abstract translation: Анотація - id: publication translation: Публікація - id: publication_type translation: Тип - id: date translation: Дата - id: last_updated translation: Останнє оновлення - id: event translation: Подія - id: location translation: Місце - id: pub_paper_conference translation: Стаття для конференції - id: pub_article_journal translation: Стаття для журнала - id: pub_article translation: Попередній друк - id: pub_report translation: Доповідь - id: pub_book translation: Книга - id: pub_chapter translation: Розділ книги - id: pub_thesis translation: Тезис - id: pub_patent translation: Патент # Project details - id: open_project_site translation: Перейти на сайт проєкта # Content types for default archive page titles and search results - id: posts translation: Дописи - id: publications translation: Публікації - id: talks translation: Бесіди - id: projects translation: Проєкти - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: Пошук - id: search_placeholder translation: Пошук... - id: search_results translation: Знайдені результати - id: search_no_results translation: Результатів не знайдено - id: search_common_queries translation: Common searches # Error 404 - id: page_not_found translation: Не вдалося знайти сторінку - id: 404_recommendations translation: Можливо, Ви шукали щось з цього? # Cookie consent - id: cookie_message translation: Щоб упевнитись у зручності користування сайтом, ми використовуємо кукі-файли. - id: cookie_dismiss translation: Зрозуміло! - id: cookie_learn translation: Дізнатися більше # Published with - id: published_with translation: Made with {hugoblox}. ================================================ FILE: modules/blox/i18n/vi.yaml ================================================ # Navigation - id: toggle_navigation translation: Chuyển Điều Hướng - id: table_of_contents translation: Mục Lục - id: on_this_page translation: Nội dung - id: back_to_top translation: Lên đầu trang - id: home translation: Trang chủ - id: close translation: Đóng - id: languages translation: Ngôn ngữ # General - id: related translation: Bài Liên Quan - id: minute_read translation: phút để đọc - id: previous translation: Trước - id: next translation: Sau - id: figure translation: 'Hình %d:' - id: edit_page translation: Chỉnh sửa trang này # Themes - id: theme_selector translation: Tùy chọn hiển thị - id: theme_light translation: Sáng - id: theme_dark translation: Tối - id: theme_auto translation: Tự động # Buttons - id: btn_preprint translation: Bản Thảo - id: btn_pdf translation: PDF - id: btn_cite translation: Trích Dẫn - id: btn_slides translation: Slides - id: btn_video translation: Video - id: btn_code translation: Mã Nguồn - id: btn_dataset translation: Dữ liệu - id: btn_project translation: Dự Án - id: btn_poster translation: Áp phích - id: btn_source translation: Mã Nguồn - id: btn_copy translation: Sao Chép - id: btn_copied translation: Copied - id: btn_download translation: Tải Về # About widget - id: interests translation: Sở Thích - id: education translation: Học Vấn - id: user_profile_latest translation: Mới nhất # Accomplishments widget - id: see_certificate translation: Xem chứng chỉ # Experience widget - id: present translation: Hiện tại # Pages widget - id: more_pages translation: Xem tất cả - id: more_posts translation: Bài Đăng Khác - id: more_talks translation: Thuyết Trình Khác - id: more_publications translation: Các Công Trình # Contact widget - id: contact_name translation: Tên - id: contact_email translation: Email - id: contact_message translation: Tin nhắn - id: contact_attachment translation: Đính kèm tệp - id: contact_send translation: Gửi - id: book_appointment translation: Đặt cuộc hẹn # Publication/Event details - id: abstract translation: Tóm tắt - id: publication translation: Công Trình - id: publication_type translation: Phân Loại - id: date translation: Thời Gian - id: last_updated translation: Cập Nhật Lần Cuối - id: event translation: Sự Kiện - id: location translation: Địa Điểm - id: pub_paper_conference translation: Bài báo hội nghị - id: pub_article_journal translation: Bài viết tạp chí - id: pub_article translation: Bài viết trước - id: pub_report translation: Báo cáo - id: pub_book translation: Sách - id: pub_chapter translation: Chương sách - id: pub_thesis translation: Luận văn - id: pub_patent translation: Bằng sáng chế # Project details - id: open_project_site translation: Đến Trang Dự Án # Content types for default archive page titles and search results - id: posts translation: Bài Đăng - id: publications translation: Công Trình - id: talks translation: Thuyết Trình - id: projects translation: Dự Án - id: slides translation: Slides - id: authors translation: Tác giả # Search - id: search translation: Tìm kiếm - id: search_placeholder translation: Tìm kiếm... - id: search_results translation: kết quả được tìm thấy - id: search_no_results translation: Không tìm thấy kết quả - id: search_common_queries translation: Tìm kiếm phổ biến # Error 404 - id: page_not_found translation: Trang không tìm thấy - id: 404_recommendations translation: Có thể bạn đang tìm những trang này # Cookie consent - id: cookie_message translation: Trang web này sử dụng cookie để đảm bảo bạn có trải nghiệm tốt nhất trên trang web của chúng tôi. - id: cookie_dismiss translation: Tôi đã hiểu! - id: cookie_learn translation: Tìm hiểu thêm # Published with - id: published_with translation: Made with {hugoblox}. # Feedback widget - id: feedback_widget_title translation: Phản hồi - id: feedback_widget_question translation: Trang này có hữu ích không? - id: feedback_widget_answer_positive translation: 😍 Có - id: feedback_widget_answer_negative translation: 😡 Không ================================================ FILE: modules/blox/i18n/zh-Hant.yaml ================================================ # Navigation - id: toggle_navigation translation: 切換導航 - id: table_of_contents translation: 目錄 - id: on_this_page translation: 於本頁 - id: back_to_top translation: 回到頂端 - id: home translation: 主頁 - id: close translation: 關閉 - id: languages translation: 語言 # General - id: related translation: 相關 - id: minute_read translation: 閱讀時間(分鐘) - id: previous translation: 上一頁 - id: next translation: 下一頁 - id: figure translation: '圖%d:' - id: edit_page translation: 編輯本業 # Themes - id: theme_selector translation: 顯示選項 - id: theme_light translation: 明亮 - id: theme_dark translation: 暗黑 - id: theme_auto translation: 自動 # Buttons - id: btn_preprint translation: 影印預覽 - id: btn_pdf translation: PDF - id: btn_cite translation: 引用 - id: btn_slides translation: 投影片 - id: btn_video translation: 影片 - id: btn_code translation: 程式碼 - id: btn_dataset translation: 數據集 - id: btn_project translation: 專案 - id: btn_poster translation: 海報 - id: btn_source translation: 原始檔 - id: btn_copy translation: 複製 - id: btn_copied translation: Copied - id: btn_download translation: 下載 # About widget - id: interests translation: 興趣 - id: education translation: 教育程度 - id: user_profile_latest translation: 最新 # Accomplishments widget - id: see_certificate translation: 查看證書 # Experience widget - id: present translation: 現在 # Pages widget - id: more_pages translation: 查看更多 - id: more_posts translation: 查看更多文章 - id: more_talks translation: 查看更多演講 - id: more_publications translation: 查看更多出版物 # Contact widget - id: contact_name translation: 姓名 - id: contact_email translation: 郵箱 - id: contact_message translation: 訊息 - id: contact_attachment translation: Attach file - id: contact_send translation: 發送 - id: book_appointment translation: 預約 # Contact info block - id: block_contact_title translation: 聯絡我們 - id: block_contact_visit_title translation: 造訪我們 - id: block_contact_office_hours translation: 辦公時間 - id: block_contact_view_on_map translation: 在地圖上查看 - id: block_contact_connect_title translation: 聯繫 - id: block_contact_follow_us translation: 追蹤我們 - id: block_contact_prospective_title translation: 潛在成員 - id: block_contact_form_title translation: 向我們發送訊息 - id: block_contact_form_name translation: 姓名 - id: block_contact_form_email translation: 郵箱 - id: block_contact_form_subject translation: 主旨 - id: block_contact_form_message translation: 訊息 - id: block_contact_form_submit translation: 發送訊息 # Publication/Event details - id: abstract translation: 摘要 - id: publication translation: 出版物 - id: publication_type translation: 類型 - id: date translation: 日期 - id: last_updated translation: 最近更新於 - id: event translation: 事件 - id: location translation: 位置 - id: pub_paper_conference translation: 會議文章 - id: pub_article_journal translation: 期刊文章 - id: pub_article translation: 影印預覽 - id: pub_report translation: 報告 - id: pub_book translation: 書籍 - id: pub_chapter translation: 章節 - id: pub_thesis translation: 論文 - id: pub_patent translation: 專利 # Project details - id: open_project_site translation: 前往專案網站 # Content types for default archive page titles and search results - id: blog translation: 博客 - id: publications translation: 出版物 - id: events translation: 活動 - id: projects translation: 專案 - id: slides translation: 投影片 - id: authors translation: 作者 # Search - id: search translation: 搜尋 - id: search_placeholder translation: 搜尋... - id: search_results translation: 搜尋结果 - id: search_no_results translation: 找不到结果 - id: search_common_queries translation: 經常搜索 # Error 404 - id: page_not_found translation: 找不到頁面 - id: 404_recommendations translation: 您可能在找? # Cookie consent - id: cookie_message translation: 本網站使用cookies來確保您可以在網站中獲得最佳體驗。 - id: cookie_dismiss translation: 知道了! - id: cookie_learn translation: 了解更多 # Published with - id: published_with translation: 由{hugoblox}支持發布——免費{repo_link}開源{/repo_link}網站,為創作者賦能。 - id: poweredby_button translation: '構建您的 →' # AI Features - id: ai_insight translation: AI 洞察 # Content Metadata - id: content_type translation: 內容類型 - id: difficulty translation: 難度 - id: prerequisites translation: 先決條件 # Card metadata - id: trending translation: 熱門 - id: article translation: 文章 - id: articles translation: 文章 - id: browse translation: 瀏覽 - id: all translation: 全部 - id: helpful translation: 有幫助 # Additional buttons - id: btn_site translation: 網站 - id: btn_canonical translation: 正規連結 - id: btn_crosspost translation: 交叉發布 - id: btn_discussion translation: 討論 - id: btn_event translation: 活動 - id: btn_calendar translation: 行事曆 - id: btn_registration translation: 註冊 - id: btn_demo translation: 示範 - id: btn_model translation: 模型 - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_note translation: 備註 - id: callout_abstract translation: 摘要 - id: callout_summary translation: 摘要 - id: callout_info translation: 資訊 - id: callout_todo translation: 待辦 - id: callout_tip translation: 提示 - id: callout_question translation: 問題 - id: callout_quote translation: 引用 - id: callout_warning translation: 警告 - id: callout_caution translation: 注意 - id: callout_danger translation: 危險 - id: callout_bug translation: 錯誤 - id: callout_example translation: 範例 - id: callout_failure translation: 失敗 - id: callout_success translation: 成功 - id: callout_important translation: 重要 # Slides - id: back_to_slides translation: 返回投影片 - id: present_slides translation: 播放 - id: present_fullscreen translation: 播放(全螢幕) - id: export_pdf_print translation: 匯出 PDF(列印) - id: slides_print_hint translation: 以列印模式開啟 - 瀏覽器列印 > 另存為 PDF - id: slides_search_placeholder translation: 依標題搜尋投影片... - id: slides_no_decks translation: 未找到投影片集 - id: slides_no_matches translation: 沒有符合篩選的投影片 - id: clear_filters translation: 清除篩選 - id: topics translation: 主題 - id: details translation: 詳細資訊 - id: related_resources translation: 相關資源 - id: copy_link translation: 複製連結 - id: copy_citation translation: 複製引用 - id: how_to_cite translation: 如何引用 - id: citation translation: 引用 - id: bibtex translation: BibTeX - id: download_cite_bib translation: 下載 cite.bib - id: lecture translation: 講座 - id: enter_fullscreen translation: 進入全螢幕 - id: exit_fullscreen translation: 離開全螢幕 - id: speaker_notes_hint translation: 用於講者備註 - id: slides_not_found translation: 找不到投影片 # Q&A - id: qa translation: 問答 - id: question translation: 問題 - id: answer translation: 回答 - id: accepted_answer translation: 已接受的回答 - id: other_answers translation: 其他回答 - id: questions translation: 問題 - id: questions_count translation: 個問題 - id: related_questions translation: 相關問題 - id: search_questions translation: 搜尋問題... - id: no_questions_yet translation: 尚無問題 - id: faq translation: 常見問題 - id: faqs translation: 常見問題 - id: browse_by_category translation: 依分類瀏覽 # General extras - id: about_me translation: 職業簡介 - id: backlinks translation: 反向連結 - id: days translation: 天 - id: hours translation: 小時 - id: minutes translation: 分鐘 - id: seconds translation: 秒 - id: developer translation: 開發者 - id: docs translation: 文件 - id: experience translation: 經驗 - id: read_more translation: 閱讀更多 - id: featured translation: 精選 - id: block_contact_follow_me translation: 在這裡找到我 - id: portfolio_link_code translation: 程式碼 - id: portfolio_link_live translation: 線上 - id: portfolio_link_demo translation: 示範 - id: portfolio_link_default translation: 連結 - id: portfolio_view_all translation: 查看所有專案 - id: scroll_to_content translation: 捲動至內容 - id: feedback_widget_title translation: 回饋 - id: feedback_widget_question translation: 此頁面有幫助嗎? - id: feedback_widget_answer_positive translation: 😍 是 - id: feedback_widget_answer_negative translation: 😡 否 ================================================ FILE: modules/blox/i18n/zh.yaml ================================================ # Navigation - id: toggle_navigation translation: 切换导航 - id: table_of_contents translation: 目录 - id: on_this_page translation: 在本页 - id: back_to_top translation: 回到顶部 - id: home translation: Home - id: close translation: Close - id: languages translation: 语言 # General - id: related translation: 相关 # Callouts - id: callout_note translation: 注意 - id: callout_tip translation: 提示 - id: callout_important translation: 重要 - id: callout_warning translation: 警告 - id: callout_caution translation: 小心 - id: minute_read translation: 分钟阅读时长 - id: previous translation: 上一页 - id: next translation: 下一页 - id: figure translation: '图%d:' - id: edit_page translation: 编辑本页 # Themes - id: theme_selector translation: Display preferences - id: theme_light translation: 浅色 - id: theme_dark translation: 深色 - id: theme_auto translation: 自动 # Buttons - id: btn_preprint translation: 预印本 - id: btn_pdf translation: PDF - id: btn_cite translation: 引用 - id: btn_slides translation: 演示文稿 - id: btn_video translation: 视频 - id: btn_code translation: 代码 - id: btn_dataset translation: 数据集 - id: btn_project translation: 项目 - id: btn_poster translation: 海报 - id: btn_source translation: 源文档 - id: btn_copy translation: 复制 - id: btn_copied translation: Copied - id: btn_download translation: 下载 # About widget - id: interests translation: 兴趣爱好 - id: education translation: 教育经历 - id: user_profile_latest translation: 最新 # Accomplishments widget - id: see_certificate translation: 查看证书 # Experience widget - id: experience translation: 工作经历 - id: present translation: 现在 # Pages widget - id: read_more translation: 阅读文章 - id: more_pages translation: 查看全部 - id: more_posts translation: 查看全部文章 - id: more_talks translation: 查看全部演讲 - id: more_publications translation: 查看全部出版物 # Contact widget - id: contact_name translation: 姓名 - id: contact_email translation: 邮箱 - id: contact_message translation: 信息 - id: contact_attachment translation: Attach file - id: contact_send translation: 发送 - id: book_appointment translation: 预约 # Contact info block - id: block_contact_title translation: 联系我们 - id: block_contact_visit_title translation: 访问我们 - id: block_contact_office_hours translation: 办公时间 - id: block_contact_view_on_map translation: 在地图上查看 - id: block_contact_connect_title translation: 联系 - id: block_contact_follow_us translation: 关注我们 - id: block_contact_prospective_title translation: 潜在成员 - id: block_contact_form_title translation: 向我们发送信息 - id: block_contact_form_name translation: 姓名 - id: block_contact_form_email translation: 邮箱 - id: block_contact_form_subject translation: 主题 - id: block_contact_form_message translation: 信息 - id: block_contact_form_submit translation: 发送信息 # Publication/Event details - id: abstract translation: 摘要 - id: publication translation: 出版物 - id: publication_type translation: 类型 - id: date translation: 日期 - id: last_updated translation: 最近更新于 - id: event translation: 事件 - id: location translation: 位置 - id: pub_paper_conference translation: 会议文章 - id: pub_article_journal translation: 期刊文章 - id: pub_article translation: 预印本 - id: pub_report translation: 报告 - id: pub_book translation: 书籍 - id: pub_chapter translation: 章节 - id: pub_thesis translation: 论文 - id: pub_patent translation: 专利 # Project details - id: open_project_site translation: 访问项目网站 # Content types for default archive page titles and search results - id: blog translation: 博客 - id: publications translation: 出版物 - id: events translation: 活动 - id: projects translation: 项目 - id: slides translation: Slides - id: authors translation: Authors # Search - id: search translation: 搜索 - id: search_placeholder translation: 搜索... - id: search_results translation: 搜索结果 - id: search_no_results translation: 没有找到结果 - id: search_common_queries translation: 经常搜寻 # Error 404 - id: page_not_found translation: 找不到页面 - id: 404_recommendations translation: 也许你在找? # Cookie consent - id: cookie_message translation: 本网站使用cookies来确保您在本网站上获得最佳体验。 - id: cookie_dismiss translation: 知道了! - id: cookie_learn translation: 了解更多 # Published with - id: published_with translation: 由{hugoblox}支持发布——免费{repo_link}开源{/repo_link}网站,为创作者赋能。 - id: poweredby_button translation: '构建您的 →' # Contact info block - id: block_contact_follow_me translation: 在这里找到我 # Dev Hero block - id: scroll_to_content translation: 滚动到内容 - id: developer translation: 开发者 # Portfolio block - id: portfolio_link_code translation: 代码 - id: portfolio_link_live translation: 在线 - id: portfolio_link_demo translation: 演示 - id: portfolio_link_default translation: 链接 - id: portfolio_view_all translation: 查看所有项目 # AI Features - id: ai_insight translation: AI 洞察 # Content Metadata - id: content_type translation: 内容类型 - id: difficulty translation: 难度 - id: prerequisites translation: 先决条件 # Card metadata - id: trending translation: 热门 - id: article translation: 文章 - id: articles translation: 文章 - id: browse translation: 浏览 - id: all translation: 全部 - id: helpful translation: 有帮助 # Additional buttons - id: btn_site translation: 网站 - id: btn_canonical translation: 规范链接 - id: btn_crosspost translation: 交叉发布 - id: btn_discussion translation: 讨论 - id: btn_event translation: 活动 - id: btn_calendar translation: 日历 - id: btn_registration translation: 注册 - id: btn_demo translation: 演示 - id: btn_model translation: 模型 - id: btn_doi translation: DOI - id: btn_hal translation: HAL - id: btn_dblp translation: DBLP - id: btn_isbn translation: ISBN - id: btn_osf translation: OSF - id: btn_zenodo translation: Zenodo - id: btn_kaggle translation: Kaggle - id: btn_openalex translation: OpenAlex - id: btn_semanticscholar translation: Semantic Scholar - id: btn_pwc translation: Papers With Code # Callouts - id: callout_abstract translation: 摘要 - id: callout_summary translation: 总结 - id: callout_info translation: 信息 - id: callout_todo translation: 待办 - id: callout_question translation: 问题 - id: callout_quote translation: 引用 - id: callout_warning translation: 警告 - id: callout_danger translation: 危险 - id: callout_bug translation: 缺陷 - id: callout_example translation: 示例 - id: callout_failure translation: 失败 - id: callout_success translation: 成功 # Slides - id: back_to_slides translation: 返回幻灯 - id: present_slides translation: 演示 - id: present_fullscreen translation: 演示(全屏) - id: export_pdf_print translation: 导出 PDF(打印) - id: slides_print_hint translation: 在打印模式打开 - 浏览器打印 > 另存为 PDF - id: slides_search_placeholder translation: 按标题搜索幻灯集... - id: slides_no_decks translation: 未找到幻灯集 - id: slides_no_matches translation: 没有符合筛选的幻灯集 - id: clear_filters translation: 清除过滤 - id: topics translation: 主题 - id: details translation: 详情 - id: related_resources translation: 相关资源 - id: copy_link translation: 复制链接 - id: copy_citation translation: 复制引用 - id: citation translation: 引用 - id: bibtex translation: BibTeX - id: download_cite_bib translation: 下载 cite.bib - id: lecture translation: 讲座 - id: enter_fullscreen translation: 进入全屏 - id: exit_fullscreen translation: 退出全屏 - id: speaker_notes_hint translation: 用于演讲者备注 - id: slides_not_found translation: 未找到幻灯 # Q&A - id: qa translation: 问答 - id: question translation: 问题 - id: answer translation: 答案 - id: accepted_answer translation: 已采纳的回答 - id: other_answers translation: 其他回答 - id: questions translation: 问题 - id: questions_count translation: 个问题 - id: related_questions translation: 相关问题 - id: search_questions translation: 搜索问题... - id: no_questions_yet translation: 尚无问题 - id: faq translation: 常见问题 - id: faqs translation: 常见问题 - id: browse_by_category translation: 按类别浏览 # General extras - id: about_me translation: 职业简介 - id: backlinks translation: 反向链接 - id: days translation: 天 - id: hours translation: 小时 - id: minutes translation: 分钟 - id: seconds translation: 秒 - id: docs translation: 文档 - id: featured translation: 精选 - id: read_more translation: 阅读更多 # Feedback widget - id: feedback_widget_title translation: 反馈 - id: feedback_widget_question translation: 此页面有帮助吗? - id: feedback_widget_answer_positive translation: 😍 是 - id: feedback_widget_answer_negative translation: 😡 否 - id: how_to_cite translation: 如何引用 ================================================ FILE: modules/blox/layouts/404.html ================================================ {{- define "main" -}} {{/* Exclude 404 page from search indexing */}}

{{ i18n "page_not_found" }}

{{/* Suggest recently published pages to the user. */}}

{{ i18n "404_recommendations" }}

{{ $query := where (where (where (where site.Pages.ByDate.Reverse "Title" "!=" "") "Kind" "in" (slice "page" "section")) "Params.private" "!=" true) "Permalink" "!=" "" }} {{ $count := len $query }} {{ if gt $count 0 }}

{{ i18n "user_profile_latest" }}

{{ end }}
{{- end -}} ================================================ FILE: modules/blox/layouts/_markup/render-blockquote.html ================================================ {{/* Hugo Blox Kit Blockquote Render Hook Renders standard blockquotes and GitHub/Obsidian-style alerts (callouts). Supports alert types: note, tip, important, warning, caution Syntax examples: - > [!NOTE] > This is a note callout. - > [!WARNING]+ Custom Title > This is a warning with custom title. */}} {{ if eq .Type "alert" }} {{/* Use custom title if provided, otherwise let render_callout handle default */}} {{ $title := .AlertTitle }} {{/* Use shared callout renderer */}} {{ partial "functions/render_callout" (dict "type" .AlertType "content" .Text "title" $title "source" "renderhook" ) }} {{ else }} {{/* Render regular blockquotes */}}
{{ .Text }}
{{ end }} ================================================ FILE: modules/blox/layouts/_markup/render-codeblock-markmap.html ================================================
{{/* No indentation before PRE and .Inner otherwise mindmap first item will be indented */}}
{{- .Inner | safeHTML -}}
{{ .Page.Store.Set "has_markmap" true }} ================================================ FILE: modules/blox/layouts/_markup/render-codeblock-mermaid.html ================================================
{{- .Inner | safeHTML }}
{{ .Page.Store.Set "has_mermaid" true }} ================================================ FILE: modules/blox/layouts/_markup/render-image.html ================================================ {{/* Markdown Image Renderer for Hugo Blox Kit. */}} {{/* Load image from page dir falling back to media library at `assets/media/` and then to remote URI. */}} {{ $destination := .Destination }} {{ $is_remote := strings.HasPrefix $destination "http" }} {{ $caption := .Title | default "" }} {{ $zoom := "true" }} {{ $id := anchorize ($caption | plainify) }} {{ $alt := .Text | default ($caption | plainify) }} {{ $img_class := "" }} {{ $fig_class := "" }} {{ $max_width := "" }} {{ $width := "" }} {{ $height := "" }} {{ $numbered := false }} {{/* Workaround Hugo v0.81 error on Windows when `resources.Get (path.Join "media" )` */}} {{- $img := "" -}} {{- if not $is_remote -}} {{- $img = (.Page.Resources.ByType "image").GetMatch $destination -}} {{- if not $img -}} {{- $img = resources.Get (path.Join "media" $destination) -}} {{- end -}} {{- end -}}
{{- if $img -}} {{- $isSVG := eq $img.MediaType.SubType "svg" -}} {{- $isGIF := eq $img.MediaType.SubType "gif" -}} {{- if $isSVG | or $isGIF -}} {{ $alt }} {{- else }} {{/* Process responsive images - use 760px as default display size */}} {{- $img_md := $img.Fit "760x760 webp" -}} {{- $responsive := partial "functions/process_responsive_image.html" (dict "image" $img_md "mode" "responsive") -}} {{- $width := $width | default $img_md.Width -}} {{- $height := $height | default $img_md.Height -}} {{ $alt }} {{- end }} {{- else -}} {{ $alt }} {{- end -}}
{{- if $caption -}} {{/* Localize the figure numbering (if enabled). */}} {{- $figure := split (i18n "figure" | default "Figure %d:") "%d" -}} {{ $caption | markdownify | emojify }} {{- end -}}
================================================ FILE: modules/blox/layouts/_markup/render-link.backlinks.json ================================================ {{- $url_struct := urls.Parse .Destination -}} {{/* Ignore anchor links to other sections of the same page. */}} {{- if not (or $url_struct.IsAbs (strings.HasPrefix $url_struct.String "#")) }} {{- $page_path := strings.TrimPrefix "./" $url_struct.Path -}} {{- with .PageInner.GetPage $page_path }} {{- $page := dict "date" ($.Page.Date.UTC.Format "2006-01-02T15:04:05-07:00") "linkTitle" $.Page.LinkTitle "relPermalink" $.Page.RelPermalink }} {{- $backlink := dict "page" $page "links_to" .RelPermalink }} {{- site.Home.Store.Add "backlinks" (slice $backlink) }} {{- end }} {{- end }} ================================================ FILE: modules/blox/layouts/_markup/render-link.html ================================================ {{- /* A Hugo Markdown render hook to parse links, opening external links in new tabs. */ -}} {{ .Text | safeHTML }} ================================================ FILE: modules/blox/layouts/_partials/blox/contact-info/config.html ================================================ {{/* Hugo Blox: Contact Info - config */}} {{/* Purpose: pre-declare dependencies before libraries load */}} {{ $page := .wcPage }} {{/* Contact block uses Alpine for copy-to-clipboard + small interactions */}} {{ $page.Store.Set "has_alpine" true }} ================================================ FILE: modules/blox/layouts/_partials/blox/dev-hero/config.html ================================================ {{/* Hugo Blox: Dev Hero - config */}} {{/* Purpose: pre-declare dependencies before libraries load */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $typewriter := $block.content.typewriter | default dict }} {{ $has_animations := or ($block.design.animations | default false) ($typewriter.enable | default false) }} {{ if $has_animations }} {{ $page.Store.Set "has_animations" true }} {{ $page.Store.Set "has_alpine" true }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/blox/portfolio/config.html ================================================ {{/* Hugo Blox: Portfolio - config */}} {{/* Purpose: pre-declare dependencies before libraries load */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{/* Portfolio always needs Alpine for filtering */}} {{ $page.Store.Set "has_alpine" true }} {{/* Enable scroll/transition helpers if animations not explicitly disabled */}} {{ if ne $block.design.animations false }} {{ $page.Store.Set "has_animations" true }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/blox/preact-wrapper.html ================================================ {{/* Hugo Blox: Generic Preact Block Wrapper */}} {{/* Single wrapper for all Preact-based blocks */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* Initialize variables */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ $block_type := .wcBlockType }} {{ $block_id := .wcIdentifier | default (printf "%s-%d" $block_type (now.Unix)) }} {{/* Prepare props for the Preact component */}} {{ $props := dict "content" $block.content "design" $block.design "id" $block_id "type" $block_type }} {{/* Resolve icon for primary_action (hero, cta blocks) */}} {{ with $block.content.primary_action.icon }} {{ $icon_data := partial "functions/get_icon_data" (dict "name" .) }} {{ if $icon_data }} {{ $props = merge $props (dict "icon_svg" $icon_data) }} {{ end }} {{ end }} {{/* Resolve icon for single button (cta-card) */}} {{ with $block.content.button.icon }} {{ $icon_data := partial "functions/get_icon_data" (dict "name" .) }} {{ if $icon_data }} {{ $props = merge $props (dict "button_icon_svg" $icon_data) }} {{ end }} {{ end }} {{/* Resolve per-item icons (stats, features, etc.) into an icon_svgs map */}} {{ $icon_svgs := dict }} {{ with $block.content.items }} {{ range . }} {{ with .icon }} {{ if not (index $icon_svgs .) }} {{ $icon_data := partial "functions/get_icon_data" (dict "name" .) }} {{ if $icon_data }} {{ $icon_svgs = merge $icon_svgs (dict . $icon_data) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if gt (len $icon_svgs) 0 }} {{ $props = merge $props (dict "icon_svgs" $icon_svgs) }} {{ end }} {{/* Resolve per-item images via Hugo's image pipeline */}} {{/* Thumbnail mode (testimonials): Fill 96x96 webp */}} {{/* Responsive mode (cta-image-paragraph): srcset with breakpoints */}} {{ $item_images := dict }} {{ with $block.content.items }} {{ range $idx, $item := . }} {{ with .image }} {{ $image_path := strings.TrimSpace (printf "%v" .) }} {{ $is_remote := or (strings.HasPrefix $image_path "http://") (strings.HasPrefix $image_path "https://") }} {{/* Resolve the image resource */}} {{ $image_resource := false }} {{ $fallback_url := "" }} {{ if $is_remote }} {{ $remote := try (resources.GetRemote $image_path) }} {{ if and $remote (not $remote.Err) }} {{ $image_resource = $remote.Value }} {{ else }} {{ $fallback_url = $image_path }} {{ end }} {{ else }} {{ $normalized := $image_path }} {{ $normalized = strings.TrimPrefix "/" $normalized }} {{ $normalized = strings.TrimPrefix "./" $normalized }} {{ $normalized = strings.TrimPrefix "assets/" $normalized }} {{ $normalized = strings.TrimPrefix "media/" $normalized }} {{ $normalized = path.Clean $normalized }} {{ if and $normalized (ne $normalized ".") }} {{ with $page }} {{ $image_resource = (.Resources.ByType "image").GetMatch $normalized }} {{ end }} {{ if not $image_resource }} {{ $image_resource = resources.Get (path.Join "media" $normalized) }} {{ end }} {{ if not $image_resource }} {{ $fallback_url = printf "/media/%s" $normalized }} {{ end }} {{ end }} {{ end }} {{ $img_data := dict }} {{ if $image_resource }} {{ $isSVG := eq $image_resource.MediaType.SubType "svg" }} {{ $isGIF := eq $image_resource.MediaType.SubType "gif" }} {{ if or $isSVG $isGIF }} {{/* SVG/GIF: no processing, just pass through */}} {{ $img_data = dict "src" $image_resource.RelPermalink }} {{ else if eq $block_type "cta-image-paragraph" }} {{/* Responsive mode: generate srcset via process_responsive_image */}} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $image_resource "mode" "fit" "sizes" (slice 400 600 800 1200) ) }} {{ $img_data = dict "srcset" $responsive.srcset "src" $responsive.fallback.RelPermalink "width" $responsive.fallback.Width "height" $responsive.fallback.Height }} {{ else }} {{/* Thumbnail mode (testimonials, etc.): Fill 96x96 */}} {{ $processed := $image_resource.Process "Fill 96x96 Center webp" }} {{ $img_data = dict "src" $processed.RelPermalink }} {{ end }} {{ else if $fallback_url }} {{ $img_data = dict "src" $fallback_url }} {{ end }} {{ if $img_data }} {{ $item_images = merge $item_images (dict (printf "%d" $idx) $img_data) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if gt (len $item_images) 0 }} {{ $props = merge $props (dict "item_images" $item_images) }} {{ end }} {{/* Resolve per-item feature_icon (cta-image-paragraph) */}} {{ with $block.content.items }} {{ range . }} {{ with .feature_icon }} {{ if not (index $icon_svgs .) }} {{ $icon_data := partial "functions/get_icon_data" (dict "name" .) }} {{ if $icon_data }} {{ $icon_svgs = merge $icon_svgs (dict . $icon_data) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if gt (len $icon_svgs) 0 }} {{ $props = merge $props (dict "icon_svgs" $icon_svgs) }} {{ end }} {{/* Convert props to JSON for client-side rendering */}} {{ $propsJSON := $props | jsonify }} {{/* Render a container that Preact will populate */}}
{{/* Empty - Preact renders everything */}} {{/* Could add a loading skeleton here if desired */}}
{{/* Preact script loading is handled by libraries.html */}} ================================================ FILE: modules/blox/layouts/_partials/blox/tech-stack/config.html ================================================ {{/* Hugo Blox: Tech Stack - config */}} {{/* Purpose: pre-declare dependencies before libraries load */}} {{ $page := .wcPage }} {{ $block := .wcBlock }} {{ if ne $block.design.animations false }} {{ $page.Store.Set "has_animations" true }} {{ $page.Store.Set "has_alpine" true }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/comments/disqus.html ================================================ {{ if site.Params.hugoblox.comments.disqus.shortname }}
comments powered by Disqus {{end}} ================================================ FILE: modules/blox/layouts/_partials/comments/giscus.html ================================================ {{ if site.Params.hugoblox.comments.giscus }} {{ $config := site.Params.hugoblox.comments.giscus }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/comments.html ================================================ {{ $provider := trim (site.Params.hugoblox.comments.provider | lower) " " }} {{ if $provider }} {{ $provider_tpl := printf "comments/%s.html" $provider }} {{ $provider_exists := templates.Exists (printf "_partials/%s" $provider_tpl) }} {{ if not $provider_exists }} {{ errorf "The '%s' comment provider was not found." $provider }} {{ end }} {{ $commentable_page := .Params.commentable }} {{ if $commentable_page }}
{{ partial $provider_tpl . }}
{{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/backlinks.html ================================================ {{ $show_backlinks := .Params.backlinks | default true }} {{ if $show_backlinks }} {{ $defer_globals := (dict "page" . )}} {{ with (templates.Defer (dict "data" $defer_globals )) }} {{ $backlinks := (site.Home.Store.Get "backlinks" | uniq) | default dict }} {{ with (where $backlinks "links_to" .page.RelPermalink) }} {{ end }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/breadcrumb.html ================================================
{{- range .Ancestors.Reverse }} {{- if not .IsHome }} {{- partial "functions/get_icon.html" (dict "name" "chevron-right" "attributes" "class=\"w-3.5 shrink-0\"") -}} {{ end -}} {{ end -}}
{{- .LinkTitle -}}
================================================ FILE: modules/blox/layouts/_partials/components/cover.html ================================================ {{/* Article Cover Component - Notion-inspired page cover with icon overlay */}} {{/* Requires: page context */}} {{ $cover := partial "functions/get_cover_image.html" . }} {{ if $cover }} {{/* Get cover configuration with defaults */}} {{ $cover_config := .Params.cover | default (dict) }} {{ if not (reflect.IsMap $cover_config) }} {{/* Simple string format: cover: "image.jpg" */}} {{ $cover_config = dict "image" $cover_config }} {{ end }} {{/* Default alt text to page title if not specified */}} {{ $alt_text := $cover_config.alt_text | default (.Title | plainify) }} {{/* Height configuration */}} {{ $height_map := dict "small" "200px" "medium" "320px" "large" "480px" "full" "60vh" }} {{ $height := index $height_map ($cover_config.height | default "medium") | default "320px" }} {{/* Style configuration */}} {{ $style := $cover_config.style | default "gradient" }} {{/* Position configuration */}} {{ $position := $cover_config.position | default (dict) }} {{ $x := $position.x | default 50 }} {{ $y := $position.y | default 50 }} {{/* Overlay configuration */}} {{ $overlay := $cover_config.overlay | default (dict) }} {{ $overlay_enabled := $overlay.enabled | default true }} {{ $overlay_type := $overlay.type | default "gradient" }} {{ $overlay_opacity := $overlay.opacity | default 0.3 }} {{ $overlay_color := $overlay.color | default "#000000" }} {{ $overlay_gradient := $overlay.gradient | default "bottom" }} {{/* Fade configuration */}} {{ $fade := $cover_config.fade | default (dict) }} {{ $fade_enabled := $fade.enabled | default true }} {{ $fade_height := $fade.height | default "60px" }} {{ $fade_blur := $fade.blur | default false }} {{/* Icon configuration */}} {{ $icon_config := $cover_config.icon | default (dict) }} {{ $has_icon := or $icon_config.name $icon_config.emoji }} {{ $icon_position := $icon_config.position | default "overlap" }} {{ $icon_size := $icon_config.size | default "large" }} {{ $icon_style := $icon_config.style | default "glass" }} {{ $icon_border := $icon_config.border | default true }} {{/* Responsive hide on mobile */}} {{ $hide_mobile := false }} {{ if $cover_config.responsive }} {{ $hide_mobile = $cover_config.responsive.hide_on_mobile | default false }} {{ end }} {{/* Process cover image */}} {{ $cover_width := 2560 }} {{ $cover_height := 520 }} {{ if eq ($cover_config.height | default "medium") "small" }} {{ $cover_height = 320 }} {{ else if eq ($cover_config.height | default "medium") "large" }} {{ $cover_height = 768 }} {{ else if eq ($cover_config.height | default "medium") "full" }} {{ $cover_height = 1080 }} {{ end }} {{/* Generate responsive images */}} {{ $processed_cover := $cover }} {{ $srcset := "" }} {{ if ne $cover.MediaType.SubType "gif" }} {{ $fill_spec := printf "%dx%d Center q85 webp" $cover_width $cover_height }} {{ $processed_cover = $cover.Fill $fill_spec }} {{ $variants := slice }} {{ $widths := slice 640 768 1024 1366 1920 2560 }} {{ range $widths }} {{ $w := . }} {{ $h := div (mul $w $cover_height) $cover_width }} {{ $variant_spec := printf "%dx%d Center q85 webp" $w $h }} {{ $variant := $cover.Fill $variant_spec }} {{ $variants = $variants | append (printf "%s %dw" $variant.RelPermalink $w) }} {{ end }} {{ $srcset = delimit $variants ", " }} {{ end }} {{/* Build CSS classes based on style */}} {{ $cover_classes := "article-cover relative w-full" }} {{ if $hide_mobile }} {{ $cover_classes = printf "%s hidden md:block" $cover_classes }} {{ end }} {{/* Container styles */}} {{ $container_style := printf "height: %s;" $height }} {{/* Calculate mask style for fade */}} {{ $mask_style := "" }} {{ if and $fade_enabled (ne $style "minimal") }} {{/* Mask fades from black (visible) to transparent (invisible) at the bottom */}} {{ $mask_style = printf "-webkit-mask-image: linear-gradient(to bottom, black calc(100%% - %s), transparent 100%%); mask-image: linear-gradient(to bottom, black calc(100%% - %s), transparent 100%%);" $fade_height $fade_height }} {{ end }}
{{/* Cover Image */}}
{{ if ne $cover.MediaType.SubType "gif" }} {{ $alt_text }} {{ else }} {{ $alt_text }} {{ end }}
{{/* Overlay Effects */}} {{ if and $overlay_enabled (ne $style "minimal") }} {{ if eq $style "gradient" }}
{{ else if eq $style "glass" }}
{{ else if eq $style "blur" }}
{{ else if eq $overlay_type "gradient" }} {{ if eq $overlay_gradient "bottom" }}
{{ else if eq $overlay_gradient "top" }}
{{ else if eq $overlay_gradient "both" }}
{{ else if eq $overlay_gradient "radial" }}
{{ end }} {{ else if eq $overlay_type "solid" }}
{{ end }} {{ end }} {{/* Blur Effect at Bottom (Optional) */}} {{ if and $fade_enabled $fade_blur (ne $style "minimal") }} {{/* Taller blur zone with mask to create smooth blur transition before fade out */}} {{/* Semi-transparent background needed for backdrop-filter to render */}}
{{ end }} {{/* Caption */}} {{ with $cover_config.caption }}
{{ . | markdownify }}
{{ end }}
{{/* Icon Overlay - Only if position is "overlap" - NOW UNCLIPPED */}} {{ if and $has_icon (eq $icon_position "overlap") }} {{ $icon_size_map := dict "small" "w-8 h-8" "medium" "w-12 h-12" "large" "w-16 h-16" }} {{ $icon_size_class := index $icon_size_map $icon_size | default "w-16 h-16" }} {{ $icon_padding := cond (eq $icon_size "small") "p-1.5" (cond (eq $icon_size "medium") "p-2" "p-3") }}
{{ if $icon_config.emoji }} {{ $icon_config.emoji }} {{ else if $icon_config.name }} {{ partial "functions/get_icon.html" (dict "name" $icon_config.name "attributes" (printf "class=\"%s text-gray-700 dark:text-gray-200\"" $icon_size_class)) }} {{ end }}
{{ end }}
{{/* Icon Below Cover - If position is "below" */}} {{ if and $has_icon (eq $icon_position "below") }} {{ $icon_size_map := dict "small" "w-8 h-8" "medium" "w-12 h-12" "large" "w-16 h-16" }} {{ $icon_size_class := index $icon_size_map $icon_size | default "w-16 h-16" }} {{ $icon_padding := cond (eq $icon_size "small") "p-1.5" (cond (eq $icon_size "medium") "p-2" "p-3") }}
{{ if $icon_config.emoji }} {{ $icon_config.emoji }} {{ else if $icon_config.name }} {{ partial "functions/get_icon.html" (dict "name" $icon_config.name "attributes" (printf "class=\"%s text-gray-700 dark:text-gray-200\"" $icon_size_class)) }} {{ end }}
{{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/feedback.html ================================================ {{/* TODO: port JS & response text from Bootstrap module. Re-integrate with GA plus Fathom/Plausible */}} {{/* $ga := site.Params.marketing.analytics.google_analytics | default "" */}} {{ $show_feedback := .Params.feedback | default true }} {{ if hugo.IsProduction | and $show_feedback }}{{/* | and $ga */}}
{{ i18n "feedback_widget_question" | default "Was this page helpful?" }}
😞
😐
🤩
{{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/footers/columns.html ================================================ {{ $branding := partialCached "functions/get_branding" . "branding" }} {{- $logo_height := site.Params.hugoblox.footer.logo_height | default 36 -}} {{ $logo := partialCached "functions/get_logo" (dict "constraint" "max_height" "size" $logo_height) "footer_logo" }} {{- $show_logo := site.Params.hugoblox.footer.show_logo | default true -}} {{- $show_title := site.Params.hugoblox.footer.show_title | default true -}} {{- $show_tagline := site.Params.hugoblox.footer.show_tagline | default true -}} {{- $footer_title := site.Params.hugoblox.footer.title | default $branding.name -}}
Footer
{{ if $show_logo }} {{ with $logo.resource }} {{ if $logo.is_svg }} {{ else }} {{ $branding.name }} {{ end }} {{ end }} {{ end }} {{ if $show_title }} {{ $footer_title }} {{ end }} {{ if $show_tagline }}

{{ site.Params.hugoblox.identity.tagline | default "" }}

{{ end }} {{- $show_social := site.Params.hugoblox.footer.show_social | default true -}} {{ if $show_social }} {{ with site.Params.hugoblox.identity.social.links }}
{{ partial "social_links" (dict "Params" (dict "profiles" .)) }}
{{ end }} {{ end }}
{{ $menu := .Site.Menus.footer }} {{ range $index, $menuItem := $menu }}

{{ $menuItem.Name }}

{{ end }}
{{/* Display copyright license. */}} {{ partial "site_footer_license" . }}
================================================ FILE: modules/blox/layouts/_partials/components/footers/minimal.html ================================================ {{ $show_translations := site.Params.hugoblox.footer.language_switcher | default true }} {{ if .IsTranslated | and $show_translations }}
{{- partial "functions/get_icon" (dict "name" "globe-alt" "attributes" `class="inline-block pr-1" style="height: 1em"`) -}} {{ i18n "languages" }}:
{{ index site.Data.languages .Lang }}
{{ range .Translations }} {{ end }}
{{ end }} {{/* Footer nav links - single level */}} {{ $menu := .Site.Menus.footer }} {{ with $menu }} {{ end }} {{/* Social links */}} {{- $show_social := site.Params.hugoblox.footer.show_social | default true -}} {{ if $show_social }} {{ with site.Params.hugoblox.identity.social.links }}
{{ partial "social_links" (dict "Params" (dict "profiles" .)) }}
{{ end }} {{ end }} {{ with site.Params.hugoblox.footer.text }}

{{ . | markdownify | emojify }}

{{ end }} {{/* Display copyright license. */}} {{ partial "site_footer_license" . }} ================================================ FILE: modules/blox/layouts/_partials/components/headers/floating-theme-toggler.html ================================================
================================================ FILE: modules/blox/layouts/_partials/components/headers/navbar-simple.html ================================================ {{/* Show site search? */}} {{ $show_search := site.Params.hugoblox.header.search | default false }} {{ if $show_search }} {{- partial "components/search-modal.html" . -}} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/headers/navbar.html ================================================ {{ $branding := partialCached "functions/get_branding" . "branding" }} {{ $logo := partialCached "functions/get_logo" (dict "constraint" "max_height" "size" 36) "navbar_logo" }} {{- $show_logo := site.Params.hugoblox.header.show_logo | default true -}} {{- $show_title := site.Params.hugoblox.header.show_title | default true -}} {{- $navbar_title := site.Params.hugoblox.header.title | default $branding.name -}} {{ if $show_search }} {{- partial "components/search-modal.html" . -}} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/language-chooser.html ================================================ {{ $page := .page }} {{ $class := .class }} {{ $hide_language_name := false }}{{/* TODO: Add to hugoblox.header.hide_language_name if needed */}} {{ $str_languages := T "languages" }} {{- if $page.IsTranslated -}}
{{- end -}} ================================================ FILE: modules/blox/layouts/_partials/components/last-edited.html ================================================ {{- $last_updated := T "last_updated" -}} {{- if (.Params.show_date_updated | default true) | and .Lastmod -}} {{ $datetime := (time.Format "2006-01-02T15:04:05.000Z" .Lastmod) }} {{- else -}}
{{- end -}} ================================================ FILE: modules/blox/layouts/_partials/components/next-in-series.html ================================================ {{ if .Params.pager | default true }} {{ if and .Section (or .NextInSection .PrevInSection) }} {{ $next := .NextInSection }} {{ $prev := .PrevInSection }} {{ if (eq (.Scratch.Get "invert_pager") true) | default .Params.invert_pager | default false }} {{ $next = .PrevInSection }} {{ $prev = .NextInSection }} {{ end }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/page_sharer.html ================================================ {{ if ne .Params.share false }}
{{ range where site.Data.page_sharer.links "enable" true }} {{/* Utilise `urlquery` over `htmlEscape` to encode sharing URL */}} {{/* See https://github.com/HugoBlox/kit/pull/2726 */}} {{ $link := replace .url "{url}" ($.Permalink | urlquery) }} {{ $link = replace $link "{title}" ($.Title | urlquery) }} {{/* Workaround `urlquery` encoding for mailto as `urlquery` encodes `+` as `%2B` and ` ` (space) as `+` */}} {{ if eq (urls.Parse $link).Scheme "mailto" }} {{ $link = replace $link "+" "%20" }} {{ end }} {{ partial "functions/get_icon" (dict "name" .icon "attributes" "style=\"height: 1em;\"") }} {{ end }}
{{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/paginator.html ================================================ {{ if or (.Paginator.HasPrev) (.Paginator.HasNext) }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/search-modal.html ================================================ {{/* Modern Search Modal - Custom Pagefind API Implementation */}} ================================================ FILE: modules/blox/layouts/_partials/components/sidebar.html ================================================ {{- $context := .context -}} {{- $no_sidebar := ne .no_sidebar false -}} {{- $pad_sidebar := true -}} {{- $sidebar_dynamic_class := cond $no_sidebar (cond $pad_sidebar "lg:hidden xl:block" "lg:hidden") "lg:sticky" -}} {{- $root_section := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}} {{- $page_url := $context.RelPermalink -}} {{/* Only replace explicit mobile menu links with automated links for Docs pages */}} {{ if not $no_sidebar }} {{/* Classes appended to `hb-sidebar-mobile-menu` are modified via sidebar JS, so do not @apply them to `hb-sidebar-mobile-menu` */}} {{ end }} {{- define "menu-links" -}} {{ template "link-tree" (dict "context" .context "level" 0 "page" .page "pageURL" .pageURL "toc" (.toc | default false)) }} {{- end -}} {{- define "link-tree" -}} {{- if ge .level 4 -}} {{- return -}} {{- end -}} {{- $context := .context -}} {{- $page := .page }} {{- $page_url := .page.RelPermalink -}} {{- $level := .level -}} {{- $toc := .toc | default false -}} {{- with $items := union .context.RegularPages .context.Sections -}} {{- $items = where $items "Params.sidebar.hidden" "!=" true -}} {{- if eq $level 0 -}} {{- range $items.ByWeight }} {{- $active := eq $page_url .RelPermalink -}} {{- $is_expanded := or (.Params.sidebar.open) (.IsAncestor $page) $active | default false }}
  • {{- template "custom-menu-link" dict "context" . "active" $active "title" .LinkTitle "link" .RelPermalink -}} {{- if and $toc $active -}} {{- template "mobile-toc" dict "page" . -}} {{- end -}} {{- template "link-tree" dict "context" . "page" $page "pageURL" $page_url "level" (add $level 1) "toc" $toc -}}
  • {{- end -}} {{- else -}}
      {{- range $items.ByWeight }} {{- $active := eq $page_url .RelPermalink -}} {{- $is_expanded := or (.Params.sidebar.open) (.IsAncestor $page) $active | default false }} {{- $title := .LinkTitle | default .File.BaseFileName -}}
    • {{- template "custom-menu-link" dict "context" . "active" $active "title" $title "link" .RelPermalink -}} {{- if and $toc $active -}} {{ template "mobile-toc" dict "page" . }} {{- end }} {{ template "link-tree" dict "context" . "page" $page "pageURL" $page_url "level" (add $level 1) "toc" $toc }}
    • {{- end -}}
    {{- end -}} {{- end }} {{- end -}} {{- define "mobile-toc" -}} {{ $page := .page }} {{ with $page.Fragments.Headings }}
      {{- range . }} {{- with .Headings }} {{- range . -}}
    • {{- .Title -}}
    • {{ end -}} {{ end -}} {{ end -}}
    {{ end }} {{- end -}} {{- define "custom-menu-links" -}} {{- range site.Menus.sidebar -}} {{- $name := .Name -}} {{ if eq .Params.type "separator" }}
  • {{ $name }}
  • {{ else }}
  • {{ template "custom-menu-link" dict "active" false "title" $name "link" (.URL | relLangURL) }}
  • {{ end }} {{- end -}} {{- end -}} {{- define "custom-menu-link" -}} {{- $is_external := strings.HasPrefix .link "http" -}} {{- $open := .open | default false -}} {{- .title -}} {{- with .context }} {{- if or .RegularPages .Sections }} {{- end }} {{ end -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/components/slides-embed.html ================================================ {{/* Hugo Blox Slides Embed Component - Reusable iframe embed with fullscreen support Usage: {{ partial "components/slides-embed.html" (dict "page" . "slides_slug" .Params.slides) }} Params: - page: current page context - slides_slug: slug of slides to embed (e.g., "example") - show_actions: (optional) show open/speaker notes links, default true - title: (optional) title for iframe, defaults to page title */}} {{ $page := .page }} {{ $slides_slug := .slides_slug }} {{ $show_actions := .show_actions | default true }} {{ $slides_label := i18n "slides" | default "Slides" }} {{ $present_fullscreen_label := i18n "present_fullscreen" | default "Present (fullscreen)" }} {{ $enter_fullscreen_label := i18n "enter_fullscreen" | default "Enter fullscreen" }} {{ $exit_fullscreen_label := i18n "exit_fullscreen" | default "Exit fullscreen" }} {{ $speaker_notes_hint := i18n "speaker_notes_hint" | default "for speaker notes" }} {{ $slides_not_found_label := i18n "slides_not_found" | default "Slides not found" }} {{ $embed_title := .title | default (printf "%s - %s" $page.Title $slides_label) }} {{/* Enable Alpine.js for fullscreen functionality */}} {{ $page.Store.Set "has_alpine" true }} {{/* Get slides page */}} {{ $slides_page := site.GetPage (printf "/slides/%s" $slides_slug) }} {{ $scr := newScratch }} {{ if $slides_page }} {{ $scr.Set "slides_url" $slides_page.RelPermalink }} {{ $scr.Set "present_url" $slides_page.RelPermalink }} {{ $scr.Set "embed_url" $slides_page.RelPermalink }} {{ $present_format := $slides_page.OutputFormats.Get "present" }} {{ if not $present_format }} {{ $present_format = $slides_page.OutputFormats.Get "Present" }} {{ end }} {{ with $present_format }} {{ $scr.Set "present_url" .RelPermalink }} {{ $scr.Set "embed_url" (printf "%s?embed=1" .RelPermalink) }} {{ end }} {{ end }} {{ $slides_url := $scr.Get "slides_url" }} {{ $present_url := $scr.Get "present_url" | default $slides_url }} {{ $embed_url := $scr.Get "embed_url" | default $slides_url }} {{ if $slides_page }}
    {{/* Slides iframe container - wrapper for fullscreen API */}}
    {{/* Fullscreen toggle button - inside container for fullscreen visibility */}}
    {{ if $show_actions }} {{/* Action links below embed */}}
    {{/* Open in new tab */}} {{ $present_fullscreen_label }} {{/* Presentation mode hint */}} S {{ $speaker_notes_hint }}
    {{ end }}
    {{ else }}

    {{ $slides_not_found_label }}: {{ $slides_slug }}

    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/components/toc.html ================================================ {{/* Table of Contents */}} {{- $toc := .Params.toc | default true -}} {{/* UI Text */}} {{- $on_this_page := T "on_this_page" }} {{- $edit_this_page := T "edit_page" }} {{/* Render Headings */}} {{- define "toc-headings" -}} {{- $headings := .headings -}} {{- $level := .level -}} {{- if ge $level 4 -}} {{ return }} {{- end -}} {{- $padding := (mul $level 4) -}}{{/* Requires inclusion in Tailwind safelist!! */}} {{- $class := cond (eq $level 0) "font-semibold" (printf "pl-%d rtl:pr-%d" $padding $padding) -}} {{- range $headings }} {{- if .Title }}
  • {{- .Title | plainify | htmlUnescape -}}
  • {{- end -}} {{- with .Headings -}} {{ template "toc-headings" (dict "headings" . "level" (add $level 1)) }} {{- end -}} {{- end -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/css.html ================================================ {{/* HB Tailwind CSS v4 Processing with Hugo's Native Function */}} {{ with resources.Get "css/main.css" }} {{/* Build dynamic @source list and prepend it before main.css */}} {{ $dynamic_sources_str := partial "tailwind_sources.html" . }} {{ $dynamic_sources_res := resources.FromString "css/_dynamic_sources.css" $dynamic_sources_str }} {{ $main_css := . }} {{ $entry := slice $dynamic_sources_res $main_css | resources.Concat "css/_entry.css" }} {{ $opts := dict "minify" (not hugo.IsDevelopment) }} {{ with $entry | css.TailwindCSS $opts }} {{ if hugo.IsDevelopment }} {{ else }} {{ with . | fingerprint }} {{ end }} {{ end }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/docs_layout.html ================================================
    {{ partial "components/sidebar.html" (dict "context" . "no_sidebar" false) }} {{ partial "components/toc.html" . }}
    {{ if (.Params.show_breadcrumb | default true) }}
    {{ partial "components/breadcrumb.html" . }}
    {{ end }} {{/* Pagefind metadata for search filtering */}}

    {{ .Title }}

    {{ .Content }} {{/* Use hidden spans for filter values - best practice per Pagefind docs */}} docs {{ with .Params.categories }} {{ index . 0 }} {{ end }}
    {{ partial "components/last-edited.html" . }} {{ .Scratch.Set "invert_pager" true }} {{ partial "components/next-in-series.html" . }} {{ partial "comments.html" . }}
    ================================================ FILE: modules/blox/layouts/_partials/functions/build_links.html ================================================ {{/* Hugo Blox Page Link Builder Build a normalized list of page links from: - Author-provided front matter `links` (array order respected) - Auto-detected resources (local PDF, cite.bib) - Derived identifiers from `hugoblox.ids` - Associated internal `projects` references Inputs: dict { "page": . , "is_list": 0|1 } Output: slice of dicts with fields: type, url, icon, labelKey, label, contexts, rel Deprecations handled with warnings and mapped: - external_link -> type: site - url_pdf -> type: pdf - url_preprint -> type: preprint - url_code -> type: code - url_dataset -> type: dataset - url_poster -> type: poster - url_project -> type: project - url_slides -> type: slides - url_source -> type: source - url_video -> type: video */}} {{ $page := .page }} {{ $is_list := .is_list }} {{ $types := site.Data.link_types.types }} {{ $derived := site.Data.link_types.derived }} {{ $links := slice }} {{ $seen := newScratch }} {{ $seen.Set "set" (dict) }} {{/* 1) Author-provided links (array order) */}} {{ with $page.Params.links }} {{ range . }} {{/* Support new fields: type, url, icon (pack/name), label, contexts, rel; legacy: name */}} {{ $type := .type | default "custom" }} {{ $url := .url | default "" }} {{/* Optional provider+id derivation for common platforms */}} {{ if and (not $url) .id }} {{ if eq $type "doi" }} {{ $url = replace (index (index $derived "doi") "url_template") "{id}" (printf "%v" .id) }} {{ else if and (eq $type "preprint") (eq .provider "arxiv") }} {{ $url = replace (index (index $derived "arxiv") "url_template") "{id}" (printf "%v" .id) }} {{ else if and (eq $type "preprint") (eq .provider "openreview") }} {{ $url = replace (index (index $derived "openreview") "url_template") "{id}" (printf "%v" .id) }} {{ end }} {{ end }} {{ $typeF := $type }} {{ $urlF := $url }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (.icon | default (index (index $types $typeF) "icon") | default "hero/link") "labelKey" (index (index $types $typeF) "label_i18n") "label" (.label | default .name) "contexts" (.contexts | default (slice "list" "page")) "rel" .rel ) }} {{ end }} {{ end }} {{ end }} {{/* 2) Associated projects (internal) */}} {{ with $page.Params.projects }} {{ range . }} {{ with (site.GetPage (printf "project/%s" .)) }} {{ $typeF := "project" }} {{ $urlF := .RelPermalink }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* 2b) Slides relation parameter (legacy but common) */}} {{ with $page.Params.slides }} {{ if reflect.IsMap . }} {{/* Skip: slides map is Reveal.js config for slide decks. */}} {{ else if reflect.IsSlice . }} {{ range . }} {{ with (site.GetPage (printf "slides/%s" .)) }} {{ $typeF := "slides" }} {{ $urlF := .RelPermalink }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ else }} {{ warnf "`slides` relation could not resolve to a page for %s" $page.File.Path }} {{ end }} {{ end }} {{ else }} {{ with (site.GetPage (printf "slides/%s" .)) }} {{ $typeF := "slides" }} {{ $urlF := .RelPermalink }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ else }} {{ warnf "`slides` relation could not resolve to a page for %s" $page.File.Path }} {{ end }} {{ end }} {{ end }} {{/* 3) Auto-detected resources (local PDF by content basename, cite.bib) */}} {{ with $page.File.ContentBaseName }} {{ with ($page.Resources.GetMatch (printf "%s.pdf" .)) }} {{ $typeF := "pdf" }} {{ $urlF := .RelPermalink }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{ end }} {{ with ($page.Resources.GetMatch "cite.bib") }} {{ $typeF := "bibtex" }} {{ $urlF := .RelPermalink }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{/* 4) Derived links from identifiers under `hugoblox.ids` */}} {{ with $page.Params.hugoblox }} {{ with .ids }} {{ range $key, $val := . }} {{ with (index $derived $key) }} {{ $der := . }} {{ $typeF := index $der "type" }} {{ $urlF := replace (index $der "url_template") "{id}" (printf "%v" $val) }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index $der "icon") "labelKey" (index $der "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* 5) Legacy fields -> deprecation warnings and normalized items */}} {{/* external_link */}} {{ with $page.Params.external_link }} {{ warnf "`external_link` is deprecated. Use `links: [{type: site, url: ...}]` in %s" $page.File.Path }} {{ $typeF := "site" }} {{ $urlF := . }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{/* top-level doi */}} {{ with $page.Params.doi }} {{ warnf "Top-level `doi` is deprecated. Use `hugoblox.ids: { doi: ... }` in %s" $page.File.Path }} {{ with (index $derived "doi") }} {{ $der := . }} {{ $typeF := index $der "type" }} {{ $urlF := replace (index $der "url_template") "{id}" (printf "%v" $page.Params.doi) }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index $der "icon") "labelKey" (index $der "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ else }} {{ $typeF := "doi" }} {{ $urlF := printf "https://doi.org/%v" $page.Params.doi }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{ end }} {{/* Map of legacy url_* to new types */}} {{ $legacy := dict "url_pdf" "pdf" "url_preprint" "preprint" "url_code" "code" "url_dataset" "dataset" "url_poster" "poster" "url_project" "project" "url_slides" "slides" "url_source" "source" "url_video" "video" }} {{ range $legacyKey, $legacyType := $legacy }} {{ with index $page.Params $legacyKey }} {{ warnf "`%s` is deprecated. Use `links: [{type: %s, url: ...}]` in %s" $legacyKey $legacyType $page.File.Path }} {{/* Resolve relative resource if present */}} {{ $u := . }} {{ with ($page.Resources.GetMatch $u) }} {{ $u = .RelPermalink }} {{ else }} {{ $u = $u | relURL }} {{ end }} {{ $typeF := $legacyType }} {{ $urlF := $u }} {{ $keyF := printf "%s::%s" $typeF $urlF }} {{ if not ($seen.Get (printf "set.%s" $keyF)) }} {{ $seen.SetInMap "set" $keyF true }} {{ $links = $links | append (dict "type" $typeF "url" $urlF "icon" (index (index $types $typeF) "icon") "labelKey" (index (index $types $typeF) "label_i18n") "contexts" (slice "list" "page") ) }} {{ end }} {{ end }} {{ end }} {{- return $links -}} ================================================ FILE: modules/blox/layouts/_partials/functions/coerce_bool.html ================================================ {{ $value := .value }} {{ $result := .default }} {{ if ne $value nil }} {{ $valueType := printf "%T" $value }} {{ if eq $valueType "bool" }} {{ $result = $value }} {{ else if or (eq $valueType "int") (eq $valueType "int8") (eq $valueType "int16") (eq $valueType "int32") (eq $valueType "int64") (eq $valueType "uint") (eq $valueType "uint8") (eq $valueType "uint16") (eq $valueType "uint32") (eq $valueType "uint64") }} {{ $result = ne (int $value) 0 }} {{ else if or (eq $valueType "float32") (eq $valueType "float64") }} {{ $result = ne (float $value) 0 }} {{ else if eq $valueType "string" }} {{ $trimmed := lower (strings.TrimSpace $value) }} {{ if in (slice "1" "true" "yes" "y" "on") $trimmed }} {{ $result = true }} {{ else if in (slice "0" "false" "no" "n" "off") $trimmed }} {{ $result = false }} {{ end }} {{ end }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/coerce_int.html ================================================ {{ $value := .value }} {{ $result := .default }} {{ if ne $value nil }} {{ $valueType := printf "%T" $value }} {{ if or (eq $valueType "int") (eq $valueType "int8") (eq $valueType "int16") (eq $valueType "int32") (eq $valueType "int64") (eq $valueType "uint") (eq $valueType "uint8") (eq $valueType "uint16") (eq $valueType "uint32") (eq $valueType "uint64") (eq $valueType "float32") (eq $valueType "float64") }} {{ $result = int $value }} {{ else if eq $valueType "string" }} {{ $trimmed := strings.TrimSpace $value }} {{ if gt (len (findRE "^-?[0-9]+$" $trimmed)) 0 }} {{ $result = int $trimmed }} {{ else if gt (len (findRE "^-?[0-9]*\\.[0-9]+$" $trimmed)) 0 }} {{ $result = int (float $trimmed) }} {{ end }} {{ end }} {{ end }} {{ if isset . "min" }} {{ if lt $result .min }} {{ $result = .min }} {{ end }} {{ end }} {{ if isset . "max" }} {{ if gt $result .max }} {{ $result = .max }} {{ end }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/deep_merge.html ================================================ {{/* Pragmatic deep merge for block sections: shallow merge + merge 'content' and 'design' submaps if present. b overrides a. */}} {{- $a := .a -}} {{- $b := .b -}} {{- if and (reflect.IsMap $a) (reflect.IsMap $b) -}} {{- $result := merge $a $b -}} {{- /* merge 'content' submap */ -}} {{- $ac := index $a "content" -}} {{- $bc := index $b "content" -}} {{- if and (reflect.IsMap $ac) (reflect.IsMap $bc) -}} {{- $result = merge $result (dict "content" (merge $ac $bc)) -}} {{- end -}} {{- /* merge 'design' submap */ -}} {{- $ad := index $a "design" -}} {{- $bd := index $b "design" -}} {{- if and (reflect.IsMap $ad) (reflect.IsMap $bd) -}} {{- $result = merge $result (dict "design" (merge $ad $bd)) -}} {{- end -}} {{- return $result -}} {{- else -}} {{- return $b -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/functions/demo_theme_styles.html ================================================ {{/* HugoBlox Theme Engine: Demo Theme Styles Generates CSS variables for ALL available theme packs. Used for the "Theme Pack Chooser" demo feature. */}} {{ $typography_config := .typography }} {{ $layout_config := .layout }} ================================================ FILE: modules/blox/layouts/_partials/functions/embed/github.html ================================================ {{/* Hugo Blox GitHub Platform Configuration Part of Hugo Blox embed system Parameters: - resource: repository identifier (e.g., "owner/repo") - type: "repo", "gist", etc. - user: username/organization - customUrl: optional override URL */}} {{- $resource := .resource -}} {{- $type := .type | default "repo" -}} {{- $user := .user -}} {{- $customUrl := .customUrl -}} {{- $showThumbnail := .showThumbnail | default false -}} {{- $width := .width | default 600 -}} {{- $height := .height | default 315 -}} {{- $quality := .quality | default 85 -}} {{- $formats := .formats | default (slice "avif" "webp" "jpg") -}} {{- $config := dict -}} {{- if $resource -}} {{- if eq $type "repo" -}} {{- if $showThumbnail -}} {{- $config = dict "apiUrl" (print "https://api.github.com/repos/" $resource) "repoLink" (print "https://github.com/" $resource) "imageUrl" (print "https://opengraph.githubassets.com/0/" $resource) "icon" "code-bracket" "brandColors" (slice "slate-800" "slate-900") "typeColor" "primary-500" "isImageEmbed" true "imageProcessing" (dict "width" $width "height" $height "quality" $quality "formats" $formats "sizes" (slice 400 600 800) ) "statsConfig" (dict "stars" (dict "icon" "star" "color" "yellow-500" "field" "stargazers_count") "forks" (dict "icon" "git-fork" "color" "primary-500" "field" "forks_count") "issues" (dict "icon" "exclamation-circle" "color" "red-500" "field" "open_issues_count") ) "titleField" "name" "descriptionField" "description" "subtypeField" "language" "ownerField" "owner.login" -}} {{- else -}} {{- $config = dict "apiUrl" (print "https://api.github.com/repos/" $resource) "repoLink" (print "https://github.com/" $resource) "icon" "code-bracket" "brandColors" (slice "slate-800" "slate-900") "typeColor" "primary-500" "statsConfig" (dict "stars" (dict "icon" "star" "color" "yellow-500" "field" "stargazers_count") "forks" (dict "icon" "git-fork" "color" "primary-500" "field" "forks_count") "issues" (dict "icon" "exclamation-circle" "color" "red-500" "field" "open_issues_count") ) "titleField" "name" "descriptionField" "description" "subtypeField" "language" "ownerField" "owner.login" -}} {{- end -}} {{- else if eq $type "gist" -}} {{- $config = dict "apiUrl" (print "https://api.github.com/gists/" $resource) "repoLink" (print "https://gist.github.com/" $resource) "icon" "document-text" "brandColors" (slice "slate-800" "slate-900") "typeColor" "secondary-500" "titleField" "description" "descriptionField" "description" -}} {{- else -}} {{- $config = dict "repoLink" (print "https://github.com/" $resource) "icon" "link" "brandColors" (slice "slate-800" "slate-900") "typeColor" "zinc-500" -}} {{- end -}} {{- else if $customUrl -}} {{- $config = dict "repoLink" $customUrl "icon" "link" "brandColors" (slice "slate-800" "slate-900") "typeColor" "zinc-500" -}} {{- end -}} {{ return $config }} ================================================ FILE: modules/blox/layouts/_partials/functions/embed/hbx_content_section.html ================================================ {{/* Content section rendering for embed cards Parameters: - customDescription: user-provided description override - embedData: data fetched from API - platform: platform name - hb_id: Hugo Blox unique identifier - config: platform configuration - processedImage: processed image data (for image embeds) */}} {{- $customDescription := .customDescription -}} {{- $embedData := .embedData -}} {{- $platform := .platform -}} {{- $hb_id := .hb_id -}} {{- $config := .config -}} {{- $processedImage := .processedImage -}} {{/* Display processed image if available */}} {{- if $processedImage -}}
    {{ if $customDescription }}{{ $customDescription }}{{ else if and $embedData $config.titleField }}{{ index $embedData $config.titleField }}{{ else }}Embedded image{{ end }}
    {{- end -}} {{/* Description handling */}} {{- $description := $customDescription -}} {{- if and (not $description) $embedData $config.descriptionField -}} {{- $description = index $embedData $config.descriptionField -}} {{/* Apply platform-specific cleanup */}} {{- if $config.descriptionCleanup -}} {{- $description = $description | replaceRE $config.descriptionCleanup "" -}} {{- end -}} {{- end -}} {{- if $description -}}

    {{ $description | plainify | htmlUnescape | truncate 200 | emojify }}

    {{- end -}} {{/* Platform-specific stats section */}} {{- if and $embedData $config.statsConfig -}}
    {{- range $statKey, $statConfig := $config.statsConfig -}} {{- $statValue := index $embedData $statConfig.field -}} {{- if $statValue -}}
    {{ partial "functions/get_icon" (dict "name" $statConfig.icon "attributes" (printf "class=\"w-4 h-4 text-%s\"" $statConfig.color)) }} {{- if and (eq $platform "github") (eq $statKey "issues") -}} {{/* Make issues count clickable for GitHub */}} {{- if gt $statValue 999 -}} {{- if gt $statValue 999999 -}} {{ div $statValue 1000000 }}M {{- else -}} {{ div $statValue 1000 }}k {{- end -}} {{- else -}} {{ $statValue }} {{- end -}} {{- else -}} {{- if gt $statValue 999 -}} {{- if gt $statValue 999999 -}} {{ div $statValue 1000000 }}M {{- else -}} {{ div $statValue 1000 }}k {{- end -}} {{- else -}} {{ $statValue }} {{- end -}} {{- end -}}
    {{- end -}} {{- end -}}
    {{- end -}} {{/* Additional platform-specific content */}} {{- if eq $platform "github" -}} {{/* Show additional GitHub-specific info if available */}} {{- if and $embedData $embedData.topics -}}
    {{- range first 3 $embedData.topics -}} {{ . | emojify }} {{- end -}} {{- if gt (len $embedData.topics) 3 -}} +{{ sub (len $embedData.topics) 3 }} {{- end -}}
    {{- end -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/functions/embed/hbx_platform_icon.html ================================================ {{/* Platform icon rendering Parameters: - platform: platform name (huggingface, github, etc.) - config: platform configuration dict - hb_id: Hugo Blox unique identifier for the embed */}} {{- $platform := .platform -}} {{- $config := .config -}} {{- $hb_id := .hb_id -}} {{- if eq $platform "huggingface" -}}
    {{ partial "functions/get_icon" (dict "name" "brands/huggingface" "attributes" "class=\"w-6 h-6 text-white\"") }}
    {{- else if eq $platform "github" -}}
    {{ partial "functions/get_icon" (dict "name" "brands/github" "attributes" "class=\"w-6 h-6 text-white\"") }}
    {{- else -}} {{/* Custom/generic embeds use neutral styling */}}
    {{ partial "functions/get_icon" (dict "name" ($config.icon | default "globe-alt") "attributes" "class=\"w-5 h-5 text-white\"") }}
    {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/functions/embed/hbx_title_section.html ================================================ {{/* Title section rendering for embed cards Parameters: - hb_id: Hugo Blox unique identifier - customTitle: user-provided title override - embedData: data fetched from API - customUrl: custom URL if provided - resource: platform resource identifier - type: resource type - platform: platform name - config: platform configuration */}} {{- $hb_id := .hb_id -}} {{- $customTitle := .customTitle -}} {{- $embedData := .embedData -}} {{- $customUrl := .customUrl -}} {{- $resource := .resource -}} {{- $type := .type -}} {{- $platform := .platform -}} {{- $config := .config -}}

    {{- if $customTitle -}} {{ $customTitle | emojify }} {{- else if and $embedData $config.titleField -}} {{ index $embedData $config.titleField | emojify }} {{- else if and $embedData $embedData.name -}} {{ $embedData.name | emojify }} {{- else if and $embedData $embedData.id -}} {{ $embedData.id | emojify }} {{- else if $customUrl -}} {{- $parsed := urls.Parse $customUrl -}} {{ $parsed.Host | emojify }} {{- else if $resource -}} {{- if eq $platform "github" -}} {{/* For GitHub, show just the repo name, not the full "owner/repo" */}} {{- $parts := split $resource "/" -}} {{- if gt (len $parts) 1 -}} {{ index $parts 1 | emojify }} {{- else -}} {{ $resource | emojify }} {{- end -}} {{- else -}} {{ $resource | emojify }} {{- end -}} {{- else -}} Embedded Resource {{- end -}}

    {{/* Resource type and subtype indicator */}} {{- $showTypeIndicator := false -}} {{- $typeText := "" -}} {{- $typeColor := $config.typeColor | default "zinc-500" -}} {{/* Always show type indicator for GitHub repos with data */}} {{- if and (eq $platform "github") $embedData $config.ownerField -}} {{- $showTypeIndicator = true -}} {{- end -}} {{/* Force metadata line for custom embeds to ensure proper alignment */}} {{- if eq $platform "custom" -}} {{- $showTypeIndicator = true -}} {{- end -}} {{- if $type -}} {{- $showTypeIndicator = true -}} {{- if and $embedData $config.subtypeField -}} {{- if $config.subtypeIndex -}} {{- $subtypes := index $embedData $config.subtypeField -}} {{- if $subtypes -}} {{- $typeText = index $subtypes $config.subtypeIndex -}} {{- else -}} {{- $typeText = $type -}} {{- end -}} {{- else -}} {{- $typeText = index $embedData $config.subtypeField | default $type -}} {{- end -}} {{- else -}} {{- $typeText = $type -}} {{- end -}} {{- else if and $embedData $config.subtypeField -}} {{- $showTypeIndicator = true -}} {{- if $config.subtypeIndex -}} {{- $subtypes := index $embedData $config.subtypeField -}} {{- if $subtypes -}} {{- $typeText = index $subtypes $config.subtypeIndex -}} {{- end -}} {{- else -}} {{- $typeText = index $embedData $config.subtypeField -}} {{- end -}} {{- end -}} {{- if $showTypeIndicator -}}
    {{/* GitHub repos: Show owner prominently, then language */}} {{- if eq $platform "github" -}} {{- $owner := "" -}} {{/* Get owner from API data if available */}} {{- if $embedData -}} {{- if eq $config.ownerField "owner.login" -}} {{/* Handle nested GitHub API structure: embedData.owner.login */}} {{- $ownerObj := index $embedData "owner" -}} {{- if $ownerObj -}} {{- $owner = index $ownerObj "login" -}} {{- end -}} {{- else if $config.ownerField -}} {{/* Handle simple field access */}} {{- $owner = index $embedData $config.ownerField -}} {{- end -}} {{- end -}} {{/* Fallback: extract owner from resource string (e.g., "HugoBlox/kit" -> "HugoBlox") */}} {{- if and (not $owner) $resource -}} {{- $parts := split $resource "/" -}} {{- if gt (len $parts) 0 -}} {{- $owner = index $parts 0 -}} {{- end -}} {{- end -}} {{- if $owner -}} by {{ $owner | emojify }} {{- if $typeText -}} {{ $typeText | emojify }} {{- end -}} {{- else if $typeText -}} {{/* No owner, just show type */}} {{ $typeText | emojify }} {{- end -}} {{- else if eq $platform "custom" -}} {{/* Custom embeds: Show domain or minimal placeholder for consistent alignment */}} {{- if $customUrl -}} {{- $parsed := urls.Parse $customUrl -}} {{- $domain := $parsed.Host -}} {{ $domain | emojify }} {{- else -}} {{/* Minimal placeholder to maintain visual spacing */}} external resource {{- end -}} {{- else -}} {{/* Other platforms: Show type with indicator */}} {{- if $typeText -}} {{ $typeText | emojify }} {{- else -}} {{/* Minimal placeholder for consistent spacing */}} platform resource {{- end -}} {{- end -}}
    {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/functions/embed/huggingface.html ================================================ {{/* HuggingFace platform configuration Parameters: - resource: model or dataset identifier - type: "model" or "dataset" - customUrl: optional override URL */}} {{- $resource := .resource -}} {{- $type := .type -}} {{- $customUrl := .customUrl -}} {{- $config := dict -}} {{- if $resource -}} {{- if eq $type "model" -}} {{- $config = dict "apiUrl" (print "https://huggingface.co/api/models/" $resource) "repoLink" (print "https://huggingface.co/" $resource) "icon" "cpu-chip" "brandColors" (slice "yellow-400" "orange-500") "typeColor" "secondary-500" "statsConfig" (dict "likes" (dict "icon" "heart" "color" "secondary-500" "field" "likes") "downloads" (dict "icon" "arrow-down-tray" "color" "primary-500" "field" "downloads") ) "titleField" "id" "descriptionField" "description" "descriptionCleanup" `Dataset Card for .+\s+Dataset Summary\s+` "subtypeField" "pipeline_tag" -}} {{- else if eq $type "dataset" -}} {{- $config = dict "apiUrl" (print "https://huggingface.co/api/datasets/" $resource) "repoLink" (print "https://huggingface.co/datasets/" $resource) "icon" "circle-stack" "brandColors" (slice "yellow-400" "orange-500") "typeColor" "primary-500" "statsConfig" (dict "likes" (dict "icon" "heart" "color" "secondary-500" "field" "likes") "downloads" (dict "icon" "arrow-down-tray" "color" "primary-500" "field" "downloads") ) "titleField" "id" "descriptionField" "description" "descriptionCleanup" `Dataset Card for .+\s+Dataset Summary\s+` "subtypeField" "task_categories" "subtypeIndex" 0 -}} {{- else -}} {{- $config = dict "repoLink" (print "https://huggingface.co/" $resource) "icon" "link" "brandColors" (slice "yellow-400" "orange-500") "typeColor" "zinc-500" -}} {{- end -}} {{- else if $customUrl -}} {{- $config = dict "repoLink" $customUrl "icon" "link" "brandColors" (slice "yellow-400" "orange-500") "typeColor" "zinc-500" -}} {{- end -}} {{ return $config }} ================================================ FILE: modules/blox/layouts/_partials/functions/generate_color_scale.html ================================================ {{/* Hugo Blox Kit: Generate Color Scale Generate Tailwind-like 50–950 scale for a given color. Supports palette names and hex values. */}} {{ $name := .name }} {{ $colorInput := .color | lower }} {{/* Tailwind 4 Color Palette Lookup Table (OKLCH/Hex) */}} {{ $tailwind_palette := dict "red" (dict "50" "oklch(0.971 0.013 17.38)" "100" "oklch(0.936 0.032 17.717)" "200" "oklch(0.885 0.062 18.334)" "300" "oklch(0.808 0.114 19.571)" "400" "oklch(0.704 0.191 22.216)" "500" "oklch(0.637 0.237 25.331)" "600" "oklch(0.577 0.245 27.325)" "700" "oklch(0.505 0.213 27.518)" "800" "oklch(0.444 0.177 26.899)" "900" "oklch(0.396 0.141 25.723)" "950" "oklch(0.258 0.092 26.042)") "orange" (dict "50" "oklch(0.98 0.016 73.684)" "100" "oklch(0.954 0.038 75.164)" "200" "oklch(0.901 0.076 70.697)" "300" "oklch(0.837 0.128 66.29)" "400" "oklch(0.75 0.183 55.934)" "500" "oklch(0.705 0.213 47.604)" "600" "oklch(0.646 0.222 41.116)" "700" "oklch(0.553 0.195 38.402)" "800" "oklch(0.47 0.157 37.304)" "900" "oklch(0.408 0.123 38.172)" "950" "oklch(0.266 0.079 36.259)") "amber" (dict "50" "oklch(0.987 0.022 95.277)" "100" "oklch(0.962 0.059 95.617)" "200" "oklch(0.924 0.12 95.746)" "300" "oklch(0.879 0.169 91.605)" "400" "oklch(0.828 0.189 84.429)" "500" "oklch(0.769 0.188 70.08)" "600" "oklch(0.666 0.179 58.318)" "700" "oklch(0.555 0.163 48.998)" "800" "oklch(0.473 0.137 46.201)" "900" "oklch(0.414 0.112 45.904)" "950" "oklch(0.279 0.077 45.635)") "yellow" (dict "50" "oklch(0.987 0.026 102.212)" "100" "oklch(0.973 0.071 103.193)" "200" "oklch(0.945 0.129 101.54)" "300" "oklch(0.905 0.182 98.111)" "400" "oklch(0.852 0.199 91.936)" "500" "oklch(0.795 0.184 86.047)" "600" "oklch(0.681 0.162 75.834)" "700" "oklch(0.554 0.135 66.442)" "800" "oklch(0.476 0.114 61.907)" "900" "oklch(0.421 0.095 57.708)" "950" "oklch(0.286 0.066 53.813)") "lime" (dict "50" "oklch(0.986 0.031 120.757)" "100" "oklch(0.967 0.067 122.328)" "200" "oklch(0.938 0.127 124.321)" "300" "oklch(0.897 0.196 126.665)" "400" "oklch(0.841 0.238 128.85)" "500" "oklch(0.768 0.233 130.85)" "600" "oklch(0.648 0.2 131.684)" "700" "oklch(0.532 0.157 131.589)" "800" "oklch(0.453 0.124 130.933)" "900" "oklch(0.405 0.101 131.063)" "950" "oklch(0.274 0.072 132.109)") "green" (dict "50" "oklch(0.982 0.018 155.826)" "100" "oklch(0.962 0.044 156.743)" "200" "oklch(0.925 0.084 155.995)" "300" "oklch(0.871 0.15 154.449)" "400" "oklch(0.792 0.209 151.711)" "500" "oklch(0.723 0.219 149.579)" "600" "oklch(0.627 0.194 149.214)" "700" "oklch(0.527 0.154 150.069)" "800" "oklch(0.448 0.119 151.328)" "900" "oklch(0.393 0.095 152.535)" "950" "oklch(0.266 0.065 152.934)") "emerald" (dict "50" "oklch(0.979 0.021 166.113)" "100" "oklch(0.95 0.052 163.051)" "200" "oklch(0.905 0.093 164.15)" "300" "oklch(0.845 0.143 164.978)" "400" "oklch(0.765 0.177 163.223)" "500" "oklch(0.696 0.17 162.48)" "600" "oklch(0.596 0.145 163.225)" "700" "oklch(0.508 0.118 165.612)" "800" "oklch(0.432 0.095 166.913)" "900" "oklch(0.378 0.077 168.94)" "950" "oklch(0.262 0.051 172.552)") "teal" (dict "50" "oklch(0.984 0.014 180.72)" "100" "oklch(0.953 0.051 180.801)" "200" "oklch(0.91 0.096 180.426)" "300" "oklch(0.855 0.138 181.071)" "400" "oklch(0.777 0.152 181.912)" "500" "oklch(0.704 0.14 182.503)" "600" "oklch(0.6 0.118 184.704)" "700" "oklch(0.511 0.096 186.391)" "800" "oklch(0.437 0.078 188.216)" "900" "oklch(0.386 0.063 188.416)" "950" "oklch(0.277 0.046 192.524)") "cyan" (dict "50" "oklch(0.984 0.019 200.873)" "100" "oklch(0.956 0.045 203.388)" "200" "oklch(0.917 0.08 205.041)" "300" "oklch(0.865 0.127 207.078)" "400" "oklch(0.789 0.154 211.53)" "500" "oklch(0.715 0.143 215.221)" "600" "oklch(0.609 0.126 221.723)" "700" "oklch(0.52 0.105 223.128)" "800" "oklch(0.45 0.085 224.283)" "900" "oklch(0.398 0.07 227.392)" "950" "oklch(0.302 0.056 229.695)") "sky" (dict "50" "oklch(0.977 0.013 236.62)" "100" "oklch(0.951 0.026 236.824)" "200" "oklch(0.901 0.058 230.902)" "300" "oklch(0.828 0.111 230.318)" "400" "oklch(0.746 0.16 232.661)" "500" "oklch(0.685 0.169 237.323)" "600" "oklch(0.588 0.158 241.966)" "700" "oklch(0.5 0.134 242.749)" "800" "oklch(0.443 0.11 240.79)" "900" "oklch(0.391 0.09 240.876)" "950" "oklch(0.293 0.066 243.157)") "blue" (dict "50" "oklch(0.97 0.014 254.604)" "100" "oklch(0.932 0.032 255.585)" "200" "oklch(0.882 0.059 254.128)" "300" "oklch(0.809 0.105 251.813)" "400" "oklch(0.707 0.165 254.624)" "500" "oklch(0.623 0.214 259.815)" "600" "oklch(0.546 0.245 262.881)" "700" "oklch(0.488 0.243 264.376)" "800" "oklch(0.424 0.199 265.638)" "900" "oklch(0.379 0.146 265.522)" "950" "oklch(0.282 0.091 267.935)") "indigo" (dict "50" "oklch(0.962 0.018 272.314)" "100" "oklch(0.93 0.034 272.788)" "200" "oklch(0.87 0.065 274.039)" "300" "oklch(0.785 0.115 274.713)" "400" "oklch(0.673 0.182 276.935)" "500" "oklch(0.585 0.233 277.117)" "600" "oklch(0.511 0.262 276.966)" "700" "oklch(0.457 0.24 277.023)" "800" "oklch(0.398 0.195 277.366)" "900" "oklch(0.359 0.144 278.697)" "950" "oklch(0.257 0.09 281.288)") "violet" (dict "50" "oklch(0.969 0.016 293.756)" "100" "oklch(0.943 0.029 294.588)" "200" "oklch(0.894 0.057 293.283)" "300" "oklch(0.811 0.111 293.571)" "400" "oklch(0.702 0.183 293.541)" "500" "oklch(0.606 0.25 292.717)" "600" "oklch(0.541 0.281 293.009)" "700" "oklch(0.491 0.27 292.581)" "800" "oklch(0.432 0.232 292.759)" "900" "oklch(0.38 0.189 293.745)" "950" "oklch(0.283 0.141 291.089)") "purple" (dict "50" "oklch(0.977 0.014 308.299)" "100" "oklch(0.946 0.033 307.174)" "200" "oklch(0.902 0.063 306.703)" "300" "oklch(0.827 0.119 306.383)" "400" "oklch(0.714 0.203 305.504)" "500" "oklch(0.627 0.265 303.9)" "600" "oklch(0.558 0.288 302.321)" "700" "oklch(0.496 0.265 301.924)" "800" "oklch(0.438 0.218 303.724)" "900" "oklch(0.381 0.176 304.987)" "950" "oklch(0.291 0.149 302.717)") "fuchsia" (dict "50" "oklch(0.977 0.017 320.058)" "100" "oklch(0.952 0.037 318.852)" "200" "oklch(0.903 0.076 319.62)" "300" "oklch(0.833 0.145 321.434)" "400" "oklch(0.74 0.238 322.16)" "500" "oklch(0.667 0.295 322.15)" "600" "oklch(0.591 0.293 322.896)" "700" "oklch(0.518 0.253 323.949)" "800" "oklch(0.452 0.211 324.591)" "900" "oklch(0.401 0.17 325.612)" "950" "oklch(0.293 0.136 325.661)") "pink" (dict "50" "oklch(0.971 0.014 343.198)" "100" "oklch(0.948 0.028 342.258)" "200" "oklch(0.899 0.061 343.231)" "300" "oklch(0.823 0.12 346.018)" "400" "oklch(0.718 0.202 349.761)" "500" "oklch(0.656 0.241 354.308)" "600" "oklch(0.592 0.249 0.584)" "700" "oklch(0.525 0.223 3.958)" "800" "oklch(0.459 0.187 3.815)" "900" "oklch(0.408 0.153 2.432)" "950" "oklch(0.284 0.109 3.907)") "rose" (dict "50" "oklch(0.969 0.015 12.422)" "100" "oklch(0.941 0.03 12.58)" "200" "oklch(0.892 0.058 10.001)" "300" "oklch(0.81 0.117 11.638)" "400" "oklch(0.712 0.194 13.428)" "500" "oklch(0.645 0.246 16.439)" "600" "oklch(0.586 0.253 17.585)" "700" "oklch(0.514 0.222 16.935)" "800" "oklch(0.455 0.188 13.697)" "900" "oklch(0.41 0.159 10.272)" "950" "oklch(0.271 0.105 12.094)") "slate" (dict "50" "oklch(0.984 0.003 247.858)" "100" "oklch(0.968 0.007 247.896)" "200" "oklch(0.929 0.013 255.508)" "300" "oklch(0.869 0.022 252.894)" "400" "oklch(0.704 0.04 256.788)" "500" "oklch(0.554 0.046 257.417)" "600" "oklch(0.446 0.043 257.281)" "700" "oklch(0.372 0.044 257.287)" "800" "oklch(0.279 0.041 260.031)" "900" "oklch(0.208 0.042 265.755)" "950" "oklch(0.129 0.042 264.695)") "gray" (dict "50" "oklch(0.985 0.002 247.839)" "100" "oklch(0.967 0.003 264.542)" "200" "oklch(0.928 0.006 264.531)" "300" "oklch(0.872 0.01 258.338)" "400" "oklch(0.707 0.022 261.325)" "500" "oklch(0.551 0.027 264.364)" "600" "oklch(0.446 0.03 256.802)" "700" "oklch(0.373 0.034 259.733)" "800" "oklch(0.278 0.033 256.848)" "900" "oklch(0.21 0.034 264.665)" "950" "oklch(0.13 0.028 261.692)") "zinc" (dict "50" "oklch(0.985 0 0)" "100" "oklch(0.967 0.001 286.375)" "200" "oklch(0.92 0.004 286.32)" "300" "oklch(0.871 0.006 286.286)" "400" "oklch(0.705 0.015 286.067)" "500" "oklch(0.552 0.016 285.938)" "600" "oklch(0.442 0.017 285.786)" "700" "oklch(0.37 0.013 285.805)" "800" "oklch(0.274 0.006 286.033)" "900" "oklch(0.21 0.006 285.885)" "950" "oklch(0.141 0.005 285.823)") "neutral" (dict "50" "oklch(0.985 0 0)" "100" "oklch(0.97 0 0)" "200" "oklch(0.922 0 0)" "300" "oklch(0.87 0 0)" "400" "oklch(0.708 0 0)" "500" "oklch(0.556 0 0)" "600" "oklch(0.439 0 0)" "700" "oklch(0.371 0 0)" "800" "oklch(0.269 0 0)" "900" "oklch(0.205 0 0)" "950" "oklch(0.145 0 0)") "stone" (dict "50" "oklch(0.985 0.001 106.423)" "100" "oklch(0.97 0.001 106.424)" "200" "oklch(0.923 0.003 48.717)" "300" "oklch(0.869 0.005 56.366)" "400" "oklch(0.709 0.01 56.259)" "500" "oklch(0.553 0.013 58.071)" "600" "oklch(0.444 0.011 73.639)" "700" "oklch(0.374 0.01 67.558)" "800" "oklch(0.268 0.007 34.298)" "900" "oklch(0.216 0.006 56.043)" "950" "oklch(0.147 0.004 49.25)") }} {{ if hasPrefix $colorInput "#" }} {{/* HEX PATH: Custom Brand Color Generate an accessible 50-950 scale by mixing the hex base with white (tints) and black (shades). We map the user's hex to the '500' slot and interpolate outwards. */}} {{ $r := 0 }}{{ $g := 0 }}{{ $b := 0 }} {{ if eq (len $colorInput) 7 }} {{ $r = printf "0x%s" (substr $colorInput 1 2) | int }} {{ $g = printf "0x%s" (substr $colorInput 3 2) | int }} {{ $b = printf "0x%s" (substr $colorInput 5 2) | int }} {{ end }} {{/* Base (500) */}} --hb-{{$name}}-500-rgb: {{ $r }} {{ $g }} {{ $b }}; --color-{{$name}}-500: rgb(var(--hb-{{$name}}-500-rgb)); {{/* Tints (50-400): Mix with White */}} {{ $tints := slice (dict "shade" "50" "percent" 95) (dict "shade" "100" "percent" 90) (dict "shade" "200" "percent" 80) (dict "shade" "300" "percent" 70) (dict "shade" "400" "percent" 60) }} {{ range $tints }} {{ $p := .percent }} {{ $rp := div (add (mul $r (sub 100 $p)) (mul 255 $p)) 100 }} {{ $gp := div (add (mul $g (sub 100 $p)) (mul 255 $p)) 100 }} {{ $bp := div (add (mul $b (sub 100 $p)) (mul 255 $p)) 100 }} --hb-{{$name}}-{{ .shade }}-rgb: {{ $rp }} {{ $gp }} {{ $bp }}; --color-{{$name}}-{{ .shade }}: rgb(var(--hb-{{$name}}-{{ .shade }}-rgb)); {{ end }} {{/* Shades (600-950): Mix with Black */}} {{ $shades := slice (dict "shade" "600" "percent" 10) (dict "shade" "700" "percent" 20) (dict "shade" "800" "percent" 35) (dict "shade" "900" "percent" 50) (dict "shade" "950" "percent" 70) }} {{ range $shades }} {{ $p := .percent }} {{ $rp := div (mul $r (sub 100 $p)) 100 }} {{ $gp := div (mul $g (sub 100 $p)) 100 }} {{ $bp := div (mul $b (sub 100 $p)) 100 }} --hb-{{$name}}-{{ .shade }}-rgb: {{ $rp }} {{ $gp }} {{ $bp }}; --color-{{$name}}-{{ .shade }}: rgb(var(--hb-{{$name}}-{{ .shade }}-rgb)); {{ end }} {{ else }} {{/* PALETTE PATH: Standard Tailwind Colors Look up the exact OKLCH values for the requested palette (e.g. "indigo"). This ensures complete visual consistency with standard Tailwind utilities. */}} {{ $palette := index $tailwind_palette $colorInput }} {{ if $palette }} {{ range $shade, $value := $palette }} {{/* Note: converting OKLCH to raw RGB CSS vars requires Tailwind 4's internal conversion or we output the raw color value directly if theme.css supports it. The existing system expects --hb-primary-50-rgb to be a comma-less RGB triplet "255 255 255". However, Tailwind 4 supports OKLCH natively. CRITICAL FIX: We must override the `rgb(var(...))` wrapper in `theme.css` if we want to use OKLCH. OR we just output the RGB approximation if we want to keep `theme.css` untouched. BUT `theme.css` defines: --color-primary-50: rgb(var(--hb-primary-50-rgb)); So we MUST provide RGB triplets. OKLCH strings like "oklch(...)" inside `rgb(...)` is invalid CSS. To fix this properly without changing `theme.css` significantly, we need RGB values in this table, OR we redefine the higher-level variables. Since we cannot easily calculate OKLCH -> RGB in Hugo templates, we should OUTPUT THE HIGHER LEVEL VARIABLES directly here to override theme.css. */}} --color-{{$name}}-{{$shade}}: {{ $value }}; {{ end }} {{/* Also set the legacy RGB vars to a fallback (500 shade) to prevent breakage in case something accesses the raw -rgb var directly, though unlikely */}} --hb-{{$name}}-500-rgb: 128 128 128; {{ else }} {{/* Unknown palette '{{$colorInput}}', falling back to Indigo-like default */}} {{ partial "functions/generate_color_scale" (dict "name" $name "color" "#6366f1") }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/functions/get-block-scripts.html ================================================ {{/* Get Block Scripts Discovers and returns a slice of JavaScript files for blocks used on the current page. */}} {{ $block_scripts := slice }} {{ if .IsPage }} {{/* Get the list of unique block types used on this page from the Page Store */}} {{ $block_types := .Page.Store.Get "block_types" | default (slice) | uniq }} {{ range $block_type := $block_types }} {{/* Check if a JS file exists for this block type */}} {{ $script_path := printf "js/hbx/blocks/%s/%s.js" $block_type $block_type }} {{ with resources.Get $script_path }} {{ $block_scripts = $block_scripts | append . }} {{ end }} {{ end }} {{ end }} {{ return $block_scripts }} ================================================ FILE: modules/blox/layouts/_partials/functions/get-build-id.html ================================================ {{/* Get Build ID - Returns a consistent build identifier for the current build cycle. This is cached across the entire build to prevent log duplication during dev rebuilds. */}} {{- printf "%d" now.Unix -}} ================================================ FILE: modules/blox/layouts/_partials/functions/get_address.html ================================================ {{/* Function to return a formatted address given a semantic address. */}} {{/* Check for valid site config. */}} {{ if not site.Data.address_formats }}{{errorf "Address formats missing from `data/address_formats.toml`!"}}{{end}} {{ $page := . }} {{ $address := .address }} {{ $format_name := $page.Params.address_format | default site.Params.hugoblox.locale.address_format | default "en-us" }} {{ if not (isset site.Data.address_formats $format_name) }}{{ errorf "Address format `%s` missing from `data/address_formats.toml`!" $format_name }}{{end}} {{ $format := index site.Data.address_formats $format_name }} {{ $address_display := slice }} {{ range $k, $v := $format.order }} {{ if eq $v "street" | and $address.street }}{{$address_display = $address_display | append (transform.HTMLEscape $address.street) | append (index $format.delimiters $k | default "") }}{{end}} {{ if eq $v "city" | and $address.city }}{{$address_display = $address_display | append (transform.HTMLEscape $address.city) | append (index $format.delimiters $k | default "") }}{{end}} {{ if eq $v "region" | and $address.region }}{{$address_display = $address_display | append (transform.HTMLEscape $address.region) | append (index $format.delimiters $k | default "") }}{{end}} {{ if eq $v "postcode" | and $address.postcode }}{{$address_display = $address_display | append (transform.HTMLEscape $address.postcode) | append (index $format.delimiters $k | default "") }}{{end}} {{ if eq $v "country" | and $address.country }}{{$address_display = $address_display | append (transform.HTMLEscape $address.country) | append (index $format.delimiters $k | default "") }}{{end}} {{end}} {{ return safeHTML (delimit $address_display "") }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_author_name.html ================================================ {{/* Get name of primary author. */}} {{ $page := . }} {{/* Get publisher as fall back. */}} {{ $branding := partialCached "functions/get_branding" $page "branding" }} {{ $publisher := $branding.organization }} {{ $author := "" }} {{ $author_slug := "" }} {{ if and (not $page.Params.authors) ($page.Scratch.Get "superuser_slug") }} {{ $author_slug = $page.Scratch.Get "superuser_slug" }} {{ else if $page.Params.authors }} {{ $author = index $page.Params.authors 0 }} {{ $author_slug = urlize $author }} {{ end }} {{ $profile := partial "functions/get_author_profile" (dict "slug" $author_slug) }} {{ if $profile.title }} {{ $author = $profile.title }} {{ else }} {{ $author = $author | default $publisher }} {{ end }} {{ return $author }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_author_profile.html ================================================ {{/* Return a normalized HugoBlox author/person profile from data. Input (flexible): - dict with "slug" key, or a raw string slug. Output (dict): - slug: string - title: string (display name, fallback to humanized slug) - role: string (optional) - bio: string (optional) - status: map (optional) - affiliations: array (optional) - ids: map (optional) - links: array (optional) - is_owner: bool (optional) - has_data: bool (true if found in data/authors) - avatar: resource (optional) – matching assets/media/authors/.* */}} {{- $input := . -}} {{- $slug := "" -}} {{- $rawTitle := "" -}} {{- $inputType := printf "%T" $input -}} {{- if (reflect.IsMap $input) -}} {{- $slug = index $input "slug" | default "" -}} {{- with index $input "title" }}{{ $rawTitle = . }}{{ end -}} {{- else if eq $inputType "string" -}} {{- $slug = $input -}} {{- $rawTitle = $input -}} {{- else -}} {{- $slug = printf "%v" $input -}} {{- end -}} {{- $rawTitle = trim $rawTitle " " -}} {{- $slug = $slug | urlize -}} {{- $authors := partialCached "functions/get_authors_data" . site.Language.Lang -}} {{- $data := index $authors $slug -}} {{- $hasData := $data -}} {{/* Structured name resolution */}} {{- $name := $data.name -}} {{- $display := "" -}} {{- $given := "" -}} {{- $family := "" -}} {{- $middle := "" -}} {{- $alternate := "" -}} {{- $namePronunciation := "" -}} {{- $namePronouns := "" -}} {{- if $name.display }}{{ $display = $name.display }}{{ end }} {{- if $name.given }}{{ $given = $name.given }}{{ end }} {{- if $name.family }}{{ $family = $name.family }}{{ end }} {{- if $name.middle }}{{ $middle = $name.middle }}{{ end }} {{- if $name.alternate }}{{ $alternate = $name.alternate }}{{ end }} {{- if $name.pronunciation }}{{ $namePronunciation = $name.pronunciation }}{{ end }} {{- if $name.pronouns }}{{ $namePronouns = $name.pronouns }}{{ end }} {{- $title := "" -}} {{- if $display -}} {{- $title = $display -}} {{- else if $data.title -}} {{- $title = $data.title -}} {{- else if $rawTitle -}} {{- $title = $rawTitle -}} {{- else -}} {{- $title = $slug | humanize | title -}} {{- end -}} {{- $role := $data.role -}} {{- $bio := $data.bio -}} {{- $status := $data.status -}} {{- $affiliations := $data.affiliations -}} {{- $ids := $data.ids -}} {{- $links := $data.links -}} {{- $isOwner := or ($data.is_owner) ($data.superuser) -}} {{- $pronouns := $namePronouns | default $data.pronouns -}} {{- $userGroups := $data.user_groups -}} {{- $interests := $data.interests -}} {{- $education := $data.education -}} {{- $experience := or $data.experience $data.work -}} {{- $skills := $data.skills -}} {{- $languages := $data.languages -}} {{- $awards := $data.awards -}} {{- $graduationYear := $data.graduation_year -}} {{- $weight := $data.weight -}} {{- $nameFamily := $data.name.family | default $family -}} {{- $postnominals := slice -}} {{- if $data.postnominals -}} {{- if (reflect.IsSlice $data.postnominals) -}} {{- $postnominals = $data.postnominals -}} {{- else -}} {{- $postnominals = slice $data.postnominals -}} {{- end -}} {{- end -}} {{- /* Avatar resolution: look in assets/media/authors/.* */ -}} {{- $avatar := resources.GetMatch (printf "media/authors/%s.*" $slug) -}} {{- $profile := dict "slug" $slug "title" $title "name_display" $display "name_given" $given "name_family" $family "name_family_pref" $nameFamily "name_middle" $middle "name_alternate" $alternate "name_pronunciation" $namePronunciation "role" $role "bio" $bio "status" $status "affiliations" $affiliations "ids" $ids "links" $links "pronouns" $pronouns "user_groups" $userGroups "interests" $interests "education" $education "experience" $experience "skills" $skills "languages" $languages "awards" $awards "graduation_year" $graduationYear "weight" $weight "postnominals" $postnominals "is_owner" $isOwner "has_data" (not (eq $hasData nil)) "avatar" $avatar -}} {{- return $profile -}} ================================================ FILE: modules/blox/layouts/_partials/functions/get_authors_data.html ================================================ {{/* Return the authors data map for the current language. For multilingual sites, language-specific author data from data//authors/ is merged on top of the default data/authors/ files. This allows translating fields like name, bio, role, etc., while inheriting non-translated fields. Usage: {{ $authors := partialCached "functions/get_authors_data" . site.Language.Lang }} Returns: map of slug → author data (same shape as site.Data.authors) */}} {{- $authors := site.Data.authors -}} {{- if not $authors -}} {{- $authors = dict -}} {{- end -}} {{/* Check for language-specific author overrides */}} {{- $lang := site.Language.Lang -}} {{- $langData := index site.Data $lang -}} {{- if $langData -}} {{- $langAuthors := index $langData "authors" -}} {{- if $langAuthors -}} {{/* Merge each language-specific author data on top of the default */}} {{- $merged := dict -}} {{/* Start with all default authors */}} {{- range $slug, $data := $authors -}} {{- $langAuthor := index $langAuthors $slug -}} {{- if $langAuthor -}} {{/* Language data overrides default; merge gives $langAuthor priority */}} {{- $mergedAuthor := merge $data $langAuthor -}} {{/* Deep-merge the 'name' submap if both have it */}} {{- $baseName := index $data "name" -}} {{- $langName := index $langAuthor "name" -}} {{- if and (reflect.IsMap $baseName) (reflect.IsMap $langName) -}} {{- $mergedAuthor = merge $mergedAuthor (dict "name" (merge $baseName $langName)) -}} {{- end -}} {{- $merged = merge $merged (dict $slug $mergedAuthor) -}} {{- else -}} {{- $merged = merge $merged (dict $slug $data) -}} {{- end -}} {{- end -}} {{/* Add any authors that only exist in the language data */}} {{- range $slug, $data := $langAuthors -}} {{- if not (index $authors $slug) -}} {{- $merged = merge $merged (dict $slug $data) -}} {{- end -}} {{- end -}} {{- $authors = $merged -}} {{- end -}} {{- end -}} {{- return $authors -}} ================================================ FILE: modules/blox/layouts/_partials/functions/get_branding.html ================================================ {{/* get_branding.html - Centralized branding configuration helper (v2) Returns a dict with: - name: Display name (navbar, footer, JSON-LD publisher) - site_title: Browser tab title / SEO title - organization: Legal/copyright entity name Fallback chain: - site_title → seo.title → name → site.Title - organization → name → site.Title */}} {{/* v2 structure: hugoblox.identity */}} {{ $hb := site.Params.hugoblox | default dict }} {{ $identity := $hb.identity | default dict }} {{ $seo := $hb.seo | default dict }} {{/* ═══════════════════════════════════════════════════════════════════════════ NAME (primary display name) Priority: hugoblox.identity.name → site.Title ═══════════════════════════════════════════════════════════════════════════ */}} {{ $name := $identity.name | default site.Title }} {{/* ═══════════════════════════════════════════════════════════════════════════ SITE_TITLE (browser tab / SEO title) Priority: hugoblox.seo.title → hugoblox.identity.name → site.Title ═══════════════════════════════════════════════════════════════════════════ */}} {{ $site_title := $seo.title | default $name }} {{/* ═══════════════════════════════════════════════════════════════════════════ ORGANIZATION (legal/copyright entity) Priority: hugoblox.identity.organization → name ═══════════════════════════════════════════════════════════════════════════ */}} {{ $organization := $identity.organization | default $name }} {{/* Return branding dict */}} {{ return dict "name" $name "site_title" $site_title "organization" $organization }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_cover_image.html ================================================ {{/* HugoBlox function to retrieve the cover image */}} {{/* Inputs: page context */}} {{/* Output: image resource, or nil if not found */}} {{/* Cover image is searched in this order: 1. Search for a file `*cover*` in the page directory 2. Search for a file `.Params.cover.image` in the page directory 3. Search for a file `.Params.cover.image` in the `assets/media/` directory */}} {{/* Search for an image "*cover*" in page folder */}} {{ $resource := (.Resources.ByType "image").GetMatch "*cover*" }} {{ if eq $resource nil }} {{/* Otherwise fall back to the image file specified in front matter */}} {{ $filename := "" }} {{ if .Params.cover }} {{ if reflect.IsMap .Params.cover }} {{ $filename = .Params.cover.image }} {{ else }} {{/* Support simple string format: cover: "image.jpg" */}} {{ $filename = .Params.cover }} {{ end }} {{ end }} {{ if $filename }} {{/* Check if it's a remote URL */}} {{ if or (strings.HasPrefix $filename "http://") (strings.HasPrefix $filename "https://") }} {{ $resource = resources.GetRemote $filename }} {{ if eq $resource nil }} {{ warnf "Remote cover image not found: %s" $filename }} {{ end }} {{ else }} {{/* Search in page folder */}} {{ $resource = (.Resources.ByType "image").GetMatch $filename }} {{/* Otherwise in `assets/media/` folder */}} {{ if eq $resource nil }} {{ $resource = resources.GetMatch (path.Join "media" $filename) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ return $resource }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_event_dates.html ================================================ {{/* Function to get event start and end dates/times. */}} {{ $start_date := .Params.event_start | default .Date }} {{ $end_date := .Params.event_end | default .Params.date_end }} {{ $all_day := .Params.event_all_day | default .Params.all_day }} {{ $t1 := time $start_date }}{{/* Start datetime. */}} {{ $str := slice (time.Format (site.Params.hugoblox.locale.date_format | default ":date_long") (time $t1)) }}{{/* Init return string with start date. */}} {{/* Show start time if not all day event. */}} {{ if not $all_day }}{{ $str = $str | append (time.Format (site.Params.hugoblox.locale.time_format | default "3:04 PM") (time $t1)) }}{{ end }} {{/* Show event end date if provided. */}} {{ if $end_date }} {{ $str = $str | append "—" }} {{ $t2 := time $end_date}}{{/* End datetime. */}} {{/* Show end date if it differs to start date. */}} {{ if not (eq $t1.Year $t2.Year | and (eq $t1.Month $t2.Month) | and (eq $t1.Day $t2.Day)) }} {{ $str = $str | append (time.Format (site.Params.hugoblox.locale.date_format | default ":date_long") (time $t2)) }} {{ end }} {{/* Show end time if not all day event. */}} {{ if not $all_day }}{{ $str = $str | append (time.Format (site.Params.hugoblox.locale.time_format | default "3:04 PM") (time $t2)) }}{{ end }} {{ end }} {{ return ((delimit $str " ") | safeHTML) }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_featured_image.html ================================================ {{/* Function to retrieve the featured image */}} {{/* Inputs: page context */}} {{/* Output: image resource, or nil if not found */}} {{/* Featured image is searched in this order: 1. Search for a file `*featured*` in the page directory 2. Search for a file `.Params.image.filename` in the page directory 3. Search for a file `.Params.image.filename` in the `assets/media/` directory */}} {{/* Search for an image "*featured*" in page folder */}} {{ $resource := (.Resources.ByType "image").GetMatch "*featured*" }} {{ if eq $resource nil }} {{/* Otherwise fall back the image file specified in front matter */}} {{ $filename := "" }} {{ if and .Params.image (reflect.IsMap .Params.image) }} {{ $filename = .Params.image.filename }} {{ end }} {{/* Search in page folder */}} {{ $resource = (.Resources.ByType "image").GetMatch $filename }} {{/* Otherwise in `assets/media/` folder */}} {{ if eq $resource nil }} {{ $resource = resources.GetMatch (path.Join "media" $filename) }} {{ end }} {{ end }} {{ return $resource }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_hook.html ================================================ {{/* Function to inject custom code into layouts without overriding files. */}} {{/* Input: hook folder name (str) */}} {{/* Output: loaded (bool) */}} {{ $loaded := false }} {{ $partial_dir := printf "hooks/%s/" .hook }} {{ $context := .context }} {{ $hook_dir_path := path.Join "layouts/_partials" $partial_dir }} {{ with try (os.ReadDir $hook_dir_path) }} {{ with .Value }} {{ range . }} {{ if not .IsDir }} {{ $partial_path := path.Join $partial_dir .Name }} {{ partial $partial_path $context }} {{ $loaded = true }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* The return statement below is for debug purposes only and prevents the above partial(s) being included in the page */}} {{/* return $loaded */}} ================================================ FILE: modules/blox/layouts/_partials/functions/get_icon.html ================================================ {{/* Return the requested SVG icon */}} {{/* Search for the icon in the Hugo Blox Kit icon library, falling back to user's icon library */}} {{ $dirFile := path.Split .name }} {{ $pack := .pack | default (strings.Replace $dirFile.Dir "/" "") | default "hero" }} {{ $name := $dirFile.File }} {{ $icon := "" }} {{- if eq $pack "emoji" -}} {{/* Handle emoji pack: convert name to :name: format and emojify */}} {{ $wrapped := cond (hasPrefix $name ":") $name (printf ":%s:" $name) }} {{ $emoji := $wrapped | emojify }} {{ $attrs := .attributes | default "" }} {{/* Convert SVG sizing to emoji text sizing with important specificity */}} {{ if in $attrs "w-24" }}{{ $attrs = replaceRE "w-24 h-24" "" $attrs }}{{ $attrs = printf "%s text-8xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-16" }}{{ $attrs = replaceRE "w-16 h-16" "" $attrs }}{{ $attrs = printf "%s text-5xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-12" }}{{ $attrs = replaceRE "w-12 h-12" "" $attrs }}{{ $attrs = printf "%s text-5xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-8" }}{{ $attrs = replaceRE "w-8 h-8" "" $attrs }}{{ $attrs = printf "%s text-4xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-6" }}{{ $attrs = replaceRE "w-6 h-6" "" $attrs }}{{ $attrs = printf "%s text-2xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-5" }}{{ $attrs = replaceRE "w-5 h-5" "" $attrs }}{{ $attrs = printf "%s text-xl leading-none" $attrs }}{{ end }} {{ if in $attrs "w-4" }}{{ $attrs = replaceRE "w-4 h-4" "" $attrs }}{{ $attrs = printf "%s text-lg leading-none" $attrs }}{{ end }} {{/* Add inline style for guaranteed sizing */}} {{ $style_attr := "" }} {{ if in $attrs "text-8xl" }}{{ $style_attr = "style=\"font-size: 6rem !important; line-height: 1 !important;\"" }}{{ end }} {{ if in $attrs "text-5xl" }}{{ $style_attr = "style=\"font-size: 3rem !important; line-height: 1 !important;\"" }}{{ end }} {{ if in $attrs "text-4xl" }}{{ $style_attr = "style=\"font-size: 2.25rem !important; line-height: 1 !important;\"" }}{{ end }} {{ if in $attrs "text-2xl" }}{{ $style_attr = "style=\"font-size: 1.5rem !important; line-height: 1 !important;\"" }}{{ end }} {{ if in $attrs "text-xl" }}{{ $style_attr = "style=\"font-size: 1.25rem !important; line-height: 1 !important;\"" }}{{ end }} {{ if in $attrs "text-lg" }}{{ $style_attr = "style=\"font-size: 1.125rem !important; line-height: 1 !important;\"" }}{{ end }} {{ $attrs = printf "%s %s" $attrs $style_attr }} {{ $icon = printf "%s" $attrs $emoji }} {{- else -}} {{- $icon_pack := index site.Data.icons $pack -}} {{- $pack_icon := index (index $icon_pack "icons") $name -}} {{ if $pack_icon }} {{ if in (slice "hb" "brands") $pack }} {{ $icon = $pack_icon }} {{/* Pass */}} {{ else }} {{ $icon_body := index $pack_icon "body" }} {{ $icon_size := index $icon_pack "height" }} {{ $icon = printf `%s` (cast.ToString $icon_size) (cast.ToString $icon_size) $icon_body }} {{ end }} {{ else }} {{/* Icon NOT found in pack - check if it's a direct Unicode emoji */}} {{ if not (strings.Contains $.name "/") }} {{/* No explicit pack specified (defaulted to hero) - treat as direct Unicode emoji */}} {{ $attrs := .attributes | default "" }} {{/* Convert SVG sizing to emoji text sizing (same as emoji pack) */}} {{ if in $attrs "w-24" }}{{ $attrs = replaceRE "w-24 h-24" "text-8xl" $attrs }}{{ end }} {{ if in $attrs "w-16" }}{{ $attrs = replaceRE "w-16 h-16" "text-5xl" $attrs }}{{ end }} {{ if in $attrs "w-12" }}{{ $attrs = replaceRE "w-12 h-12" "text-5xl" $attrs }}{{ end }} {{ if in $attrs "w-8" }}{{ $attrs = replaceRE "w-8 h-8" "text-4xl" $attrs }}{{ end }} {{ if in $attrs "w-6" }}{{ $attrs = replaceRE "w-6 h-6" "text-2xl" $attrs }}{{ end }} {{ if in $attrs "w-5" }}{{ $attrs = replaceRE "w-5 h-5" "text-xl" $attrs }}{{ end }} {{ if in $attrs "w-4" }}{{ $attrs = replaceRE "w-4 h-4" "text-lg" $attrs }}{{ end }} {{/* Add centering and line-height classes if not already present */}} {{ if not (in $attrs "flex") }}{{ $attrs = replaceRE "class=\"" "class=\"flex items-center justify-center leading-none " $attrs }}{{ end }} {{ $icon = printf "%s" $attrs $.name }} {{ else }} {{/* Explicit pack specified but icon not found - continue with fallback logic */}} {{ with index (index site.Data.icons.hb "icons") $name -}} {{ $icon = . }} {{ else }} {{- $prefix := printf "media/icons/%s/" $pack -}} {{- $icon_path := printf "%s%s.svg" $prefix $name -}} {{- if not (fileExists (printf "assets/%s" $icon_path)) -}} {{ $pageRef := "unknown location" }} {{ if .Page }} {{ if .Page.File }} {{ if .Page.File.Path }} {{ $pageRef = .Page.File.Path }} {{ else if .Page.RelPermalink }} {{ $pageRef = .Page.RelPermalink }} {{ end }} {{ else if .Page.RelPermalink }} {{ $pageRef = .Page.RelPermalink }} {{ end }} {{ end }} {{ partial "functions/logger" (dict "page" .Page "level" "warn" "id" (printf "missing-icon-%s-%s" $pack $name) "message" (printf "The icon `%s` was not found in `assets/media/icons/%s/`. Referenced in: %s" $name $pack $pageRef) ) }} {{- end -}} {{- $icon_resource := resources.Get $icon_path -}} {{ if $icon_resource }} {{ $icon = $icon_resource.Content }} {{ else }} {{ $icon = index (index site.Data.icons.brands "icons") "hugo" }} {{ end }} {{ end }} {{ end }} {{ end }} {{- end -}} {{ if .attributes }} {{ $icon = replaceRE " wrapper around "body" content using pack "height" 2. HB/Brands packs: Returns stored SVG strings as-is 3. User assets: Returns content from assets/media/icons/{pack}/{name}.svg 4. Fallback: Returns Hugo brand icon if not found PARAMETERS: - name: Icon name, optionally with pack prefix (e.g., "arrow-right" or "hero/arrow-right") - pack: Icon pack name (defaults to "hero" if not specified in name) */}} {{/* Return the raw SVG content for a requested icon */}} {{- $name := .name | default "" -}} {{- $icon_content := "" -}} {{- if $name -}} {{- $dirFile := path.Split $name -}} {{- $pack := .pack | default (strings.Replace $dirFile.Dir "/" "") | default "hero" -}} {{- $iconName := $dirFile.File -}} {{- $icon_pack := index site.Data.icons $pack -}} {{- with index (index $icon_pack "icons") $iconName -}} {{- /* If this pack stores full SVG strings (hb/brands), return as-is. */ -}} {{- if in (slice "hb" "brands") $pack -}} {{- $icon_content = . -}} {{- else -}} {{- $icon_body := index . "body" -}} {{- $icon_size := index $icon_pack "height" -}} {{- $icon_content = printf `%s` (cast.ToString $icon_size) (cast.ToString $icon_size) $icon_body -}} {{- end -}} {{- else -}} {{- with resources.GetMatch (path.Join "media" "icons" $pack (printf "%s.svg" $iconName)) -}} {{- $icon_content = .Content -}} {{- else -}} {{- /* Fallback to a default icon if not found. */ -}} {{- with index (index site.Data.icons.brands "icons") "hugo" -}} {{- $icon_content = . -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- $icon_content -}} ================================================ FILE: modules/blox/layouts/_partials/functions/get_logo.html ================================================ {{/* HugoBlox Image Engine: Get website logo SVG-first detection for crisp rendering at any size. Auto-detects from assets/media/: 1. logo.svg (preferred - vector, infinite scalability) 2. logo.png (fallback - raster, processed by Hugo) Inputs: - constraint: "max_height" or "fit" (default: "fit") - size: int - Target size in pixels Output: dict with: - resource: The logo resource (processed if PNG) - type: MIME type ("image/svg+xml" or "image/png") - is_svg: boolean */}} {{ $constraint := .constraint | default "fit" }} {{ $size := .size | default 36 }} {{ $result := dict "resource" nil "type" "" "is_svg" false }} {{/* 1. Check for SVG first (preferred) */}} {{ $logo_svg := resources.Get "media/logo.svg" }} {{ if $logo_svg }} {{ $result = dict "resource" $logo_svg "type" "image/svg+xml" "is_svg" true }} {{ else }} {{/* 2. Fallback to PNG */}} {{ $logo_png := resources.Get "media/logo.png" }} {{ if $logo_png }} {{ $logo_processed := $logo_png }} {{ if eq $constraint "max_height" }} {{ $logo_processed = $logo_png.Resize (printf "x%d" $size) }} {{ else }} {{ $logo_processed = $logo_png.Fit (printf "%dx%d" $size $size) }} {{ end }} {{ $result = dict "resource" $logo_processed "type" "image/png" "is_svg" false }} {{ end }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_logo_url.html ================================================ {{/* Function to get logo URL for JSONLD. */}} {{/* Inputs: page context */}} {{/* Output: logo URL (URL) */}} {{ $logo_url := "" }} {{ if resources.Get "media/logo.png" | or (resources.Get "media/logo.svg") }} {{/* !CACHED! Can safely cache this site logo variant */}} {{ $logo_url = (partialCached "functions/get_logo" (dict "constraint" "fit" "size" 192)).Permalink }} {{ else }} {{ $logo_url = (partial "functions/get_site_icon" 192).Permalink }} {{ end }} {{ return $logo_url }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_page_title.html ================================================ {{ $title := "" }} {{ with .Params.seo.title }} {{ $title = replace . "{brand}" site.Title }} {{ else }} {{ $title = .Title | default site.Title }} {{ if ne $title site.Title }}{{ $title = printf "%s | %s" $title site.Title }}{{ end }} {{ end }} {{ return $title }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_site_icon.html ================================================ {{/* HugoBlox Image Engine: Get website favicon/icon SVG-first detection for modern browser support. Auto-detects from assets/media/: 1. icon.svg (preferred - vector, supports dark mode) 2. icon.png (fallback - raster, processed by Hugo) Input: size (int) - Only used for PNG processing Output: dict with: - resource: The icon resource - type: MIME type ("image/svg+xml" or "image/png") - is_svg: boolean */}} {{ $size := . | default 32 }} {{ $result := dict "resource" nil "type" "" "is_svg" false }} {{/* 1. Check for SVG first (preferred) */}} {{ $icon_svg := resources.Get "media/icon.svg" }} {{ if $icon_svg }} {{ $result = dict "resource" $icon_svg "type" "image/svg+xml" "is_svg" true }} {{ else }} {{/* 2. Fallback to PNG */}} {{ $icon_png := resources.Get "media/icon.png" }} {{ if $icon_png }} {{ $icon_resized := $icon_png.Fill (printf "%sx%s Center" (string $size) (string $size)) }} {{ $result = dict "resource" $icon_resized "type" "image/png" "is_svg" false }} {{ else }} {{/* 3. Ultimate fallback: Try to generate from logo */}} {{ $logo_png := resources.Get "media/logo.png" }} {{ if $logo_png }} {{ $icon_from_logo := $logo_png.Fill (printf "%sx%s Center" (string $size) (string $size)) }} {{ $result = dict "resource" $icon_from_logo "type" "image/png" "is_svg" false }} {{ else }} {{/* 4. No icon found */}} {{ warnf "No favicon found. Please add assets/media/icon.svg (preferred) or assets/media/icon.png" }} {{ end }} {{ end }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_sort_by_parameter.html ================================================ {{/* Uniform 'sort_by' parameter between built-in Hugo and Hugo Blox Kit ones */}} {{/* Input: 'sort_by' parameter (string) */}} {{/* Output: fixed 'sort_by' parameter (string) */}} {{/* Fix the 'sort_by' parameter, by adding "Params." as prefix if it is not a built-in Hugo parameter. Since Hugo Blox Kit parameters are all standardised to lowercase-underscore convention, we: - remove any leading ".": ".Date" is the same as "Date" - check the first letter: - if it is capitalized, then we have a built-in Hugo parameter, and we do nothing - otherwise, it is a custom Hugo Blox Kit parameter, and we add "Params." as prefix This logic should also be backward compatible, since "Params.my_param" is not modified. */}} {{ $param := strings.TrimLeft "." . }} {{/* Get first letter */}} {{ $first := substr $param 0 }} {{/* Check if it is lowercase */}} {{ if eq $first (lower $first) }} {{/* Add 'Params.' prefix */}} {{ $param = printf "Params.%s" $param }} {{ end }} {{ return $param }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_summary.html ================================================ {{/* Get page summary with fallback priority: Params.summary > Params.description > Params.abstract > Summary */}} {{ $summary := .Params.summary | default .Params.description | default .Params.abstract | default .Summary }} {{ return $summary }} ================================================ FILE: modules/blox/layouts/_partials/functions/get_theme_config.html ================================================ {{/* HugoBlox Theme Engine: Get theme configuration (v2) Returns a dict with: - mode: 'light' | 'dark' | 'system' - light: Light theme pack name (default: "default") - dark: Dark theme pack name (default: "default") - colors: Global color overrides { primary, secondary, neutral } - colors_light: Light-mode specific color overrides - colors_dark: Dark-mode specific color overrides - surfaces: Semantic surface colors { background, foreground, header, footer } - typography: { font, size } - layout: { radius, spacing } */}} {{/* v2 structure */}} {{ $hb := site.Params.hugoblox | default dict }} {{ $hb_theme := $hb.theme | default dict }} {{/* ═══════════════════════════════════════════════════════════════════════════ MODE (light/dark/system) ═══════════════════════════════════════════════════════════════════════════ */}} {{ $mode := $hb_theme.mode | default "system" }} {{/* ═══════════════════════════════════════════════════════════════════════════ THEME PACK SELECTION (light/dark) Pack can be: - String: "default" (applies to both) - Object: { light: "latte", dark: "americano" } ═══════════════════════════════════════════════════════════════════════════ */}} {{ $light_pack := "default" }} {{ $dark_pack := "default" }} {{ $pack := $hb_theme.pack | default "default" }} {{ if reflect.IsMap $pack }} {{ $light_pack = $pack.light | default "default" }} {{ $dark_pack = $pack.dark | default "default" }} {{ else }} {{/* Single string applies to both */}} {{ $light_pack = $pack }} {{ $dark_pack = $pack }} {{ end }} {{/* ═══════════════════════════════════════════════════════════════════════════ COLOR OVERRIDES ═══════════════════════════════════════════════════════════════════════════ */}} {{ $colors := $hb_theme.colors | default dict }} {{ $colors_light := $hb_theme.colors_light | default dict }} {{ $colors_dark := $hb_theme.colors_dark | default dict }} {{/* ═══════════════════════════════════════════════════════════════════════════ SEMANTIC SURFACE COLORS ═══════════════════════════════════════════════════════════════════════════ */}} {{ $surfaces := $hb_theme.surfaces | default dict }} {{/* ═══════════════════════════════════════════════════════════════════════════ TYPOGRAPHY Font packs are loaded from data/fonts/ and provide: - families: { heading, body, code, nav } - weights: { heading, body, code, nav } (arrays) - sizes: { base, sm, lg } - leading: { heading, body, code } - tracking: { heading, body, caps } Legacy support: typography.font (sans/serif/native) maps to pack names ═══════════════════════════════════════════════════════════════════════════ */}} {{ $hb_typography := $hb.typography | default dict }} {{/* Resolve font pack name */}} {{ $font_pack_name := $hb_typography.pack | default "modern" }} {{/* Load the font pack */}} {{ $font_pack := partial "functions/load_font_pack" $font_pack_name }} {{/* Resolve families — inline overrides take priority */}} {{ $pack_families := $font_pack.families | default dict }} {{ $inline_families := $hb_typography.families | default dict }} {{ $families := dict "heading" ($inline_families.heading | default $pack_families.heading | default "Inter") "body" ($inline_families.body | default $pack_families.body | default "Inter") "code" ($inline_families.code | default $pack_families.code | default "JetBrains Mono") "nav" ($inline_families.nav | default $pack_families.nav | default "") }} {{/* Resolve weights — inline overrides take priority */}} {{ $pack_weights := $font_pack.weights | default dict }} {{ $inline_weights := $hb_typography.weights | default dict }} {{ $weights := dict "heading" ($inline_weights.heading | default $pack_weights.heading | default (slice 700)) "body" ($inline_weights.body | default $pack_weights.body | default (slice 400)) "code" ($inline_weights.code | default $pack_weights.code | default (slice 400)) "nav" ($inline_weights.nav | default $pack_weights.nav | default (slice)) }} {{/* Resolve sizes — inline overrides take priority */}} {{ $pack_sizes := $font_pack.sizes | default dict }} {{ $inline_sizes := $hb_typography.sizes | default dict }} {{ $sizes := dict "base" ($inline_sizes.base | default $pack_sizes.base | default "1rem") "sm" ($inline_sizes.sm | default $pack_sizes.sm | default "0.875rem") "lg" ($inline_sizes.lg | default $pack_sizes.lg | default "1.125rem") }} {{/* Resolve leading (line-height) */}} {{ $pack_leading := $font_pack.leading | default dict }} {{ $inline_leading := $hb_typography.leading | default dict }} {{ $leading := dict "heading" ($inline_leading.heading | default $pack_leading.heading | default 1.2) "body" ($inline_leading.body | default $pack_leading.body | default 1.6) "code" ($inline_leading.code | default $pack_leading.code | default 1.5) }} {{/* Resolve tracking (letter-spacing) */}} {{ $pack_tracking := $font_pack.tracking | default dict }} {{ $inline_tracking := $hb_typography.tracking | default dict }} {{ $tracking := dict "heading" ($inline_tracking.heading | default $pack_tracking.heading | default "-0.02em") "body" ($inline_tracking.body | default $pack_tracking.body | default "0") "caps" ($inline_tracking.caps | default $pack_tracking.caps | default "0.05em") }} {{/* Resolve variable font flags */}} {{ $pack_variable := $font_pack.variable | default dict }} {{ $inline_variable := $hb_typography.variable | default dict }} {{ $variable := dict "heading" ($inline_variable.heading | default $pack_variable.heading | default false) "body" ($inline_variable.body | default $pack_variable.body | default false) "code" ($inline_variable.code | default $pack_variable.code | default false) "nav" ($inline_variable.nav | default $pack_variable.nav | default false) }} {{ $typography := dict "pack" $font_pack_name "style" ($font_pack.meta.style | default "sans") "families" $families "weights" $weights "variable" $variable "sizes" $sizes "leading" $leading "tracking" $tracking }} {{/* ═══════════════════════════════════════════════════════════════════════════ LAYOUT TOKENS ═══════════════════════════════════════════════════════════════════════════ */}} {{ $hb_layout := $hb.layout | default dict }} {{ $layout := dict "radius" ($hb_layout.radius | default "md") "spacing" ($hb_layout.spacing | default "comfortable") }} {{/* Return theme config dict */}} {{ return dict "mode" $mode "light" $light_pack "dark" $dark_pack "colors" $colors "colors_light" $colors_light "colors_dark" $colors_dark "surfaces" $surfaces "typography" $typography "layout" $layout }} ================================================ FILE: modules/blox/layouts/_partials/functions/has_attachments.html ================================================ {{/* Return true if the page has attachments or link buttons to display. */}} {{ $page := . }} {{ $pdf_link := false }} {{/* Prevent Hugo warning ".File.ContentBaseName on zero object." for content not backed by a Markdown file, */}} {{/* such as auto-generated taxonomy pages, and sections without an explicit index file. */}} {{/* The file check is required when called from `_default/list.html`, the fallback list view for the above cases. */}} {{ with $page.File }} {{ $slug := $page.File.ContentBaseName }} {{ $resource := $page.Resources.GetMatch (printf "%s.pdf" $slug) }} {{ with $resource }} {{ $pdf_link = true }} {{ end }} {{ end }} {{ $cite_link := false }} {{ $resource := $page.Resources.GetMatch "cite.bib" }} {{ with $resource }} {{ $cite_link = true }} {{ end }} {{ return ($cite_link | or $pdf_link | or .Params.url_preprint | or .Params.url_pdf | or .Params.url_slides | or .Params.url_video | or .Params.url_source | or .Params.url_code | or .Params.url_dataset | or .Params.url_poster | or .Params.url_project | or .Params.doi | or .Params.links | or .Params.projects | or .Params.slides) }} ================================================ FILE: modules/blox/layouts/_partials/functions/hbx_verify.html ================================================ {{/* Hugo Blox Kit Ecosystem Verification Reusable verification function for Hugo Blox components. Ensures all required Hugo Blox Kit dependencies are present. Usage: {{ partial "functions/hbx_verify.html" . }} Returns: "verified" or "failed" Used by: shortcodes, blocks, advanced components */}} {{/* Check for Hugo Blox specific icon system */}} {{- $hb_icon_check := partial "functions/get_icon" (dict "name" "academic-cap" "attributes" "style=\"display: none;\"") -}} {{/* Verify Hugo Blox data structures */}} {{- $hb_data_check := site.Data.icons.hero -}} {{/* Verify Hugo Blox UID generation */}} {{- $hb_uid_check := partial "functions/uid.html" . -}} {{/* DEBUG: Print hugo.Deps output for analysis (dev only) */}} {{- if getenv "HUGO_BLOX_DEBUG" -}} {{- warnf "=== DEBUG hugo.Deps output ===" -}} {{- range $index, $dep := hugo.Deps -}} {{- warnf "DEP %d: Path=%s, Version=%s, Vendor=%t" $index $dep.Path $dep.Version $dep.Vendor -}} {{- end -}} {{- warnf "=== END hugo.Deps ===" -}} {{- end -}} {{/* Check for required Hugo Blox module dependencies */}} {{- $hb_module_check := false -}} {{- $required_modules := slice "blox" -}} {{- range $required := $required_modules -}} {{- range $dep := hugo.Deps -}} {{- if strings.Contains $dep.Path $required -}} {{/* Accept both official GitHub org paths AND local development paths */}} {{- if or (strings.Contains $dep.Path "github.com/HugoBlox/") (strings.Contains $dep.Path "../../../modules") -}} {{- $hb_module_check = true -}} {{- if getenv "HUGO_BLOX_DEBUG" -}} {{- warnf "Found Hugo Blox module: %s" $dep.Path -}} {{- end -}} {{- break -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{/* Verify Hugo Blox brands icon pack */}} {{- $hb_brands_check := site.Data.icons.brands -}} {{/* Debug output to identify failing check (dev only) */}} {{- if getenv "HUGO_BLOX_DEBUG" -}} {{- warnf "=== VERIFICATION RESULTS ===" -}} {{- warnf "Icon check: %t" (and $hb_icon_check true) -}} {{- warnf "Data check: %t" (and $hb_data_check true) -}} {{- warnf "UID check: %t" (and $hb_uid_check true) -}} {{- warnf "Module check: %t" $hb_module_check -}} {{- warnf "Brands check: %t" (and $hb_brands_check true) -}} {{- warnf "=== END VERIFICATION ===" -}} {{- end -}} {{/* Set return value based on verification results */}} {{- $return := "failed" -}} {{- if and $hb_icon_check $hb_data_check $hb_uid_check $hb_module_check $hb_brands_check -}} {{- $return = "verified" -}} {{- end -}} {{/* Return result using proper Hugo function pattern */}} {{ return $return }} ================================================ FILE: modules/blox/layouts/_partials/functions/layout_tokens.html ================================================ {{/* HugoBlox Theme Engine: Layout Tokens Resolves layout design tokens (radius, spacing) from the theme config and emits them as CSS custom properties. Input: Theme config dict from get_theme_config: - layout: { radius, spacing } Output: ================================================ FILE: modules/blox/layouts/_partials/functions/load_font_pack.html ================================================ {{/* HugoBlox Theme Engine: Loads and validates a HugoBlox font pack Input: Font pack name (string), e.g. "modern-sans" or "acme/editorial" Returns: The font pack data object (families, weights, sizes, leading, tracking) or empty dict if invalid Validates: - Font pack exists in data/fonts/ - Required 'hugoblox' wrapper is present - Required 'meta.format' starts with 'hugoblox-font@' */}} {{ $pack_name := . }} {{ $result := dict }} {{/* Parse vendor/name format */}} {{ $vendor := "" }} {{ $name := $pack_name }} {{ if strings.Contains $pack_name "/" }} {{ $parts := split $pack_name "/" }} {{ $vendor = index $parts 0 }} {{ $name = index $parts 1 }} {{ end }} {{/* Load raw font pack data */}} {{ $raw_pack := dict }} {{ if $vendor }} {{/* Third-party font pack: data/fonts/vendor/name.yaml */}} {{ $vendor_fonts := index site.Data.fonts $vendor }} {{ if $vendor_fonts }} {{ $raw_pack = index $vendor_fonts $name }} {{ end }} {{ else }} {{/* Built-in or user font pack: data/fonts/name.yaml */}} {{ with index site.Data.fonts $name }} {{ $raw_pack = . }} {{ end }} {{ end }} {{/* Validate font pack structure */}} {{ if not $raw_pack }} {{ warnf "FONT PACK ERROR: Font pack '%s' not found in data/fonts/" $pack_name }} {{ else if not $raw_pack.hugoblox }} {{ warnf "FONT PACK ERROR: Font pack '%s' is not a valid HugoBlox font pack (missing 'hugoblox' key)" $pack_name }} {{ else }} {{ $pack := $raw_pack.hugoblox }} {{ if not $pack.meta }} {{ warnf "FONT PACK ERROR: Font pack '%s' is missing the required 'meta' block" $pack_name }} {{ else }} {{/* Validate format version */}} {{ $format := $pack.meta.format | default "" }} {{ if not (hasPrefix $format "hugoblox-font@") }} {{ warnf "FONT PACK ERROR: Font pack '%s' has invalid format '%s'. Expected 'hugoblox-font@1'" $pack_name $format }} {{ end }} {{ end }} {{/* Return the validated font pack data (without the hugoblox wrapper) */}} {{ $result = $pack }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/load_theme_pack.html ================================================ {{/* HugoBlox Theme Engine: Loads and validates a HugoBlox theme pack Input: Theme pack name (string), e.g. "minimal" or "acme/corporate" Returns: The theme data object (type, light, dark, etc.) or nil if invalid Validates: - Theme exists in data/themes/ - Required 'hugoblox' wrapper is present - Required 'meta.format' starts with 'hugoblox-theme@' */}} {{ $pack_name := . }} {{ $result := dict }} {{/* Parse vendor/name format */}} {{ $vendor := "" }} {{ $name := $pack_name }} {{ if strings.Contains $pack_name "/" }} {{ $parts := split $pack_name "/" }} {{ $vendor = index $parts 0 }} {{ $name = index $parts 1 }} {{ end }} {{/* Load raw theme data */}} {{ $raw_theme := dict }} {{ if $vendor }} {{/* Third-party theme: data/themes/vendor/name.yaml */}} {{ $vendor_themes := index site.Data.themes $vendor }} {{ if $vendor_themes }} {{ $raw_theme = index $vendor_themes $name }} {{ end }} {{ else }} {{/* Built-in or user theme: data/themes/name.yaml */}} {{ $raw_theme = index site.Data.themes $name }} {{ end }} {{/* Validate theme structure */}} {{ if not $raw_theme }} {{ warnf "THEME ERROR: Theme pack '%s' not found in data/themes/" $pack_name }} {{ else if not $raw_theme.hugoblox }} {{ warnf "THEME ERROR: Theme '%s' is not a valid HugoBlox theme (missing 'hugoblox' key)" $pack_name }} {{ else }} {{ $theme := $raw_theme.hugoblox }} {{/* Validate format version */}} {{ $format := $theme.meta.format | default "" }} {{ if not (hasPrefix $format "hugoblox-theme@") }} {{ warnf "THEME ERROR: Theme '%s' has invalid format '%s'. Expected 'hugoblox-theme@1'" $pack_name $format }} {{ end }} {{/* Return the validated theme data (without the hugoblox wrapper) */}} {{ $result = $theme }} {{ end }} {{ return $result }} ================================================ FILE: modules/blox/layouts/_partials/functions/logger.html ================================================ {{/* Hugo Blox Logger: A pragmatic, centralized logging helper for Hugo. This partial is the single source of truth for all build-time logging. Hugo's template logging is limited to WARN and ERROR. INFO is only shown in the Dev HUD/JSON, not the CLI. Usage: {{ partial "functions/logger" (dict "page" . "level" "info" | "warn" | "error" (default: "info") "message" "Your log message here." "id" "a-unique-id" (optional, for suppressible warnings) "source" (dict "type" "shortcode|partial|template" "name" "callout|sections" ) (optional) ) }} */}} {{- $level := lower (.level | default "info") -}} {{- $message := .message | default "" -}} {{- $id := .id | default "" -}} {{- $source := .source | default dict -}} {{- $page := .page | default . -}} {{- $isDev := hugo.IsServer -}} {{/* Store log entry for future debug widget/JSON, regardless of environment. */}} {{- with $page -}} {{- with .Store -}} {{- $buildId := partialCached "functions/get-build-id.html" "hbx-build-id" -}} {{- $log_entry := dict "level" $level "message" $message "page" ($.RelPermalink | default "/") "timestamp" now.Unix "id" $id "source" $source "buildId" $buildId -}} {{- $current_logs := .Get "hbx_logs" | default slice -}} {{- $currentBuildId := .Get "hbx_build_id" | default "" -}} {{/* Clear logs if this is a new build cycle */}} {{- if ne $currentBuildId $buildId -}} {{- .Set "hbx_build_id" $buildId -}} {{- $current_logs = slice -}} {{- end -}} {{- .Set "hbx_logs" ($current_logs | append $log_entry) -}} {{- end -}} {{- end -}} {{/* Emit to CLI using fmt with proper severity. Do not print INFO to CLI. */}} {{- if eq $level "error" -}} {{- fmt.Errorf "HBX ERROR: %s" $message -}} {{- else if eq $level "warn" -}} {{- if $id -}} {{- fmt.Warnidf $id "HBX WARN: %s" $message -}} {{- else -}} {{- fmt.Warnf "HBX WARN: %s" $message -}} {{- end -}} {{- else -}} {{/* info: no CLI output; visible via Dev HUD/JSON only */}} {{- end -}} {{- "" -}} ================================================ FILE: modules/blox/layouts/_partials/functions/notebook/render.html ================================================ {{- $ctx := . -}} {{- $hbxVerification := partial "functions/hbx_verify.html" $ctx -}} {{- if ne $hbxVerification "verified" -}} {{- errorf "Install HugoBlox to use the Notebook shortcode at: %s" $ctx.Position -}} {{- end -}} {{- $shortcodeName := $ctx.Name | default "notebook" -}} {{- $src := "" -}} {{- if $ctx.IsNamedParams -}} {{- $src = $ctx.Get "src" | default ($ctx.Get "file") -}} {{- else -}} {{- $src = $ctx.Get 0 -}} {{- end -}} {{- if not $src -}} {{- errorf "%s shortcode: provide a notebook path via positional argument or src=..." $shortcodeName -}} {{- end -}} {{- $displayName := $src -}} {{- with urls.Parse $src -}} {{- if .Path -}} {{- $displayName = path.Base .Path -}} {{- end -}} {{- end -}} {{- $title := $ctx.Get "title" | default $displayName -}} {{- $languageOverride := $ctx.Get "language" -}} {{- $showCode := $ctx.Get "show_code" | default true -}} {{- $showMarkdown := $ctx.Get "show_markdown" | default true -}} {{- $showOutputs := $ctx.Get "show_outputs" | default true -}} {{- $showMetadata := $ctx.Get "show_metadata" | default false -}} {{- $lineNumbers := $ctx.Get "line_numbers" | default false -}} {{- $dense := $ctx.Get "dense" | default false -}} {{- $maxOutputHeight := $ctx.Get "max_output_height" | default "26rem" -}} {{- $sourceURL := $ctx.Get "source_url" -}} {{- $showDownload := $ctx.Get "show_download" | default true -}} {{- $downloadLabel := $ctx.Get "download_label" | default "Download notebook" -}} {{- $emptyMessage := $ctx.Get "empty_message" | default "Notebook is empty or hidden by the current view options." -}} {{- $id := delimit (slice "hb-notebook" (partial "functions/uid.html" $ctx)) "-" -}} {{- $isRemote := and $src (ne (urls.Parse $src).Scheme "") -}} {{- $normalizedSrc := $src -}} {{- if not $isRemote -}} {{- $normalizedSrc = strings.TrimPrefix "./" $normalizedSrc -}} {{- $normalizedSrc = strings.TrimPrefix "/" $normalizedSrc -}} {{- if $normalizedSrc -}} {{- $normalizedSrc = path.Clean $normalizedSrc -}} {{- end -}} {{- if eq $normalizedSrc "." -}} {{- $normalizedSrc = "" -}} {{- end -}} {{- if strings.HasPrefix $normalizedSrc ".." -}} {{- errorf "%s shortcode: refusing to read outside the project for %q" $shortcodeName $src -}} {{- end -}} {{- end -}} {{- $notebookContent := "" -}} {{- $resource := dict -}} {{- $resourceFound := false -}} {{- if $isRemote -}} {{- $remote := try (resources.GetRemote $src) -}} {{- if $remote.Err -}} {{- errorf "%s shortcode: unable to fetch remote notebook %q (%s)" $shortcodeName $src $remote.Err -}} {{- else -}} {{- $resource = $remote.Value -}} {{- $resourceFound = true -}} {{- $notebookContent = $resource.Content -}} {{- if not $sourceURL -}} {{- $sourceURL = $src -}} {{- end -}} {{- end -}} {{- else -}} {{- with $ctx.Page -}} {{- with .Resources -}} {{- with .GetMatch $normalizedSrc -}} {{- $resource = . -}} {{- $resourceFound = true -}} {{- else -}} {{- if not (strings.Contains $normalizedSrc "/") -}} {{- with .GetMatch (printf "**/%s" $normalizedSrc) -}} {{- $resource = . -}} {{- $resourceFound = true -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- if $resourceFound -}} {{- $notebookContent = $resource.Content -}} {{- if not $sourceURL -}} {{- $sourceURL = $resource.RelPermalink -}} {{- end -}} {{- end -}} {{- if not $notebookContent -}} {{- $searchPaths := slice $normalizedSrc -}} {{- $pageDir := "" -}} {{- with $ctx.Page.File -}} {{- $pageDir = path.Dir .Path -}} {{- end -}} {{- if $pageDir -}} {{- $searchPaths = $searchPaths | append (path.Join $pageDir $normalizedSrc) -}} {{- if not (strings.HasPrefix $normalizedSrc "content/") -}} {{- $searchPaths = $searchPaths | append (printf "content/%s" (path.Join $pageDir $normalizedSrc)) -}} {{- end -}} {{- end -}} {{- if not (strings.HasPrefix $normalizedSrc "content/") -}} {{- $searchPaths = $searchPaths | append (printf "content/%s" $normalizedSrc) -}} {{- end -}} {{- if not (strings.HasPrefix $normalizedSrc "assets/") -}} {{- $searchPaths = $searchPaths | append (printf "assets/%s" $normalizedSrc) -}} {{- end -}} {{- if not (strings.HasPrefix $normalizedSrc "static/") -}} {{- $searchPaths = $searchPaths | append (printf "static/%s" $normalizedSrc) -}} {{- end -}} {{- range $candidate := $searchPaths }} {{- if not $notebookContent -}} {{- $fileAttempt := try (readFile $candidate) -}} {{- if not $fileAttempt.Err -}} {{- $notebookContent = $fileAttempt.Value -}} {{- if and (strings.HasPrefix $candidate "static/") (not $sourceURL) -}} {{- $public := strings.TrimPrefix $candidate "static" -}} {{- if not (strings.HasPrefix $public "/") -}} {{- $public = printf "/%s" $public -}} {{- end -}} {{- $sourceURL = relLangURL $public -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}} {{- if not $notebookContent -}} {{- $pagePath := "" -}} {{- with $ctx.Page.File -}} {{- $pagePath = .Path -}} {{- end -}} {{- errorf "%s shortcode: notebook %q could not be located relative to %s. Please check that you have removed \\.ipynb$ from ignoreFiles in your config/_default/hugo.yaml." $shortcodeName $src $pagePath -}} {{- end -}} {{- $parsed := dict -}} {{- $parsedResult := try (transform.Unmarshal $notebookContent) -}} {{- if $parsedResult.Err -}} {{- errorf "%s shortcode: %q is not valid notebook JSON (%s)" $shortcodeName $src $parsedResult.Err -}} {{- else -}} {{- $parsed = $parsedResult.Value -}} {{- end -}} {{- $cells := slice -}} {{- with index $parsed "cells" -}} {{- if reflect.IsSlice . -}} {{- $cells = . -}} {{- end -}} {{- end -}} {{- $metadata := index $parsed "metadata" | default dict -}} {{- $language := $languageOverride -}} {{- if not $language -}} {{- with index $metadata "language_info" -}} {{- with index . "name" -}} {{- $language = printf "%v" . -}} {{- end -}} {{- end -}} {{- end -}} {{- if not $language -}} {{- $language = "python" -}} {{- end -}} {{- $language = lower $language -}} {{- $languageVersion := "" -}} {{- with index $metadata "language_info" -}} {{- with index . "version" -}} {{- $languageVersion = printf "%v" . -}} {{- end -}} {{- end -}} {{- $kernelDisplay := "" -}} {{- with index $metadata "kernelspec" -}} {{- with index . "display_name" -}} {{- $kernelDisplay = printf "%v" . -}} {{- end -}} {{- end -}} {{- $kernelName := "" -}} {{- with index $metadata "kernelspec" -}} {{- with index . "name" -}} {{- $kernelName = printf "%v" . -}} {{- end -}} {{- end -}} {{- $nbformat := "" -}} {{- with index $parsed "nbformat" -}} {{- $nbformat = printf "%v" . -}} {{- end -}} {{- with index $parsed "nbformat_minor" -}} {{- if $nbformat -}} {{- $nbformat = printf "%s.%v" $nbformat . -}} {{- else -}} {{- $nbformat = printf "%v" . -}} {{- end -}} {{- end -}} {{- $cellCount := len $cells -}} {{- $containerClass := "hb-notebook not-prose" -}} {{- if $dense -}} {{- $containerClass = printf "%s %s" $containerClass "hb-notebook--dense" -}} {{- end -}} {{- $subtitleParts := slice -}} {{- if $language -}} {{- $subtitleParts = $subtitleParts | append (strings.Title $language) -}} {{- end -}} {{- if $kernelDisplay -}} {{- $subtitleParts = $subtitleParts | append (printf "Kernel: %s" $kernelDisplay) -}} {{- end -}} {{- if $nbformat -}} {{- $subtitleParts = $subtitleParts | append (printf "nbformat %s" $nbformat) -}} {{- end -}} {{- if gt $cellCount 0 -}} {{- $subtitleParts = $subtitleParts | append (printf "%d cells" $cellCount) -}} {{- end -}} {{- $metaItems := slice -}} {{- $metaItems = $metaItems | append (dict "label" "Language" "value" (strings.Title $language)) -}} {{- if $languageVersion -}} {{- $metaItems = $metaItems | append (dict "label" "Version" "value" $languageVersion) -}} {{- end -}} {{- if or $kernelDisplay $kernelName -}} {{- $metaItems = $metaItems | append (dict "label" "Kernel" "value" (strings.TrimSpace (printf "%s %s" $kernelDisplay $kernelName))) -}} {{- end -}} {{- if $nbformat -}} {{- $metaItems = $metaItems | append (dict "label" "nbformat" "value" $nbformat) -}} {{- end -}} {{- with index $metadata "authors" -}} {{- $authors := slice -}} {{- if reflect.IsSlice . -}} {{- range . -}} {{- $name := "" -}} {{- with index . "name" -}} {{- $name = printf "%v" . -}} {{- end -}} {{- if not $name -}} {{- $name = printf "%v" . -}} {{- end -}} {{- if $name -}} {{- $authors = $authors | append $name -}} {{- end -}} {{- end -}} {{- else -}} {{- $authors = $authors | append (printf "%v" .) -}} {{- end -}} {{- if gt (len $authors) 0 -}} {{- $metaItems = $metaItems | append (dict "label" "Authors" "value" (delimit $authors ", ")) -}} {{- end -}} {{- end -}} {{- $sourceURLIsRemote := false -}} {{- if $sourceURL -}} {{- $sourceURLIsRemote = ne (urls.Parse $sourceURL).Scheme "" -}} {{- if not $sourceURLIsRemote -}} {{- if not (strings.HasPrefix $sourceURL "/") -}} {{- $sourceURL = printf "/%s" $sourceURL -}} {{- end -}} {{- $sourceURL = relLangURL $sourceURL -}} {{- end -}} {{- end -}} {{- $styleAttr := printf "--hb-notebook-output-max-height:%s;" $maxOutputHeight | safeCSS -}}

    {{ $title }}

    {{- with $subtitleParts }}

    {{ delimit . " · " }}

    {{- end }}
    {{- if and $showDownload $sourceURL }} {{ partial "functions/get_icon" (dict "name" "arrow-down-tray" "attributes" "class=\"w-4 h-4\"") }} {{ $downloadLabel }} {{- end }}
    {{- if and $showMetadata (gt (len $metaItems) 0) }} {{- end }} {{- $visibleScratch := newScratch -}} {{- $visibleScratch.Set "visible" 0 -}}
    {{- range $cells }} {{- $cellType := index . "cell_type" | default "raw" -}} {{- $cellMetadata := index . "metadata" | default dict -}} {{- $cellTags := slice -}} {{- with index $cellMetadata "tags" -}} {{- if reflect.IsSlice . -}} {{- range . -}} {{- $cellTags = $cellTags | append (printf "%v" .) -}} {{- end -}} {{- else -}} {{- $cellTags = $cellTags | append (printf "%v" .) -}} {{- end -}} {{- end -}} {{- $executionCount := "" -}} {{- with index . "execution_count" -}} {{- $executionCount = printf "%v" . -}} {{- end -}} {{- $outputs := slice -}} {{- with index . "outputs" -}} {{- if reflect.IsSlice . -}} {{- $outputs = . -}} {{- end -}} {{- end -}} {{- $shouldRender := or (and (eq $cellType "markdown") $showMarkdown) (and (eq $cellType "raw") $showMarkdown) (and (eq $cellType "code") (or $showCode (and $showOutputs (gt (len $outputs) 0)))) -}} {{- if $shouldRender }} {{- $visibleScratch.Add "visible" 1 -}}
    {{- if eq $cellType "code" -}} {{- printf "In [%s]" (cond $executionCount $executionCount " ") -}} {{- else -}} {{- strings.Title $cellType -}} {{- end -}} {{- if gt (len $cellTags) 0 }}
    {{- range $cellTags }} {{ . }} {{- end }}
    {{- end }}
    {{- if eq $cellType "markdown" }} {{- $source := index . "source" -}} {{- $sourceContent := "" -}} {{- if reflect.IsSlice $source -}} {{- $sourceContent = delimit $source "" -}} {{- else if $source -}} {{- $sourceContent = printf "%v" $source -}} {{- end -}} {{- $sourceContent = replace $sourceContent "\r\n" "\n" -}} {{- if $sourceContent }}
    {{ $sourceContent | markdownify }}
    {{- end -}} {{- else if eq $cellType "raw" }} {{- $raw := index . "source" -}} {{- $rawContent := "" -}} {{- if reflect.IsSlice $raw -}} {{- $rawContent = delimit $raw "" -}} {{- else if $raw -}} {{- $rawContent = printf "%v" $raw -}} {{- end -}} {{- if $rawContent }}
    {{ $rawContent | htmlEscape }}
    {{- end -}} {{- else if eq $cellType "code" }} {{- $source := index . "source" -}} {{- $sourceContent := "" -}} {{- if reflect.IsSlice $source -}} {{- $sourceContent = delimit $source "" -}} {{- else if $source -}} {{- $sourceContent = printf "%v" $source -}} {{- end -}} {{- $sourceContent = replace $sourceContent "\r\n" "\n" -}} {{- $sourceContent = strings.TrimSuffix "\n" $sourceContent -}} {{- $sourceContent = strings.TrimSuffix "\r" $sourceContent -}} {{- if and $showCode $sourceContent }}
    {{- $options := "" -}} {{- if $lineNumbers -}} {{- $options = "linenos=table" -}} {{- end -}} {{- $hl := highlight $sourceContent $language $options -}} {{- if $hl -}} {{ $hl | safeHTML }} {{- else -}}
    {{ $sourceContent | htmlEscape }}
    {{- end -}}
    {{- end -}} {{- if and $showOutputs (gt (len $outputs) 0) }}
    {{- range $outputs }} {{- $outputType := index . "output_type" | default "" -}} {{- if eq $outputType "stream" }} {{- $text := index . "text" -}} {{- $textContent := "" -}} {{- if reflect.IsSlice $text -}} {{- $textContent = delimit $text "" -}} {{- else if $text -}} {{- $textContent = printf "%v" $text -}} {{- end -}}
    {{ $textContent | htmlEscape }}
    {{- else if eq $outputType "error" }} {{- $ename := index . "ename" | default "" -}} {{- $evalue := index . "evalue" | default "" -}} {{- $trace := index . "traceback" | default slice -}} {{- $traceContent := "" -}} {{- if reflect.IsSlice $trace -}} {{- $traceContent = delimit $trace "\n" -}} {{- else if $trace -}} {{- $traceContent = printf "%v" $trace -}} {{- end -}}
    {{ printf "%s: %s" $ename $evalue }} {{- if $traceContent }}
    {{ $traceContent | htmlEscape }}
    {{- end -}}
    {{- else }} {{- $data := index . "data" | default dict -}} {{- $outputScratch := newScratch -}} {{- $outputScratch.Set "rendered" false -}} {{- with index $data "text/html" }} {{- $htmlPayload := "" -}} {{- if reflect.IsSlice . -}} {{- $htmlPayload = delimit . "" -}} {{- else -}} {{- $htmlPayload = printf "%v" . -}} {{- end -}} {{- if $htmlPayload }}
    {{ $htmlPayload | safeHTML }}
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with index $data "text/markdown" }} {{- $markdownPayload := "" -}} {{- if reflect.IsSlice . -}} {{- $markdownPayload = delimit . "" -}} {{- else -}} {{- $markdownPayload = printf "%v" . -}} {{- end -}} {{- if $markdownPayload }}
    {{ $markdownPayload | markdownify }}
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with index $data "text/latex" }} {{- $latexPayload := "" -}} {{- if reflect.IsSlice . -}} {{- $latexPayload = delimit . "" -}} {{- else -}} {{- $latexPayload = printf "%v" . -}} {{- end -}} {{- if $latexPayload }}
    {{ printf "$$%s$$" $latexPayload | safeHTML }}
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with index $data "image/png" }} {{- $pngPayload := printf "%v" . -}} {{- if $pngPayload }}
    Notebook output image
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with index $data "image/jpeg" }} {{- $jpegPayload := printf "%v" . -}} {{- if $jpegPayload }}
    Notebook output image
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with index $data "image/svg+xml" }} {{- $svgPayload := "" -}} {{- if reflect.IsSlice . -}} {{- $svgPayload = delimit . "" -}} {{- else -}} {{- $svgPayload = printf "%v" . -}} {{- end -}} {{- if $svgPayload }}
    {{ $svgPayload | safeHTML }}
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- with or (index $data "application/vnd.plotly.v1+json") (index $data "application/json") }} {{- $jsonFormatted := . | jsonify (dict "indent" " ") -}}
    {{ $jsonFormatted }}
    {{- $outputScratch.Set "rendered" true -}} {{- end }} {{- if not ($outputScratch.Get "rendered") }} {{- with index $data "text/plain" }} {{- $textPayload := "" -}} {{- if reflect.IsSlice . -}} {{- $textPayload = delimit . "" -}} {{- else -}} {{- $textPayload = printf "%v" . -}} {{- end -}} {{- if $textPayload }}
    {{ $textPayload | htmlEscape }}
    {{- $outputScratch.Set "rendered" true -}} {{- end -}} {{- end }} {{- end }} {{- if not ($outputScratch.Get "rendered") }}
    {{ $data | jsonify | htmlEscape }}
    {{- end }} {{- end }} {{- end }}
    {{- end }} {{- end }}
    {{- end }} {{- end }}
    {{- if eq ($visibleScratch.Get "visible") 0 }}
    {{ $emptyMessage }}
    {{- end }}
    Powered by Hugo Blox Kit - https://github.com/HugoBlox/kit
    ================================================ FILE: modules/blox/layouts/_partials/functions/parse_block_v3.html ================================================ {{/* Hugo Blox Parser v3 - Preact Component Support */}} {{/* Documentation: https://hugoblox.com/blocks/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{ $page := .page }} {{ $block := .block }} {{- $block_type := partial "hbx/resolve-block-param" (dict "config" $block "context" "content section") | default "markdown" -}} {{ $block_type = lower $block_type }} {{/* Handle block renames/aliases */}} {{ range $r := site.Data.blox_aliases.renames }} {{ $block_type = cond (eq $block_type $r.old) $r.new $block_type }} {{ end }} {{/* Check if this is a Preact-enabled block by looking for component file */}} {{ $component_path := printf "js/hbx/blocks/%s/component.jsx" $block_type }} {{ $is_preact := resources.Get $component_path }} {{/* Apply styling wrapper for all blocks (both Preact and traditional) */}} {{ $bg := $block.design.background }} {{ $style := "" }} {{ $style_bg := "" }} {{/* Process background colors */}} {{ if $bg.color }} {{ $color_type := printf "%T" $bg.color }} {{ if eq $color_type "map[string]interface {}" }} {{ if and $bg.color.light $bg.color.dark }} {{ $light_color := $bg.color.light }} {{ $dark_color := $bg.color.dark }} {{ $style_bg = printf "background-color: %s;" $light_color }} {{ $style_bg = printf "%s--dark-bg-color: %s;" $style_bg $dark_color }} {{ else if $bg.color.light }} {{ $light_color := $bg.color.light }} {{ $style_bg = printf "background-color: %s;" $light_color }} {{ else if $bg.color.dark }} {{ $dark_color := $bg.color.dark }} {{ $style_bg = printf "--dark-bg-color: %s; background-color: var(--dark-bg-color);" $dark_color }} {{ end }} {{ else }} {{ $bg_color := $bg.color }} {{ $style_bg = printf "background-color: %s;" $bg_color }} {{ end }} {{ end }} {{/* Process gradients and images */}} {{ $background_layers := slice }} {{ $gradient_layer := "" }} {{ $has_gradient_mesh := false }} {{ $gradient_mesh_html := "" }} {{/* Enhanced Gradient Mesh System */}} {{ $gradient_mesh := $bg.gradient_mesh | default dict }} {{ if $gradient_mesh.enable }} {{ $has_gradient_mesh = true }} {{ $mesh_style := $gradient_mesh.style | default "orbs" }} {{ $mesh_animation_raw := $gradient_mesh.animation | default "pulse" }} {{ $mesh_intensity := $gradient_mesh.intensity | default "subtle" }} {{/* Auto-theme: Mix Primary and Secondary brand colors for dynamic personalization */}} {{ $mesh_colors := $gradient_mesh.colors | default (slice "primary-500/20" "secondary-500/20") }} {{/* Map animation names to CSS classes */}} {{ $mesh_animation := "" }} {{ if eq $mesh_animation_raw "pulse" }} {{ $mesh_animation = "pulse" }} {{ else if eq $mesh_animation_raw "float" }} {{ $mesh_animation = "float" }} {{ else if eq $mesh_animation_raw "rotate" }} {{ $mesh_animation = "rotate-slow" }} {{ else if ne $mesh_animation_raw "none" }} {{ $mesh_animation = "pulse" }} {{/* Default fallback */}} {{ end }} {{/* Build gradient mesh HTML */}} {{ $mesh_html := "
    " }} {{/* Base gradient overlay */}} {{ $base_gradient := printf "
    " (index $mesh_colors 0) (index $mesh_colors 1) }} {{ $mesh_html = printf "%s%s" $mesh_html $base_gradient }} {{/* Animated elements based on style */}} {{ if eq $mesh_style "orbs" }} {{ $orb_count := $gradient_mesh.orb_count | default 2 }} {{ $orb_positions := $gradient_mesh.positions | default (slice "top-0 left-1/4" "bottom-0 right-1/4") }} {{ $orb_sizes := $gradient_mesh.sizes | default (slice "w-96 h-96" "w-96 h-96") }} {{ range $index, $position := first $orb_count $orb_positions }} {{ $size := index $orb_sizes $index | default "w-96 h-96" }} {{ $color := index $mesh_colors $index | default "primary-500/30" }} {{ $blur_class := cond (eq $mesh_intensity "bold") "blur-2xl" (cond (eq $mesh_intensity "medium") "blur-3xl" "blur-3xl") }} {{ $opacity := cond (eq $mesh_intensity "bold") "40" (cond (eq $mesh_intensity "medium") "30" "30") }} {{/* Extract base color and adjust opacity for orbs */}} {{ $orb_color := $color }} {{ if not (in $color "/") }} {{ $orb_color = printf "%s/%s" $color $opacity }} {{ end }} {{ $animation_delay := "" }} {{ if gt $index 0 }} {{ $animation_delay = printf " style=\"animation-delay: %ds;\"" (mul $index 2) }} {{ end }} {{/* Build orb with or without animation */}} {{ $animate_class := cond (ne $mesh_animation "") (printf "animate-%s" $mesh_animation) "" }} {{ $orb := printf "
    " $position $size $orb_color $blur_class $animate_class $animation_delay }} {{ $mesh_html = printf "%s%s" $mesh_html $orb }} {{ end }} {{ else if eq $mesh_style "waves" }} {{/* Flowing wave effect - multiple horizontal bands */}} {{ $wave_count := $gradient_mesh.wave_count | default 3 }} {{ $blur_class := cond (eq $mesh_intensity "bold") "blur-2xl" (cond (eq $mesh_intensity "medium") "blur-3xl" "blur-3xl") }} {{ range $index := seq 0 (sub $wave_count 1) }} {{ $color_index := mod $index (len $mesh_colors) }} {{ $color := index $mesh_colors $color_index }} {{ $top_pos := mul $index 33 }} {{ $height := "h-64" }} {{ $anim_delay := printf " style=\"animation-delay: %ds; animation-duration: %ds;\"" (mul $index 1) (add 8 (mul $index 2)) }} {{/* Apply animation if not none */}} {{ $animate_class := cond (ne $mesh_animation "") (printf "animate-%s" $mesh_animation) "" }} {{ $wave := printf "
    " $height $color $blur_class $animate_class $top_pos $anim_delay }} {{ $mesh_html = printf "%s%s" $mesh_html $wave }} {{ end }} {{ else if eq $mesh_style "dots" }} {{/* Dotted grid pattern */}} {{ $dot_size := $gradient_mesh.dot_size | default "w-4 h-4" }} {{ $spacing := $gradient_mesh.spacing | default "16" }} {{ $color := index $mesh_colors 0 | default "primary-500/20" }} {{/* Create a dotted pattern background */}} {{ $dots := printf "
    " $spacing $spacing (div (int $spacing) 2) (div (int $spacing) 2) }} {{ $mesh_html = printf "%s%s" $mesh_html $dots }} {{ else if eq $mesh_style "grid" }} {{/* Grid lines pattern */}} {{ $color := index $mesh_colors 0 | default "primary-500/10" }} {{ $line_width := $gradient_mesh.line_width | default "1" }} {{ $spacing := $gradient_mesh.spacing | default "32" }} {{/* Create grid pattern */}} {{ $grid := printf "
    " $line_width $line_width $line_width $line_width $spacing $spacing }} {{ $mesh_html = printf "%s%s" $mesh_html $grid }} {{ end }} {{ $mesh_html = printf "%s
    " $mesh_html }} {{ $gradient_mesh_html = $mesh_html | safeHTML }} {{ end }} {{/* Legacy simple gradient support */}} {{ if and $bg.gradient.start $bg.gradient.end }} {{ $angle := string $bg.gradient.direction | default "135" }} {{ $start_color := $bg.gradient.start }} {{ $end_color := $bg.gradient.end }} {{ $gradient_layer = printf "linear-gradient(%sdeg, %s, %s)" $angle $start_color $end_color }} {{ end }} {{/* Process video backgrounds */}} {{ $bg_video := "" }} {{ $bg_video_class := "" }} {{ if $bg.video.filename }} {{ $bg_video = resources.Get (printf "media/%s" $bg.video.filename) }} {{ if $bg.video.flip }} {{ $bg_video_class = "flip" }} {{ end }} {{ end }} {{/* Process image backgrounds */}} {{ if $bg.image.filename }} {{ $bg_img := resources.Get (printf "media/%s" $bg.image.filename) }} {{ if $bg_img }} {{ if ne $bg_img.MediaType.SubType "svg" }} {{ $bg_img = $bg_img.Fit "1920x1920 webp" }} {{ end }} {{ $image_layer := printf "url('%s')" $bg_img.RelPermalink }} {{ $background_layers = $background_layers | append $image_layer }} {{ else }} {{ errorf "Couldn't find `%s` in the `assets/media/` folder - please add it." $bg.image.filename }} {{ end }} {{ end }} {{ if or $background_layers $gradient_layer }} {{ $all_layers := $background_layers }} {{ if $gradient_layer }} {{ $all_layers = $all_layers | append $gradient_layer }} {{ end }} {{ if $all_layers }} {{ $combined_backgrounds := delimit $all_layers ", " }} {{ $style_bg = printf "%sbackground-image: %s;" $style_bg $combined_backgrounds }} {{/* Background image size/position/repeat properties */}} {{ $layer_count := len $all_layers }} {{ if gt $layer_count 1 }} {{/* Multiple layers: image + gradient */}} {{ $img_size := $bg.image.size | default "cover" }} {{ $img_position := $bg.image.position | default "center" }} {{ $img_repeat := $bg.image.repeat | default "no-repeat" }} {{ if eq $img_position "repeat" }} {{ $img_repeat = "repeat" }} {{ $img_position = "center" }} {{ end }} {{ $style_bg = printf "%sbackground-size: %s, cover;" $style_bg $img_size }} {{ $style_bg = printf "%sbackground-position: %s, center;" $style_bg $img_position }} {{ $style_bg = printf "%sbackground-repeat: %s, no-repeat;" $style_bg $img_repeat }} {{ else }} {{/* Single layer */}} {{ if $background_layers }} {{ with $bg.image.size }} {{ $style_bg = printf "%sbackground-size: %s;" $style_bg . }} {{ end }} {{ with $bg.image.position }} {{ if eq . "repeat" }} {{ $style_bg = printf "%sbackground-position: center;" $style_bg }} {{ $style_bg = printf "%sbackground-repeat: repeat;" $style_bg }} {{ else }} {{ $style_bg = printf "%sbackground-position: %s;" $style_bg . }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* Background image filters: brightness, blur, contrast, saturate, grayscale */}} {{ with $bg.image.filters }} {{ $filter_parts := slice }} {{ with .brightness }} {{ $filter_parts = $filter_parts | append (printf "brightness(%s)" (string .)) }} {{ end }} {{ with .blur }} {{ $filter_parts = $filter_parts | append (printf "blur(%s)" (string .)) }} {{ end }} {{ with .contrast }} {{ $filter_parts = $filter_parts | append (printf "contrast(%s)" (string .)) }} {{ end }} {{ with .saturate }} {{ $filter_parts = $filter_parts | append (printf "saturate(%s)" (string .)) }} {{ end }} {{ with .grayscale }} {{ $filter_parts = $filter_parts | append (printf "grayscale(%s)" (string .)) }} {{ end }} {{ if $filter_parts }} {{ $style_bg = printf "%sfilter: %s;" $style_bg (delimit $filter_parts " ") }} {{ end }} {{ end }} {{ with $block.design.spacing.padding }} {{ $style_pad := printf "padding: %s;" (delimit . " ") }} {{ $style = print $style $style_pad }} {{ end }} {{ with $block.design.css_style }} {{ $style = print $style . }} {{ end }} {{/* Support for clip path (design.clip_path) */}} {{ with $block.design.clip_path }} {{ $style = printf "%sclip-path: %s;" $style . }} {{ end }} {{ $hash_id := $block.id | default (printf "section-%s" (replace $block_type "." "-")) }} {{ $css_classes := $block.design.css_class | default "" }} {{ $widget_class := printf "blox-%s" (replace (replace $block_type "." "-") "_" "-") }} {{/* Extract background-specific CSS classes */}} {{ $bg_css_classes := $bg.css_class | default "" }} {{/* Route to appropriate handler */}} {{ if $is_preact }} {{/* Render Preact block with styling wrapper */}}
    {{/* Gradient Mesh Background */}} {{ if $has_gradient_mesh }}{{ $gradient_mesh_html }}{{ end }}
    {{with $bg_video}}{{end}}
    {{/* Use generic Preact wrapper for content */}} {{ partial "blox/preact-wrapper" (dict "wcPage" $page "wcBlock" $block "wcBlockType" $block_type "wcIdentifier" $hash_id) }}
    {{ else }} {{/* Fall back to traditional Go template blocks */}} {{ $block_path := printf "hbx/blocks/%s/block.html" $block_type }} {{ if not (templates.Exists (printf "_partials/%s" $block_path)) }} {{ errorf "%s uses a `%s` block but the `%s` block was not found at `%s`. Check the name of the block and ensure it exists in the blox/%s/ directory." $page.File.Path $block_type $block_type $block_path $block_type }} {{ end }} {{/* Handle legacy block requirements */}} {{ if $block.Page.Store.Get "has_mermaid" }} {{ $page.Page.Store.Set "has_mermaid" true }} {{ end }} {{ if (gt (len (findRE `\{\{< gallery` $block.content.text 1)) 0) }} {{ $page.Page.Store.Set "has_gallery" true }} {{ end }} {{ $widget_args := dict "wcPage" $page "wcBlock" $block "wcIdentifier" $hash_id }} {{/* Render traditional block with wrapper */}}
    {{/* Gradient Mesh Background */}} {{ if $has_gradient_mesh }}{{ $gradient_mesh_html }}{{ end }}
    {{with $bg_video}}{{end}}
    {{ partial $block_path $widget_args }}
    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/functions/process_responsive_image.html ================================================ {{/* Responsive Image Processor for Hugo Blox Kit (HBB) Uses Hugo's .Process method with configurable quality and responsive breakpoints Parameters: - image: Hugo image resource (required) - sizes: Array of widths for responsive breakpoints (optional, defaults to comprehensive set) - mode: Processing mode - "fit", "fill", "resize", or "responsive" (optional, defaults to "fit") - "fit": Maintains original aspect ratio, scales to fit within width (ignores aspect_ratio param) - "fill": Crops to exact dimensions, requires aspect_ratio for height calculation - "resize": Same as fit, maintains aspect ratio - "responsive": Creates responsive variants from already-processed image (no further processing) - anchor: Anchor point for cropping when using fill (optional, defaults to "smart") - aspect_ratio: Target aspect ratio for fill mode only (optional, format "width:height") - quality: Image quality override (optional, uses Hugo config by default) Returns: Map with processed images and srcset string - .srcset: Complete srcset attribute value - .fallback: Default/smallest image for src attribute - .sizes: Array of processed image resources */}} {{ $image := .image }} {{ $sizes := .sizes | default (slice 320 480 768 1024 1366 1920 2560) }} {{ $mode := .mode | default "fit" }} {{ $anchor := .anchor | default "smart" }} {{ $aspect_ratio := .aspect_ratio | default "" }} {{ $quality := .quality }} {{/* Initialize return variables */}} {{ $processed_images := slice }} {{ $srcset_parts := slice }} {{ $fallback_image := "" }} {{/* Check if image supports processing - only allow known processable formats */}} {{ $can_process := false }} {{ if $image.MediaType }} {{ $format := $image.MediaType.SubType }} {{ $isJPEG := eq $format "jpeg" }} {{ $isPNG := eq $format "png" }} {{ $isWebP := eq $format "webp" }} {{ $can_process = or $isJPEG $isPNG $isWebP }} {{ else }} {{/* Try detecting by file extension if MediaType not available */}} {{ $ext := path.Ext $image.RelPermalink | lower }} {{ $isJPEG := or (eq $ext ".jpg") (eq $ext ".jpeg") }} {{ $isPNG := eq $ext ".png" }} {{ $isWebP := eq $ext ".webp" }} {{ $can_process = or $isJPEG $isPNG $isWebP }} {{ end }} {{ if $can_process }} {{/* Handle responsive mode - for already processed images */}} {{ if eq $mode "responsive" }} {{/* Convert to WebP if needed */}} {{ $base_image := $image }} {{ if ne $image.MediaType.SubType "gif" }}{{ $base_image = $image.Process "webp" }}{{ end }} {{/* Create responsive variants by resizing down from the processed image */}} {{ range $width := $sizes }} {{/* Only create smaller variants */}} {{ if and (le $width $base_image.Width) (gt $width 0) }} {{ $resized := $base_image.Resize (printf "%dx webp" $width) }} {{ $processed_images = $processed_images | append $resized }} {{/* Add to srcset */}} {{ $srcset_part := printf "%s %dw" $resized.RelPermalink $resized.Width }} {{ $srcset_parts = $srcset_parts | append $srcset_part }} {{/* Set fallback to smallest image */}} {{ if not $fallback_image }} {{ $fallback_image = $resized }} {{ end }} {{ end }} {{ end }} {{/* Always include the original size as the largest option */}} {{ $srcset_part := printf "%s %dw" $base_image.RelPermalink $base_image.Width }} {{ $srcset_parts = $srcset_parts | append $srcset_part }} {{ $processed_images = $processed_images | append $base_image }} {{ if not $fallback_image }}{{ $fallback_image = $base_image }}{{ end }} {{ else }} {{/* Process images for each breakpoint */}} {{ range $width := $sizes }} {{/* Only process if the source image is larger than target width */}} {{ if ge $image.Width $width }} {{ $process_params := "" }} {{/* Build processing parameters based on mode */}} {{- if eq $mode "resize" -}} {{- if $quality -}} {{- $process_params = printf "resize %dx webp q%d" $width $quality -}} {{- else -}} {{- $process_params = printf "resize %dx webp" $width -}} {{- end -}} {{- else if eq $mode "fill" -}} {{- if $aspect_ratio -}} {{- $ratio_parts := split $aspect_ratio ":" -}} {{- $ratio_width := int (index $ratio_parts 0) -}} {{- $ratio_height := int (index $ratio_parts 1) -}} {{- $height := div (mul $width $ratio_height) $ratio_width -}} {{- if $quality -}} {{- $process_params = printf "fill %dx%d webp q%d %s" $width $height $quality $anchor -}} {{- else -}} {{- $process_params = printf "fill %dx%d webp %s" $width $height $anchor -}} {{- end -}} {{- else -}} {{/* Fill mode without aspect ratio - use resize instead to maintain original proportions */}} {{- if $quality -}} {{- $process_params = printf "resize %dx webp q%d" $width $quality -}} {{- else -}} {{- $process_params = printf "resize %dx webp" $width -}} {{- end -}} {{- end -}} {{- else -}} {{/* Default to fit - always maintain original aspect ratio */}} {{/* Fit mode should not force an aspect ratio, it should fit within bounds */}} {{- if $quality -}} {{- $process_params = printf "resize %dx webp q%d" $width $quality -}} {{- else -}} {{- $process_params = printf "resize %dx webp" $width -}} {{- end -}} {{- end -}} {{/* Process the image */}} {{- $processed := $image.Process $process_params -}} {{- $processed_images = $processed_images | append $processed -}} {{/* Add to srcset */}} {{- $srcset_part := printf "%s %dw" $processed.RelPermalink $processed.Width -}} {{- $srcset_parts = $srcset_parts | append $srcset_part -}} {{/* Set fallback to smallest image */}} {{- if not $fallback_image -}} {{- $fallback_image = $processed -}} {{- end -}} {{- end -}} {{- end -}} {{ end }} {{- else -}} {{/* Handle unsupported formats (SVG, GIF) - skip srcset as width/height are unavailable for SVGs */}} {{- $fallback_image = $image -}} {{- $processed_images = $processed_images | append $image -}} {{- end -}} {{/* Return processed data */}} {{ return (dict "srcset" (delimit $srcset_parts ", ") "fallback" $fallback_image "sizes" $processed_images ) }} ================================================ FILE: modules/blox/layouts/_partials/functions/render_callout.html ================================================ {{/* Hugo Blox Kit Shared Callout Renderer Renders callouts with consistent styling for both shortcodes and render hooks. Parameters: - type: The callout type (note, tip, important, warning, caution, or custom icon name) - content: The callout content (HTML) - title: Optional title for the callout - source: "shortcode" or "renderhook" for context */}} {{ $type := (lower .type) | default "note" }} {{ $content := .content }} {{ $title := .title }} {{ if or (not $title) (eq $title "") }} {{/* Try i18n translation with "callout_" prefix, fall back to title case */}} {{ $i18n_key := printf "callout_%s" $type }} {{ $title = or (i18n $i18n_key) (title $type) }} {{ end }} {{ $source := .source | default "shortcode" }} {{/* Define icon and styling mappings for all Obsidian callout types */}} {{ $alertConfigs := dict "note" (dict "icon" "pencil" "class" "bg-blue-100 dark:bg-blue-900" "textClass" "text-blue-600 dark:text-blue-300" "borderClass" "border-blue-500" ) "abstract" (dict "icon" "clipboard-document-list" "class" "bg-cyan-100 dark:bg-cyan-900" "textClass" "text-cyan-600 dark:text-cyan-300" "borderClass" "border-cyan-500" ) "summary" (dict "icon" "clipboard-document-list" "class" "bg-cyan-100 dark:bg-cyan-900" "textClass" "text-cyan-600 dark:text-cyan-300" "borderClass" "border-cyan-500" ) "info" (dict "icon" "information-circle" "class" "bg-blue-100 dark:bg-blue-900" "textClass" "text-blue-600 dark:text-blue-300" "borderClass" "border-blue-500" ) "todo" (dict "icon" "check-circle" "class" "bg-blue-100 dark:bg-blue-900" "textClass" "text-blue-600 dark:text-blue-300" "borderClass" "border-blue-500" ) "tip" (dict "icon" "light-bulb" "class" "bg-emerald-100 dark:bg-emerald-900" "textClass" "text-emerald-600 dark:text-emerald-300" "borderClass" "border-emerald-500" ) "success" (dict "icon" "check-circle" "class" "bg-green-100 dark:bg-green-900" "textClass" "text-green-600 dark:text-green-300" "borderClass" "border-green-500" ) "question" (dict "icon" "question-mark-circle" "class" "bg-yellow-100 dark:bg-yellow-900" "textClass" "text-yellow-700 dark:text-yellow-300" "borderClass" "border-yellow-500" ) "warning" (dict "icon" "exclamation-triangle" "class" "bg-orange-100 dark:bg-orange-900" "textClass" "text-orange-600 dark:text-orange-300" "borderClass" "border-orange-500" ) "failure" (dict "icon" "x-circle" "class" "bg-red-100 dark:bg-red-900" "textClass" "text-red-600 dark:text-red-300" "borderClass" "border-red-500" ) "danger" (dict "icon" "exclamation-triangle" "class" "bg-red-100 dark:bg-red-900" "textClass" "text-red-600 dark:text-red-300" "borderClass" "border-red-500" ) "bug" (dict "icon" "bug-ant" "class" "bg-red-100 dark:bg-red-900" "textClass" "text-red-600 dark:text-red-300" "borderClass" "border-red-500" ) "example" (dict "icon" "beaker" "class" "bg-purple-100 dark:bg-purple-900" "textClass" "text-purple-600 dark:text-purple-300" "borderClass" "border-purple-500" ) "quote" (dict "icon" "chat-bubble-left-right" "class" "bg-gray-100 dark:bg-gray-800" "textClass" "text-gray-600 dark:text-gray-300" "borderClass" "border-gray-500" ) "important" (dict "icon" "exclamation-circle" "class" "bg-purple-100 dark:bg-purple-900" "textClass" "text-purple-600 dark:text-purple-300" "borderClass" "border-purple-500" ) "caution" (dict "icon" "exclamation-triangle" "class" "bg-red-100 dark:bg-red-900" "textClass" "text-red-600 dark:text-red-300" "borderClass" "border-red-500" ) }} {{/* Get configuration for this callout type, or use fallback */}} {{ $config := index $alertConfigs $type }} {{ $icon := $type }} {{ $class := "bg-blue-100 dark:bg-blue-900" }} {{ $textClass := "text-blue-600 dark:text-blue-300" }} {{ $borderClass := "border-blue-500" }} {{ if $config }} {{ $icon = $config.icon }} {{ $class = $config.class }} {{ $textClass = $config.textClass }} {{ $borderClass = $config.borderClass }} {{ end }}
    {{ partial "functions/get_icon" (dict "name" $icon "attributes" "height=\"24\"") }}
    {{/* Display title if provided */}} {{- with $title -}}
    {{- . -}}
    {{- end -}} {{/* Display content */}}
    {{- $content -}}
    ================================================ FILE: modules/blox/layouts/_partials/functions/render_view.html ================================================ {{/* Hugo Blox Kit content preview renderer */}} {{ $page := .page }} {{ $item := .item }} {{ $view := lower .view | default "card" }} {{ $fragment := .fragment | default "body" }} {{ $view_dtype := printf "%T" $view }} {{ $index := .index }} {{ $html := "" }} {{ if not (templates.Exists (printf "_partials/views/%s.html" $view)) }} {{/* Fallback to card view */}} {{ warnf "Failed to locate view at `_partials/views/%s.html`. Check you specified a supported `view` in `%s`" $view $page.File.Path }} {{ $view = "card" }} {{ end }} {{ if eq $fragment "body" }} {{ $html = (partial (printf "views/%s" $view) (dict "page" $page "item" $item "index" $index "config" (.config | default dict))) }} {{ else }} {{ $html = (partial (printf "views/%s--%s" $view $fragment) (dict "page" $page "item" $item "index" $index "config" (.config | default dict))) }} {{ end }} {{ return $html }} ================================================ FILE: modules/blox/layouts/_partials/functions/theme_generator.html ================================================ {{/* HugoBlox Theme Engine: Generates CSS Variables for Light and Dark modes Input: Theme config dict from get_theme_config helper: - mode: 'light' | 'dark' | 'system' - light: Light theme pack name - dark: Dark theme pack name - colors: Global color overrides { primary, secondary, neutral } - colors_light: Light-mode specific color overrides - colors_dark: Dark-mode specific color overrides - surfaces: Semantic surface color overrides */}} {{ $config := . }} {{ $light_theme_name := $config.light | default "default" }} {{ $dark_theme_name := $config.dark | default "default" }} {{ $global_colors := $config.colors | default dict }} {{ $colors_light := $config.colors_light | default dict }} {{ $colors_dark := $config.colors_dark | default dict }} {{ $surfaces_overrides := $config.surfaces | default dict }} {{/* Load Theme Data using the new loader */}} {{ if not site.Data.themes }} {{ warnf "THEME ENGINE ERROR: site.Data.themes is empty! Check modules/blox-tailwind/data/themes/" }} {{ end }} {{ $light_theme := partial "functions/load_theme_pack" $light_theme_name }} {{ $dark_theme := partial "functions/load_theme_pack" $dark_theme_name }} {{/* Fallback for missing themes */}} {{ if not $light_theme }} {{ warnf "THEME ENGINE WARNING: Light theme '%s' not found or invalid. Defaulting to 'default'." $light_theme_name }} {{ $light_theme = partial "functions/load_theme_pack" "default" }} {{ end }} {{ if not $dark_theme }} {{ warnf "THEME ENGINE WARNING: Dark theme '%s' not found or invalid. Defaulting to 'default'." $dark_theme_name }} {{ $dark_theme = partial "functions/load_theme_pack" "default" }} {{ end }} {{/* Resolve effective light/dark mode objects from theme files */}} {{ $light_base := $light_theme.light | default $light_theme }} {{ $dark_base := $dark_theme.dark | default $dark_theme }} {{/* ═══════════════════════════════════════════════════════════════════════════ APPLY COLOR OVERRIDES Priority: colors_light/colors_dark → colors (global) → theme pack defaults ═══════════════════════════════════════════════════════════════════════════ */}} {{/* Apply global color overrides to LIGHT mode */}} {{ if $light_base }} {{ $light_colors := merge (dict) ($light_base.colors | default dict) }} {{/* Global overrides */}} {{ with $global_colors.primary }} {{ $light_colors = merge $light_colors (dict "primary" .) }} {{ end }} {{ with $global_colors.secondary }} {{ $light_colors = merge $light_colors (dict "secondary" .) }} {{ end }} {{ with $global_colors.neutral }} {{ $light_colors = merge $light_colors (dict "neutral" .) }} {{ end }} {{/* Mode-specific overrides (highest priority) */}} {{ with $colors_light.primary }} {{ $light_colors = merge $light_colors (dict "primary" .) }} {{ end }} {{ with $colors_light.secondary }} {{ $light_colors = merge $light_colors (dict "secondary" .) }} {{ end }} {{ with $colors_light.neutral }} {{ $light_colors = merge $light_colors (dict "neutral" .) }} {{ end }} {{ $light_base = merge $light_base (dict "colors" $light_colors) }} {{/* Apply surface overrides (only non-empty values) */}} {{ if $surfaces_overrides }} {{ $light_surfaces := merge (dict) ($light_base.surfaces | default dict) }} {{ with $surfaces_overrides.background }} {{ if ne . "" }} {{ $light_surfaces = merge $light_surfaces (dict "background" .) }} {{ end }} {{ end }} {{ with $surfaces_overrides.foreground }} {{ if ne . "" }} {{ $light_surfaces = merge $light_surfaces (dict "foreground" .) }} {{ end }} {{ end }} {{ with $surfaces_overrides.header }} {{ $header := merge (dict) ($light_surfaces.header | default dict) }} {{ with .background }} {{ if ne . "" }} {{ $header = merge $header (dict "background" .) }} {{ end }} {{ end }} {{ with .foreground }} {{ if ne . "" }} {{ $header = merge $header (dict "foreground" .) }} {{ end }} {{ end }} {{ if gt (len $header) 0 }} {{ $light_surfaces = merge $light_surfaces (dict "header" $header) }} {{ end }} {{ end }} {{ with $surfaces_overrides.footer }} {{ $footer := merge (dict) ($light_surfaces.footer | default dict) }} {{ with .background }} {{ if ne . "" }} {{ $footer = merge $footer (dict "background" .) }} {{ end }} {{ end }} {{ with .foreground }} {{ if ne . "" }} {{ $footer = merge $footer (dict "foreground" .) }} {{ end }} {{ end }} {{ if gt (len $footer) 0 }} {{ $light_surfaces = merge $light_surfaces (dict "footer" $footer) }} {{ end }} {{ end }} {{ $light_base = merge $light_base (dict "surfaces" $light_surfaces) }} {{ end }} {{ end }} {{/* Apply global color overrides to DARK mode */}} {{ if $dark_base }} {{ $dark_colors := merge (dict) ($dark_base.colors | default dict) }} {{/* Global overrides */}} {{ with $global_colors.primary }} {{ $dark_colors = merge $dark_colors (dict "primary" .) }} {{ end }} {{ with $global_colors.secondary }} {{ $dark_colors = merge $dark_colors (dict "secondary" .) }} {{ end }} {{ with $global_colors.neutral }} {{ $dark_colors = merge $dark_colors (dict "neutral" .) }} {{ end }} {{/* Mode-specific overrides (highest priority) */}} {{ with $colors_dark.primary }} {{ $dark_colors = merge $dark_colors (dict "primary" .) }} {{ end }} {{ with $colors_dark.secondary }} {{ $dark_colors = merge $dark_colors (dict "secondary" .) }} {{ end }} {{ with $colors_dark.neutral }} {{ $dark_colors = merge $dark_colors (dict "neutral" .) }} {{ end }} {{ $dark_base = merge $dark_base (dict "colors" $dark_colors) }} {{/* Apply surface overrides (only non-empty values) */}} {{ if $surfaces_overrides }} {{ $dark_surfaces := merge (dict) ($dark_base.surfaces | default dict) }} {{ with $surfaces_overrides.background }} {{ if ne . "" }} {{ $dark_surfaces = merge $dark_surfaces (dict "background" .) }} {{ end }} {{ end }} {{ with $surfaces_overrides.foreground }} {{ if ne . "" }} {{ $dark_surfaces = merge $dark_surfaces (dict "foreground" .) }} {{ end }} {{ end }} {{ with $surfaces_overrides.header }} {{ $header := merge (dict) ($dark_surfaces.header | default dict) }} {{ with .background }} {{ if ne . "" }} {{ $header = merge $header (dict "background" .) }} {{ end }} {{ end }} {{ with .foreground }} {{ if ne . "" }} {{ $header = merge $header (dict "foreground" .) }} {{ end }} {{ end }} {{ if gt (len $header) 0 }} {{ $dark_surfaces = merge $dark_surfaces (dict "header" $header) }} {{ end }} {{ end }} {{ with $surfaces_overrides.footer }} {{ $footer := merge (dict) ($dark_surfaces.footer | default dict) }} {{ with .background }} {{ if ne . "" }} {{ $footer = merge $footer (dict "background" .) }} {{ end }} {{ end }} {{ with .foreground }} {{ if ne . "" }} {{ $footer = merge $footer (dict "foreground" .) }} {{ end }} {{ end }} {{ if gt (len $footer) 0 }} {{ $dark_surfaces = merge $dark_surfaces (dict "footer" $footer) }} {{ end }} {{ end }} {{ $dark_base = merge $dark_base (dict "surfaces" $dark_surfaces) }} {{ end }} {{ end }} {{/* ═══════════════════════════════════════════════════════════════════════════ GENERATE CSS OUTPUT ═══════════════════════════════════════════════════════════════════════════ */}} ================================================ FILE: modules/blox/layouts/_partials/functions/theme_variables.html ================================================ {{/* HugoBlox Theme Helper to output CSS variables for a specific theme block */}} {{ $data := .data }} {{/* 1. Palette Generation (Primary/Secondary Scales) */}} {{ $primary := $data.colors.primary | default "#3b82f6" }} {{ $secondary := $data.colors.secondary | default "#10b981" }} {{ partial "functions/generate_color_scale" (dict "name" "primary" "color" $primary) }} {{ partial "functions/generate_color_scale" (dict "name" "secondary" "color" $secondary) }} {{ if $data.colors.neutral }} {{/* Map user 'neutral' to Tailwind 'gray' utility to override text-gray-* classes */}} {{ partial "functions/generate_color_scale" (dict "name" "gray" "color" $data.colors.neutral) }} {{ end }} {{/* 2. Semantic Surface Variables */}} --hb-color-background: {{ $data.surfaces.background | default "#ffffff" }}; --hb-color-foreground: {{ $data.surfaces.foreground | default "#000000" }}; {{/* Header */}} --hb-color-header-bg: {{ $data.surfaces.header.background | default $data.surfaces.background | default "#ffffff" }}; --hb-color-header-fg: {{ $data.surfaces.header.foreground | default $data.surfaces.foreground | default "#000000" }}; {{/* Footer */}} --hb-color-footer-bg: {{ $data.surfaces.footer.background | default $data.surfaces.background | default "#f3f4f6" }}; --hb-color-footer-fg: {{ $data.surfaces.footer.foreground | default $data.surfaces.foreground | default "#000000" }}; ================================================ FILE: modules/blox/layouts/_partials/functions/typography.html ================================================ {{/* HugoBlox Theme Engine: Typography Rendering Resolves font families, emits @font-face for bundled fonts, Google Fonts tags for remote fonts, and CSS custom properties. Font resolution order (per family): 1. system-sans / system-serif / system-mono → native OS font stack 2. Bundled file in assets/dist/font/* → local @font-face 3. Fallback → Google Fonts CDN Input: Theme config dict from get_theme_config: - typography: { families, weights, sizes, leading, tracking, variable } Output: @font-face (bundled) + (Google Fonts) + {{ end }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* Build Google Fonts URL */}} {{ $gf_families := slice }} {{ $seen := dict }} {{ range $role := $roles }} {{ with index $resolve_family $role }} {{ if .google }} {{ $name := .name }} {{ $is_variable := index $variable $role | default false }} {{/* Use full range for variable fonts, discrete weights for static */}} {{ $weight_spec := "" }} {{ if $is_variable }} {{ $weight_spec = "100..900" }} {{ else }} {{ $role_weights := index $weights $role | default (slice 400) }} {{ $weight_spec = delimit $role_weights "," }} {{ end }} {{/* Dedup key includes weight spec so the same font can appear as both static and variable if needed */}} {{ $dedup_key := printf "%s|%s" $name $weight_spec }} {{ if not (index $seen $dedup_key) }} {{ $seen = merge $seen (dict $dedup_key true) }} {{ $encoded := replace $name " " "+" }} {{ $gf_families = $gf_families | append (printf "%s:wght@%s" $encoded $weight_spec) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ if gt (len $gf_families) 0 }} {{ $gf_url := printf "https://fonts.googleapis.com/css2?%s&display=swap" (delimit (apply $gf_families "printf" "family=%s" ".") "&") }} {{ end }} {{/* Font size vars */}} {{ $font_size_base := $sizes.base | default "1rem" }} {{ $font_size_sm := $sizes.sm | default "0.875rem" }} {{ $font_size_lg := $sizes.lg | default "1.125rem" }} {{/* Resolve CSS font-family values */}} {{ $heading_css := $system_sans }} {{ with index $resolve_family "heading" }}{{ $heading_css = .css }}{{ end }} {{ $body_css := $system_sans }} {{ with index $resolve_family "body" }}{{ $body_css = .css }}{{ end }} {{ $code_css := $system_mono }} {{ with index $resolve_family "code" }}{{ $code_css = .css }}{{ end }} {{ $nav_css := $heading_css }} {{ with index $resolve_family "nav" }}{{ if .css }}{{ $nav_css = .css }}{{ end }}{{ end }} {{/* Get primary weight for each role (first in array) */}} {{ $heading_weight := 700 }} {{ with $weights.heading }}{{ $heading_weight = index . 0 }}{{ end }} {{ $body_weight := 400 }} {{ with $weights.body }}{{ $body_weight = index . 0 }}{{ end }} {{/* Bold body weight: second value in array, or primary + 200 (capped at 900) */}} {{ $body_weight_bold := math.Min 900 (add $body_weight 200) }} {{ with $weights.body }}{{ if ge (len .) 2 }}{{ $body_weight_bold = index . 1 }}{{ end }}{{ end }} ================================================ FILE: modules/blox/layouts/_partials/functions/uid.html ================================================ {{/* Hugo Blox UID Generator Generate a unique ID for shortcodes and components. Uses the page's unique ID combined with ordinal for uniqueness. */}} {{ $uid := .Page.File.UniqueID }} {{ $ctx := . }} {{ range seq 16 }} {{ with $ctx }} {{ $uid = printf "%s-%d" $uid .Ordinal }} {{ $ctx = .Parent }} {{ else }} {{ break }} {{ end }} {{ end }} {{ return (crypto.MD5 $uid) }} ================================================ FILE: modules/blox/layouts/_partials/hbx/resolve-block-param.html ================================================ {{/* Context-aware block parameter resolution with backward compatibility */}} {{/* Strategy: Prefers "block" over "blox" (legacy) in configs */}} {{- $config := .config -}} {{- $context := .context | default "component" -}} {{- $block_id := "" -}} {{- $using_legacy := false -}} {{- if $config.style -}} {{- $block_id = $config.style -}} {{- else if $config.block -}} {{- $block_id = $config.block -}} {{- else if $config.blox -}} {{- $block_id = $config.blox -}} {{- $using_legacy = true -}} {{- end -}} {{- if $using_legacy -}} {{- warnf "HBX: Using legacy 'blox' parameter for %s. Please update to 'block' for consistency. (Found: blox=%s)" $context $block_id -}} {{- end -}} {{- return $block_id -}} ================================================ FILE: modules/blox/layouts/_partials/hbx/resolve.html ================================================ {{/* HBX resolver: maps a section { block: "", ... } to the block partial. This resolver looks up blocks from the blox//block.html structure, which are mounted to layouts/_partials/hbx/blocks//block.html via module.yaml. */}} {{- $id := .section.block -}} {{- if not $id }}{{ errorf "HBX: section is missing 'block' key: %v" .section }}{{ end -}} {{- $params := .section -}} {{- $path := printf "hbx/blocks/%s/block.html" $id -}} {{- if templates.Exists (printf "_partials/%s" $path) -}} {{ partial $path (dict "wcPage" .ctx "wcBlock" $params "wcIdentifier" ($params.id | default (printf "section-%s" $id))) }} {{- else -}} {{ errorf "HBX: block '%s' not found at %q" $id $path }} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/hbx/sections.html ================================================ {{/* Returns sections from front matter, linked data, or from data. */}} {{- $sections := .Params.sections -}} {{- $source := "front matter" -}} {{/* 1) Linked-data: sections_source */}} {{- with .Params.sections_source -}} {{- $key := . -}} {{- if hasPrefix $key "pages/" -}}{{- $key = (replace $key "pages/" "") -}}{{- end -}} {{- with index site.Data.pages $key -}} {{- $base := .sections -}} {{- if $sections -}} {{- $merged := slice -}} {{- range $i, $b := $base -}} {{- $ov := index $sections $i -}} {{- if $ov -}} {{- $merged = $merged | append (partial "functions/deep_merge" (dict "a" $b "b" $ov)) -}} {{- else -}} {{- $merged = $merged | append $b -}} {{- end -}} {{- end -}} {{- if gt (len $sections) (len $base) -}} {{- range $i, $ov := $sections -}} {{- if ge $i (len $base) -}} {{- $merged = $merged | append $ov -}} {{- end -}} {{- end -}} {{- end -}} {{- $sections = $merged -}} {{- else -}} {{- $sections = $base -}} {{- end -}} {{- $source = printf "data/pages/%s.yaml (sections_source)" $key -}} {{- else -}} {{- partial "functions/logger" (dict "page" . "level" "warn" "id" (printf "sections-source-missing-%s" $key) "message" (printf "sections_source '%s' not found under data/pages/" $key) "source" (dict "type" "partial" "name" "hbx/sections")) -}} {{- end -}} {{- end -}} {{/* 2) Fallbacks if still no sections */}} {{- if not $sections -}} {{/* Fallback: Legacy data-driven pages */}} {{- $p := "home" -}}{{/* Default to "home" for homepage */}} {{- with .File -}} {{- $basename := .ContentBaseName -}} {{- if $basename -}} {{- $p = $basename -}} {{/* Special case: homepage _index.md should use "home" data file */}} {{- if eq $p "_index" -}} {{- $p = "home" -}} {{- end -}} {{- end -}} {{- end -}} {{/* Ensure homepage always uses "home" data file */}} {{- if eq $.RelPermalink "/" -}} {{- $p = "home" -}} {{- end -}} {{- with index site.Data.pages $p -}} {{- $sections = .sections -}} {{- $source = printf "data/pages/%s.yaml" $p -}} {{- end -}} {{- end -}} {{/* 3) Per-section ref: load from data/blocks/.yaml and deep-merge with inline (inline wins) */}} {{- if $sections -}} {{- $resolved := slice -}} {{- range $i, $s := $sections -}} {{- $sec := $s -}} {{- with $s.ref -}} {{- $ref := . | lower -}} {{- $path := cond (hasPrefix $ref "blocks/") $ref (printf "blocks/%s" $ref) -}} {{- $parts := split $path "/" -}} {{- $data := site.Data -}} {{- range $j, $p := $parts -}} {{- if $data -}} {{- $data = index $data $p -}} {{- end -}} {{- end -}} {{- if $data -}} {{- /* shallow merge */ -}} {{- $merged := merge $data $sec -}} {{- /* merge 'content' */ -}} {{- $ac := index $data "content" -}}{{- $bc := index $sec "content" -}} {{- if and (reflect.IsMap $ac) (reflect.IsMap $bc) -}} {{- $merged = merge $merged (dict "content" (merge $ac $bc)) -}} {{- end -}} {{- /* merge 'design' */ -}} {{- $ad := index $data "design" -}}{{- $bd := index $sec "design" -}} {{- if and (reflect.IsMap $ad) (reflect.IsMap $bd) -}} {{- $merged = merge $merged (dict "design" (merge $ad $bd)) -}} {{- end -}} {{- $sec = $merged -}} {{- else -}} {{- partial "functions/logger" (dict "page" $ "level" "warn" "id" (printf "section-ref-missing-%s" $ref) "message" (printf "HBX: section ref '%s' not found under data/blocks/" $ref) "source" (dict "type" "partial" "name" "hbx/sections")) -}} {{- end -}} {{- end -}} {{- $resolved = $resolved | append $sec -}} {{- end -}} {{- $sections = $resolved -}} {{- end -}} {{- if $sections -}} {{- partial "functions/logger" (dict "page" . "level" "info" "message" (printf "✅ Using sections from %s for page %s (found %d sections)" $source $.RelPermalink (len $sections)) "source" (dict "type" "partial" "name" "hbx/sections")) -}} {{- else -}} {{- partial "functions/logger" (dict "page" . "level" "warn" "id" (printf "sections-none-%s" $.RelPermalink) "message" (printf "HBX: No sections found for page %s (checked %s)" $.RelPermalink $source) "source" (dict "type" "partial" "name" "hbx/sections")) -}} {{- end -}} {{- return $sections -}} ================================================ FILE: modules/blox/layouts/_partials/hooks/body-end/hbx-debug-export.html ================================================ {{/* Hugo Blox: Export Debug Logs for Dev HUD (window var) */}} {{- if site.Params.hugoblox.debug.export_logs | default true -}} {{- /* Collect all logs from all pages (site-wide) */ -}} {{- $entries := slice -}} {{- range .Site.Pages -}} {{- with .Store -}} {{- with .Get "hbx_logs" -}} {{- $entries = $entries | append . -}} {{- end -}} {{- end -}} {{- end -}} {{- /* Summarize dependencies */ -}} {{- $deps := slice -}} {{- range $i, $d := hugo.Deps -}} {{- $dep := dict "path" $d.Path "version" $d.Version "vendor" $d.Vendor -}} {{- with $d.Owner -}} {{- $dep = merge $dep (dict "owner_path" .Path) -}} {{- end -}} {{- with $d.Replace -}} {{- $dep = merge $dep (dict "replace_path" .Path) -}} {{- end -}} {{- with $d.Time -}} {{- $dep = merge $dep (dict "time" (printf "%v" .)) -}} {{- end -}} {{- $deps = $deps | append $dep -}} {{- end -}} {{- /* Detect blox-tailwind module version if present */ -}} {{- $bloxTW := dict -}} {{- range $deps -}} {{- $p := .path -}} {{- if and $p (in $p "blox-tailwind") -}} {{- $bloxTW = dict "path" .path "version" .version -}} {{- end -}} {{- end -}} {{- /* Current page information */ -}} {{- $filePath := "" -}} {{- with .File -}} {{- $filePath = .Path -}} {{- end -}} {{- $buildId := partialCached "functions/get-build-id.html" "hbx-build-id" -}} {{- $currentPage := dict "path" .RelPermalink "type" .Type "layout" (.Layout | default "") "kind" .Kind "section" .Section "title" .Title "file" $filePath "buildId" $buildId -}} {{- $payload := dict "version" 1 "generatedAt" (now.UTC.Format "2006-01-02T15:04:05Z07:00") "hugo" (dict "version" hugo.Version "goVersion" hugo.GoVersion) "deps" $deps "modules" (dict "bloxTailwind" $bloxTW) "entries" $entries "currentPage" $currentPage -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/hooks/body-end/hbx-debug-hud.html ================================================ {{/* Hugo Blox: Dev HUD (floating button + panel). Dev only. */}} ================================================ FILE: modules/blox/layouts/_partials/init.html ================================================ {{/* Workaround Hugo concurrency issues (e.g. not detecting Page.Store variables) */}} {{/* Use cases: Page.Store use within shortcodes, blox, and backlinks. */}} {{/* See https://discourse.gohugo.io/t/persisting-data-across-the-build-of-a-site/41114/6 */}} {{/* Pre-warm only content pages so Page.Store/backlinks are populated deterministically */}} {{- range where .Site.Pages "Kind" "page" -}} {{- $ := .Content -}} {{- end -}} {{/* Preload block configs for landing pages */}} {{- range where .Site.Pages "Type" "landing" -}} {{ $page := . }} {{/* Resolve sections: front matter, sections_source, fallback to data/pages */}} {{ $sections := $page.Params.sections }} {{/* Linked-data: sections_source support */}} {{ with $page.Params.sections_source }} {{ $key := . }} {{ if hasPrefix $key "pages/" }}{{ $key = replace $key "pages/" "" }}{{ end }} {{ with index $.Site.Data.pages $key }} {{ $base := .sections }} {{ if $sections }} {{ $merged := slice }} {{ range $i, $b := $base }} {{ $ov := index $sections $i }} {{ if $ov }} {{ $merged = $merged | append (merge $b $ov) }} {{ else }} {{ $merged = $merged | append $b }} {{ end }} {{ end }} {{ if gt (len $sections) (len $base) }} {{ range $i, $ov := $sections }} {{ if ge $i (len $base) }} {{ $merged = $merged | append $ov }} {{ end }} {{ end }} {{ end }} {{ $sections = $merged }} {{ else }} {{ $sections = $base }} {{ end }} {{ end }} {{ end }} {{ if not $sections }} {{/* Data-driven fallback (home) */}} {{ $p := "home" }} {{ with $page.File }} {{ $basename := .ContentBaseName }} {{ if $basename }} {{ $p = $basename }} {{ if eq $p "_index" }}{{ $p = "home" }}{{ end }} {{ end }} {{ end }} {{ if eq $page.RelPermalink "/" }}{{ $p = "home" }}{{ end }} {{ with index $.Site.Data.pages $p }} {{ $sections = .sections }} {{ end }} {{ end }} {{/* Resolve per-section ref from data/blocks/* for block detection */}} {{ if $sections }} {{ $resolved := slice }} {{ range $i, $s := $sections }} {{ $sec := $s }} {{ with $s.ref }} {{ $ref := lower . }} {{ $path := cond (hasPrefix $ref "blocks/") $ref (printf "blocks/%s" $ref) }} {{ $parts := split $path "/" }} {{ $data := $.Site.Data }} {{ range $j, $p := $parts }} {{ if $data }}{{ $data = index $data $p }}{{ end }} {{ end }} {{ if $data }} {{/* Shallow merge so base can provide block type */}} {{ $sec = merge $data $sec }} {{ end }} {{ end }} {{ $resolved = $resolved | append $sec }} {{ end }} {{ $sections = $resolved }} {{ end }} {{ range $index, $block := $sections }} {{/* Do not show sections intended only for the demo site. */}} {{ if or (not $block.demo) ($block.demo | and (eq (os.Getenv "HUGO_BLOX_DEMO") "true")) }} {{- $block_type := partial "hbx/resolve-block-param" (dict "config" $block "context" "content section") | default "markdown" -}} {{ $block_type = lower $block_type }} {{ range $r := .Site.Data.blox_aliases.renames }} {{ $block_type = cond (eq $block_type $r.old) $r.new $block_type }} {{ end }} {{/* Store the block type in the page store for asset bundling */}} {{ $current_blocks := $page.Store.Get "block_types" | default (slice) }} {{ $page.Store.Set "block_types" ($current_blocks | append $block_type) }} {{/* Check if this is a Preact-enabled block that needs hydration */}} {{ $component_path := printf "js/hbx/blocks/%s/client.jsx" $block_type }} {{ if resources.Get $component_path }} {{ $page.Store.Set "needs_preact" true }} {{/* Store which Preact blocks are used on this page */}} {{ $preact_blocks := $page.Store.Get "preact_blocks" | default slice }} {{ if not (in $preact_blocks $block_type) }} {{ $preact_blocks = $preact_blocks | append $block_type }} {{ $page.Store.Set "preact_blocks" $preact_blocks }} {{ end }} {{ end }} {{/* Detect FAQ blocks for JSON-LD structured data (avoid race conditions) */}} {{ if eq $block_type "faq" }} {{ if $block.content.items }} {{ $faq_items := $page.Store.Get "faq_items" | default slice }} {{ range $block.content.items }} {{ $faq_items = $faq_items | append (dict "question" .question "answer" .answer) }} {{ end }} {{ $page.Store.Set "faq_items" $faq_items }} {{ end }} {{ end }} {{ $widget_config_file := printf "blox/%s/config.html" $block_type }} {{ if templates.Exists (printf "_partials/%s" $widget_config_file) }} {{ $hash_id := $block.id | default (printf "section-%s" (replace $block_type "." "-")) }} {{ $widget_args := dict "wcPage" $page "wcBlock" $block "wcIdentifier" $hash_id }} {{ partial $widget_config_file $widget_args }} {{ end }} {{ end }} {{ end }} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/article.html ================================================ {{- $page := .page }} {{ $summary := .summary }} {{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }} {{/* Get schema type. */}} {{ $schema := "Article" }} {{ if eq $page.Type "blog" }} {{ $schema = "BlogPosting" }} {{ end }} {{ $author := partial "functions/get_author_name" $page }} {{ $branding := partialCached "functions/get_branding" $page "branding" }} {{ $publisher := $branding.organization }} {{ $logo_url := partial "functions/get_logo_url" $page -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/breadcrumbs.html ================================================ {{- $page := .page -}} {{- if not $page.IsHome -}} {{- $items := slice -}} {{- $position := 1 -}} {{- with site.Home -}} {{- $home_title := .LinkTitle | default site.Title | default "Home" -}} {{- $item := dict "@type" "ListItem" "position" $position "name" ($home_title | plainify) "item" (dict "@id" .Permalink "name" ($home_title | plainify)) -}} {{- $items = $items | append $item -}} {{- $position = add $position 1 -}} {{- end -}} {{- with $page.Ancestors -}} {{- range .Reverse -}} {{- if not .IsHome -}} {{- $item := dict "@type" "ListItem" "position" $position "name" (.LinkTitle | plainify) "item" (dict "@id" .Permalink "name" (.LinkTitle | plainify)) -}} {{- $items = $items | append $item -}} {{- $position = add $position 1 -}} {{- end -}} {{- end -}} {{- end -}} {{- $item := dict "@type" "ListItem" "position" $position "name" ($page.LinkTitle | default $page.Title | plainify) "item" (dict "@id" $page.Permalink "name" ($page.LinkTitle | default $page.Title | plainify)) -}} {{- $items = $items | append $item -}} {{- if gt (len $items) 1 -}} {{- $breadcrumb := dict "@context" "https://schema.org" "@type" "BreadcrumbList" "itemListElement" $items -}} {{- end -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/business.html ================================================ {{- $sharing_image := resources.GetMatch (path.Join "media" "sharing.*") -}} {{- $branding := partialCached "functions/get_branding" . "branding" -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/collectionpage.html ================================================ {{- $page := .page -}} {{- $summary := .summary -}} {{- $language := $page.Language.LanguageCode | default site.LanguageCode | default "en" -}} {{- $description := $summary | default ($page.Params.summary | default $page.Summary) -}} {{- $description = $description | plainify -}} {{- $listed_pages := $page.Pages -}} {{- if $page.IsHome -}} {{- $listed_pages = slice -}} {{- else if $listed_pages -}} {{- $listed_pages = $listed_pages.ByDate.Reverse -}} {{- else -}} {{- $listed_pages = slice -}} {{- end -}} {{- $items := slice -}} {{- $max_items := 10 -}} {{- range $index, $item := $listed_pages -}} {{- if ge $index $max_items -}} {{- break -}} {{- end -}} {{- $items = $items | append (dict "@type" "ListItem" "position" (add $index 1) "item" (dict "@type" "WebPage" "@id" $item.Permalink "name" ($item.LinkTitle | default $item.Title | plainify) "url" $item.Permalink ) ) -}} {{- end -}} {{- $item_list := dict "@type" "ItemList" "itemListOrder" "Descending" "numberOfItems" (len $items) "itemListElement" $items -}} {{- $collection := dict "@context" "https://schema.org" "@type" "CollectionPage" "@id" $page.Permalink "url" $page.Permalink "name" ($page.LinkTitle | default $page.Title | plainify) "inLanguage" $language "isPartOf" (dict "@type" "WebSite" "@id" site.BaseURL "url" site.BaseURL "name" site.Title ) -}} {{- if $description }} {{- $collection = merge $collection (dict "description" $description) -}} {{- end -}} {{- if not $page.Lastmod.IsZero }} {{- $collection = merge $collection (dict "dateModified" ($page.Lastmod.Format "2006-01-02T15:04:05Z07:00")) -}} {{- end -}} {{- if gt (len $items) 0 }} {{- $collection = merge $collection (dict "mainEntity" $item_list) -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/event.html ================================================ {{ $page := .page }} {{ $summary := .summary }} {{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }} {{ $author := partial "functions/get_author_name" $page }} ================================================ FILE: modules/blox/layouts/_partials/jsonld/faqpage.html ================================================ {{- $page := .page }} {{ $summary := .summary }} {{/* Get FAQ items - can be from params.faqs, Page.Store (from init.html), or child pages */}} {{ $faq_items := slice }} {{/* Method 1: FAQ items defined in front matter */}} {{ if $page.Params.faqs }} {{ $faq_items = $page.Params.faqs }} {{ end }} {{/* Method 2: Extract from Page.Store (populated by init.html to avoid race conditions) */}} {{ if not $faq_items }} {{ with $page.Store.Get "faq_items" }} {{ $faq_items = . }} {{ end }} {{ end }} {{/* Method 3: Auto-generate from child pages in a FAQ section */}} {{ if and (not $faq_items) ($page.IsSection) }} {{ range $page.RegularPages }} {{ $faq_items = $faq_items | append (dict "question" (.Params.question | default .Title) "answer" (.Params.answer | default .Summary | default (.Content | plainify))) }} {{ end }} {{ end }} {{/* Only output FAQ schema if we have FAQ items */}} {{ if $faq_items }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/jsonld/main.html ================================================ {{ $page := .page }} {{ $summary := .summary }} {{ $site_type := site.Params.hugoblox.identity.type | humanize | default "Person" }} {{- if $page.IsHome -}} {{ partialCached "jsonld/website.html" $page }} {{ if ne $site_type "Person" }} {{ partial "jsonld/business.html" $page }} {{ end }} {{- else if $page.IsPage -}} {{ if (eq $page.Type "blog") | or (eq $page.Type "publications") | or (eq $page.Type "projects") }} {{ partial "jsonld/article.html" (dict "page" $page "summary" $summary) }} {{ end }} {{ if eq $page.Type "events" }} {{ partial "jsonld/event.html" (dict "page" $page "summary" $summary) }} {{ end }} {{/* Q&A Page - individual question/answer page */}} {{ if eq $page.Type "questions" }} {{ partial "jsonld/qapage.html" (dict "page" $page "summary" $summary) }} {{ end }} {{/* FAQ Page type */}} {{ if eq $page.Type "faq" }} {{ partial "jsonld/faqpage.html" (dict "page" $page "summary" $summary) }} {{ end }} {{ partial "jsonld/webpage.html" (dict "page" $page "summary" $summary) }} {{- else -}} {{ partial "jsonld/collectionpage.html" (dict "page" $page "summary" $summary) }} {{- end }} {{ if not $page.IsHome }} {{ partial "jsonld/breadcrumbs.html" (dict "page" $page) }} {{ end }} {{/* FAQ content - can appear on any page type including landing pages and homepage */}} {{ if or ($page.Params.faq_page) ($page.Params.faqs) }} {{ partial "jsonld/faqpage.html" (dict "page" $page "summary" $summary) }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/jsonld/qapage.html ================================================ {{- $page := .page }} {{ $summary := .summary }} {{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }} {{/* Get author and publisher info */}} {{ $author := partial "functions/get_author_name" $page }} {{ $branding := partialCached "functions/get_branding" $page "branding" }} {{ $publisher := $branding.organization }} {{/* Extract question - prioritize explicit param, fallback to title */}} {{ $question := $page.Params.question | default $page.Title }} {{/* Extract answer - prioritize explicit param, fallback to summary, then content */}} {{ $answer := "" }} {{ if $page.Params.answer }} {{ $answer = $page.Params.answer }} {{ else if $page.Params.summary }} {{ $answer = $page.Params.summary }} {{ else }} {{ $answer = $page.Content | plainify | truncate 500 }} {{ end }} {{/* Get upvote/downvote counts if available */}} {{ $upvote_count := $page.Params.upvote_count | default 0 }} {{ $downvote_count := $page.Params.downvote_count | default 0 }} ================================================ FILE: modules/blox/layouts/_partials/jsonld/webpage.html ================================================ {{- $page := .page -}} {{- $summary := .summary -}} {{- $language := $page.Language.LanguageCode | default site.LanguageCode | default "en" -}} {{- $description := $summary | default ($page.Params.summary | default $page.Summary) -}} {{- $description = $description | plainify -}} {{- $image := partial "functions/get_featured_image" $page -}} {{- if not $image -}} {{- $image = partial "functions/get_site_icon" 512 -}} {{- end -}} {{- $image_obj := dict -}} {{- with $image -}} {{- $image_obj = dict "@type" "ImageObject" "url" .Permalink -}} {{- with .Width }}{{ $image_obj = merge $image_obj (dict "width" .) }}{{ end -}} {{- with .Height }}{{ $image_obj = merge $image_obj (dict "height" .) }}{{ end -}} {{- end -}} {{- $webpage := dict "@context" "https://schema.org" "@type" "WebPage" "@id" $page.Permalink "url" $page.Permalink "name" ($page.LinkTitle | default $page.Title | plainify) "inLanguage" $language "isPartOf" (dict "@type" "WebSite" "@id" site.BaseURL "url" site.BaseURL "name" site.Title ) -}} {{- if $description }} {{- $webpage = merge $webpage (dict "description" $description) -}} {{- end -}} {{- if not $page.Date.IsZero }} {{- $webpage = merge $webpage (dict "datePublished" ($page.Date.Format "2006-01-02T15:04:05Z07:00")) -}} {{- end -}} {{- if not $page.Lastmod.IsZero }} {{- $webpage = merge $webpage (dict "dateModified" ($page.Lastmod.Format "2006-01-02T15:04:05Z07:00")) -}} {{- end -}} {{- with $image_obj }} {{- $webpage = merge $webpage (dict "primaryImageOfPage" .) -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/jsonld/website.html ================================================ ================================================ FILE: modules/blox/layouts/_partials/landing_page.html ================================================ {{/* Load Hugo Blox - HBX resolver-based system Blocks live in `blox//block.html` and are mounted to `layouts/_partials/hbx/blocks//block.html`. Landing pages must specify `sections: [{ block: '', ... }]`. */}} {{/* Use unified sections source */}} {{- $sections := partial "hbx/sections.html" . -}} {{ range $index, $block := $sections }} {{/* Do not show sections intended only for the demo site. */}} {{ if or (not $block.demo) ($block.demo | and (eq (os.Getenv "HUGO_BLOX_DEMO") "true")) }} {{ partial "functions/parse_block_v3" (dict "page" $ "block" $block) }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/libraries.html ================================================ {{/* Load Preact for component-based blocks */}} {{/* Check if any blocks on this page use Preact (set by init.html) */}} {{ if .Page.Store.Get "needs_preact" }} {{ $preact_blocks := .Page.Store.Get "preact_blocks" | default slice }} {{/* Preact is now bundled with each template via js.Build and node_modules */}} {{/* Build and load each Preact block's client script */}} {{ range $block_type := $preact_blocks }} {{ $client_path := printf "js/hbx/blocks/%s/client.jsx" $block_type }} {{ $client_jsx := resources.Get $client_path }} {{ if $client_jsx }} {{/* Build the client-side JSX using Hugo's official integration */}} {{ $jsx_opts := dict "targetPath" (printf "assets/js/preact-built/%s.js" $block_type) "JSX" "automatic" "JSXImportSource" "preact" "format" "iife" "minify" hugo.IsProduction "sourceMap" (cond hugo.IsDevelopment "external" "") }} {{ $built_jsx := $client_jsx | js.Build $jsx_opts }} {{ if hugo.IsProduction }} {{ $built_jsx = $built_jsx | fingerprint "sha256" }} {{ end }} {{ end }} {{ end }} {{ end }} {{/* Show site search? */}} {{ $show_search := site.Params.hugoblox.header.search | default false }} {{/* Hugo Blox Animations - load synchronously BEFORE Alpine.js to register components */}} {{ if .Page.Store.Get "has_animations" }} {{ $animations_js := resources.Get "js/hb-animations.js" | resources.Minify }} {{- if hugo.IsProduction -}} {{ $animations_js = $animations_js | fingerprint "sha256" }} {{- end -}} {{ end }} {{/* Load Alpine JS extension? */}} {{/* Alpine is needed for search modal and other interactive components */}} {{ $needs_alpine := or (.Page.Store.Get "has_alpine") $show_search (.Page.Store.Get "has_animations") }} {{ if $needs_alpine }} {{ $alpine_js := resources.Get "dist/lib/alpinejs/cdn.min.js" }} {{ $alpine_js = $alpine_js | resources.Fingerprint "sha256" }} {{ end }} {{/* Hugo Blox Search JavaScript (CSS is in main.css) */}} {{ if $show_search }} {{ $search_js := resources.Get "js/hb-search.js" | resources.Minify }} {{- if hugo.IsProduction -}} {{ $search_js = $search_js | fingerprint "sha256" }} {{- end -}} {{ end }} {{/* Mermaid */}} {{ if (.Page.Store.Get "has_mermaid") }} {{ $mermaid_js := resources.Get "dist/lib/mermaid/mermaid.min.js" }} {{ $mermaid_config_js := resources.Get "js/hb-mermaid-config.js" }} {{ $mermaid_config_js = $mermaid_config_js | resources.Minify }} {{ $mermaid_bundle := slice $mermaid_js $mermaid_config_js | resources.Concat "js/mermaid.bundle.js" | resources.Fingerprint "sha256" }} {{ end }} {{/* Markmap */}} {{ if (.Page.Store.Get "has_markmap") }} {{ $markmap_js := resources.Get "dist/lib/markmap/index.js" }} {{ $markmap_js = $markmap_js | resources.Minify | resources.Fingerprint "sha256" }} {{ end }} {{/* Katex */}} {{ if (.Page.HasShortcode "math") | or .Params.math | or site.Params.hugoblox.content.math.enable }} {{ $katex_css := resources.Get "dist/lib/katex/katex.min.css" }} {{ $katex_css = $katex_css | resources.Fingerprint "sha256" }} {{ $katex_js := resources.Get "dist/lib/katex/katex.min.js" }} {{ $katex_js = $katex_js | resources.Fingerprint "sha256" }} {{ $katex_render_js := resources.Get "dist/lib/katex/auto-render.min.js" }} {{ $katex_config_js := resources.Get "js/katex-config.js" }} {{ $katex_config_js = $katex_config_js | resources.Minify }} {{ $katex_bundle := slice $katex_render_js $katex_config_js | resources.Concat "js/katex-renderer.js" | resources.Fingerprint "sha256" }} {{ $katex_fonts := resources.Match "dist/lib/katex/fonts/*" }} {{ range $katex_fonts }} {{ .Publish }} {{ end }} {{ end }} {{/* Plotly */}} {{ if .Page.HasShortcode "chart" }} {{ $plotly_js := resources.Get "dist/lib/plotly/plotly.min.js" }} {{ $plotly_js = $plotly_js | resources.Fingerprint "sha256" }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/notification-container.html ================================================ {{/* Notification Container for toasts/alerts */}} {{/* This container is placed at the page level to ensure proper z-index and visibility */}} {{/* Used by hb-notifier.js module for showing toast notifications */}}
    ================================================ FILE: modules/blox/layouts/_partials/page_author.html ================================================ {{/* Author profile box */}} {{/* Don't show author box on normal pages or if author box disabled. */}} {{ if ne .Type "page" | and (not (or (eq site.Params.profile false) (eq .Params.profile false))) }} {{ $authors := .Params.authors }} {{/* If authors not set, fallback to superuser/owner from Scratch */}} {{ if (not $authors) }} {{ $superuser := .Scratch.Get "superuser_slug" }} {{ if $superuser }} {{ $authors = (slice $superuser) }} {{ end }} {{ end }} {{ if $authors }} {{ range $idx, $slug := $authors }} {{ $profile := partial "functions/get_author_profile" $slug }} {{ if $profile.has_data }} {{ partial "page_author_card" (dict "profile" $profile "page" .) }} {{ end }} {{ end }} {{ end }} {{end}}{{/* Show profile block */}} ================================================ FILE: modules/blox/layouts/_partials/page_author_card.html ================================================ {{ $profile := .profile }} {{ $page := .page }} {{ $site_type := site.Params.hugoblox.identity.type | humanize | default "Person" }} {{ $avatar_shape := site.Params.hugoblox.layout.avatar_shape | default "circle" }} {{ if $profile }} {{/* If it's a personal site and the profile is owner, link home */}} {{ $profile_url := printf "/authors/%s/" $profile.slug }} {{ if and (eq $site_type "Person") ($profile.is_owner) }} {{ $profile_url = site.BaseURL }} {{ end }} {{ $avatar := $profile.avatar }}
    {{ if $avatar }} {{ $isSVG := eq $avatar.MediaType.SubType "svg" }} {{ if $isSVG }} {{$profile.title}} {{ else }} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $avatar "mode" "fill" "aspect_ratio" "1:1" "anchor" "Center" "sizes" (slice 96 192 288 384) ) }} {{$profile.title}} {{ end }} {{ end }}
    {{ i18n "authors" }}
    {{if $profile_url}}{{end}} {{$profile.title}} {{if $profile_url}}{{end}} {{- with $profile.pronouns -}} ({{ . }}) {{- end -}}
    {{ with $profile.role }}
    {{. | markdownify | emojify}}
    {{end}} {{ with $profile.bio }}
    {{ . | markdownify | emojify }}
    {{ end }}
    {{ partial "social_links" (dict "Params" (dict "profiles" $profile.links)) }}
    {{end}}{{/* End Check for Author Profile */}} ================================================ FILE: modules/blox/layouts/_partials/page_edit.html ================================================ {{/* Add link to let visitors edit the page on GitHub. */}} {{/* Perform short-circuit check that page is backed by a file. */}} {{ if and .File .Params.editable | and site.Params.hugoblox.repository.url }} {{/* Get language subfolder for multilingual sites. */}} {{/* Limitations: the subfolder param, `.contentDir`, is unexposed in the Hugo `site` API so we attempt to workaround this issue. */}} {{ $content_dir := "content" }} {{ if site.Params.hugoblox.repository.content_dir }} {{ $content_dir = site.Params.hugoblox.repository.content_dir }} {{else}} {{/* Attempt to get content dir from the LanguagePrefix URI, but defaultContentLanguageInSubdir can break this assumption. */}} {{ $content_dir = cond site.IsMultiLingual (cond (ne .Site.LanguagePrefix "") (printf "%s%s" $content_dir .Site.LanguagePrefix) $content_dir) $content_dir }} {{end}}

    📝 {{ i18n "edit_page" | default "Edit this page" }}

    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/page_footer.html ================================================
    {{/* Moved to TOC sidebar */}} {{/* partial "page_edit" . */}} {{ partial "tags" . }} {{ partial "components/page_sharer" . }} {{ partial "page_author" . }} {{ partial "components/next-in-series" . }} {{ partial "page_related" . }} {{ partial "comments" . }}
    ================================================ FILE: modules/blox/layouts/_partials/page_links.html ================================================ {{ $is_list := .is_list }} {{ $page := .page }} {{/* Build normalized links (new API) */}} {{ $built := partial "functions/build_links" (dict "page" $page "is_list" $is_list) }} {{ $ctx := cond $is_list "list" "page" }} {{/* English fallbacks if i18n key is missing in a locale */}} {{ $fallbackByKey := dict "btn_pdf" "PDF" "btn_preprint" "Preprint" "btn_doi" "DOI" "btn_code" "Code" "btn_dataset" "Dataset" "btn_model" "Model" "btn_slides" "Slides" "btn_video" "Video" "btn_poster" "Poster" "btn_project" "Project" "btn_site" "Site" "btn_source" "Source Document" "btn_canonical" "Canonical" "btn_crosspost" "Crosspost" "btn_discussion" "Discussion" "btn_event" "Event" "btn_calendar" "Calendar" "btn_registration" "Registration" "btn_demo" "Demo" "btn_cite" "Cite" }} {{ range $built }} {{ if in .contexts $ctx }} {{ $url := .url | default "" }} {{ $scheme := (urls.Parse $url).Scheme }} {{ $target := "" }} {{ $rel := slice }} {{ with .rel }}{{ $rel = . }}{{ end }} {{ if not $scheme }} {{ with ($page.Resources.GetMatch $url) }} {{ $url = .RelPermalink }} {{ else }} {{ $url = $url | relURL }} {{ end }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\"" }} {{ $rel = $rel | append "noopener" }} {{ end }} {{ $classes := printf "hb-attachment-link %s" (cond $is_list "hb-attachment-link-small" "hb-attachment-link-large") }} {{ $label := .label }} {{ with .labelKey }} {{ if not $label }} {{ $label = (i18n .) | default (index $fallbackByKey .) | default "Link" }} {{ end }} {{ end }} {{ if not $label }} {{ $label = "Link" }} {{ end }} {{ if eq .type "bibtex" }} {{ else }} {{ partial "functions/get_icon" (dict "name" (.icon | default "hero/link") "attributes" "style=\"height: 1em\" class='inline-block'") }} {{ $label }} {{ end }} {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/page_links_div.html ================================================ {{/* Div wrapper around page links. Hidden if page has no links. */}} {{ $built := partial "functions/build_links" (dict "page" . "is_list" 0) }} {{ if gt (len $built) 0 }}
    {{ partial "page_links" (dict "page" . "is_list" 0) }}
    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/page_metadata_authors.html ================================================ {{/* Display author list. */}} {{- $authors := .Params.authors -}} {{ if $authors }} {{- if not (reflect.IsSlice $authors) -}} {{- $authors = slice $authors -}} {{- end -}} {{ range $index, $raw := $authors }} {{- $slug := $raw | urlize -}} {{- $profile := partial "functions/get_author_profile" (dict "slug" $slug "title" $raw) -}} {{- $termPage := site.GetPage (printf "/authors/%s" $slug) -}} {{- $display := $profile.title | default $raw -}} {{- $highlight_name := false -}} {{- if gt $index 0 }}, {{ end -}} {{- if $termPage -}} {{ $display }} {{- else -}} {{ $display }} {{- end -}} {{- if isset $.Params "author_notes" -}} {{- with (index $.Params.author_notes $index) -}}
    {{.}}
    {{- end -}} {{- end -}} {{- end -}} {{- end -}} ================================================ FILE: modules/blox/layouts/_partials/page_related.html ================================================ {{/* Show related/recommended content. */}} {{ if .Params.show_related }} {{ $related := site.RegularPages.Related . | first 5 }} {{ with $related }}

    {{ i18n "related" }}

    {{ end }} {{ end }} ================================================ FILE: modules/blox/layouts/_partials/site_footer.html ================================================
    {{ partial "functions/get_hook" (dict "hook" "footer-start" "context" .) }} {{/* Load footer block */}} {{- $footer_config := site.Params.hugoblox.footer | default dict -}} {{- $footer_section_name := partial "hbx/resolve-block-param" (dict "config" $footer_config "context" "footer") | default "minimal" -}} {{ $footer_section_path := printf "components/footers/%s.html" $footer_section_name }} {{ if not (templates.Exists (printf "_partials/%s" $footer_section_path)) }} {{ errorf "Check your `params.yaml`. Cannot find footer block at `layouts/_partials/%s`" $footer_section_path }} {{ end }} {{ partial $footer_section_path . }} {{/* Attribution - PLEASE DO NOT REMOVE THIS, SUPPORT OPEN SOURCE */}} {{/* Check for Pro license key */}} {{- $license_key := getenv "HUGO_BLOX_LICENSE" -}} {{- $has_pro_license := false -}} {{- if $license_key -}} {{/* Validate UUID v4 format */}} {{- $uuid_pattern := "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" -}} {{- $is_valid_format := findRE $uuid_pattern (lower $license_key) -}} {{- $has_pro_license = gt (len $is_valid_format) 0 -}} {{- end -}} {{/* Check user preference */}} {{- $wants_to_hide := site.Params.hugoblox.pro.hide_attribution | default false -}} {{/* Determine if we show attribution */}} {{- $show_attribution := true -}} {{- if $has_pro_license -}} {{/* Pro user - respect their choice */}} {{- $show_attribution = not $wants_to_hide -}} {{- else if $wants_to_hide -}} {{/* Free user trying to hide - show warning and attribution */}} {{- warnf "Attribution removal requires HugoBlox Premium. Get Premium at https://hugoblox.com/premium \nAlready purchased Premium? Reach out in the Premium Discord channel for support." -}} {{- $show_attribution = true -}} {{- end -}} {{- if $show_attribution -}} {{- $base := "https://hugoblox.com" -}} {{- $tid := "" -}} {{- $ref := .Site.Params.hugoblox.pro.affiliate_code | default "" -}} {{/* Detect Template */}} {{ $hugoblox_file := "" }} {{ if fileExists "hugoblox.yaml" }} {{ $hugoblox_file = readFile "hugoblox.yaml" }} {{ if $hugoblox_file }} {{ $hugoblox_data := $hugoblox_file | transform.Unmarshal }} {{ $tid = $hugoblox_data.template.id | default "" }} {{ end }} {{ end }} {{/* Per-site variant selection */}} {{- $brandOptions := slice "Hugo Blox" "Hugo Blox Kit" "Hugo Blox — Open Source" -}} {{- $ctaWhenTemplate := slice "Duplicate this template →" "Clone this template →" "Build yours →" "Create yours →" "Build your site →" "Create your site →" -}} {{- $ctaNoTemplate := slice "Start free →" "Build yours →" "Create yours →" "Build your site →" "Create your site →" -}} {{- $seed := .Site.BaseURL -}} {{- $h := md5 $seed -}} {{- $digits := replaceRE "[^0-9]" "" $h -}} {{- if lt (len $digits) 6 }}{{- $digits = printf "%s123456" $digits -}}{{- end -}} {{- $first6 := substr $digits 0 6 -}} {{/* Fix for Hugo's int() function treating leading zeros as octal numbers. Strings like "095186" fail because 8 and 9 aren't valid octal digits. Replace leading zero with 1 to ensure valid decimal parsing. */}} {{- if eq (substr $first6 0 1) "0" -}} {{- $first6 = printf "1%s" (substr $first6 1 5) -}} {{- end -}} {{- $n := int $first6 -}} {{- $brandText := index $brandOptions (mod $n (len $brandOptions)) -}} {{- $ctaText := cond (ne $tid "") (index $ctaWhenTemplate (mod $n (len $ctaWhenTemplate))) (index $ctaNoTemplate (mod $n (len $ctaNoTemplate))) -}} {{- $target := cond (ne $tid "") (printf "%s/templates/%s/start" $base $tid) (printf "%s/start" $base) -}} {{- $brandHref := printf "%s?utm_source=site_footer&utm_medium=referral&utm_campaign=poweredby_oss&utm_content=brand_%s" $base (cond (ne $tid "") (printf "%s" $tid) "na") -}} {{- $ctaHref := printf "%s?utm_source=site_footer&utm_medium=referral&utm_campaign=poweredby_oss&utm_content=cta_%s" $target (cond (ne $tid "") (printf "%s" $tid) "na") -}} {{- if ne $ref "" -}} {{- $brandHref = printf "%s&ref=%s" $brandHref $ref -}} {{- $ctaHref = printf "%s&ref=%s" $ctaHref $ref -}} {{- end -}}

    {{ $published_with := "Made with {hugoblox}." }} {{ $i18n_published_with := i18n "published_with" | default $published_with }} {{ $defaultEnText := "Build yours →" }} {{ $i18n_ctaText := i18n "poweredby_button" | default $ctaText }} {{ if eq $i18n_ctaText $defaultEnText }} {{ $i18n_ctaText = $ctaText }} {{ end }} {{ if not (findRE "{hugoblox}" $i18n_published_with) }} {{ warnf "Please attribute Hugo Blox using `{hugoblox}` in the i18n `published_with` text or sponsor with All Access to remove attribution." }} {{ $i18n_published_with = $published_with }} {{ end }} {{ $i18n_published_with = replace $i18n_published_with "{hugoblox}" (printf "%s" $brandHref $brandText) | safeHTML }} {{ $i18n_published_with = replace $i18n_published_with "{repo_link}" "" | safeHTML }} {{ $i18n_published_with = replace $i18n_published_with "{/repo_link}" "" | safeHTML }} {{ $i18n_published_with | safeHTML }} {{ $i18n_ctaText }}

    {{- end -}}{{/* end $show_attribution */}}
    ================================================ FILE: modules/blox/layouts/_partials/site_footer_license.html ================================================ {{/* Display copyright license. */}} {{ $branding := partialCached "functions/get_branding" . "branding" }} {{ $page_copyright := .Params.copyright | default dict }} {{ $site_copyright := site.Params.hugoblox.copyright | default dict }} {{ $copyright_license := $page_copyright.license | default $site_copyright.license | default dict }} {{ $notice := $page_copyright.notice | default $site_copyright.notice }} {{ $license_type := $copyright_license.type | default "cc" }} {{ $license_label := "" }} {{ $license_url := "" }} {{ $show_cc_icons := false }} {{ $allow_commercial := $copyright_license.allow_commercial | default false }} {{ $allow_derivatives := $copyright_license.allow_derivatives | default false }} {{ $share_alike := $copyright_license.share_alike | default true }} {{ if eq $license_type "cc" }} {{ $cc_code := "by" }} {{ if not $allow_commercial }} {{ $cc_code = printf "%s-nc" $cc_code }} {{end}} {{ if and $allow_derivatives $share_alike }} {{ $cc_code = printf "%s-sa" $cc_code }} {{ else if not $allow_derivatives }} {{ $cc_code = printf "%s-nd" $cc_code }} {{end}} {{ $license_url = printf "https://creativecommons.org/licenses/%s/4.0" ($cc_code | urlize) }} {{ $license_label = printf "CC %s 4.0" $license_url (replace $cc_code "-" " " | upper) }} {{ $show_cc_icons = true }} {{ else if eq $license_type "custom" }} {{ $custom_label := $copyright_license.label | default $copyright_license.text | default "" }} {{ $custom_url := $copyright_license.url | default "" }} {{ if and $custom_label $custom_url }} {{ $license_label = printf "%s" $custom_url $custom_label }} {{ else }} {{ $license_label = $custom_label }} {{ end }} {{ end }} {{ if and $show_cc_icons $license_url }} {{ end }} {{ with $notice }}

    {{ $processed := replace . "{year}" now.Year }} {{ $processed = replace $processed "{name}" $branding.organization }} {{ $processed = replace $processed "{license}" $license_label }} {{ $processed | markdownify }}

    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/site_head.html ================================================ {{ $scr := .Scratch }} {{/* EXTENSIBILITY HOOK: HEAD-START */}} {{ partial "functions/get_hook" (dict "hook" "head-start" "context" .) }} {{ if .Params.private }} {{- end -}} {{/* Attempt to load superuser/person from data. */}} {{ $superuser_name := "" }} {{ $superuser_slug := "" }} {{ $superuser_role := "" }} {{/* Prefer is_owner flag, fallback to slug 'me' */}} {{ $authors := partialCached "functions/get_authors_data" . site.Language.Lang }} {{ range $slug, $data := $authors }} {{ if and (not $superuser_slug) ($data.is_owner) }} {{ $superuser_slug = $slug }} {{ end }} {{ end }} {{ if and (eq $superuser_slug "") (index $authors "me") }} {{ $superuser_slug = "me" }} {{ end }} {{ if $superuser_slug }} {{ $profile := partial "functions/get_author_profile" (dict "slug" $superuser_slug) }} {{ $superuser_name = $profile.title }} {{ $superuser_role = $profile.role }} {{ end }} {{ $scr.Set "superuser_slug" $superuser_slug }}{{/* Set superuser globally for author rendering. */}} {{ with $superuser_name }}{{ end }} {{/* Generate page description. */}} {{ $desc := "" }} {{ $desc = partial "functions/get_summary" . }} {{ if site.Params.hugoblox.identity.description | and (not $desc) }} {{ $desc = site.Params.hugoblox.identity.description }} {{ end }} {{ if not $desc }} {{ $desc = $superuser_role }} {{ end }} {{ range .Translations }} {{ end }} {{/* Hugo Blox Theme Engine Initialization */}} {{/* Uses get_theme_config helper for backward-compatible config resolution */}} {{ $theme_config := partialCached "functions/get_theme_config" . "theme_config" }} {{ partial "functions/theme_generator.html" $theme_config }} {{/* Demo Theme Pack Styles (if enabled) */}} {{ if site.Params.hugoblox.header.theme_picker }} {{ partial "functions/demo_theme_styles.html" (dict "typography" $theme_config.typography "layout" $theme_config.layout) }} {{ end }} {{/* Tailwind CSS v4 Processing */}} {{/* Use templates.Defer to process CSS after all content is analyzed */}} {{ with (templates.Defer (dict "key" "tailwind-css")) }} {{ partial "css.html" . }} {{ end }} {{/* Load community blox styles */}} {{ $hb_community_styles := resources.Match "dist/community/blox/**.css" }} {{ with $hb_community_styles }} {{ $hb_community_styles = $hb_community_styles | resources.Concat "css/community-hugo-blox.css" }} {{- if hugo.IsProduction -}} {{- $hb_community_styles = $hb_community_styles | minify | fingerprint "sha256" -}} {{- end -}} {{ end }} {{ if fileExists "assets/css/custom.css" }} {{ $styles := resources.Get "css/custom.css" | minify | fingerprint "sha256" }} {{ end }} {{/* Externalized init scripts for CSP-friendly head */}} {{- $hb_head := resources.Get "js/hb-head.js" | js.Build | resources.Minify -}} {{- if hugo.IsProduction -}} {{- $hb_head = $hb_head | fingerprint "sha256" -}} {{- end -}} {{/* Analytics & Verification */}} {{/* !CACHED! All analytics and verification code is at site level */}} {{ partialCached "blox-analytics/index" . }} {{/* RSS Feed */}} {{ $branding := partialCached "functions/get_branding" . "branding" }} {{ with .OutputFormats.Get "RSS" }} {{ end }} {{/* Progressive Web App (PWA) Icon - SVG preferred */}} {{ $icon := partial "functions/get_site_icon" 32 }} {{ with $icon.resource }} {{ end }} {{/* Apple Touch Icon - requires PNG */}} {{ $icon_apple := partial "functions/get_site_icon" 180 }} {{ if not $icon_apple.is_svg }} {{ with $icon_apple.resource }} {{ end }} {{ else }} {{/* SVG icon - need PNG fallback for Apple */}} {{ $icon_png := resources.Get "media/icon.png" }} {{ with $icon_png }} {{ $apple_icon := .Fill "180x180 Center" }} {{ end }} {{ end }} {{/* Get page image for sharing. */}} {{ $sharing_image := resources.GetMatch (path.Join "media" "sharing.*") }} {{ $featured_image := (.Resources.ByType "image").GetMatch "*featured*" }} {{ $avatar_image := (.Resources.ByType "image").GetMatch "avatar*" }} {{ $has_logo := fileExists "assets/media/logo.png" | or (fileExists "assets/media/logo.svg") }} {{ $og_image := "" }} {{ $twitter_card := "summary_large_image" }} {{ if and (eq .Kind "term") (eq .Data.Singular "author") }} {{/* Try data-driven avatar for author term pages */}} {{ $termSlug := .Data.Term | urlize }} {{ $profile := partial "functions/get_author_profile" (dict "slug" $termSlug) }} {{ with $profile.avatar }} {{ $og_image = (.Fill "540x540 Center").Permalink }} {{ $twitter_card = "summary" }} {{ end }} {{ else if (and (eq .Kind "term") $avatar_image) }} {{ $og_image = ($avatar_image.Fill "540x540 Center").Permalink }} {{ $twitter_card = "summary" }} {{ else if $featured_image }} {{ $og_image = $featured_image.Permalink }} {{ else if $sharing_image }} {{ $og_image = $sharing_image.Permalink }} {{ else if $has_logo }} {{/* !CACHED! Can safely cache this site logo variant */}} {{ $logo_data := partialCached "functions/get_logo" (dict "constraint" "fit" "size" 300) "logo_og" }} {{ with $logo_data.resource }} {{ $og_image = .Permalink }} {{ end }} {{ $twitter_card = "summary" }} {{ else }} {{ $icon_og := partial "functions/get_site_icon" 512 }} {{ with $icon_og.resource }} {{ $og_image = .Permalink }} {{ end }} {{ $twitter_card = "summary" }} {{ end }} {{ $scr.Set "og_image" $og_image }}{{/* Set `og_image` globally for `rss.xml`. */}} {{ $title := "" }} {{ with .Params.seo.title }} {{ $title = replace . "{brand}" $branding.site_title }} {{ else }} {{ $title = .Title | default $branding.site_title }} {{ if ne $title $branding.site_title }}{{ $title = printf "%s | %s" $title $branding.site_title }}{{ end }} {{ end }} {{ with site.Params.hugoblox.identity.social.twitter }} {{ end }} {{- with $og_image -}} {{- end -}} {{ if .IsPage }} {{ if not .PublishDate.IsZero }} {{ else if not .Date.IsZero }} {{ end }} {{ if not .Lastmod.IsZero }}{{ end }} {{ else }} {{ if not .Date.IsZero }} {{ end }} {{ end }} {{ partial "jsonld/main" (dict "page" . "summary" $desc) }} {{$title}} {{/* Typography: font loading, font families, and sizes */}} {{ partial "functions/typography.html" $theme_config }} {{/* Layout tokens: radius and spacing */}} {{ partial "functions/layout_tokens.html" $theme_config }} {{ if .Params.design.background.image.filename }} {{/* See Hugo note on linking assets in styles: https://github.com/gohugoio/hugoThemes#common-permalink-issues */}} {{ $bg_img := resources.Get (printf "media/%s" .Params.design.background.image.filename) }} {{ if $bg_img }} {{/* Exception for SVG as Hugo doesn't yet support image processing on SVG. */}} {{ if ne $bg_img.MediaType.SubType "svg" }} {{ $bg_img = $bg_img.Fit "1920x1920 webp" }} {{ end }} {{ else }} {{ errorf "Couldn't find page background `%s` in the `assets/media/` folder - please add it." .Params.design.background.image.filename }} {{ end }} {{ end }} {{/* Init prior to auto-chunking/bundling scripts due to Hugo concurrency issues */}} {{/* !CACHED! Initialized once at site level and then cached for each page */}} {{- partialCached "init.html" . "hb_init_once" -}} {{ $js_license := printf "/*! Hugo Blox Kit Tailwind UI v%s | https://hugoblox.com/ */\n" site.Data.hugoblox.version }} {{ $js_license := $js_license | printf "%s/*! Copyright 2016-present George Cushen (https://georgecushen.com/) */\n" }} {{ $js_license := $js_license | printf "%s/*! License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */\n" }} {{ $js_bundle_head := $js_license | resources.FromString "js/bundle-head.js" }} {{ $i18n := dict "copy" (i18n "btn_copy") "copied" (i18n "btn_copied" | default "Copied") }} {{ $js_params := dict "hugoEnvironment" hugo.Environment "i18n" $i18n }} {{ $js_hugoblox := resources.Get "js/hb-code-copy.js" | js.Build (dict "targetPath" (printf "js/hugoblox-core-%s.js" .Lang ) "params" $js_params) }} {{ $js_hugoblox := $js_hugoblox | resources.Minify }} {{- $js_theme := resources.Get "js/hb-theme.js" | resources.Minify -}} {{- $js_lang := resources.Get "js/hb-i18n.js" | resources.Minify -}} {{- $js_nav := resources.Get "js/hb-nav.js" | resources.Minify -}} {{- $js_sidebar := resources.Get "js/hb-sidebar.js" | resources.Minify -}} {{- $js_notifier := resources.Get "js/hb-notifier.js" | js.Build (dict "targetPath" (printf "js/hb-notifier-%s.js" .Lang ) "params" $js_params) | resources.Minify -}} {{- $js_clipboard := resources.Get "js/hb-clipboard.js" | js.Build (dict "targetPath" (printf "js/hb-clipboard-%s.js" .Lang ) "params" $js_params) | resources.Minify -}} {{- $js_citation := resources.Get "js/hb-citation.js" | js.Build (dict "targetPath" (printf "js/hb-citation-%s.js" .Lang ) "params" $js_params) | resources.Minify -}} {{/* Start with the core scripts */}} {{ $js_bundle_contents := slice $js_bundle_head $js_hugoblox $js_theme $js_lang $js_nav $js_sidebar $js_notifier $js_clipboard $js_citation }} {{/* Discover and include block-specific JavaScript */}} {{- with partial "functions/get-block-scripts.html" . -}} {{ $js_bundle_contents = $js_bundle_contents | append . }} {{- end -}} {{ $js_bundle := $js_bundle_contents | resources.Concat (printf "js/hugo-blox-%s.min.js" .Lang) }} {{- if hugo.IsProduction -}} {{ $js_bundle = $js_bundle | fingerprint "sha256" }} {{- end -}} {{/* Load Third-Party Libraries */}} {{ partial "libraries.html" . }} {{/* EXTENSIBILITY HOOK: HEAD-END */}} {{ partial "functions/get_hook" (dict "hook" "head-end" "context" .) }} ================================================ FILE: modules/blox/layouts/_partials/social_links.html ================================================ {{ if .Params.profiles }}
    {{ range $links := .Params.profiles }} {{ $link := .url }} {{ $scheme := (urls.Parse $link).Scheme }} {{ $target := "" }} {{ if not $scheme }} {{ $link = .url | relLangURL }} {{ else if in (slice "http" "https") $scheme }} {{ $target = "target=\"_blank\" rel=\"noopener\" rel=\"me noopener noreferrer\"" }} {{ end }} {{ partial "functions/get_icon" (dict "name" .icon "attributes" "style=\"height: 1em;\"") }} {{ end }}
    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/tags.html ================================================ {{ if .Params.tags }}
    {{ range $index, $value := (.GetTerms "tags") }} {{ .LinkTitle }} {{ end }}
    {{ end }} ================================================ FILE: modules/blox/layouts/_partials/tailwind_sources.html ================================================ {{/* Hugo Blox: Dynamic Tailwind @source generation for Hugo modules */}} {{/* Documentation: https://hugoblox.com/docs/ */}} {{/* License: https://github.com/HugoBlox/kit/blob/main/LICENSE.md */}} {{/* This partial generates Tailwind CSS @source directives that tell Tailwind where to scan for CSS classes. It provides a robust bridge between Hugo's virtual filesystem (which includes module mounts) and Tailwind's real filesystem scanner. */}} {{ $paths := slice }} {{/* 1. Always scan the site's source files. */}} {{ $paths = $paths | append `content/**/*.md` }} {{ $paths = $paths | append `layouts/**/*.html` }} {{ $paths = $paths | append `assets/js/**/*.js` }} {{ $paths = $paths | append `assets/js/**/*.jsx` }} {{ $paths = $paths | append `assets/js/**/*.tsx` }} {{ $paths = $paths | append `hugo_stats.json` }} {{/* 2. Crucially, scan Hugo's generated JS output from Preact components. These files are built by Hugo's `js.Build` into a predictable location within the project's `assets` directory, making them a reliable source for Tailwind to scan. This step happens before Tailwind runs, thanks to `templates.Defer` in `site_head.html`. */}} {{ $paths = $paths | append `assets/js/preact-built/**/*.js` }} {{/* 3. Comprehensive class extraction from Preact JSX/TSX source files. Hugo's virtual filesystem mounts block JSX/TSX into assets/js/hbx/blocks/. Tailwind's @source file paths only work on the real filesystem, but these files exist only in Hugo's virtual FS (or in a module cache for remote modules). So we read the file content via resources.Match and extract class candidates inline. Strategy: Extract ALL string literal content — not just class= attributes. This catches classes in any pattern: - Static attrs: class="gap-8 items-center" - JSX expressions: class={"gap-8 items-center"} - Template literals: class={`gap-8 ${cond ? "md:grid" : ""}`} - Utility fns: cn("gap-8", condition && "md:grid-cols-2") Tailwind's scanner automatically ignores non-class tokens (import paths, error messages, etc.), so false positives are harmless. */}} {{ $all_jsx := resources.Match "js/hbx/**/*.jsx" }} {{ $all_tsx := resources.Match "js/hbx/**/*.tsx" }} {{ $extracted_classes := slice }} {{ range $f := $all_jsx | append $all_tsx }} {{ $code := $f.Content }} {{/* A) Extract content of all double-quoted strings */}} {{ $dq_matches := findRE `"[^"]*"` $code }} {{ range $m := $dq_matches }} {{ $str := strings.TrimPrefix `"` (strings.TrimSuffix `"` $m) }} {{ range split $str " " }} {{ $t := strings.TrimSpace . }} {{/* Filter out tokens with unsafe characters (braces, quotes, parens) */}} {{ if and $t (not (findRE `[\{\}\(\)"';]` $t)) }} {{ $extracted_classes = $extracted_classes | append $t }} {{ end }} {{ end }} {{ end }} {{/* B) Extract static parts of template literals (backtick strings) */}} {{/* Removes ${...} interpolations, keeping surrounding text */}} {{ $bt_matches := findRE "`[^`]*`" $code }} {{ range $m := $bt_matches }} {{ $str := strings.TrimPrefix "`" (strings.TrimSuffix "`" $m) }} {{ $static := replaceRE `\$\{[^}]*\}` " " $str }} {{ range split $static " " }} {{ $t := strings.TrimSpace . }} {{/* Filter out tokens with unsafe characters (braces, quotes, parens) */}} {{ if and $t (not (findRE `[\{\}\(\)"';]` $t)) }} {{ $extracted_classes = $extracted_classes | append $t }} {{ end }} {{ end }} {{ end }} {{ end }} {{ $extracted_classes = $extracted_classes | uniq }} {{ range $class := $extracted_classes }} @source inline("{{ $class }}"); {{ end }} {{/* Generate the @source rules */}} {{ range $paths }} @source "{{ . }}"; {{ end }} ================================================ FILE: modules/blox/layouts/_partials/views/article-grid--end.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/article-grid--start.html ================================================ {{ $columns := .config.columns | default 2 }} {{ $len := .config.len | default 2 }} {{/* NOTE: dynamic `md:grid-cols-{{$columns}}` class requires Tailwind exception */}}
    ================================================ FILE: modules/blox/layouts/_partials/views/article-grid.html ================================================ {{- partial "views/card.html" . -}} ================================================ FILE: modules/blox/layouts/_partials/views/card--end.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/card--start.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/card.html ================================================ {{ $item := .item }} {{ $link := $item.RelPermalink }} {{ $target := "" }} {{ if $item.Params.external_link }} {{ $link = $item.Params.external_link }} {{ $target = "target=\"_blank\" rel=\"noopener\"" }} {{ end }} {{ $resource := partial "functions/get_featured_image.html" $item }} {{ $anchor := "Center" }} {{ if and $item.Params.image (reflect.IsMap $item.Params.image) }} {{ $anchor = $item.Params.image.focal_point | default "Center" }} {{ end }} {{ $fill_image := .config.fill_image | default true }} {{ $showDate := .config.show_date | default true }} {{ $showReadTime := .config.show_read_time | default true }} {{ $showReadMore := .config.show_read_more | default true }} {{ $hasMeta := or $showDate $showReadTime $showReadMore }} {{ $index := .index }} {{ $isEvent := eq $item.Type "events" }} {{ $event_dates := "" }} {{ if $isEvent }} {{ $event_dates = partial "functions/get_event_dates" $item }} {{ end }}
    {{ with $item.Params.content_meta }} {{ if .trending }}
    {{ i18n "trending" | default "Trending" }}
    {{ end }} {{ end }} {{ with $resource }} {{ if strings.Contains .MediaType.SubType "svg" }} {{ $item.Title | plainify }} featured image {{ else if ne .MediaType.SubType "gif" }} {{ $original_image := "" }} {{ if $fill_image }} {{ $original_image = .Fill (printf "800x450 %s" $anchor) }} {{ else }} {{ $original_image = .Fit (printf "800x450 %s" $anchor) }} {{ end }} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $original_image "mode" "responsive" "sizes" (slice 400 600 800) "formats" (slice "avif" "webp" "jpg") ) }} {{ $item.Title | plainify }} featured image {{ else }} {{ $item.Title | plainify }} featured image {{ end }} {{ else }}
    {{end}}
    {{ with $item.Params.content_meta }} {{ if or .content_type .difficulty }}
    {{ with .content_type }} {{ . }} {{ end }} {{ with .difficulty }} {{ i18n "difficulty" }}: {{ . }} {{ end }}
    {{ end }} {{ end }} {{ if and $item.Params.tags (gt (len $item.Params.tags) 0) }}
    {{ with index ($item.GetTerms "tags") 0 }} {{ .Page.LinkTitle }} {{ end }}
    {{ end }}

    {{ $item.Title }} {{ if $item.Params.external_link }} {{ partial "functions/get_icon" (dict "name" "arrow-top-right-on-square" "attributes" "style=\"height: 1em;\" class=\"inline-flex h-4 w-4 ml-1 align-text-top\"") }} {{ end }}

    {{ (partial "functions/get_summary" $item) | plainify | htmlUnescape | truncate 180 }}

    {{ with $item.Params.content_meta.prerequisites }} {{ $max := 2 }} {{ $count := len . }}
    {{ i18n "prerequisites" }}: {{ range (first $max .) }} {{ . }} {{ end }} {{ if gt $count $max }} +{{ sub $count $max }} {{ end }}
    {{ end }} {{ if $hasMeta }}
    {{ if $item.Params.authors }}
    {{ $slug := index $item.Params.authors 0 | urlize }} {{ $profile := partial "functions/get_author_profile" $slug }} {{ $avatar := $profile.avatar }}
    {{ if $avatar }} {{ $avatar_48 := $avatar.Process "Fill 48x48 Center webp" }} avatar {{ else }}
    {{ partial "functions/get_icon" (dict "name" "hero/user" "attributes" "class=\"w-4 h-4 text-gray-500 dark:text-gray-400\"") }}
    {{ end }}
    {{ $profile.title }}
    {{ end }} {{ if $showDate }} {{ if $isEvent }} {{ else }} {{ end }} {{ end }} {{ if and $showDate $showReadTime }} {{ end }} {{ if $showReadTime }} {{ $content := $item.Content | plainify }} {{ $words := len (split $content " ") }} {{ $readTime := div $words 200 }} {{ if lt $readTime 1 }}{{ $readTime = 1 }}{{ end }} {{ end }}
    {{ if $showReadMore }} {{ end }}
    {{ end }} {{ if $item.Params.ai_insights }}
    {{ i18n "ai_insight" }}: {{ $item.Params.ai_insights }}
    {{ end }}
    ================================================ FILE: modules/blox/layouts/_partials/views/citation--end.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/citation--start.html ================================================ {{/* Left alignment / width is set so that multiple blocks with this view & variable length content all left align. */}}
    ================================================ FILE: modules/blox/layouts/_partials/views/citation.html ================================================ {{ $item := .item }} {{ $year_value := $item.Params.event_start | default $item.Date }} {{ $year := (time $year_value).Format "2006" }} {{ $has_attachments := partial "functions/has_attachments" $item }}
    {{/* APA Style */}} {{ if eq (site.Params.hugoblox.content.citations.style | default "apa") "apa" }} ({{- $year -}}). {{ $item.Title }}. {{ if $item.Params.publication_short }} {{- $item.Params.publication_short | markdownify -}}. {{ else if $item.Params.publication }} {{- $item.Params.publication | markdownify -}}. {{ end }} {{ if $has_attachments }}
    {{ partial "page_links" (dict "page" $item "is_list" 1) }}
    {{ end }} {{/* MLA Style */}} {{ else }} {{ $item.Title }}. {{ if $item.Params.publication_short }} {{- $item.Params.publication_short | markdownify -}}, {{ else if $item.Params.publication }} {{- $item.Params.publication | markdownify -}}, {{ end }} {{- $year -}}. {{ if $has_attachments }}
    {{ partial "page_links" (dict "page" $item "is_list" 1) }}
    {{ end }} {{ end }}
    ================================================ FILE: modules/blox/layouts/_partials/views/date-title-summary--end.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/date-title-summary--start.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/date-title-summary.html ================================================ {{ $item := .item }} {{ $page := .page }} {{ $summary := partial "functions/get_summary" $item }} {{ $summary = $summary | page.RenderString }} {{ $displayDate := .item.Params.event_start | default .item.Date }}

    {{$item.Title}}

    {{$summary}}

    ================================================ FILE: modules/blox/layouts/_partials/views/slides-gallery--end.html ================================================
    ================================================ FILE: modules/blox/layouts/_partials/views/slides-gallery--start.html ================================================ {{ $columns := .config.columns | default 2 }} {{ $len := .config.len | default 1 }} {{/* Grid layout optimized for slide deck previews - 16:9 aspect ratio cards */}}
    ================================================ FILE: modules/blox/layouts/_partials/views/slides-gallery.html ================================================ {{/* Hugo Blox Slides Gallery View - Optimized for slide deck presentations */}} {{/* Features: 16:9 aspect ratio, play button overlay, slide count, tags, featured badge */}} {{ $item := .item }} {{ $link := $item.RelPermalink }} {{ $html_format := $item.OutputFormats.Get "HTML" }} {{ if not $html_format }} {{ $html_format = $item.OutputFormats.Get "html" }} {{ end }} {{ with $html_format }} {{ $link = .RelPermalink }} {{ end }} {{ $present_link := $link }} {{ $present_format := $item.OutputFormats.Get "present" }} {{ if not $present_format }} {{ $present_format = $item.OutputFormats.Get "Present" }} {{ end }} {{ with $present_format }} {{ $present_link = .RelPermalink }} {{ end }} {{ $resource := partial "functions/get_featured_image.html" $item }} {{ $index := .index }} {{ $featured_label := i18n "featured" | default "Featured" }} {{ $details_label := i18n "details" | default "Details" }} {{ $present_label := i18n "present_slides" | default "Present" }} {{ $present_fullscreen_label := i18n "present_fullscreen" | default "Present (fullscreen)" }} {{ $slides_label := i18n "slides" | default "Slides" }} {{/* Check if featured/pinned */}} {{ $isFeatured := or $item.Params.featured $item.Params.pinned }} {{/* Calculate slide count by counting "---" separators in content */}} {{ $content := $item.RawContent }} {{ $slideCount := 1 }} {{ $separators := findRE "(?m)^---$" $content }} {{ if $separators }} {{ $slideCount = add (len $separators) 1 }} {{/* Subtract 1 for front matter separator if content starts with --- */}} {{ if hasPrefix $content "---" }} {{ $slideCount = sub $slideCount 1 }} {{ end }} {{ end }} {{/* Get summary - use description from front matter or truncate content */}} {{ $summary := $item.Description | default $item.Summary | default "" }} {{ $summary = $summary | plainify | truncate 160 }}
    {{/* Featured Badge */}} {{ if $isFeatured }}
    {{ $featured_label }}
    {{ end }} {{/* Slide Preview Image - 16:9 aspect ratio */}} {{ with $resource }} {{ if strings.Contains .MediaType.SubType "svg" }} {{ $item.Title | plainify }} {{ else if ne .MediaType.SubType "gif" }} {{ $image := .Fill "800x450 Center" }} {{ $responsive := partial "functions/process_responsive_image.html" (dict "image" $image "mode" "responsive" "sizes" (slice 400 600 800) "formats" (slice "avif" "webp" "jpg") ) }} {{ $item.Title | plainify }} {{ else }} {{ $item.Title | plainify }} {{ end }} {{ else }} {{/* Fallback: Decorative gradient with slide icon - smaller, cleaner */}}
    {{ end }} {{/* Play button overlay on hover */}}
    {{/* Slide count badge */}} {{ if gt $slideCount 1 }}
    {{ $slideCount }} {{ $slides_label | lower }}
    {{ end }}
    {{/* Content Section */}}
    {{/* Tags */}} {{ if $item.Params.tags }}
    {{ range first 3 $item.Params.tags }} {{ . }} {{ end }} {{ if gt (len $item.Params.tags) 3 }} +{{ sub (len $item.Params.tags) 3 }} {{ end }}
    {{ end }} {{ $authors := slice }} {{ with $item.Params.authors }} {{ if reflect.IsSlice . }} {{ $authors = . }} {{ else }} {{ $authors = slice . }} {{ end }} {{ end }} {{ if gt (len $authors) 0 }} {{ $author := index $authors 0 }} {{ $profile := partial "functions/get_author_profile" $author }} {{ $avatar := $profile.avatar }} {{ $authorName := $author }} {{ if $profile.has_data }} {{ $authorName = $profile.title }} {{ end }}
    {{ if $avatar }} {{ $avatar_48 := $avatar.Process "Fill 48x48 Center webp" }} {{ $authorName }} {{ else }}
    {{ partial "functions/get_icon" (dict "name" "hero/user" "attributes" "class=\"w-4 h-4 text-zinc-500 dark:text-zinc-400\"") }}
    {{ end }}
    {{ $authorName }}
    {{ end }} {{/* Title */}}

    {{ $item.Title }}

    {{/* Summary */}}

    {{ if $summary }}{{ $summary }}{{ else }} {{ end }}

    {{/* Footer: Venue, Year, Details + Present Links */}}
    {{ with $item.Params.venue }} {{ . }} · {{ end }}
    ================================================ FILE: modules/blox/layouts/_shortcodes/audio.html ================================================ {{/* Audio Shortcode for Hugo Blox Kit. */}} {{/* Load audio from page dir falling back to media library at `assets/media/` and then to remote URI. */}} {{/* Supports primarily MP3 and MP4. */}} {{/* Docs: https://docs.hugoblox.com/content/writing-markdown-latex/#audio Parameters ---------- src : Path to file or url for the audio file. If a local file, first it is searched in the page directory, and then in `assets/media/` . id : optional Custom id "audio-{id}" to associate to the